Kaynağa Gözat

Merge pull request #2614 from ameijer/atm/protobuf-usage

Cliff Colvin 2 yıl önce
ebeveyn
işleme
88e4488af6

+ 0 - 165
core/pkg/model/customcost_helpers.go

@@ -1,165 +0,0 @@
-package model
-
-import (
-	"fmt"
-
-	"github.com/opencost/opencost/core/pkg/model/pb"
-	"github.com/opencost/opencost/core/pkg/opencost"
-	"google.golang.org/protobuf/types/known/timestamppb"
-)
-
-func ToCustomCostResponse(ccrpb *pb.CustomCostResponse) *CustomCostResponse {
-	window := opencost.NewClosedWindow(ccrpb.Start.AsTime().UTC(), ccrpb.End.AsTime().UTC())
-	var errs []error
-	for _, errStr := range ccrpb.Errors {
-		errs = append(errs, fmt.Errorf(errStr))
-	}
-	var costs []*CustomCost
-	for _, cost := range ccrpb.Costs {
-		costs = append(costs, ToCustomCost(cost, &window))
-	}
-	return &CustomCostResponse{
-		Metadata:   ccrpb.Metadata,
-		Costsource: ccrpb.CostSource,
-		Domain:     ccrpb.Domain,
-		Version:    ccrpb.Version,
-		Currency:   ccrpb.Currency,
-		Window:     window,
-		Costs:      costs,
-		Errors:     errs,
-	}
-}
-
-func ToCustomCost(ccpb *pb.CustomCost, window *opencost.Window) *CustomCost {
-	return &CustomCost{
-		Metadata:           ccpb.Metadata,
-		Zone:               ccpb.Zone,
-		BilledCost:         ccpb.BilledCost,
-		AccountName:        ccpb.AccountName,
-		ChargeCategory:     ccpb.ChargeCategory,
-		Description:        ccpb.Description,
-		ListCost:           ccpb.ListCost,
-		ListUnitPrice:      ccpb.ListUnitPrice,
-		ResourceName:       ccpb.ResourceName,
-		ResourceType:       ccpb.ResourceType,
-		Id:                 ccpb.Id,
-		ProviderId:         ccpb.ProviderId,
-		Window:             window,
-		Labels:             ccpb.Labels,
-		UsageQty:           ccpb.UsageQuantity,
-		UsageUnit:          ccpb.UsageUnit,
-		ExtendedAttributes: ToCustomCostExtendedAttributes(ccpb.ExtendedAttributes),
-	}
-}
-
-func ToCustomCostExtendedAttributes(ea *pb.CustomCostExtendedAttributes) *ExtendedCustomCostAttributes {
-	if ea == nil {
-		return nil
-	}
-	billingPeriod := opencost.NewClosedWindow(ea.BillingPeriodStart.AsTime().UTC(), ea.BillingPeriodEnd.AsTime().UTC())
-	return &ExtendedCustomCostAttributes{
-		BillingPeriod:              &billingPeriod,
-		AccountID:                  *ea.AccountId,
-		ChargeFrequency:            *ea.ChargeFrequency,
-		Subcategory:                *ea.Subcategory,
-		CommitmentDiscountCategory: *ea.CommitmentDiscountCategory,
-		CommitmentDiscountID:       *ea.CommitmentDiscountId,
-		CommitmentDiscountName:     *ea.CommitmentDiscountName,
-		CommitmentDiscountType:     *ea.CommitmentDiscountType,
-		EffectiveCost:              *ea.EffectiveCost,
-		InvoiceIssuer:              *ea.InvoiceIssuer,
-		Provider:                   *ea.Provider,
-		Publisher:                  *ea.Publisher,
-		ServiceCategory:            *ea.ServiceCategory,
-		ServiceName:                *ea.ServiceName,
-		SkuID:                      *ea.SkuId,
-		SkuPriceID:                 *ea.SkuPriceId,
-		SubAccountID:               *ea.SubAccountId,
-		SubAccountName:             *ea.SubAccountName,
-		PricingQuantity:            *ea.PricingQuantity,
-		PricingUnit:                *ea.PricingUnit,
-		PricingCategory:            *ea.PricingCategory,
-	}
-}
-
-func ToCustomCostResponsePB(ccr *CustomCostResponse) *pb.CustomCostResponse {
-	var errs []string
-	for _, err := range ccr.Errors {
-		errs = append(errs, err.Error())
-	}
-	var costs []*pb.CustomCost
-	for _, cost := range ccr.Costs {
-		costs = append(costs, ToCustomCostPB(cost))
-	}
-
-	return &pb.CustomCostResponse{
-		Metadata:   ccr.Metadata,
-		CostSource: ccr.Costsource,
-		Domain:     ccr.Domain,
-		Version:    ccr.Version,
-		Currency:   ccr.Currency,
-		Start:      timestamppb.New(ccr.Window.Start().UTC()),
-		End:        timestamppb.New(ccr.Window.End().UTC()),
-		Costs:      costs,
-		Errors:     errs,
-	}
-}
-
-func ToCustomCostPB(cc *CustomCost) *pb.CustomCost {
-	return &pb.CustomCost{
-		Metadata:           cc.Metadata,
-		Zone:               cc.Zone,
-		AccountName:        cc.AccountName,
-		ChargeCategory:     cc.ChargeCategory,
-		Description:        cc.Description,
-		ResourceName:       cc.ResourceName,
-		ResourceType:       cc.ResourceType,
-		Id:                 cc.Id,
-		ProviderId:         cc.ProviderId,
-		BilledCost:         cc.BilledCost,
-		ListCost:           cc.ListCost,
-		ListUnitPrice:      cc.ListUnitPrice,
-		UsageQuantity:      cc.UsageQty,
-		UsageUnit:          cc.UsageUnit,
-		Labels:             cc.Labels,
-		ExtendedAttributes: ToCustomCostExtendedAttributesPB(cc.ExtendedAttributes),
-	}
-}
-
-func ToCustomCostExtendedAttributesPB(ecca *ExtendedCustomCostAttributes) *pb.CustomCostExtendedAttributes {
-	if ecca == nil {
-		return nil
-	}
-
-	var billingPeriodStart *timestamppb.Timestamp
-	var billingPeriodEnd *timestamppb.Timestamp
-	if ecca != nil && !ecca.BillingPeriod.IsOpen() {
-		billingPeriodStart = timestamppb.New(ecca.BillingPeriod.Start().UTC())
-		billingPeriodEnd = timestamppb.New(ecca.BillingPeriod.End().UTC())
-	}
-
-	return &pb.CustomCostExtendedAttributes{
-		BillingPeriodStart:         billingPeriodStart,
-		BillingPeriodEnd:           billingPeriodEnd,
-		AccountId:                  &ecca.AccountID,
-		ChargeFrequency:            &ecca.ChargeFrequency,
-		Subcategory:                &ecca.Subcategory,
-		CommitmentDiscountCategory: &ecca.CommitmentDiscountCategory,
-		CommitmentDiscountId:       &ecca.CommitmentDiscountID,
-		CommitmentDiscountName:     &ecca.CommitmentDiscountName,
-		CommitmentDiscountType:     &ecca.CommitmentDiscountType,
-		EffectiveCost:              &ecca.EffectiveCost,
-		InvoiceIssuer:              &ecca.InvoiceIssuer,
-		Provider:                   &ecca.Provider,
-		Publisher:                  &ecca.Publisher,
-		ServiceCategory:            &ecca.ServiceCategory,
-		ServiceName:                &ecca.ServiceName,
-		SkuId:                      &ecca.SkuID,
-		SkuPriceId:                 &ecca.SkuPriceID,
-		SubAccountId:               &ecca.SubAccountID,
-		SubAccountName:             &ecca.SubAccountName,
-		PricingQuantity:            &ecca.PricingQuantity,
-		PricingUnit:                &ecca.PricingUnit,
-		PricingCategory:            &ecca.PricingCategory,
-	}
-}

+ 0 - 29
core/pkg/model/customcostrequest.go

@@ -1,29 +0,0 @@
-package model
-
-import (
-	"time"
-
-	"github.com/opencost/opencost/core/pkg/opencost"
-)
-
-type CustomCostRequest struct {
-	// specifies the window for data to be
-	// retrieved
-	TargetWindow *opencost.Window
-
-	// the step size to return
-	Resolution time.Duration
-}
-
-func (c CustomCostRequest) GetTargetWindow() *opencost.Window {
-	return c.TargetWindow
-}
-
-func (c CustomCostRequest) GetTargetResolution() time.Duration {
-	return c.Resolution
-}
-
-type CustomCostRequestInterface interface {
-	GetTargetWindow() *opencost.Window
-	GetTargetResolution() time.Duration
-}

+ 0 - 406
core/pkg/model/customcostresponse.go

