open-consul/agent/consul/operator_usage_endpoint.go
Kyle Havlovitz 220ca06201
Add the operator usage instances command and api endpoint (#16205)
This endpoint shows total services, connect service instances and
billable service instances in the local datacenter or globally. Billable
instances = total service instances - connect services - consul server instances.
2023-02-08 12:07:21 -08:00

63 lines
1.7 KiB
Go

package consul
import (
"github.com/hashicorp/consul/acl"
"github.com/hashicorp/consul/agent/consul/state"
"github.com/hashicorp/consul/agent/structs"
"github.com/hashicorp/go-memdb"
)
// Usage returns counts for service usage within catalog.
func (op *Operator) Usage(args *structs.OperatorUsageRequest, reply *structs.Usage) error {
reply.Usage = make(map[string]structs.ServiceUsage)
if args.Global {
remoteDCs := op.srv.router.GetDatacenters()
for _, dc := range remoteDCs {
remoteArgs := &structs.OperatorUsageRequest{
DCSpecificRequest: structs.DCSpecificRequest{
Datacenter: dc,
QueryOptions: structs.QueryOptions{
Token: args.Token,
},
},
}
var resp structs.Usage
if _, err := op.srv.ForwardRPC("Operator.Usage", remoteArgs, &resp); err != nil {
op.logger.Warn("error forwarding usage request to remote datacenter", "datacenter", dc, "error", err)
}
if usage, ok := resp.Usage[dc]; ok {
reply.Usage[dc] = usage
}
}
}
var authzContext acl.AuthorizerContext
authz, err := op.srv.ResolveTokenAndDefaultMeta(args.Token, structs.DefaultEnterpriseMetaInDefaultPartition(), &authzContext)
if err != nil {
return err
}
err = authz.ToAllowAuthorizer().OperatorReadAllowed(&authzContext)
if err != nil {
return err
}
if err = op.srv.validateEnterpriseRequest(&args.EnterpriseMeta, false); err != nil {
return err
}
return op.srv.blockingQuery(
&args.QueryOptions,
&reply.QueryMeta,
func(ws memdb.WatchSet, state *state.Store) error {
// Get service usage.
index, serviceUsage, err := state.ServiceUsage(ws)
if err != nil {
return err
}
reply.QueryMeta.Index, reply.Usage[op.srv.config.Datacenter] = index, serviceUsage
return nil
})
}