@@ -1,406 +0,0 @@
-package model
-
-import "github.com/opencost/opencost/core/pkg/opencost"
-
-// see design at https://link.excalidraw.com/l/ABLQ24dkKai/CBEQtjH6Mr
-// for additional details on how these objects work in the context of
-// opencost's plugin system
-
-type CustomCostResponse struct {
-	// provides metadata on the Custom CostResponse
-	// deliberately left unstructured
-	Metadata map[string]string
-	// declared by plugin
-	// eg snowflake == "data management",
-	// datadog == "observability" etc
-	// intended for top level agg
-	Costsource string
-	// the name of the custom cost source
-	// e.g., "datadog"
-	Domain string
-	// the version of the Custom Cost response
-	// is set by the plugin, will vary between
-	// different plugins
-	Version string
-	// FOCUS billing currency
-	Currency string
-	// the window of the returned objects
-	Window opencost.Window
-	// array of CustomCosts
-	Costs []*CustomCost
-	// any errors in processing
-	Errors []error
-}
-
-// designed to provide a superset of the FOCUS spec
-// https://github.com/FinOps-Open-Cost-and-Usage-Spec/FOCUS_Spec/releases/latest/download/spec.pdf
-type CustomCost struct {
-	// provides metadata on the Custom CostResponse
-	// deliberately left unstructured
-	Metadata map[string]string
-	// the region that the resource was incurred
-	// corresponds to 'availability zone' of FOCUS
-	Zone string
-	// FOCUS billed Cost
-	BilledCost float32
-	// FOCUS billing account name
-	AccountName string
-	// FOCUS charge category
-	ChargeCategory string
-	// FOCUS charge description
-	Description string
-	// FOCUS List Cost
-	ListCost float32
-	// FOCUS List Unit Price
-	ListUnitPrice float32
-	// FOCUS Resource Name
-	ResourceName string
-	// FOCUS Resource type
-	// if not set, assumed to be domain
-	ResourceType string
-	// ID of the individual cost. should be globally
-	// unique. Assigned by plugin on read
-	Id string
-	// the provider's ID for the cost, if
-	// available
-	// FOCUS resource ID
-	ProviderId string
-	// the window of the returned specific
-	// custom cost
-	// equivalent to charge period start/end of FOCUS
-	Window *opencost.Window
-	// Returns key/value sets of labels
-	// equivalent to Tags in focus spec
-	Labels map[string]string
-	// FOCUS usage quantity
-	UsageQty float32
-	// FOCUS usage Unit
-	UsageUnit string
-	// Optional struct to implement other focus
-	// spec attributes
-	ExtendedAttributes *ExtendedCustomCostAttributes
-}
-
-// These parts of the FOCUS spec are not expected
-// to be implemented by every plugin
-// however, if these bits of information are available,
-// they should be provided
-type ExtendedCustomCostAttributes struct {
-	// FOCUS billing period start/end
-	BillingPeriod *opencost.Window
-	// FOCUS Billing Account ID
-	AccountID string
-	// FOCUS Charge Frequency
-	ChargeFrequency string
-	// FOCUS Charge Subcategory
-	Subcategory string
-	// FOCUS Commitment Discount Category
-	CommitmentDiscountCategory string
-	// FOCUS Commitment Discount ID
-	CommitmentDiscountID string
-	// FOCUS Commitment Discount Name
-	CommitmentDiscountName string
-	// FOCUS Commitment Discount Type
-	CommitmentDiscountType string
-	// FOCUS Effective Cost
-	EffectiveCost float32
-	// FOCUS Invoice Issuer
-	InvoiceIssuer string
-	// FOCUS Provider
-	// if unset, assumed to be domain
-	Provider string
-	// FOCUS Publisher
-	// if unset, assumed to be domain
-	Publisher string
-	// FOCUS Service Category
-	// if unset, assumed to be cost source
-	ServiceCategory string
-	// FOCUS Service Name
-	// if unset, assumed to be cost source
-	ServiceName string
-	// FOCUS SKU ID
-	SkuID string
-	// FOCUS SKU Price ID
-	SkuPriceID string
-	// FOCUS Sub Account ID
-	SubAccountID string
-	// FOCUS Sub Account Name
-	SubAccountName string
-	// FOCUS Pricing Quantity
-	PricingQuantity float32
-	// FOCUS Pricing Unit
-	PricingUnit string
-	// FOCUS Pricing Category
-	PricingCategory string
-}
-
-func (c *CustomCostResponse) Clone() CustomCostResponse {
-	win := c.GetWindow().Clone()
-	costClones := []*CustomCost{}
-
-	for _, cost := range c.GetCosts() {
-		clone := cost.Clone()
-		costClones = append(costClones, &clone)
-	}
-
-	errClones := []error{}
-	for _, err := range c.GetErrors() {
-		errClones = append(errClones, err)
-	}
-	return CustomCostResponse{
-		Metadata:   cloneMap(c.GetMetadata()),
-		Costsource: c.GetCostSource(),
-		Domain:     c.GetDomain(),
-		Version:    c.GetVersion(),
-		Currency:   c.GetCurrency(),
-		Window:     win,
-		Costs:      costClones,
-		Errors:     errClones,
-	}
-}
-
-func cloneMap(input map[string]string) map[string]string {
-	if input == nil {
-		return nil
-	}
-	result := map[string]string{}
-	for key, val := range input {
-		result[key] = val
-	}
-	return result
-}
-
-func (c *CustomCost) Clone() CustomCost {
-	win := c.GetWindow().Clone()
-	var ext ExtendedCustomCostAttributes
-	if c.GetExtendedAttributes() != nil {
-		ext = c.GetExtendedAttributes().Clone()
-	}
-	return CustomCost{
-		Metadata:           cloneMap(c.GetMetadata()),
-		Zone:               c.GetCostIncurredZone(),
-		BilledCost:         c.GetBilledCost(),
-		AccountName:        c.GetAccountName(),
-		ChargeCategory:     c.GetChargeCategory(),
-		Description:        c.GetDescription(),
-		ListCost:           c.GetListCost(),
-		ListUnitPrice:      c.GetListUnitPrice(),
-		ResourceName:       c.GetResourceName(),
-		ResourceType:       c.GetResourceType(),
-		Id:                 c.GetID(),
-		ProviderId:         c.GetProviderID(),
-		Window:             &win,
-		Labels:             cloneMap(c.GetLabels()),
-		UsageQty:           c.GetUsageQuantity(),
-		UsageUnit:          c.GetUsageUnit(),
-		ExtendedAttributes: &ext,
-	}
-}
-func (e *ExtendedCustomCostAttributes) Clone() ExtendedCustomCostAttributes {
-	win := e.BillingPeriod.Clone()
-	return ExtendedCustomCostAttributes{
-		BillingPeriod:              &win,
-		AccountID:                  e.GetAccountID(),
-		ChargeFrequency:            e.GetChargeFrequency(),
-		Subcategory:                e.GetSubcategory(),
-		CommitmentDiscountCategory: e.GetCommitmentDiscountCategory(),
-		CommitmentDiscountID:       e.GetCommitmentDiscountID(),
-		CommitmentDiscountName:     e.GetCommitmentDiscountName(),
-		CommitmentDiscountType:     e.GetCommitmentDiscountType(),
-		EffectiveCost:              e.GetEffectiveCost(),
-		InvoiceIssuer:              e.GetInvoiceIssuer(),
-		Provider:                   e.GetProvider(),
-		Publisher:                  e.GetPublisher(),
-		ServiceCategory:            e.GetServiceCategory(),
-		ServiceName:                e.GetServiceName(),
-		SkuID:                      e.GetSKUID(),
-		SkuPriceID:                 e.GetSKUPriceID(),
-		SubAccountID:               e.GetSubAccountID(),
-		SubAccountName:             e.GetSubAccountName(),
-		PricingQuantity:            e.GetPricingQuantity(),
-		PricingUnit:                e.GetPricingUnit(),
-		PricingCategory:            e.GetPricingCategory(),
-	}
-}
-
-func (e *ExtendedCustomCostAttributes) GetBillingPeriod() *opencost.Window {
-	return e.BillingPeriod
-}
-
-func (e *ExtendedCustomCostAttributes) GetAccountID() string {
-	return e.AccountID
-}
-
-func (e *ExtendedCustomCostAttributes) GetChargeFrequency() string {
-	return e.ChargeFrequency
-}
-
-func (e *ExtendedCustomCostAttributes) GetSubcategory() string {
-	return e.Subcategory
-}
-
-func (e *ExtendedCustomCostAttributes) GetCommitmentDiscountCategory() string {
-	return e.CommitmentDiscountCategory
-}
-
-func (e *ExtendedCustomCostAttributes) GetCommitmentDiscountID() string {
-	return e.CommitmentDiscountID
-}
-
-func (e *ExtendedCustomCostAttributes) GetCommitmentDiscountName() string {
-	return e.CommitmentDiscountName
-}
-
-func (e *ExtendedCustomCostAttributes) GetCommitmentDiscountType() string {
-	return e.CommitmentDiscountType
-}
-
-func (e *ExtendedCustomCostAttributes) GetEffectiveCost() float32 {
-	return e.EffectiveCost
-}
-
-func (e *ExtendedCustomCostAttributes) GetInvoiceIssuer() string {
-	return e.InvoiceIssuer
-}
-
-func (e *ExtendedCustomCostAttributes) GetProvider() string {
-	return e.Provider
-}
-
-func (e *ExtendedCustomCostAttributes) GetPublisher() string {
-	return e.Publisher
-}
-
-func (e *ExtendedCustomCostAttributes) GetServiceCategory() string {
-	return e.ServiceCategory
-}
-
-func (e *ExtendedCustomCostAttributes) GetServiceName() string {
-	return e.ServiceName
-}
-
-func (e *ExtendedCustomCostAttributes) GetSKUID() string {
-	return e.SkuID
-}
-
-func (e *ExtendedCustomCostAttributes) GetSKUPriceID() string {
-	return e.SkuPriceID
-}
-
-func (e *ExtendedCustomCostAttributes) GetSubAccountID() string {
-	return e.SubAccountID
-}
-
-func (e *ExtendedCustomCostAttributes) GetSubAccountName() string {
-	return e.SubAccountName
-}
-func (e *ExtendedCustomCostAttributes) GetPricingQuantity() float32 {
-	return e.PricingQuantity
-}
-func (e *ExtendedCustomCostAttributes) GetPricingUnit() string {
-	return e.PricingUnit
-}
-
-func (e *ExtendedCustomCostAttributes) GetPricingCategory() string {
-	return e.PricingCategory
-}
-
-func (d *CustomCost) GetMetadata() map[string]string {
-	return d.Metadata
-}
-
-func (d *CustomCost) GetCostIncurredZone() string {
-	return d.Zone
-}
-
-func (d *CustomCost) GetBilledCost() float32 {
-	return d.BilledCost
-}
-
-func (d *CustomCost) GetAccountName() string {
-	return d.AccountName
-}
-
-func (d *CustomCost) GetChargeCategory() string {
-	return d.ChargeCategory
-}
-
-func (d *CustomCost) GetDescription() string {
-	return d.Description
-}
-
-func (d *CustomCost) GetListCost() float32 {
-	return d.ListCost
-}
-
-func (d *CustomCost) GetListUnitPrice() float32 {
-	return d.ListUnitPrice
-}
-
-func (d *CustomCost) GetResourceName() string {
-	return d.ResourceName
-}
-
-func (d *CustomCost) GetID() string {
-	return d.Id
-}
-
-func (d *CustomCost) GetProviderID() string {
-	return d.ProviderId
-}
-
-func (d *CustomCost) GetWindow() *opencost.Window {
-	return d.Window
-}
-
-func (d *CustomCost) GetLabels() map[string]string {
-	return d.Labels
-}
-
-func (d *CustomCost) GetUsageQuantity() float32 {
-	return d.UsageQty
-}
-
-func (d *CustomCost) GetUsageUnit() string {
-	return d.UsageUnit
-}
-
-func (d *CustomCost) GetExtendedAttributes() *ExtendedCustomCostAttributes {
-	return d.ExtendedAttributes
-}
-
-func (d *CustomCost) GetResourceType() string {
-	return d.ResourceType
-}
-
-func (d *CustomCostResponse) GetMetadata() map[string]string {
-	return d.Metadata
-}
-
-func (d *CustomCostResponse) GetCostSource() string {
-	return d.Costsource
-}
-
-func (d *CustomCostResponse) GetDomain() string {
-	return d.Domain
-}
-
-func (d *CustomCostResponse) GetVersion() string {
-	return d.Version
-}
-
-func (d *CustomCostResponse) GetCurrency() string {
-	return d.Currency
-}
-
-func (d *CustomCostResponse) GetWindow() opencost.Window {
-	return d.Window
-}
-
-func (d *CustomCostResponse) GetCosts() []*CustomCost {
-	return d.Costs
-}
-
-func (d *CustomCostResponse) GetErrors() []error {
-	return d.Errors
-}

+ 390 - 217
core/pkg/model/pb/messages.pb.go

@@ -1,7 +1,7 @@
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.32.0
-// 	protoc        v4.25.3
+// 	protoc-gen-go v1.30.0
+// 	protoc        v3.21.12
 // source: protos/customcost/messages.proto
 
 package pb
@@ -9,6 +9,7 @@ package pb
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	durationpb "google.golang.org/protobuf/types/known/durationpb"
 	timestamppb "google.golang.org/protobuf/types/known/timestamppb"
 	reflect "reflect"
 	sync "sync"
@@ -21,6 +22,118 @@ const (
 	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
 )
 
+type CustomCostRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// the window of the returned objects
+	Start *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=start,proto3" json:"start,omitempty"`
+	End   *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=end,proto3" json:"end,omitempty"`
+	// resolution of steps to return
+	Resolution *durationpb.Duration `protobuf:"bytes,3,opt,name=resolution,proto3" json:"resolution,omitempty"`
+}
+
+func (x *CustomCostRequest) Reset() {
+	*x = CustomCostRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protos_customcost_messages_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *CustomCostRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CustomCostRequest) ProtoMessage() {}
+
+func (x *CustomCostRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protos_customcost_messages_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use CustomCostRequest.ProtoReflect.Descriptor instead.
+func (*CustomCostRequest) Descriptor() ([]byte, []int) {
+	return file_protos_customcost_messages_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *CustomCostRequest) GetStart() *timestamppb.Timestamp {
+	if x != nil {
+		return x.Start
+	}
+	return nil
+}
+
+func (x *CustomCostRequest) GetEnd() *timestamppb.Timestamp {
+	if x != nil {
+		return x.End
+	}
+	return nil
+}
+
+func (x *CustomCostRequest) GetResolution() *durationpb.Duration {
+	if x != nil {
+		return x.Resolution
+	}
+	return nil
+}
+
+type CustomCostResponseSet struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Resps []*CustomCostResponse `protobuf:"bytes,1,rep,name=resps,proto3" json:"resps,omitempty"`
+}
+
+func (x *CustomCostResponseSet) Reset() {
+	*x = CustomCostResponseSet{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protos_customcost_messages_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *CustomCostResponseSet) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CustomCostResponseSet) ProtoMessage() {}
+
+func (x *CustomCostResponseSet) ProtoReflect() protoreflect.Message {
+	mi := &file_protos_customcost_messages_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use CustomCostResponseSet.ProtoReflect.Descriptor instead.
+func (*CustomCostResponseSet) Descriptor() ([]byte, []int) {
+	return file_protos_customcost_messages_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *CustomCostResponseSet) GetResps() []*CustomCostResponse {
+	if x != nil {
+		return x.Resps
+	}
+	return nil
+}
+
 type CustomCostResponse struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -55,7 +168,7 @@ type CustomCostResponse struct {
 func (x *CustomCostResponse) Reset() {
 	*x = CustomCostResponse{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_protos_customcost_messages_proto_msgTypes[0]
+		mi := &file_protos_customcost_messages_proto_msgTypes[2]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -68,7 +181,7 @@ func (x *CustomCostResponse) String() string {
 func (*CustomCostResponse) ProtoMessage() {}
 
 func (x *CustomCostResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_protos_customcost_messages_proto_msgTypes[0]
+	mi := &file_protos_customcost_messages_proto_msgTypes[2]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -81,7 +194,7 @@ func (x *CustomCostResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use CustomCostResponse.ProtoReflect.Descriptor instead.
 func (*CustomCostResponse) Descriptor() ([]byte, []int) {
-	return file_protos_customcost_messages_proto_rawDescGZIP(), []int{0}
+	return file_protos_customcost_messages_proto_rawDescGZIP(), []int{2}
 }
 
 func (x *CustomCostResponse) GetMetadata() map[string]string {
@@ -197,7 +310,7 @@ type CustomCost struct {
 func (x *CustomCost) Reset() {
 	*x = CustomCost{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_protos_customcost_messages_proto_msgTypes[1]
+		mi := &file_protos_customcost_messages_proto_msgTypes[3]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -210,7 +323,7 @@ func (x *CustomCost) String() string {
 func (*CustomCost) ProtoMessage() {}
 
 func (x *CustomCost) ProtoReflect() protoreflect.Message {
-	mi := &file_protos_customcost_messages_proto_msgTypes[1]
+	mi := &file_protos_customcost_messages_proto_msgTypes[3]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -223,7 +336,7 @@ func (x *CustomCost) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use CustomCost.ProtoReflect.Descriptor instead.
 func (*CustomCost) Descriptor() ([]byte, []int) {
-	return file_protos_customcost_messages_proto_rawDescGZIP(), []int{1}
+	return file_protos_customcost_messages_proto_rawDescGZIP(), []int{3}
 }
 
 func (x *CustomCost) GetMetadata() map[string]string {
@@ -396,7 +509,7 @@ type CustomCostExtendedAttributes struct {
 func (x *CustomCostExtendedAttributes) Reset() {
 	*x = CustomCostExtendedAttributes{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_protos_customcost_messages_proto_msgTypes[2]
+		mi := &file_protos_customcost_messages_proto_msgTypes[4]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -409,7 +522,7 @@ func (x *CustomCostExtendedAttributes) String() string {
 func (*CustomCostExtendedAttributes) ProtoMessage() {}
 
 func (x *CustomCostExtendedAttributes) ProtoReflect() protoreflect.Message {
-	mi := &file_protos_customcost_messages_proto_msgTypes[2]
+	mi := &file_protos_customcost_messages_proto_msgTypes[4]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -422,7 +535,7 @@ func (x *CustomCostExtendedAttributes) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use CustomCostExtendedAttributes.ProtoReflect.Descriptor instead.
 func (*CustomCostExtendedAttributes) Descriptor() ([]byte, []int) {
-	return file_protos_customcost_messages_proto_rawDescGZIP(), []int{2}
+	return file_protos_customcost_messages_proto_rawDescGZIP(), []int{4}
 }
 
 func (x *CustomCostExtendedAttributes) GetBillingPeriodStart() *timestamppb.Timestamp {
@@ -587,188 +700,215 @@ var file_protos_customcost_messages_proto_rawDesc = []byte{
 	0x74, 0x6f, 0x12, 0x13, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x63, 0x6f, 0x73, 0x74, 0x2e, 0x6d,
 	0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f,
 	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
-	0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc2, 0x03, 0x0a, 0x12, 0x43, 0x75, 0x73,
-	0x74, 0x6f, 0x6d, 0x43, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
-	0x51, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x03, 0x28,
-	0x0b, 0x32, 0x35, 0x2e, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x63, 0x6f, 0x73, 0x74, 0x2e, 0x6d,
+	0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+	0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69,
+	0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xae, 0x01, 0x0a, 0x11, 0x43, 0x75, 0x73,
+	0x74, 0x6f, 0x6d, 0x43, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x30,
+	0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e,
+	0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
+	0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74,
+	0x12, 0x2c, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e,
+	0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
+	0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x12, 0x39,
+	0x0a, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01,
+	0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x72,
+	0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x56, 0x0a, 0x15, 0x43, 0x75, 0x73,
+	0x74, 0x6f, 0x6d, 0x43, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x53,
+	0x65, 0x74, 0x12, 0x3d, 0x0a, 0x05, 0x72, 0x65, 0x73, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28,
+	0x0b, 0x32, 0x27, 0x2e, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x63, 0x6f, 0x73, 0x74, 0x2e, 0x6d,
 	0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x43, 0x6f,
-	0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64,
-	0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61,
-	0x74, 0x61, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x73, 0x74, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63,
-	0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x73, 0x74, 0x53, 0x6f, 0x75,
-	0x72, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x03, 0x20,
-	0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76,
-	0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65,
-	0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63,
-	0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63,
-	0x79, 0x12, 0x30, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b,
-	0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
-	0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x05, 0x73, 0x74,
-	0x61, 0x72, 0x74, 0x12, 0x2c, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b,
-	0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
-	0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x03, 0x65, 0x6e,
-	0x64, 0x12, 0x35, 0x0a, 0x05, 0x63, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b,
-	0x32, 0x1f, 0x2e, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x63, 0x6f, 0x73, 0x74, 0x2e, 0x6d, 0x65,
-	0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x43, 0x6f, 0x73,
-	0x74, 0x52, 0x05, 0x63, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x65, 0x72, 0x72, 0x6f,
-	0x72, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73,
-	0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72,
-	0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
-	0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01,
-	0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xbe, 0x06,
-	0x0a, 0x0a, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x43, 0x6f, 0x73, 0x74, 0x12, 0x49, 0x0a, 0x08,
-	0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d,
-	0x2e, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x63, 0x6f, 0x73, 0x74, 0x2e, 0x6d, 0x65, 0x73, 0x73,
-	0x61, 0x67, 0x65, 0x73, 0x2e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x43, 0x6f, 0x73, 0x74, 0x2e,
-	0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d,
-	0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x7a, 0x6f, 0x6e, 0x65, 0x18,
-	0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x7a, 0x6f, 0x6e, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x61,
-	0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28,
-	0x09, 0x52, 0x0b, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x27,
-	0x0a, 0x0f, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x5f, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72,
-	0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x43,
-	0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72,
-	0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65,
-	0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x73,
-	0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09,
-	0x52, 0x0c, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x23,
-	0x0a, 0x0d, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18,
-	0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54,
-	0x79, 0x70, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52,
-	0x02, 0x69, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f,
-	0x69, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64,
-	0x65, 0x72, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x62, 0x69, 0x6c, 0x6c, 0x65, 0x64, 0x5f, 0x63,
-	0x6f, 0x73, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x02, 0x52, 0x0a, 0x62, 0x69, 0x6c, 0x6c, 0x65,
-	0x64, 0x43, 0x6f, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x63, 0x6f,
-	0x73, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x02, 0x52, 0x08, 0x6c, 0x69, 0x73, 0x74, 0x43, 0x6f,
-	0x73, 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x75, 0x6e, 0x69, 0x74, 0x5f,
-	0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x02, 0x52, 0x0d, 0x6c, 0x69, 0x73,
-	0x74, 0x55, 0x6e, 0x69, 0x74, 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x75, 0x73,
-	0x61, 0x67, 0x65, 0x5f, 0x71, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x0d, 0x20, 0x01,
-	0x28, 0x02, 0x52, 0x0d, 0x75, 0x73, 0x61, 0x67, 0x65, 0x51, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x74,
-	0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x75, 0x6e, 0x69, 0x74, 0x18,
-	0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, 0x61, 0x67, 0x65, 0x55, 0x6e, 0x69, 0x74,
-	0x12, 0x43, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x0f, 0x20, 0x03, 0x28, 0x0b,
-	0x32, 0x2b, 0x2e, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x63, 0x6f, 0x73, 0x74, 0x2e, 0x6d, 0x65,
-	0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x43, 0x6f, 0x73,
-	0x74, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x6c,
-	0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x67, 0x0a, 0x13, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65,
-	0x64, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x10, 0x20, 0x01,
-	0x28, 0x0b, 0x32, 0x31, 0x2e, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x63, 0x6f, 0x73, 0x74, 0x2e,
-	0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x43,
-	0x6f, 0x73, 0x74, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x41, 0x74, 0x74, 0x72, 0x69,
-	0x62, 0x75, 0x74, 0x65, 0x73, 0x48, 0x00, 0x52, 0x12, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65,
-	0x64, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x88, 0x01, 0x01, 0x1a, 0x3b,
-	0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12,
-	0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65,
-	0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
-	0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x39, 0x0a, 0x0b, 0x4c,
-	0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,
+	0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x05, 0x72, 0x65, 0x73, 0x70,
+	0x73, 0x22, 0xc2, 0x03, 0x0a, 0x12, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x43, 0x6f, 0x73, 0x74,
+	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61,
+	0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x63, 0x75, 0x73,
+	0x74, 0x6f, 0x6d, 0x63, 0x6f, 0x73, 0x74, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73,
+	0x2e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x43, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f,
+	0x6e, 0x73, 0x65, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72,
+	0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1f, 0x0a, 0x0b, 0x63,
+	0x6f, 0x73, 0x74, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x0a, 0x63, 0x6f, 0x73, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06,
+	0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f,
+	0x6d, 0x61, 0x69, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18,
+	0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a,
+	0x0a, 0x08, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x08, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x30, 0x0a, 0x05, 0x73, 0x74,
+	0x61, 0x72, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
+	0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65,
+	0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x2c, 0x0a, 0x03,
+	0x65, 0x6e, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
+	0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65,
+	0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x12, 0x35, 0x0a, 0x05, 0x63, 0x6f,
+	0x73, 0x74, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x63, 0x75, 0x73, 0x74,
+	0x6f, 0x6d, 0x63, 0x6f, 0x73, 0x74, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e,
+	0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x43, 0x6f, 0x73, 0x74, 0x52, 0x05, 0x63, 0x6f, 0x73, 0x74,
+	0x73, 0x12, 0x16, 0x0a, 0x06, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28,
+	0x09, 0x52, 0x06, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74,
+	0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,
 	0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05,
 	0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c,
-	0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x16, 0x0a, 0x14, 0x5f, 0x65, 0x78, 0x74, 0x65, 0x6e,
-	0x64, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x22, 0x94,
-	0x0c, 0x0a, 0x1c, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x43, 0x6f, 0x73, 0x74, 0x45, 0x78, 0x74,
-	0x65, 0x6e, 0x64, 0x65, 0x64, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12,
-	0x51, 0x0a, 0x14, 0x62, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x5f, 0x70, 0x65, 0x72, 0x69, 0x6f,
-	0x64, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e,
-	0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
-	0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x48, 0x00, 0x52, 0x12, 0x62, 0x69, 0x6c,
-	0x6c, 0x69, 0x6e, 0x67, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x53, 0x74, 0x61, 0x72, 0x74, 0x88,
-	0x01, 0x01, 0x12, 0x4d, 0x0a, 0x12, 0x62, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x5f, 0x70, 0x65,
-	0x72, 0x69, 0x6f, 0x64, 0x5f, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a,
-	0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
-	0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x48, 0x01, 0x52, 0x10, 0x62, 0x69,
-	0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x45, 0x6e, 0x64, 0x88, 0x01,
-	0x01, 0x12, 0x22, 0x0a, 0x0a, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18,
-	0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x02, 0x52, 0x09, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74,
-	0x49, 0x64, 0x88, 0x01, 0x01, 0x12, 0x2e, 0x0a, 0x10, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x5f,
-	0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48,
-	0x03, 0x52, 0x0f, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e,
-	0x63, 0x79, 0x88, 0x01, 0x01, 0x12, 0x25, 0x0a, 0x0b, 0x73, 0x75, 0x62, 0x63, 0x61, 0x74, 0x65,
-	0x67, 0x6f, 0x72, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x48, 0x04, 0x52, 0x0b, 0x73, 0x75,
-	0x62, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x88, 0x01, 0x01, 0x12, 0x45, 0x0a, 0x1c,
+	0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xbe, 0x06, 0x0a, 0x0a, 0x43, 0x75, 0x73, 0x74, 0x6f,
+	0x6d, 0x43, 0x6f, 0x73, 0x74, 0x12, 0x49, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
+	0x61, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d,
+	0x63, 0x6f, 0x73, 0x74, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x43, 0x75,
+	0x73, 0x74, 0x6f, 0x6d, 0x43, 0x6f, 0x73, 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
+	0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
+	0x12, 0x12, 0x0a, 0x04, 0x7a, 0x6f, 0x6e, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
+	0x7a, 0x6f, 0x6e, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f,
+	0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x63, 0x63, 0x6f,
+	0x75, 0x6e, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x63, 0x68, 0x61, 0x72, 0x67,
+	0x65, 0x5f, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x0e, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79,
+	0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18,
+	0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69,
+	0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6e,
+	0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, 0x73, 0x6f, 0x75,
+	0x72, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x73, 0x6f, 0x75,
+	0x72, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c,
+	0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0e, 0x0a, 0x02,
+	0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1f, 0x0a, 0x0b,
+	0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1f, 0x0a,
+	0x0b, 0x62, 0x69, 0x6c, 0x6c, 0x65, 0x64, 0x5f, 0x63, 0x6f, 0x73, 0x74, 0x18, 0x0a, 0x20, 0x01,
+	0x28, 0x02, 0x52, 0x0a, 0x62, 0x69, 0x6c, 0x6c, 0x65, 0x64, 0x43, 0x6f, 0x73, 0x74, 0x12, 0x1b,
+	0x0a, 0x09, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x63, 0x6f, 0x73, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28,
+	0x02, 0x52, 0x08, 0x6c, 0x69, 0x73, 0x74, 0x43, 0x6f, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x6c,
+	0x69, 0x73, 0x74, 0x5f, 0x75, 0x6e, 0x69, 0x74, 0x5f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x0c,
+	0x20, 0x01, 0x28, 0x02, 0x52, 0x0d, 0x6c, 0x69, 0x73, 0x74, 0x55, 0x6e, 0x69, 0x74, 0x50, 0x72,
+	0x69, 0x63, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x71, 0x75, 0x61,
+	0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x02, 0x52, 0x0d, 0x75, 0x73, 0x61,
+	0x67, 0x65, 0x51, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73,
+	0x61, 0x67, 0x65, 0x5f, 0x75, 0x6e, 0x69, 0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09,
+	0x75, 0x73, 0x61, 0x67, 0x65, 0x55, 0x6e, 0x69, 0x74, 0x12, 0x43, 0x0a, 0x06, 0x6c, 0x61, 0x62,
+	0x65, 0x6c, 0x73, 0x18, 0x0f, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x63, 0x75, 0x73, 0x74,
+	0x6f, 0x6d, 0x63, 0x6f, 0x73, 0x74, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e,
+	0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x43, 0x6f, 0x73, 0x74, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c,
+	0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x67,
+	0x0a, 0x13, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x69,
+	0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x63, 0x75,
+	0x73, 0x74, 0x6f, 0x6d, 0x63, 0x6f, 0x73, 0x74, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
+	0x73, 0x2e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x43, 0x6f, 0x73, 0x74, 0x45, 0x78, 0x74, 0x65,
+	0x6e, 0x64, 0x65, 0x64, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x48, 0x00,
+	0x52, 0x12, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62,
+	0x75, 0x74, 0x65, 0x73, 0x88, 0x01, 0x01, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64,
+	0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61,
+	0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
+	0x3a, 0x02, 0x38, 0x01, 0x1a, 0x39, 0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e,
+	0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42,
+	0x16, 0x0a, 0x14, 0x5f, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x74,
+	0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x22, 0x94, 0x0c, 0x0a, 0x1c, 0x43, 0x75, 0x73, 0x74,
+	0x6f, 0x6d, 0x43, 0x6f, 0x73, 0x74, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x41, 0x74,
+	0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x51, 0x0a, 0x14, 0x62, 0x69, 0x6c, 0x6c,
+	0x69, 0x6e, 0x67, 0x5f, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
+	0x6d, 0x70, 0x48, 0x00, 0x52, 0x12, 0x62, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x50, 0x65, 0x72,
+	0x69, 0x6f, 0x64, 0x53, 0x74, 0x61, 0x72, 0x74, 0x88, 0x01, 0x01, 0x12, 0x4d, 0x0a, 0x12, 0x62,
+	0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x5f, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x5f, 0x65, 0x6e,
+	0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+	0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74,
+	0x61, 0x6d, 0x70, 0x48, 0x01, 0x52, 0x10, 0x62, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x50, 0x65,
+	0x72, 0x69, 0x6f, 0x64, 0x45, 0x6e, 0x64, 0x88, 0x01, 0x01, 0x12, 0x22, 0x0a, 0x0a, 0x61, 0x63,
+	0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x02,
+	0x52, 0x09, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x64, 0x88, 0x01, 0x01, 0x12, 0x2e,
+	0x0a, 0x10, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x5f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e,
+	0x63, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x03, 0x52, 0x0f, 0x63, 0x68, 0x61, 0x72,
+	0x67, 0x65, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x88, 0x01, 0x01, 0x12, 0x25,
+	0x0a, 0x0b, 0x73, 0x75, 0x62, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x18, 0x05, 0x20,
+	0x01, 0x28, 0x09, 0x48, 0x04, 0x52, 0x0b, 0x73, 0x75, 0x62, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f,
+	0x72, 0x79, 0x88, 0x01, 0x01, 0x12, 0x45, 0x0a, 0x1c, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d,
+	0x65, 0x6e, 0x74, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x63, 0x61, 0x74,
+	0x65, 0x67, 0x6f, 0x72, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x48, 0x05, 0x52, 0x1a, 0x63,
+	0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x75, 0x6e,
+	0x74, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x88, 0x01, 0x01, 0x12, 0x39, 0x0a, 0x16,
 	0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f,
-	0x75, 0x6e, 0x74, 0x5f, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x18, 0x06, 0x20, 0x01,
-	0x28, 0x09, 0x48, 0x05, 0x52, 0x1a, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74,
-	0x44, 0x69, 0x73, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79,
-	0x88, 0x01, 0x01, 0x12, 0x39, 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e,
-	0x74, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20,
-	0x01, 0x28, 0x09, 0x48, 0x06, 0x52, 0x14, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e,
-	0x74, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x64, 0x88, 0x01, 0x01, 0x12, 0x3d,
-	0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x64, 0x69, 0x73,
-	0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09,
-	0x48, 0x07, 0x52, 0x16, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x69,
-	0x73, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x3d, 0x0a,
-	0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x64, 0x69, 0x73, 0x63,
-	0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x48,
-	0x08, 0x52, 0x16, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x69, 0x73,
-	0x63, 0x6f, 0x75, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x88, 0x01, 0x01, 0x12, 0x2a, 0x0a, 0x0e,
-	0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x63, 0x6f, 0x73, 0x74, 0x18, 0x0a,
-	0x20, 0x01, 0x28, 0x02, 0x48, 0x09, 0x52, 0x0d, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76,
-	0x65, 0x43, 0x6f, 0x73, 0x74, 0x88, 0x01, 0x01, 0x12, 0x2a, 0x0a, 0x0e, 0x69, 0x6e, 0x76, 0x6f,
-	0x69, 0x63, 0x65, 0x5f, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09,
-	0x48, 0x0a, 0x52, 0x0d, 0x69, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x49, 0x73, 0x73, 0x75, 0x65,
-	0x72, 0x88, 0x01, 0x01, 0x12, 0x1f, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72,
-	0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x48, 0x0b, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64,
-	0x65, 0x72, 0x88, 0x01, 0x01, 0x12, 0x21, 0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68,
-	0x65, 0x72, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x48, 0x0c, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c,
-	0x69, 0x73, 0x68, 0x65, 0x72, 0x88, 0x01, 0x01, 0x12, 0x2e, 0x0a, 0x10, 0x73, 0x65, 0x72, 0x76,
-	0x69, 0x63, 0x65, 0x5f, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x18, 0x0e, 0x20, 0x01,
-	0x28, 0x09, 0x48, 0x0d, 0x52, 0x0f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x61, 0x74,
-	0x65, 0x67, 0x6f, 0x72, 0x79, 0x88, 0x01, 0x01, 0x12, 0x26, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76,
-	0x69, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x48, 0x0e,
-	0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01,
-	0x12, 0x1a, 0x0a, 0x06, 0x73, 0x6b, 0x75, 0x5f, 0x69, 0x64, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09,
-	0x48, 0x0f, 0x52, 0x05, 0x73, 0x6b, 0x75, 0x49, 0x64, 0x88, 0x01, 0x01, 0x12, 0x25, 0x0a, 0x0c,
-	0x73, 0x6b, 0x75, 0x5f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x11, 0x20, 0x01,
-	0x28, 0x09, 0x48, 0x10, 0x52, 0x0a, 0x73, 0x6b, 0x75, 0x50, 0x72, 0x69, 0x63, 0x65, 0x49, 0x64,
-	0x88, 0x01, 0x01, 0x12, 0x29, 0x0a, 0x0e, 0x73, 0x75, 0x62, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75,
-	0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x12, 0x20, 0x01, 0x28, 0x09, 0x48, 0x11, 0x52, 0x0c, 0x73,
-	0x75, 0x62, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x64, 0x88, 0x01, 0x01, 0x12, 0x2d,
-	0x0a, 0x10, 0x73, 0x75, 0x62, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x6e, 0x61,
-	0x6d, 0x65, 0x18, 0x13, 0x20, 0x01, 0x28, 0x09, 0x48, 0x12, 0x52, 0x0e, 0x73, 0x75, 0x62, 0x41,
-	0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x2e, 0x0a,
-	0x10, 0x70, 0x72, 0x69, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x71, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x74,
-	0x79, 0x18, 0x14, 0x20, 0x01, 0x28, 0x02, 0x48, 0x13, 0x52, 0x0f, 0x70, 0x72, 0x69, 0x63, 0x69,
-	0x6e, 0x67, 0x51, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x88, 0x01, 0x01, 0x12, 0x26, 0x0a,
-	0x0c, 0x70, 0x72, 0x69, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x75, 0x6e, 0x69, 0x74, 0x18, 0x15, 0x20,
-	0x01, 0x28, 0x09, 0x48, 0x14, 0x52, 0x0b, 0x70, 0x72, 0x69, 0x63, 0x69, 0x6e, 0x67, 0x55, 0x6e,
-	0x69, 0x74, 0x88, 0x01, 0x01, 0x12, 0x2e, 0x0a, 0x10, 0x70, 0x72, 0x69, 0x63, 0x69, 0x6e, 0x67,
-	0x5f, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x18, 0x16, 0x20, 0x01, 0x28, 0x09, 0x48,
-	0x15, 0x52, 0x0f, 0x70, 0x72, 0x69, 0x63, 0x69, 0x6e, 0x67, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f,
-	0x72, 0x79, 0x88, 0x01, 0x01, 0x42, 0x17, 0x0a, 0x15, 0x5f, 0x62, 0x69, 0x6c, 0x6c, 0x69, 0x6e,
-	0x67, 0x5f, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x42, 0x15,
-	0x0a, 0x13, 0x5f, 0x62, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x5f, 0x70, 0x65, 0x72, 0x69, 0x6f,
-	0x64, 0x5f, 0x65, 0x6e, 0x64, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e,
-	0x74, 0x5f, 0x69, 0x64, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x5f,
-	0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x73, 0x75,
-	0x62, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x42, 0x1f, 0x0a, 0x1d, 0x5f, 0x63, 0x6f,
-	0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x75, 0x6e,
-	0x74, 0x5f, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x42, 0x19, 0x0a, 0x17, 0x5f, 0x63,
-	0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x75,
-	0x6e, 0x74, 0x5f, 0x69, 0x64, 0x42, 0x1b, 0x0a, 0x19, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74,
-	0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x6e, 0x61,
-	0x6d, 0x65, 0x42, 0x1b, 0x0a, 0x19, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e,
-	0x74, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x42,
-	0x11, 0x0a, 0x0f, 0x5f, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x63, 0x6f,
-	0x73, 0x74, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x69, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x5f, 0x69,
-	0x73, 0x73, 0x75, 0x65, 0x72, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64,
-	0x65, 0x72, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x72,
-	0x42, 0x13, 0x0a, 0x11, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x63, 0x61, 0x74,
-	0x65, 0x67, 0x6f, 0x72, 0x79, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
-	0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x73, 0x6b, 0x75, 0x5f, 0x69,
-	0x64, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x73, 0x6b, 0x75, 0x5f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x5f,
-	0x69, 0x64, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x73, 0x75, 0x62, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75,
-	0x6e, 0x74, 0x5f, 0x69, 0x64, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x73, 0x75, 0x62, 0x5f, 0x61, 0x63,
-	0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x70,
-	0x72, 0x69, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x71, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x42,
-	0x0f, 0x0a, 0x0d, 0x5f, 0x70, 0x72, 0x69, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x75, 0x6e, 0x69, 0x74,
-	0x42, 0x13, 0x0a, 0x11, 0x5f, 0x70, 0x72, 0x69, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x61, 0x74,
-	0x65, 0x67, 0x6f, 0x72, 0x79, 0x42, 0x30, 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
-	0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6f, 0x73, 0x74, 0x2f, 0x6f, 0x70, 0x65,
-	0x6e, 0x63, 0x6f, 0x73, 0x74, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x6d,
-	0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x75, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x48, 0x06, 0x52, 0x14,
+	0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x75,
+	0x6e, 0x74, 0x49, 0x64, 0x88, 0x01, 0x01, 0x12, 0x3d, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x69,
+	0x74, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x6e,
+	0x61, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x48, 0x07, 0x52, 0x16, 0x63, 0x6f, 0x6d,
+	0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x4e,
+	0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x3d, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74,
+	0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x74, 0x79,
+	0x70, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x48, 0x08, 0x52, 0x16, 0x63, 0x6f, 0x6d, 0x6d,
+	0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x54, 0x79,
+	0x70, 0x65, 0x88, 0x01, 0x01, 0x12, 0x2a, 0x0a, 0x0e, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69,
+	0x76, 0x65, 0x5f, 0x63, 0x6f, 0x73, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x02, 0x48, 0x09, 0x52,
+	0x0d, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x43, 0x6f, 0x73, 0x74, 0x88, 0x01,
+	0x01, 0x12, 0x2a, 0x0a, 0x0e, 0x69, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x73, 0x73,
+	0x75, 0x65, 0x72, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x48, 0x0a, 0x52, 0x0d, 0x69, 0x6e, 0x76,
+	0x6f, 0x69, 0x63, 0x65, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x88, 0x01, 0x01, 0x12, 0x1f, 0x0a,
+	0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x48,
+	0x0b, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x88, 0x01, 0x01, 0x12, 0x21,
+	0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x72, 0x18, 0x0d, 0x20, 0x01, 0x28,
+	0x09, 0x48, 0x0c, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x72, 0x88, 0x01,
+	0x01, 0x12, 0x2e, 0x0a, 0x10, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x63, 0x61, 0x74,
+	0x65, 0x67, 0x6f, 0x72, 0x79, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x48, 0x0d, 0x52, 0x0f, 0x73,
+	0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x88, 0x01,
+	0x01, 0x12, 0x26, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d,
+	0x65, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x48, 0x0e, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69,
+	0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x1a, 0x0a, 0x06, 0x73, 0x6b, 0x75,
+	0x5f, 0x69, 0x64, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, 0x48, 0x0f, 0x52, 0x05, 0x73, 0x6b, 0x75,
+	0x49, 0x64, 0x88, 0x01, 0x01, 0x12, 0x25, 0x0a, 0x0c, 0x73, 0x6b, 0x75, 0x5f, 0x70, 0x72, 0x69,
+	0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x48, 0x10, 0x52, 0x0a, 0x73,
+	0x6b, 0x75, 0x50, 0x72, 0x69, 0x63, 0x65, 0x49, 0x64, 0x88, 0x01, 0x01, 0x12, 0x29, 0x0a, 0x0e,
+	0x73, 0x75, 0x62, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x12,
+	0x20, 0x01, 0x28, 0x09, 0x48, 0x11, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x41, 0x63, 0x63, 0x6f, 0x75,
+	0x6e, 0x74, 0x49, 0x64, 0x88, 0x01, 0x01, 0x12, 0x2d, 0x0a, 0x10, 0x73, 0x75, 0x62, 0x5f, 0x61,
+	0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x13, 0x20, 0x01, 0x28,
+	0x09, 0x48, 0x12, 0x52, 0x0e, 0x73, 0x75, 0x62, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x4e,
+	0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x2e, 0x0a, 0x10, 0x70, 0x72, 0x69, 0x63, 0x69, 0x6e,
+	0x67, 0x5f, 0x71, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x14, 0x20, 0x01, 0x28, 0x02,
+	0x48, 0x13, 0x52, 0x0f, 0x70, 0x72, 0x69, 0x63, 0x69, 0x6e, 0x67, 0x51, 0x75, 0x61, 0x6e, 0x74,
+	0x69, 0x74, 0x79, 0x88, 0x01, 0x01, 0x12, 0x26, 0x0a, 0x0c, 0x70, 0x72, 0x69, 0x63, 0x69, 0x6e,
+	0x67, 0x5f, 0x75, 0x6e, 0x69, 0x74, 0x18, 0x15, 0x20, 0x01, 0x28, 0x09, 0x48, 0x14, 0x52, 0x0b,
+	0x70, 0x72, 0x69, 0x63, 0x69, 0x6e, 0x67, 0x55, 0x6e, 0x69, 0x74, 0x88, 0x01, 0x01, 0x12, 0x2e,
+	0x0a, 0x10, 0x70, 0x72, 0x69, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f,
+	0x72, 0x79, 0x18, 0x16, 0x20, 0x01, 0x28, 0x09, 0x48, 0x15, 0x52, 0x0f, 0x70, 0x72, 0x69, 0x63,
+	0x69, 0x6e, 0x67, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x88, 0x01, 0x01, 0x42, 0x17,
+	0x0a, 0x15, 0x5f, 0x62, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x5f, 0x70, 0x65, 0x72, 0x69, 0x6f,
+	0x64, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x42, 0x15, 0x0a, 0x13, 0x5f, 0x62, 0x69, 0x6c, 0x6c,
+	0x69, 0x6e, 0x67, 0x5f, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x5f, 0x65, 0x6e, 0x64, 0x42, 0x0d,
+	0x0a, 0x0b, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x42, 0x13, 0x0a,
+	0x11, 0x5f, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x5f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e,
+	0x63, 0x79, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x73, 0x75, 0x62, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f,
+	0x72, 0x79, 0x42, 0x1f, 0x0a, 0x1d, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e,
+	0x74, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x63, 0x61, 0x74, 0x65, 0x67,
+	0x6f, 0x72, 0x79, 0x42, 0x19, 0x0a, 0x17, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65,
+	0x6e, 0x74, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x42, 0x1b,
+	0x0a, 0x19, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x64, 0x69,
+	0x73, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x1b, 0x0a, 0x19, 0x5f,
+	0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f,
+	0x75, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x65, 0x66, 0x66,
+	0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x63, 0x6f, 0x73, 0x74, 0x42, 0x11, 0x0a, 0x0f, 0x5f,
+	0x69, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x42, 0x0b,
+	0x0a, 0x09, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x42, 0x0c, 0x0a, 0x0a, 0x5f,
+	0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x72, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x73, 0x65,
+	0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x42, 0x0f,
+	0x0a, 0x0d, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x42,
+	0x09, 0x0a, 0x07, 0x5f, 0x73, 0x6b, 0x75, 0x5f, 0x69, 0x64, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x73,
+	0x6b, 0x75, 0x5f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x42, 0x11, 0x0a, 0x0f, 0x5f,
+	0x73, 0x75, 0x62, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x42, 0x13,
+	0x0a, 0x11, 0x5f, 0x73, 0x75, 0x62, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x6e,
+	0x61, 0x6d, 0x65, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x70, 0x72, 0x69, 0x63, 0x69, 0x6e, 0x67, 0x5f,
+	0x71, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x70, 0x72, 0x69,
+	0x63, 0x69, 0x6e, 0x67, 0x5f, 0x75, 0x6e, 0x69, 0x74, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x70, 0x72,
+	0x69, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x32, 0x79,
+	0x0a, 0x11, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x43, 0x6f, 0x73, 0x74, 0x73, 0x53, 0x6f, 0x75,
+	0x72, 0x63, 0x65, 0x12, 0x64, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d,
+	0x43, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x26, 0x2e, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x63, 0x6f,
+	0x73, 0x74, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x43, 0x75, 0x73, 0x74,
+	0x6f, 0x6d, 0x43, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e,
+	0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x63, 0x6f, 0x73, 0x74, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61,
+	0x67, 0x65, 0x73, 0x2e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x43, 0x6f, 0x73, 0x74, 0x52, 0x65,
+	0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x53, 0x65, 0x74, 0x42, 0x30, 0x5a, 0x2e, 0x67, 0x69, 0x74,
+	0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6f, 0x73, 0x74,
+	0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6f, 0x73, 0x74, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70,
+	0x6b, 0x67, 0x2f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x33,
 }
 
 var (
@@ -783,31 +923,40 @@ func file_protos_customcost_messages_proto_rawDescGZIP() []byte {
 	return file_protos_customcost_messages_proto_rawDescData
 }
 
-var file_protos_customcost_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
+var file_protos_customcost_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 8)
 var file_protos_customcost_messages_proto_goTypes = []interface{}{
-	(*CustomCostResponse)(nil),           // 0: customcost.messages.CustomCostResponse
-	(*CustomCost)(nil),                   // 1: customcost.messages.CustomCost
-	(*CustomCostExtendedAttributes)(nil), // 2: customcost.messages.CustomCostExtendedAttributes
-	nil,                                  // 3: customcost.messages.CustomCostResponse.MetadataEntry
-	nil,                                  // 4: customcost.messages.CustomCost.MetadataEntry
-	nil,                                  // 5: customcost.messages.CustomCost.LabelsEntry
-	(*timestamppb.Timestamp)(nil),        // 6: google.protobuf.Timestamp
+	(*CustomCostRequest)(nil),            // 0: customcost.messages.CustomCostRequest
+	(*CustomCostResponseSet)(nil),        // 1: customcost.messages.CustomCostResponseSet
+	(*CustomCostResponse)(nil),           // 2: customcost.messages.CustomCostResponse
+	(*CustomCost)(nil),                   // 3: customcost.messages.CustomCost
+	(*CustomCostExtendedAttributes)(nil), // 4: customcost.messages.CustomCostExtendedAttributes
+	nil,                                  // 5: customcost.messages.CustomCostResponse.MetadataEntry
+	nil,                                  // 6: customcost.messages.CustomCost.MetadataEntry
+	nil,                                  // 7: customcost.messages.CustomCost.LabelsEntry
+	(*timestamppb.Timestamp)(nil),        // 8: google.protobuf.Timestamp
+	(*durationpb.Duration)(nil),          // 9: google.protobuf.Duration
 }
 var file_protos_customcost_messages_proto_depIdxs = []int32{
-	3, // 0: customcost.messages.CustomCostResponse.metadata:type_name -> customcost.messages.CustomCostResponse.MetadataEntry
-	6, // 1: customcost.messages.CustomCostResponse.start:type_name -> google.protobuf.Timestamp
-	6, // 2: customcost.messages.CustomCostResponse.end:type_name -> google.protobuf.Timestamp
-	1, // 3: customcost.messages.CustomCostResponse.costs:type_name -> customcost.messages.CustomCost
-	4, // 4: customcost.messages.CustomCost.metadata:type_name -> customcost.messages.CustomCost.MetadataEntry
-	5, // 5: customcost.messages.CustomCost.labels:type_name -> customcost.messages.CustomCost.LabelsEntry
-	2, // 6: customcost.messages.CustomCost.extended_attributes:type_name -> customcost.messages.CustomCostExtendedAttributes
-	6, // 7: customcost.messages.CustomCostExtendedAttributes.billing_period_start:type_name -> google.protobuf.Timestamp
-	6, // 8: customcost.messages.CustomCostExtendedAttributes.billing_period_end:type_name -> google.protobuf.Timestamp
-	9, // [9:9] is the sub-list for method output_type
-	9, // [9:9] is the sub-list for method input_type
-	9, // [9:9] is the sub-list for extension type_name
-	9, // [9:9] is the sub-list for extension extendee
-	0, // [0:9] is the sub-list for field type_name
+	8,  // 0: customcost.messages.CustomCostRequest.start:type_name -> google.protobuf.Timestamp
+	8,  // 1: customcost.messages.CustomCostRequest.end:type_name -> google.protobuf.Timestamp
+	9,  // 2: customcost.messages.CustomCostRequest.resolution:type_name -> google.protobuf.Duration
+	2,  // 3: customcost.messages.CustomCostResponseSet.resps:type_name -> customcost.messages.CustomCostResponse
+	5,  // 4: customcost.messages.CustomCostResponse.metadata:type_name -> customcost.messages.CustomCostResponse.MetadataEntry
+	8,  // 5: customcost.messages.CustomCostResponse.start:type_name -> google.protobuf.Timestamp
+	8,  // 6: customcost.messages.CustomCostResponse.end:type_name -> google.protobuf.Timestamp
+	3,  // 7: customcost.messages.CustomCostResponse.costs:type_name -> customcost.messages.CustomCost
+	6,  // 8: customcost.messages.CustomCost.metadata:type_name -> customcost.messages.CustomCost.MetadataEntry
+	7,  // 9: customcost.messages.CustomCost.labels:type_name -> customcost.messages.CustomCost.LabelsEntry
+	4,  // 10: customcost.messages.CustomCost.extended_attributes:type_name -> customcost.messages.CustomCostExtendedAttributes
+	8,  // 11: customcost.messages.CustomCostExtendedAttributes.billing_period_start:type_name -> google.protobuf.Timestamp
+	8,  // 12: customcost.messages.CustomCostExtendedAttributes.billing_period_end:type_name -> google.protobuf.Timestamp
+	0,  // 13: customcost.messages.CustomCostsSource.GetCustomCosts:input_type -> customcost.messages.CustomCostRequest
+	1,  // 14: customcost.messages.CustomCostsSource.GetCustomCosts:output_type -> customcost.messages.CustomCostResponseSet
+	14, // [14:15] is the sub-list for method output_type
+	13, // [13:14] is the sub-list for method input_type
+	13, // [13:13] is the sub-list for extension type_name
+	13, // [13:13] is the sub-list for extension extendee
+	0,  // [0:13] is the sub-list for field type_name
 }
 
 func init() { file_protos_customcost_messages_proto_init() }
@@ -817,7 +966,7 @@ func file_protos_customcost_messages_proto_init() {
 	}
 	if !protoimpl.UnsafeEnabled {
 		file_protos_customcost_messages_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*CustomCostResponse); i {
+			switch v := v.(*CustomCostRequest); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -829,7 +978,7 @@ func file_protos_customcost_messages_proto_init() {
 			}
 		}
 		file_protos_customcost_messages_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*CustomCost); i {
+			switch v := v.(*CustomCostResponseSet); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -841,6 +990,30 @@ func file_protos_customcost_messages_proto_init() {
 			}
 		}
 		file_protos_customcost_messages_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*CustomCostResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protos_customcost_messages_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*CustomCost); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protos_customcost_messages_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*CustomCostExtendedAttributes); i {
 			case 0:
 				return &v.state
@@ -853,17 +1026,17 @@ func file_protos_customcost_messages_proto_init() {
 			}
 		}
 	}
-	file_protos_customcost_messages_proto_msgTypes[1].OneofWrappers = []interface{}{}
-	file_protos_customcost_messages_proto_msgTypes[2].OneofWrappers = []interface{}{}
+	file_protos_customcost_messages_proto_msgTypes[3].OneofWrappers = []interface{}{}
+	file_protos_customcost_messages_proto_msgTypes[4].OneofWrappers = []interface{}{}
 	type x struct{}
 	out := protoimpl.TypeBuilder{
 		File: protoimpl.DescBuilder{
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 			RawDescriptor: file_protos_customcost_messages_proto_rawDesc,
 			NumEnums:      0,
-			NumMessages:   6,
+			NumMessages:   8,
 			NumExtensions: 0,
-			NumServices:   0,
+			NumServices:   1,
 		},
 		GoTypes:           file_protos_customcost_messages_proto_goTypes,
 		DependencyIndexes: file_protos_customcost_messages_proto_depIdxs,

+ 109 - 0
core/pkg/model/pb/messages_grpc.pb.go

@@ -0,0 +1,109 @@
+// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
+// versions:
+// - protoc-gen-go-grpc v1.3.0
+// - protoc             v3.21.12
+// source: protos/customcost/messages.proto
+
+package pb
+
+import (
+	context "context"
+	grpc "google.golang.org/grpc"
+	codes "google.golang.org/grpc/codes"
+	status "google.golang.org/grpc/status"
+)
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.32.0 or later.
+const _ = grpc.SupportPackageIsVersion7
+
+const (
+	CustomCostsSource_GetCustomCosts_FullMethodName = "/customcost.messages.CustomCostsSource/GetCustomCosts"
+)
+
+// CustomCostsSourceClient is the client API for CustomCostsSource service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
+type CustomCostsSourceClient interface {
+	GetCustomCosts(ctx context.Context, in *CustomCostRequest, opts ...grpc.CallOption) (*CustomCostResponseSet, error)
+}
+
+type customCostsSourceClient struct {
+	cc grpc.ClientConnInterface
+}
+
+func NewCustomCostsSourceClient(cc grpc.ClientConnInterface) CustomCostsSourceClient {
+	return &customCostsSourceClient{cc}
+}
+
+func (c *customCostsSourceClient) GetCustomCosts(ctx context.Context, in *CustomCostRequest, opts ...grpc.CallOption) (*CustomCostResponseSet, error) {
+	out := new(CustomCostResponseSet)
+	err := c.cc.Invoke(ctx, CustomCostsSource_GetCustomCosts_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+// CustomCostsSourceServer is the server API for CustomCostsSource service.
+// All implementations must embed UnimplementedCustomCostsSourceServer
+// for forward compatibility
+type CustomCostsSourceServer interface {
+	GetCustomCosts(context.Context, *CustomCostRequest) (*CustomCostResponseSet, error)
+	mustEmbedUnimplementedCustomCostsSourceServer()
+}
+
+// UnimplementedCustomCostsSourceServer must be embedded to have forward compatible implementations.
+type UnimplementedCustomCostsSourceServer struct {
+}
+
+func (UnimplementedCustomCostsSourceServer) GetCustomCosts(context.Context, *CustomCostRequest) (*CustomCostResponseSet, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method GetCustomCosts not implemented")
+}
+func (UnimplementedCustomCostsSourceServer) mustEmbedUnimplementedCustomCostsSourceServer() {}
+
+// UnsafeCustomCostsSourceServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to CustomCostsSourceServer will
+// result in compilation errors.
+type UnsafeCustomCostsSourceServer interface {
+	mustEmbedUnimplementedCustomCostsSourceServer()
+}
+
+func RegisterCustomCostsSourceServer(s grpc.ServiceRegistrar, srv CustomCostsSourceServer) {
+	s.RegisterService(&CustomCostsSource_ServiceDesc, srv)
+}
+
+func _CustomCostsSource_GetCustomCosts_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(CustomCostRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(CustomCostsSourceServer).GetCustomCosts(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: CustomCostsSource_GetCustomCosts_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(CustomCostsSourceServer).GetCustomCosts(ctx, req.(*CustomCostRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+// CustomCostsSource_ServiceDesc is the grpc.ServiceDesc for CustomCostsSource service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var CustomCostsSource_ServiceDesc = grpc.ServiceDesc{
+	ServiceName: "customcost.messages.CustomCostsSource",
+	HandlerType: (*CustomCostsSourceServer)(nil),
+	Methods: []grpc.MethodDesc{
+		{
+			MethodName: "GetCustomCosts",
+			Handler:    _CustomCostsSource_GetCustomCosts_Handler,
+		},
+	},
+	Streams:  []grpc.StreamDesc{},
+	Metadata: "protos/customcost/messages.proto",
+}

+ 46 - 0
core/pkg/plugin/grpc.go

@@ -0,0 +1,46 @@
+package plugin
+
+import (
+	"context"
+
+	"github.com/opencost/opencost/core/pkg/model/pb"
+)
+
+// GRPCClient is an implementation of CustomCostsSource that talks over RPC.
+type GRPCClient struct{ client pb.CustomCostsSourceClient }
+
+func (m *GRPCClient) GetCustomCosts(req pb.CustomCostRequest) []pb.CustomCostResponse {
+	resp, err := m.client.GetCustomCosts(context.Background(), &req)
+	if err != nil {
+		return []pb.CustomCostResponse{
+			{
+				Errors: []string{err.Error()},
+			},
+		}
+	}
+	derefs := []pb.CustomCostResponse{}
+	for _, resp := range resp.Resps {
+		derefs = append(derefs, *resp)
+	}
+	return derefs
+}
+
+// Here is the gRPC server that GRPCClient talks to.
+type GRPCServer struct {
+	pb.UnimplementedCustomCostsSourceServer
+	// This is the real implementation
+	Impl CustomCostSource
+}
+
+func (m *GRPCServer) GetCustomCosts(
+	ctx context.Context,
+	req *pb.CustomCostRequest) (*pb.CustomCostResponseSet, error) {
+	ptrs := []*pb.CustomCostResponse{}
+	costs := m.Impl.GetCustomCosts(*req)
+	for _, cost := range costs {
+		ptrs = append(ptrs, &cost)
+	}
+	return &pb.CustomCostResponseSet{
+		Resps: ptrs,
+	}, nil
+}

+ 10 - 44
core/pkg/plugin/plugin_interface.go

@@ -1,55 +1,20 @@
 package plugin
 
 import (
-	"encoding/gob"
-	"fmt"
-	"net/rpc"
+	"context"
 
 	"github.com/hashicorp/go-plugin"
-	"github.com/opencost/opencost/core/pkg/log"
-	"github.com/opencost/opencost/core/pkg/model"
+	"github.com/opencost/opencost/core/pkg/model/pb"
+	grpc "google.golang.org/grpc"
 )
 
 // plugin interface
 type CustomCostSource interface {
-	GetCustomCosts(req model.CustomCostRequestInterface) []model.CustomCostResponse
-}
-
-// RPC impl
-type CustomCostRPC struct{ client *rpc.Client }
-
-func init() {
-	gob.Register(model.CustomCostRequest{})
-}
-func (c *CustomCostRPC) GetCustomCosts(req model.CustomCostRequestInterface) []model.CustomCostResponse {
-
-	var resp []model.CustomCostResponse
-	err := c.client.Call("Plugin.GetCustomCosts", &req, &resp)
-	if err != nil {
-		log.Errorf("error calling plugin: %v", err)
-		resp = []model.CustomCostResponse{
-			{
-				Errors: []error{
-					fmt.Errorf("error calling plugin: %v", err),
-				},
-			},
-		}
-	}
-
-	return resp
-}
-
-type CustomCostRPCServer struct {
-	// This is the real implementation
-	Impl CustomCostSource
-}
-
-func (s *CustomCostRPCServer) GetCustomCosts(args interface{}, resp *[]model.CustomCostResponse) error {
-	*resp = s.Impl.GetCustomCosts(args.(model.CustomCostRequestInterface))
-	return nil
+	GetCustomCosts(req pb.CustomCostRequest) []pb.CustomCostResponse
 }
 
 type CustomCostPlugin struct {
+	plugin.Plugin
 	// Impl Injection
 	Impl CustomCostSource
 }
@@ -57,13 +22,14 @@ type CustomCostPlugin struct {
 // this method is called for as part of the reference plugin implementation
 // see https://github.com/hashicorp/go-plugin/blob/main/examples/basic/shared/greeter_interface.go#L59
 // for context and details
-func (p *CustomCostPlugin) Server(*plugin.MuxBroker) (interface{}, error) {
-	return &CustomCostRPCServer{Impl: p.Impl}, nil
+func (p *CustomCostPlugin) GRPCServer(broker *plugin.GRPCBroker, s *grpc.Server) error {
+	pb.RegisterCustomCostsSourceServer(s, &GRPCServer{Impl: p.Impl})
+	return nil
 }
 
 // this method is called for as part of the reference plugin implementation
 // see https://github.com/hashicorp/go-plugin/blob/main/examples/basic/shared/greeter_interface.go#L63
 // for context and details
-func (CustomCostPlugin) Client(b *plugin.MuxBroker, c *rpc.Client) (interface{}, error) {
-	return &CustomCostRPC{client: c}, nil
+func (CustomCostPlugin) GRPCClient(context context.Context, b *plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error) {
+	return &GRPCClient{client: pb.NewCustomCostsSourceClient(c)}, nil
 }

+ 11 - 9
pkg/customcost/ingestor.go

@@ -8,9 +8,11 @@ import (
 	"time"
 
 	"github.com/hashicorp/go-plugin"
+	"google.golang.org/protobuf/types/known/durationpb"
+	"google.golang.org/protobuf/types/known/timestamppb"
 
 	"github.com/opencost/opencost/core/pkg/log"
-	"github.com/opencost/opencost/core/pkg/model"
+	"github.com/opencost/opencost/core/pkg/model/pb"
 	"github.com/opencost/opencost/core/pkg/opencost"
 	ocplugin "github.com/opencost/opencost/core/pkg/plugin"
 	"github.com/opencost/opencost/core/pkg/util/stringutil"
@@ -157,10 +159,10 @@ func (ing *CustomCostIngestor) BuildWindow(start, end time.Time) {
 }
 
 func (ing *CustomCostIngestor) buildSingleDomain(start, end time.Time, domain string) {
-	target := opencost.NewWindow(&start, &end)
-	req := model.CustomCostRequest{
-		TargetWindow: &target,
-		Resolution:   ing.resolution,
+	req := pb.CustomCostRequest{
+		Start:      timestamppb.New(start),
+		End:        timestamppb.New(end),
+		Resolution: durationpb.New(ing.resolution),
 	}
 	log.Infof("ingestor: building window %s for plugin %s", opencost.NewWindow(&start, &end), domain)
 	// make RPC call via plugin
@@ -196,17 +198,17 @@ func (ing *CustomCostIngestor) buildSingleDomain(start, end time.Time, domain st
 			for _, errResp := range ccr.Errors {
 				log.Errorf("error in getting custom costs for plugin %s: %v", domain, errResp)
 			}
-			log.Errorf("not adding any costs for window %v on plugin %s", req.TargetWindow, domain)
+			log.Errorf("not adding any costs for window %v-%v on plugin %s", req.Start, req.End, domain)
 			continue
 		}
-		log.Debugf("BuildWindow[%s]: GetCustomCost: writing custom costs for window %s: %d", domain, ccr.Window, len(ccr.Costs))
+		log.Debugf("BuildWindow[%s]: GetCustomCost: writing custom costs for window %v-%v: %d", domain, ccr.Start, ccr.End, len(ccr.Costs))
 
 		err2 := ing.repo.Put(&ccr)
 		if err2 != nil {
-			log.Errorf("CustomCost[%s]: ingestor: failed to save Custom Cost Set with window %s: %s", domain, ccr.GetWindow().String(), err2.Error())
+			log.Errorf("CustomCost[%s]: ingestor: failed to save Custom Cost Set with window %v-%v: %s", domain, ccr.Start, ccr.End, err2.Error())
 		}
 
-		ing.expandCoverage(ccr.Window, domain)
+		ing.expandCoverage(opencost.NewClosedWindow(ccr.Start.AsTime(), ccr.End.AsTime()), domain)
 	}
 }
 

+ 5 - 4
pkg/customcost/pipelineservice.go

@@ -84,10 +84,11 @@ func getRegisteredPlugins(configDir string, execDir string) (map[string]*plugin.
 			"CustomCostSource": &ocplugin.CustomCostPlugin{},
 		}
 		configs[name] = &plugin.ClientConfig{
-			HandshakeConfig: handshakeConfig,
-			Plugins:         pluginMap,
-			Cmd:             exec.Command(fmt.Sprintf(execFmt, execDir, name, runtime.GOOS, version.Architecture), config),
-			Logger:          logger,
+			HandshakeConfig:  handshakeConfig,
+			Plugins:          pluginMap,
+			Cmd:              exec.Command(fmt.Sprintf(execFmt, execDir, name, runtime.GOOS, version.Architecture), config),
+			Logger:           logger,
+			AllowedProtocols: []plugin.Protocol{plugin.ProtocolGRPC},
 		}
 	}
 

+ 19 - 1
protos/customcost/messages.proto

@@ -3,7 +3,7 @@ syntax = "proto3";
 package customcost.messages;
 
 import "google/protobuf/timestamp.proto";
-
+import "google/protobuf/duration.proto";
 // Sets the golang package for the protobuf generated code
 option go_package = "github.com/opencost/opencost/core/pkg/model/pb";
 
@@ -11,6 +11,20 @@ option go_package = "github.com/opencost/opencost/core/pkg/model/pb";
 // for additional details on how these objects work in the context of
 // opencost's plugin system
 
+message CustomCostRequest {
+  // the window of the returned objects
+  google.protobuf.Timestamp start = 1;
+  google.protobuf.Timestamp end = 2;
+
+  // resolution of steps to return
+  google.protobuf.Duration resolution = 3;
+
+}
+
+message CustomCostResponseSet {
+  repeated CustomCostResponse resps = 1;
+}
+
 message CustomCostResponse {
   // provides metadata on the Custom CostResponse
   // deliberately left unstructured
@@ -133,4 +147,8 @@ message CustomCostExtendedAttributes {
   optional string pricing_unit = 21;
   // FOCUS Pricing Category
   optional string pricing_category = 22;
+}
+
+service CustomCostsSource {
+    rpc GetCustomCosts(CustomCostRequest) returns (CustomCostResponseSet);
 }