diff --git a/agent.proto b/agent.proto index f687d08..9b69fc8 100644 --- a/agent.proto +++ b/agent.proto @@ -1,57 +1,110 @@ syntax = "proto3"; import "google/protobuf/struct.proto"; +import "google/protobuf/timestamp.proto"; option go_package = "github.com/formancehq/membership/internal/grpc/generated"; package server; +// Legacy bidirectional streaming agent service. +// Kept alongside AgentService for ~3 months to support old agent binaries that +// haven't yet migrated to the pull model. Sunset target: 2026-09-09. New +// agents must use AgentService. Membership-api keeps Server registered behind +// a feature flag. service Server { rpc Join(stream Message) returns (stream Order) {} } -message ConnectRequest { - string id = 1; - map tags = 2; - string baseUrl = 3; - bool production = 4; +// Pull-based agent service. The agent polls for stacks and reports status via unary RPCs. +service AgentService { + // Agent pulls stacks that need syncing, paginated by (updated_at, id) cursor + rpc ListStacks(ListStacksRequest) returns (ListStacksResponse); + + // Agent reports observed state back to membership + rpc ReportStackStatus(ReportStackStatusRequest) returns (ReportStackStatusResponse); + rpc ReportStackDeleted(ReportStackDeletedRequest) returns (ReportStackDeletedResponse); + rpc ReportModuleStatus(ReportModuleStatusRequest) returns (ReportModuleStatusResponse); + rpc ReportModuleDeleted(ReportModuleDeletedRequest) returns (ReportModuleDeletedResponse); + + // Version management + rpc UpsertVersion(UpsertVersionRequest) returns (UpsertVersionResponse); + rpc DeleteVersion(DeleteVersionRequest) returns (DeleteVersionResponse); + + // Agent heartbeat (replaces ping/pong) + rpc Heartbeat(HeartbeatRequest) returns (HeartbeatResponse); + + // Graceful disconnect — marks the region as inactive + rpc Disconnect(DisconnectRequest) returns (DisconnectResponse); } -message Order { - reserved 5; - oneof message { - Connected connected = 1; - Stack existingStack = 2; - DeletedStack deletedStack = 3; - Ping ping = 4; - DisabledStack disabledStack = 6; - EnabledStack enabledStack = 7; - } - map metadata = 8; +// ─── ListStacks ─── + +message ListStacksRequest { + string region_id = 1; + int32 page_size = 2; + string cursor = 3; // opaque, base64-encoded (updated_at, id). Empty = start from beginning. } -message Message { - oneof message { - StatusChanged statusChanged = 1; - Pong pong = 2; - - AddedVersion addedVersion = 3; - DeletedVersion deletedVersion = 4; - UpdatedVersion updatedVersion = 5; - - ModuleStatusChanged moduleStatusChanged = 6; - ModuleDeleted moduleDeleted = 7; +message ListStacksResponse { + repeated Stack stacks = 1; + string next_cursor = 2; // empty if last page + bool has_more = 3; +} - DeletedStack stackDeleted = 8; - } - map metadata = 9; +// ─── Report messages ─── + +message ReportStackStatusRequest { + StatusChanged status_changed = 1; } +message ReportStackStatusResponse {} -message Connected {} +message ReportStackDeletedRequest { + DeletedStack stack_deleted = 1; +} +message ReportStackDeletedResponse {} -message Ping {} +message ReportModuleStatusRequest { + ModuleStatusChanged module_status_changed = 1; +} +message ReportModuleStatusResponse {} -message Pong {} +message ReportModuleDeletedRequest { + ModuleDeleted module_deleted = 1; +} +message ReportModuleDeletedResponse {} + +// ─── Version management ─── + +message UpsertVersionRequest { + string name = 1; + map versions = 2; + bool deprecated = 3; +} +message UpsertVersionResponse {} + +message DeleteVersionRequest { + string name = 1; +} +message DeleteVersionResponse {} + +// ─── Heartbeat ─── + +message HeartbeatRequest { + string region_id = 1; + string base_url = 2; + repeated string additional_base_urls = 3; + string version = 4; + bool production = 5; + repeated string capabilities = 6; + repeated string modules = 7; +} +message HeartbeatResponse {} + +message DisconnectRequest {} +message DisconnectResponse {} + +// ─── Shared data types ─── message Stack { string clusterName = 1; @@ -66,6 +119,8 @@ message Stack { map additionalLabels = 10; map additionalAnnotations = 11; repeated Module modules = 12; + string expectedStatus = 13; + google.protobuf.Timestamp updated_at = 14; } message Module { @@ -112,14 +167,6 @@ message DeletedStack { string clusterName = 1; } -message DisabledStack { - string clusterName = 1; -} - -message EnabledStack { - string clusterName = 1; -} - message AuthConfig { string clientId = 1; string clientSecret = 2; @@ -145,4 +192,58 @@ message UpdatedVersion { message DeletedVersion { string name = 1; -} \ No newline at end of file +} + +// ─── Legacy streaming protocol messages (Server.Join) ─── +// Kept for backwards compatibility with old agents. Remove on 2026-09-09 sunset. + +message ConnectRequest { + string id = 1; + map tags = 2; + string baseUrl = 3; + bool production = 4; +} + +message Order { + reserved 5; + oneof message { + Connected connected = 1; + Stack existingStack = 2; + DeletedStack deletedStack = 3; + Ping ping = 4; + DisabledStack disabledStack = 6; + EnabledStack enabledStack = 7; + } + map metadata = 8; +} + +message Message { + oneof message { + StatusChanged statusChanged = 1; + Pong pong = 2; + + AddedVersion addedVersion = 3; + DeletedVersion deletedVersion = 4; + UpdatedVersion updatedVersion = 5; + + ModuleStatusChanged moduleStatusChanged = 6; + ModuleDeleted moduleDeleted = 7; + + DeletedStack stackDeleted = 8; + } + map metadata = 9; +} + +message Connected {} + +message Ping {} + +message Pong {} + +message DisabledStack { + string clusterName = 1; +} + +message EnabledStack { + string clusterName = 1; +} diff --git a/cmd/root.go b/cmd/root.go index c3a7414..0ad6795 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -52,6 +52,7 @@ const ( productionFlag = "production" outdatedFlag = "outdated" resyncPeriodFlag = "resync-period" + pollIntervalFlag = "poll-interval" ) var rootCmd = &cobra.Command{ @@ -89,6 +90,7 @@ func init() { rootCmd.Flags().Bool(productionFlag, false, "Is a production agent") rootCmd.Flags().Bool(outdatedFlag, false, "Set the region as outdated when connecting") rootCmd.Flags().Duration(resyncPeriodFlag, 5*time.Minute, "Resync period of K8S resources") + rootCmd.Flags().Duration(pollIntervalFlag, 10*time.Second, "Poll interval for membership API") rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") } @@ -107,13 +109,13 @@ func runAgent(cmd *cobra.Command, _ []string) error { return errors.New("missing id") } - credentials, err := createGRPCTransportCredentials(cmd) + creds, err := createGRPCTransportCredentials(cmd) if err != nil { return err } dialOptions := make([]grpc.DialOption, 0) - dialOptions = append(dialOptions, grpc.WithTransportCredentials(credentials)) + dialOptions = append(dialOptions, grpc.WithTransportCredentials(creds)) baseUrlString, _ := cmd.Flags().GetString(baseUrlFlag) if baseUrlString == "" { @@ -152,6 +154,7 @@ func runAgent(cmd *cobra.Command, _ []string) error { resyncPeriod, _ := cmd.Flags().GetDuration(resyncPeriodFlag) outdated, _ := cmd.Flags().GetBool(outdatedFlag) additionalBaseUrls, _ := cmd.Flags().GetStringSlice(additionalBaseUrlsFlag) + pollInterval, _ := cmd.Flags().GetDuration(pollIntervalFlag) options := []fx.Option{ fx.Supply(restConfig), @@ -160,7 +163,6 @@ func runAgent(cmd *cobra.Command, _ []string) error { return logging.ContextWithLogger(cmd.Context(), l) }), internal.NewModule( - service.IsDebug(cmd), serverAddress, authenticator, internal.ClientInfo{ @@ -171,6 +173,7 @@ func runAgent(cmd *cobra.Command, _ []string) error { Outdated: outdated, Version: Version, }, resyncPeriod, + pollInterval, dialOptions..., ), otlp.FXModuleFromFlags(cmd, otlp.WithServiceVersion(Version)), diff --git a/go.mod b/go.mod index 731c417..d5f1480 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,6 @@ module github.com/formancehq/stack/components/agent go 1.25.0 require ( - github.com/alitto/pond v1.9.2 github.com/formancehq/go-libs/v2 v2.2.4 github.com/formancehq/operator/v3 v3.10.0 github.com/google/uuid v1.6.0 @@ -14,11 +13,9 @@ require ( github.com/spf13/cobra v1.10.2 github.com/stretchr/testify v1.11.1 github.com/zitadel/oidc/v3 v3.45.5 - go.opentelemetry.io/otel v1.43.0 - go.opentelemetry.io/otel/trace v1.43.0 go.uber.org/fx v1.24.0 - go.uber.org/mock v0.6.0 golang.org/x/oauth2 v0.36.0 + golang.org/x/sync v0.20.0 google.golang.org/grpc v1.80.0 google.golang.org/protobuf v1.36.11 k8s.io/apiextensions-apiserver v0.35.3 @@ -100,6 +97,7 @@ require ( go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 // indirect go.opentelemetry.io/contrib/propagators/b3 v1.42.0 // indirect + go.opentelemetry.io/otel v1.43.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.42.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 // indirect @@ -107,6 +105,7 @@ require ( go.opentelemetry.io/otel/log v0.18.0 // indirect go.opentelemetry.io/otel/metric v1.43.0 // indirect go.opentelemetry.io/otel/sdk v1.43.0 // indirect + go.opentelemetry.io/otel/trace v1.43.0 // indirect go.opentelemetry.io/proto/otlp v1.10.0 // indirect go.uber.org/dig v1.19.0 // indirect go.uber.org/multierr v1.11.0 // indirect @@ -116,7 +115,6 @@ require ( golang.org/x/crypto v0.52.0 // indirect golang.org/x/mod v0.35.0 // indirect golang.org/x/net v0.55.0 // indirect - golang.org/x/sync v0.20.0 // indirect golang.org/x/sys v0.45.0 // indirect golang.org/x/term v0.43.0 // indirect golang.org/x/text v0.37.0 // indirect diff --git a/go.sum b/go.sum index 90324c0..f44e170 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,6 @@ github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1 github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/ThreeDotsLabs/watermill v1.5.1 h1:t5xMivyf9tpmU3iozPqyrCZXHvoV1XQDfihas4sV0fY= github.com/ThreeDotsLabs/watermill v1.5.1/go.mod h1:Uop10dA3VeJWsSvis9qO3vbVY892LARrKAdki6WtXS4= -github.com/alitto/pond v1.9.2 h1:9Qb75z/scEZVCoSU+osVmQ0I0JOeLfdTDafrbcJ8CLs= -github.com/alitto/pond v1.9.2/go.mod h1:xQn3P/sHTYcU/1BR3i86IGIrilcrGC2LiS+E2+CJWsI= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bmatcuk/doublestar/v4 v4.10.0 h1:zU9WiOla1YA122oLM6i4EXvGW62DvKZVxIe6TYWexEs= @@ -266,8 +264,6 @@ go.uber.org/fx v1.24.0 h1:wE8mruvpg2kiiL1Vqd0CC+tr0/24XIB10Iwp2lLWzkg= go.uber.org/fx v1.24.0/go.mod h1:AmDeGyS+ZARGKM4tlH4FY2Jr63VjbEDJHtqXTGP5hbo= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= -go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= diff --git a/internal/authenticator.go b/internal/authenticator.go index 636542e..fefc641 100644 --- a/internal/authenticator.go +++ b/internal/authenticator.go @@ -3,12 +3,29 @@ package internal import ( "context" "net/http" + "strconv" + "sync" - oidcclient "github.com/zitadel/oidc/v3/pkg/client" + "github.com/zitadel/oidc/v3/pkg/client" + "github.com/zitadel/oidc/v3/pkg/oidc" "golang.org/x/oauth2/clientcredentials" + "google.golang.org/grpc" "google.golang.org/grpc/metadata" ) +const ( + metadataID = "id" + metadataBaseUrl = "baseUrl" + metadataAdditionalBaseUrls = "additionalBaseUrls" + metadataProduction = "production" + metadataOutdated = "outdated" + metadataVersion = "version" + metadataCapabilities = "capabilities" + + capabilityEE = "EE" + capabilityModuleList = "MODULE_LIST" +) + type Authenticator interface { authenticate(ctx context.Context) (metadata.MD, error) } @@ -24,28 +41,84 @@ func TokenAuthenticator(token string) AuthenticatorFn { } } -func BearerAuthenticator(issuer, clientID, clientSecret string) AuthenticatorFn { +type bearerAuthenticator struct { + issuer string + clientID string + clientSecret string - return func(ctx context.Context) (metadata.MD, error) { + mu sync.Mutex + discovery *oidc.DiscoveryConfiguration +} - discovery, err := oidcclient.Discover(ctx, issuer, http.DefaultClient) +func (b *bearerAuthenticator) authenticate(ctx context.Context) (metadata.MD, error) { + b.mu.Lock() + if b.discovery == nil { + disc, err := client.Discover(ctx, b.issuer, http.DefaultClient) if err != nil { + b.mu.Unlock() return nil, err } + b.discovery = disc + } + tokenURL := b.discovery.TokenEndpoint + b.mu.Unlock() - config := clientcredentials.Config{ - ClientID: "region_" + clientID, - ClientSecret: clientSecret, - TokenURL: discovery.TokenEndpoint, - } + config := clientcredentials.Config{ + ClientID: "region_" + b.clientID, + ClientSecret: b.clientSecret, + TokenURL: tokenURL, + } - token, err := config.Token(ctx) + token, err := config.Token(ctx) + if err != nil { + return nil, err + } + + return metadata.New(map[string]string{ + "bearer": token.AccessToken, + }), nil +} + +func BearerAuthenticator(issuer, clientID, clientSecret string) Authenticator { + return &bearerAuthenticator{ + issuer: issuer, + clientID: clientID, + clientSecret: clientSecret, + } +} + +// MetadataUnaryInterceptor returns a gRPC unary client interceptor that attaches +// authentication and client info metadata to every outgoing unary RPC call. +func MetadataUnaryInterceptor( + authenticator Authenticator, + clientInfo ClientInfo, + modules modules, + eeModules eeModules, +) grpc.UnaryClientInterceptor { + return func( + ctx context.Context, + method string, + req, reply any, + cc *grpc.ClientConn, + invoker grpc.UnaryInvoker, + opts ...grpc.CallOption, + ) error { + md, err := authenticator.authenticate(ctx) if err != nil { - return nil, err + return err } - return metadata.New(map[string]string{ - "bearer": token.AccessToken, - }), nil + md.Append(metadataID, clientInfo.ID) + md.Append(metadataBaseUrl, clientInfo.BaseUrl.String()) + md.Append(metadataAdditionalBaseUrls, clientInfo.AdditionalBaseURLs...) + md.Append(metadataProduction, strconv.FormatBool(clientInfo.Production)) + md.Append(metadataOutdated, strconv.FormatBool(clientInfo.Outdated)) + md.Append(metadataVersion, clientInfo.Version) + md.Append(metadataCapabilities, capabilityEE, capabilityModuleList) + md.Append(capabilityModuleList, modules.Singular()...) + md.Append(capabilityEE, eeModules.Singular()...) + + ctx = metadata.NewOutgoingContext(ctx, md) + return invoker(ctx, method, req, reply, cc, opts...) } } diff --git a/internal/generated/agent.pb.go b/internal/generated/agent.pb.go index d41e6a4..c575317 100644 --- a/internal/generated/agent.pb.go +++ b/internal/generated/agent.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.6 -// protoc v5.29.4 +// protoc-gen-go v1.36.11 +// protoc v7.35.0 // source: agent.proto package generated @@ -10,6 +10,7 @@ import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" structpb "google.golang.org/protobuf/types/known/structpb" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" reflect "reflect" sync "sync" unsafe "unsafe" @@ -74,30 +75,29 @@ func (StackStatus) EnumDescriptor() ([]byte, []int) { return file_agent_proto_rawDescGZIP(), []int{0} } -type ConnectRequest struct { +type ListStacksRequest struct { state protoimpl.MessageState `protogen:"open.v1"` - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Tags map[string]string `protobuf:"bytes,2,rep,name=tags,proto3" json:"tags,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - BaseUrl string `protobuf:"bytes,3,opt,name=baseUrl,proto3" json:"baseUrl,omitempty"` - Production bool `protobuf:"varint,4,opt,name=production,proto3" json:"production,omitempty"` + RegionId string `protobuf:"bytes,1,opt,name=region_id,json=regionId,proto3" json:"region_id,omitempty"` + PageSize int32 `protobuf:"varint,2,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` + Cursor string `protobuf:"bytes,3,opt,name=cursor,proto3" json:"cursor,omitempty"` // opaque, base64-encoded (updated_at, id). Empty = start from beginning. unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *ConnectRequest) Reset() { - *x = ConnectRequest{} +func (x *ListStacksRequest) Reset() { + *x = ListStacksRequest{} mi := &file_agent_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *ConnectRequest) String() string { +func (x *ListStacksRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*ConnectRequest) ProtoMessage() {} +func (*ListStacksRequest) ProtoMessage() {} -func (x *ConnectRequest) ProtoReflect() protoreflect.Message { +func (x *ListStacksRequest) ProtoReflect() protoreflect.Message { mi := &file_agent_proto_msgTypes[0] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -109,69 +109,55 @@ func (x *ConnectRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use ConnectRequest.ProtoReflect.Descriptor instead. -func (*ConnectRequest) Descriptor() ([]byte, []int) { +// Deprecated: Use ListStacksRequest.ProtoReflect.Descriptor instead. +func (*ListStacksRequest) Descriptor() ([]byte, []int) { return file_agent_proto_rawDescGZIP(), []int{0} } -func (x *ConnectRequest) GetId() string { +func (x *ListStacksRequest) GetRegionId() string { if x != nil { - return x.Id + return x.RegionId } return "" } -func (x *ConnectRequest) GetTags() map[string]string { +func (x *ListStacksRequest) GetPageSize() int32 { if x != nil { - return x.Tags + return x.PageSize } - return nil + return 0 } -func (x *ConnectRequest) GetBaseUrl() string { +func (x *ListStacksRequest) GetCursor() string { if x != nil { - return x.BaseUrl + return x.Cursor } return "" } -func (x *ConnectRequest) GetProduction() bool { - if x != nil { - return x.Production - } - return false -} - -type Order struct { - state protoimpl.MessageState `protogen:"open.v1"` - // Types that are valid to be assigned to Message: - // - // *Order_Connected - // *Order_ExistingStack - // *Order_DeletedStack - // *Order_Ping - // *Order_DisabledStack - // *Order_EnabledStack - Message isOrder_Message `protobuf_oneof:"message"` - Metadata map[string]string `protobuf:"bytes,8,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` +type ListStacksResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Stacks []*Stack `protobuf:"bytes,1,rep,name=stacks,proto3" json:"stacks,omitempty"` + NextCursor string `protobuf:"bytes,2,opt,name=next_cursor,json=nextCursor,proto3" json:"next_cursor,omitempty"` // empty if last page + HasMore bool `protobuf:"varint,3,opt,name=has_more,json=hasMore,proto3" json:"has_more,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *Order) Reset() { - *x = Order{} +func (x *ListStacksResponse) Reset() { + *x = ListStacksResponse{} mi := &file_agent_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *Order) String() string { +func (x *ListStacksResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*Order) ProtoMessage() {} +func (*ListStacksResponse) ProtoMessage() {} -func (x *Order) ProtoReflect() protoreflect.Message { +func (x *ListStacksResponse) ProtoReflect() protoreflect.Message { mi := &file_agent_proto_msgTypes[1] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -183,152 +169,134 @@ func (x *Order) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use Order.ProtoReflect.Descriptor instead. -func (*Order) Descriptor() ([]byte, []int) { +// Deprecated: Use ListStacksResponse.ProtoReflect.Descriptor instead. +func (*ListStacksResponse) Descriptor() ([]byte, []int) { return file_agent_proto_rawDescGZIP(), []int{1} } -func (x *Order) GetMessage() isOrder_Message { +func (x *ListStacksResponse) GetStacks() []*Stack { if x != nil { - return x.Message + return x.Stacks } return nil } -func (x *Order) GetConnected() *Connected { +func (x *ListStacksResponse) GetNextCursor() string { if x != nil { - if x, ok := x.Message.(*Order_Connected); ok { - return x.Connected - } + return x.NextCursor } - return nil + return "" } -func (x *Order) GetExistingStack() *Stack { +func (x *ListStacksResponse) GetHasMore() bool { if x != nil { - if x, ok := x.Message.(*Order_ExistingStack); ok { - return x.ExistingStack - } + return x.HasMore } - return nil + return false } -func (x *Order) GetDeletedStack() *DeletedStack { - if x != nil { - if x, ok := x.Message.(*Order_DeletedStack); ok { - return x.DeletedStack - } - } - return nil +type ReportStackStatusRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + StatusChanged *StatusChanged `protobuf:"bytes,1,opt,name=status_changed,json=statusChanged,proto3" json:"status_changed,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } -func (x *Order) GetPing() *Ping { - if x != nil { - if x, ok := x.Message.(*Order_Ping); ok { - return x.Ping - } - } - return nil +func (x *ReportStackStatusRequest) Reset() { + *x = ReportStackStatusRequest{} + mi := &file_agent_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } -func (x *Order) GetDisabledStack() *DisabledStack { - if x != nil { - if x, ok := x.Message.(*Order_DisabledStack); ok { - return x.DisabledStack - } - } - return nil +func (x *ReportStackStatusRequest) String() string { + return protoimpl.X.MessageStringOf(x) } -func (x *Order) GetEnabledStack() *EnabledStack { +func (*ReportStackStatusRequest) ProtoMessage() {} + +func (x *ReportStackStatusRequest) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_msgTypes[2] if x != nil { - if x, ok := x.Message.(*Order_EnabledStack); ok { - return x.EnabledStack + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) } + return ms } - return nil + return mi.MessageOf(x) } -func (x *Order) GetMetadata() map[string]string { +// Deprecated: Use ReportStackStatusRequest.ProtoReflect.Descriptor instead. +func (*ReportStackStatusRequest) Descriptor() ([]byte, []int) { + return file_agent_proto_rawDescGZIP(), []int{2} +} + +func (x *ReportStackStatusRequest) GetStatusChanged() *StatusChanged { if x != nil { - return x.Metadata + return x.StatusChanged } return nil } -type isOrder_Message interface { - isOrder_Message() -} - -type Order_Connected struct { - Connected *Connected `protobuf:"bytes,1,opt,name=connected,proto3,oneof"` +type ReportStackStatusResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } -type Order_ExistingStack struct { - ExistingStack *Stack `protobuf:"bytes,2,opt,name=existingStack,proto3,oneof"` +func (x *ReportStackStatusResponse) Reset() { + *x = ReportStackStatusResponse{} + mi := &file_agent_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } -type Order_DeletedStack struct { - DeletedStack *DeletedStack `protobuf:"bytes,3,opt,name=deletedStack,proto3,oneof"` +func (x *ReportStackStatusResponse) String() string { + return protoimpl.X.MessageStringOf(x) } -type Order_Ping struct { - Ping *Ping `protobuf:"bytes,4,opt,name=ping,proto3,oneof"` -} +func (*ReportStackStatusResponse) ProtoMessage() {} -type Order_DisabledStack struct { - DisabledStack *DisabledStack `protobuf:"bytes,6,opt,name=disabledStack,proto3,oneof"` +func (x *ReportStackStatusResponse) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -type Order_EnabledStack struct { - EnabledStack *EnabledStack `protobuf:"bytes,7,opt,name=enabledStack,proto3,oneof"` +// Deprecated: Use ReportStackStatusResponse.ProtoReflect.Descriptor instead. +func (*ReportStackStatusResponse) Descriptor() ([]byte, []int) { + return file_agent_proto_rawDescGZIP(), []int{3} } -func (*Order_Connected) isOrder_Message() {} - -func (*Order_ExistingStack) isOrder_Message() {} - -func (*Order_DeletedStack) isOrder_Message() {} - -func (*Order_Ping) isOrder_Message() {} - -func (*Order_DisabledStack) isOrder_Message() {} - -func (*Order_EnabledStack) isOrder_Message() {} - -type Message struct { - state protoimpl.MessageState `protogen:"open.v1"` - // Types that are valid to be assigned to Message: - // - // *Message_StatusChanged - // *Message_Pong - // *Message_AddedVersion - // *Message_DeletedVersion - // *Message_UpdatedVersion - // *Message_ModuleStatusChanged - // *Message_ModuleDeleted - // *Message_StackDeleted - Message isMessage_Message `protobuf_oneof:"message"` - Metadata map[string]string `protobuf:"bytes,9,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` +type ReportStackDeletedRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + StackDeleted *DeletedStack `protobuf:"bytes,1,opt,name=stack_deleted,json=stackDeleted,proto3" json:"stack_deleted,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *Message) Reset() { - *x = Message{} - mi := &file_agent_proto_msgTypes[2] +func (x *ReportStackDeletedRequest) Reset() { + *x = ReportStackDeletedRequest{} + mi := &file_agent_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *Message) String() string { +func (x *ReportStackDeletedRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*Message) ProtoMessage() {} +func (*ReportStackDeletedRequest) ProtoMessage() {} -func (x *Message) ProtoReflect() protoreflect.Message { - mi := &file_agent_proto_msgTypes[2] +func (x *ReportStackDeletedRequest) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_msgTypes[4] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -339,170 +307,119 @@ func (x *Message) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use Message.ProtoReflect.Descriptor instead. -func (*Message) Descriptor() ([]byte, []int) { - return file_agent_proto_rawDescGZIP(), []int{2} +// Deprecated: Use ReportStackDeletedRequest.ProtoReflect.Descriptor instead. +func (*ReportStackDeletedRequest) Descriptor() ([]byte, []int) { + return file_agent_proto_rawDescGZIP(), []int{4} } -func (x *Message) GetMessage() isMessage_Message { +func (x *ReportStackDeletedRequest) GetStackDeleted() *DeletedStack { if x != nil { - return x.Message + return x.StackDeleted } return nil } -func (x *Message) GetStatusChanged() *StatusChanged { - if x != nil { - if x, ok := x.Message.(*Message_StatusChanged); ok { - return x.StatusChanged - } - } - return nil +type ReportStackDeletedResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } -func (x *Message) GetPong() *Pong { - if x != nil { - if x, ok := x.Message.(*Message_Pong); ok { - return x.Pong - } - } - return nil +func (x *ReportStackDeletedResponse) Reset() { + *x = ReportStackDeletedResponse{} + mi := &file_agent_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } -func (x *Message) GetAddedVersion() *AddedVersion { - if x != nil { - if x, ok := x.Message.(*Message_AddedVersion); ok { - return x.AddedVersion - } - } - return nil +func (x *ReportStackDeletedResponse) String() string { + return protoimpl.X.MessageStringOf(x) } -func (x *Message) GetDeletedVersion() *DeletedVersion { +func (*ReportStackDeletedResponse) ProtoMessage() {} + +func (x *ReportStackDeletedResponse) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_msgTypes[5] if x != nil { - if x, ok := x.Message.(*Message_DeletedVersion); ok { - return x.DeletedVersion + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) } + return ms } - return nil + return mi.MessageOf(x) } -func (x *Message) GetUpdatedVersion() *UpdatedVersion { - if x != nil { - if x, ok := x.Message.(*Message_UpdatedVersion); ok { - return x.UpdatedVersion - } - } - return nil +// Deprecated: Use ReportStackDeletedResponse.ProtoReflect.Descriptor instead. +func (*ReportStackDeletedResponse) Descriptor() ([]byte, []int) { + return file_agent_proto_rawDescGZIP(), []int{5} } -func (x *Message) GetModuleStatusChanged() *ModuleStatusChanged { +type ReportModuleStatusRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + ModuleStatusChanged *ModuleStatusChanged `protobuf:"bytes,1,opt,name=module_status_changed,json=moduleStatusChanged,proto3" json:"module_status_changed,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ReportModuleStatusRequest) Reset() { + *x = ReportModuleStatusRequest{} + mi := &file_agent_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ReportModuleStatusRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReportModuleStatusRequest) ProtoMessage() {} + +func (x *ReportModuleStatusRequest) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_msgTypes[6] if x != nil { - if x, ok := x.Message.(*Message_ModuleStatusChanged); ok { - return x.ModuleStatusChanged + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) } + return ms } - return nil + return mi.MessageOf(x) } -func (x *Message) GetModuleDeleted() *ModuleDeleted { +// Deprecated: Use ReportModuleStatusRequest.ProtoReflect.Descriptor instead. +func (*ReportModuleStatusRequest) Descriptor() ([]byte, []int) { + return file_agent_proto_rawDescGZIP(), []int{6} +} + +func (x *ReportModuleStatusRequest) GetModuleStatusChanged() *ModuleStatusChanged { if x != nil { - if x, ok := x.Message.(*Message_ModuleDeleted); ok { - return x.ModuleDeleted - } + return x.ModuleStatusChanged } return nil } -func (x *Message) GetStackDeleted() *DeletedStack { - if x != nil { - if x, ok := x.Message.(*Message_StackDeleted); ok { - return x.StackDeleted - } - } - return nil -} - -func (x *Message) GetMetadata() map[string]string { - if x != nil { - return x.Metadata - } - return nil -} - -type isMessage_Message interface { - isMessage_Message() -} - -type Message_StatusChanged struct { - StatusChanged *StatusChanged `protobuf:"bytes,1,opt,name=statusChanged,proto3,oneof"` -} - -type Message_Pong struct { - Pong *Pong `protobuf:"bytes,2,opt,name=pong,proto3,oneof"` -} - -type Message_AddedVersion struct { - AddedVersion *AddedVersion `protobuf:"bytes,3,opt,name=addedVersion,proto3,oneof"` -} - -type Message_DeletedVersion struct { - DeletedVersion *DeletedVersion `protobuf:"bytes,4,opt,name=deletedVersion,proto3,oneof"` -} - -type Message_UpdatedVersion struct { - UpdatedVersion *UpdatedVersion `protobuf:"bytes,5,opt,name=updatedVersion,proto3,oneof"` -} - -type Message_ModuleStatusChanged struct { - ModuleStatusChanged *ModuleStatusChanged `protobuf:"bytes,6,opt,name=moduleStatusChanged,proto3,oneof"` -} - -type Message_ModuleDeleted struct { - ModuleDeleted *ModuleDeleted `protobuf:"bytes,7,opt,name=moduleDeleted,proto3,oneof"` -} - -type Message_StackDeleted struct { - StackDeleted *DeletedStack `protobuf:"bytes,8,opt,name=stackDeleted,proto3,oneof"` -} - -func (*Message_StatusChanged) isMessage_Message() {} - -func (*Message_Pong) isMessage_Message() {} - -func (*Message_AddedVersion) isMessage_Message() {} - -func (*Message_DeletedVersion) isMessage_Message() {} - -func (*Message_UpdatedVersion) isMessage_Message() {} - -func (*Message_ModuleStatusChanged) isMessage_Message() {} - -func (*Message_ModuleDeleted) isMessage_Message() {} - -func (*Message_StackDeleted) isMessage_Message() {} - -type Connected struct { +type ReportModuleStatusResponse struct { state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *Connected) Reset() { - *x = Connected{} - mi := &file_agent_proto_msgTypes[3] +func (x *ReportModuleStatusResponse) Reset() { + *x = ReportModuleStatusResponse{} + mi := &file_agent_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *Connected) String() string { +func (x *ReportModuleStatusResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*Connected) ProtoMessage() {} +func (*ReportModuleStatusResponse) ProtoMessage() {} -func (x *Connected) ProtoReflect() protoreflect.Message { - mi := &file_agent_proto_msgTypes[3] +func (x *ReportModuleStatusResponse) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_msgTypes[7] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -513,32 +430,33 @@ func (x *Connected) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use Connected.ProtoReflect.Descriptor instead. -func (*Connected) Descriptor() ([]byte, []int) { - return file_agent_proto_rawDescGZIP(), []int{3} +// Deprecated: Use ReportModuleStatusResponse.ProtoReflect.Descriptor instead. +func (*ReportModuleStatusResponse) Descriptor() ([]byte, []int) { + return file_agent_proto_rawDescGZIP(), []int{7} } -type Ping struct { +type ReportModuleDeletedRequest struct { state protoimpl.MessageState `protogen:"open.v1"` + ModuleDeleted *ModuleDeleted `protobuf:"bytes,1,opt,name=module_deleted,json=moduleDeleted,proto3" json:"module_deleted,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *Ping) Reset() { - *x = Ping{} - mi := &file_agent_proto_msgTypes[4] +func (x *ReportModuleDeletedRequest) Reset() { + *x = ReportModuleDeletedRequest{} + mi := &file_agent_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *Ping) String() string { +func (x *ReportModuleDeletedRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*Ping) ProtoMessage() {} +func (*ReportModuleDeletedRequest) ProtoMessage() {} -func (x *Ping) ProtoReflect() protoreflect.Message { - mi := &file_agent_proto_msgTypes[4] +func (x *ReportModuleDeletedRequest) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_msgTypes[8] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -549,32 +467,39 @@ func (x *Ping) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use Ping.ProtoReflect.Descriptor instead. -func (*Ping) Descriptor() ([]byte, []int) { - return file_agent_proto_rawDescGZIP(), []int{4} +// Deprecated: Use ReportModuleDeletedRequest.ProtoReflect.Descriptor instead. +func (*ReportModuleDeletedRequest) Descriptor() ([]byte, []int) { + return file_agent_proto_rawDescGZIP(), []int{8} } -type Pong struct { +func (x *ReportModuleDeletedRequest) GetModuleDeleted() *ModuleDeleted { + if x != nil { + return x.ModuleDeleted + } + return nil +} + +type ReportModuleDeletedResponse struct { state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *Pong) Reset() { - *x = Pong{} - mi := &file_agent_proto_msgTypes[5] +func (x *ReportModuleDeletedResponse) Reset() { + *x = ReportModuleDeletedResponse{} + mi := &file_agent_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *Pong) String() string { +func (x *ReportModuleDeletedResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*Pong) ProtoMessage() {} +func (*ReportModuleDeletedResponse) ProtoMessage() {} -func (x *Pong) ProtoReflect() protoreflect.Message { - mi := &file_agent_proto_msgTypes[5] +func (x *ReportModuleDeletedResponse) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_msgTypes[9] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -585,42 +510,35 @@ func (x *Pong) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use Pong.ProtoReflect.Descriptor instead. -func (*Pong) Descriptor() ([]byte, []int) { - return file_agent_proto_rawDescGZIP(), []int{5} +// Deprecated: Use ReportModuleDeletedResponse.ProtoReflect.Descriptor instead. +func (*ReportModuleDeletedResponse) Descriptor() ([]byte, []int) { + return file_agent_proto_rawDescGZIP(), []int{9} } -type Stack struct { - state protoimpl.MessageState `protogen:"open.v1"` - ClusterName string `protobuf:"bytes,1,opt,name=clusterName,proto3" json:"clusterName,omitempty"` - Seed string `protobuf:"bytes,2,opt,name=seed,proto3" json:"seed,omitempty"` - AuthConfig *AuthConfig `protobuf:"bytes,3,opt,name=authConfig,proto3" json:"authConfig,omitempty"` - StaticClients []*AuthClient `protobuf:"bytes,4,rep,name=staticClients,proto3" json:"staticClients,omitempty"` - StargateConfig *StargateConfig `protobuf:"bytes,5,opt,name=stargateConfig,proto3" json:"stargateConfig,omitempty"` - Disabled bool `protobuf:"varint,6,opt,name=disabled,proto3" json:"disabled,omitempty"` - Versions string `protobuf:"bytes,8,opt,name=versions,proto3" json:"versions,omitempty"` - AdditionalLabels map[string]string `protobuf:"bytes,10,rep,name=additionalLabels,proto3" json:"additionalLabels,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - AdditionalAnnotations map[string]string `protobuf:"bytes,11,rep,name=additionalAnnotations,proto3" json:"additionalAnnotations,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - Modules []*Module `protobuf:"bytes,12,rep,name=modules,proto3" json:"modules,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache +type UpsertVersionRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Versions map[string]string `protobuf:"bytes,2,rep,name=versions,proto3" json:"versions,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + Deprecated bool `protobuf:"varint,3,opt,name=deprecated,proto3" json:"deprecated,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } -func (x *Stack) Reset() { - *x = Stack{} - mi := &file_agent_proto_msgTypes[6] +func (x *UpsertVersionRequest) Reset() { + *x = UpsertVersionRequest{} + mi := &file_agent_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *Stack) String() string { +func (x *UpsertVersionRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*Stack) ProtoMessage() {} +func (*UpsertVersionRequest) ProtoMessage() {} -func (x *Stack) ProtoReflect() protoreflect.Message { - mi := &file_agent_proto_msgTypes[6] +func (x *UpsertVersionRequest) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_msgTypes[10] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -631,103 +549,90 @@ func (x *Stack) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use Stack.ProtoReflect.Descriptor instead. -func (*Stack) Descriptor() ([]byte, []int) { - return file_agent_proto_rawDescGZIP(), []int{6} -} - -func (x *Stack) GetClusterName() string { - if x != nil { - return x.ClusterName - } - return "" +// Deprecated: Use UpsertVersionRequest.ProtoReflect.Descriptor instead. +func (*UpsertVersionRequest) Descriptor() ([]byte, []int) { + return file_agent_proto_rawDescGZIP(), []int{10} } -func (x *Stack) GetSeed() string { +func (x *UpsertVersionRequest) GetName() string { if x != nil { - return x.Seed + return x.Name } return "" } -func (x *Stack) GetAuthConfig() *AuthConfig { +func (x *UpsertVersionRequest) GetVersions() map[string]string { if x != nil { - return x.AuthConfig + return x.Versions } return nil } -func (x *Stack) GetStaticClients() []*AuthClient { +func (x *UpsertVersionRequest) GetDeprecated() bool { if x != nil { - return x.StaticClients + return x.Deprecated } - return nil + return false } -func (x *Stack) GetStargateConfig() *StargateConfig { - if x != nil { - return x.StargateConfig - } - return nil +type UpsertVersionResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } -func (x *Stack) GetDisabled() bool { - if x != nil { - return x.Disabled - } - return false +func (x *UpsertVersionResponse) Reset() { + *x = UpsertVersionResponse{} + mi := &file_agent_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } -func (x *Stack) GetVersions() string { - if x != nil { - return x.Versions - } - return "" +func (x *UpsertVersionResponse) String() string { + return protoimpl.X.MessageStringOf(x) } -func (x *Stack) GetAdditionalLabels() map[string]string { - if x != nil { - return x.AdditionalLabels - } - return nil -} +func (*UpsertVersionResponse) ProtoMessage() {} -func (x *Stack) GetAdditionalAnnotations() map[string]string { +func (x *UpsertVersionResponse) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_msgTypes[11] if x != nil { - return x.AdditionalAnnotations + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms } - return nil + return mi.MessageOf(x) } -func (x *Stack) GetModules() []*Module { - if x != nil { - return x.Modules - } - return nil +// Deprecated: Use UpsertVersionResponse.ProtoReflect.Descriptor instead. +func (*UpsertVersionResponse) Descriptor() ([]byte, []int) { + return file_agent_proto_rawDescGZIP(), []int{11} } -type Module struct { +type DeleteVersionRequest struct { state protoimpl.MessageState `protogen:"open.v1"` Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *Module) Reset() { - *x = Module{} - mi := &file_agent_proto_msgTypes[7] +func (x *DeleteVersionRequest) Reset() { + *x = DeleteVersionRequest{} + mi := &file_agent_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *Module) String() string { +func (x *DeleteVersionRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*Module) ProtoMessage() {} +func (*DeleteVersionRequest) ProtoMessage() {} -func (x *Module) ProtoReflect() protoreflect.Message { - mi := &file_agent_proto_msgTypes[7] +func (x *DeleteVersionRequest) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_msgTypes[12] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -738,41 +643,39 @@ func (x *Module) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use Module.ProtoReflect.Descriptor instead. -func (*Module) Descriptor() ([]byte, []int) { - return file_agent_proto_rawDescGZIP(), []int{7} +// Deprecated: Use DeleteVersionRequest.ProtoReflect.Descriptor instead. +func (*DeleteVersionRequest) Descriptor() ([]byte, []int) { + return file_agent_proto_rawDescGZIP(), []int{12} } -func (x *Module) GetName() string { +func (x *DeleteVersionRequest) GetName() string { if x != nil { return x.Name } return "" } -type VersionKind struct { +type DeleteVersionResponse struct { state protoimpl.MessageState `protogen:"open.v1"` - Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"` - Kind string `protobuf:"bytes,2,opt,name=kind,proto3" json:"kind,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *VersionKind) Reset() { - *x = VersionKind{} - mi := &file_agent_proto_msgTypes[8] +func (x *DeleteVersionResponse) Reset() { + *x = DeleteVersionResponse{} + mi := &file_agent_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *VersionKind) String() string { +func (x *DeleteVersionResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*VersionKind) ProtoMessage() {} +func (*DeleteVersionResponse) ProtoMessage() {} -func (x *VersionKind) ProtoReflect() protoreflect.Message { - mi := &file_agent_proto_msgTypes[8] +func (x *DeleteVersionResponse) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_msgTypes[13] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -783,49 +686,39 @@ func (x *VersionKind) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use VersionKind.ProtoReflect.Descriptor instead. -func (*VersionKind) Descriptor() ([]byte, []int) { - return file_agent_proto_rawDescGZIP(), []int{8} +// Deprecated: Use DeleteVersionResponse.ProtoReflect.Descriptor instead. +func (*DeleteVersionResponse) Descriptor() ([]byte, []int) { + return file_agent_proto_rawDescGZIP(), []int{13} } -func (x *VersionKind) GetVersion() string { - if x != nil { - return x.Version - } - return "" +type HeartbeatRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + RegionId string `protobuf:"bytes,1,opt,name=region_id,json=regionId,proto3" json:"region_id,omitempty"` + BaseUrl string `protobuf:"bytes,2,opt,name=base_url,json=baseUrl,proto3" json:"base_url,omitempty"` + AdditionalBaseUrls []string `protobuf:"bytes,3,rep,name=additional_base_urls,json=additionalBaseUrls,proto3" json:"additional_base_urls,omitempty"` + Version string `protobuf:"bytes,4,opt,name=version,proto3" json:"version,omitempty"` + Production bool `protobuf:"varint,5,opt,name=production,proto3" json:"production,omitempty"` + Capabilities []string `protobuf:"bytes,6,rep,name=capabilities,proto3" json:"capabilities,omitempty"` + Modules []string `protobuf:"bytes,7,rep,name=modules,proto3" json:"modules,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } -func (x *VersionKind) GetKind() string { - if x != nil { - return x.Kind - } - return "" +func (x *HeartbeatRequest) Reset() { + *x = HeartbeatRequest{} + mi := &file_agent_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } -type ModuleStatusChanged struct { - state protoimpl.MessageState `protogen:"open.v1"` - ClusterName string `protobuf:"bytes,1,opt,name=clusterName,proto3" json:"clusterName,omitempty"` - Status *structpb.Struct `protobuf:"bytes,2,opt,name=status,proto3" json:"status,omitempty"` - Vk *VersionKind `protobuf:"bytes,3,opt,name=vk,proto3" json:"vk,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *ModuleStatusChanged) Reset() { - *x = ModuleStatusChanged{} - mi := &file_agent_proto_msgTypes[9] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *ModuleStatusChanged) String() string { +func (x *HeartbeatRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*ModuleStatusChanged) ProtoMessage() {} +func (*HeartbeatRequest) ProtoMessage() {} -func (x *ModuleStatusChanged) ProtoReflect() protoreflect.Message { - mi := &file_agent_proto_msgTypes[9] +func (x *HeartbeatRequest) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_msgTypes[14] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -836,109 +729,81 @@ func (x *ModuleStatusChanged) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use ModuleStatusChanged.ProtoReflect.Descriptor instead. -func (*ModuleStatusChanged) Descriptor() ([]byte, []int) { - return file_agent_proto_rawDescGZIP(), []int{9} +// Deprecated: Use HeartbeatRequest.ProtoReflect.Descriptor instead. +func (*HeartbeatRequest) Descriptor() ([]byte, []int) { + return file_agent_proto_rawDescGZIP(), []int{14} } -func (x *ModuleStatusChanged) GetClusterName() string { +func (x *HeartbeatRequest) GetRegionId() string { if x != nil { - return x.ClusterName + return x.RegionId } return "" } -func (x *ModuleStatusChanged) GetStatus() *structpb.Struct { +func (x *HeartbeatRequest) GetBaseUrl() string { if x != nil { - return x.Status + return x.BaseUrl } - return nil + return "" } -func (x *ModuleStatusChanged) GetVk() *VersionKind { +func (x *HeartbeatRequest) GetAdditionalBaseUrls() []string { if x != nil { - return x.Vk + return x.AdditionalBaseUrls } return nil } -type ModuleDeleted struct { - state protoimpl.MessageState `protogen:"open.v1"` - ClusterName string `protobuf:"bytes,1,opt,name=clusterName,proto3" json:"clusterName,omitempty"` - Vk *VersionKind `protobuf:"bytes,2,opt,name=vk,proto3" json:"vk,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *ModuleDeleted) Reset() { - *x = ModuleDeleted{} - mi := &file_agent_proto_msgTypes[10] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *ModuleDeleted) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ModuleDeleted) ProtoMessage() {} - -func (x *ModuleDeleted) ProtoReflect() protoreflect.Message { - mi := &file_agent_proto_msgTypes[10] +func (x *HeartbeatRequest) GetVersion() string { if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms + return x.Version } - return mi.MessageOf(x) + return "" } -// Deprecated: Use ModuleDeleted.ProtoReflect.Descriptor instead. -func (*ModuleDeleted) Descriptor() ([]byte, []int) { - return file_agent_proto_rawDescGZIP(), []int{10} +func (x *HeartbeatRequest) GetProduction() bool { + if x != nil { + return x.Production + } + return false } -func (x *ModuleDeleted) GetClusterName() string { +func (x *HeartbeatRequest) GetCapabilities() []string { if x != nil { - return x.ClusterName + return x.Capabilities } - return "" + return nil } -func (x *ModuleDeleted) GetVk() *VersionKind { +func (x *HeartbeatRequest) GetModules() []string { if x != nil { - return x.Vk + return x.Modules } return nil } -type StatusChanged struct { +type HeartbeatResponse struct { state protoimpl.MessageState `protogen:"open.v1"` - ClusterName string `protobuf:"bytes,1,opt,name=clusterName,proto3" json:"clusterName,omitempty"` - Status StackStatus `protobuf:"varint,2,opt,name=status,proto3,enum=server.StackStatus" json:"status,omitempty"` - Statuses *structpb.Struct `protobuf:"bytes,3,opt,name=statuses,proto3" json:"statuses,omitempty"` - Vk *VersionKind `protobuf:"bytes,4,opt,name=vk,proto3" json:"vk,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *StatusChanged) Reset() { - *x = StatusChanged{} - mi := &file_agent_proto_msgTypes[11] +func (x *HeartbeatResponse) Reset() { + *x = HeartbeatResponse{} + mi := &file_agent_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *StatusChanged) String() string { +func (x *HeartbeatResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*StatusChanged) ProtoMessage() {} +func (*HeartbeatResponse) ProtoMessage() {} -func (x *StatusChanged) ProtoReflect() protoreflect.Message { - mi := &file_agent_proto_msgTypes[11] +func (x *HeartbeatResponse) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_msgTypes[15] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -949,63 +814,32 @@ func (x *StatusChanged) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use StatusChanged.ProtoReflect.Descriptor instead. -func (*StatusChanged) Descriptor() ([]byte, []int) { - return file_agent_proto_rawDescGZIP(), []int{11} -} - -func (x *StatusChanged) GetClusterName() string { - if x != nil { - return x.ClusterName - } - return "" -} - -func (x *StatusChanged) GetStatus() StackStatus { - if x != nil { - return x.Status - } - return StackStatus_Progressing -} - -func (x *StatusChanged) GetStatuses() *structpb.Struct { - if x != nil { - return x.Statuses - } - return nil -} - -func (x *StatusChanged) GetVk() *VersionKind { - if x != nil { - return x.Vk - } - return nil +// Deprecated: Use HeartbeatResponse.ProtoReflect.Descriptor instead. +func (*HeartbeatResponse) Descriptor() ([]byte, []int) { + return file_agent_proto_rawDescGZIP(), []int{15} } -type StargateConfig struct { +type DisconnectRequest struct { state protoimpl.MessageState `protogen:"open.v1"` - Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"` - Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` - DisableTLS bool `protobuf:"varint,3,opt,name=disableTLS,proto3" json:"disableTLS,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *StargateConfig) Reset() { - *x = StargateConfig{} - mi := &file_agent_proto_msgTypes[12] +func (x *DisconnectRequest) Reset() { + *x = DisconnectRequest{} + mi := &file_agent_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *StargateConfig) String() string { +func (x *DisconnectRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*StargateConfig) ProtoMessage() {} +func (*DisconnectRequest) ProtoMessage() {} -func (x *StargateConfig) ProtoReflect() protoreflect.Message { - mi := &file_agent_proto_msgTypes[12] +func (x *DisconnectRequest) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_msgTypes[16] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1016,54 +850,32 @@ func (x *StargateConfig) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use StargateConfig.ProtoReflect.Descriptor instead. -func (*StargateConfig) Descriptor() ([]byte, []int) { - return file_agent_proto_rawDescGZIP(), []int{12} -} - -func (x *StargateConfig) GetEnabled() bool { - if x != nil { - return x.Enabled - } - return false -} - -func (x *StargateConfig) GetUrl() string { - if x != nil { - return x.Url - } - return "" -} - -func (x *StargateConfig) GetDisableTLS() bool { - if x != nil { - return x.DisableTLS - } - return false +// Deprecated: Use DisconnectRequest.ProtoReflect.Descriptor instead. +func (*DisconnectRequest) Descriptor() ([]byte, []int) { + return file_agent_proto_rawDescGZIP(), []int{16} } -type DeletedStack struct { +type DisconnectResponse struct { state protoimpl.MessageState `protogen:"open.v1"` - ClusterName string `protobuf:"bytes,1,opt,name=clusterName,proto3" json:"clusterName,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *DeletedStack) Reset() { - *x = DeletedStack{} - mi := &file_agent_proto_msgTypes[13] +func (x *DisconnectResponse) Reset() { + *x = DisconnectResponse{} + mi := &file_agent_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *DeletedStack) String() string { +func (x *DisconnectResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*DeletedStack) ProtoMessage() {} +func (*DisconnectResponse) ProtoMessage() {} -func (x *DeletedStack) ProtoReflect() protoreflect.Message { - mi := &file_agent_proto_msgTypes[13] +func (x *DisconnectResponse) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_msgTypes[17] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1074,40 +886,44 @@ func (x *DeletedStack) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use DeletedStack.ProtoReflect.Descriptor instead. -func (*DeletedStack) Descriptor() ([]byte, []int) { - return file_agent_proto_rawDescGZIP(), []int{13} -} - -func (x *DeletedStack) GetClusterName() string { - if x != nil { - return x.ClusterName - } - return "" +// Deprecated: Use DisconnectResponse.ProtoReflect.Descriptor instead. +func (*DisconnectResponse) Descriptor() ([]byte, []int) { + return file_agent_proto_rawDescGZIP(), []int{17} } -type DisabledStack struct { - state protoimpl.MessageState `protogen:"open.v1"` - ClusterName string `protobuf:"bytes,1,opt,name=clusterName,proto3" json:"clusterName,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache +type Stack struct { + state protoimpl.MessageState `protogen:"open.v1"` + ClusterName string `protobuf:"bytes,1,opt,name=clusterName,proto3" json:"clusterName,omitempty"` + Seed string `protobuf:"bytes,2,opt,name=seed,proto3" json:"seed,omitempty"` + AuthConfig *AuthConfig `protobuf:"bytes,3,opt,name=authConfig,proto3" json:"authConfig,omitempty"` + StaticClients []*AuthClient `protobuf:"bytes,4,rep,name=staticClients,proto3" json:"staticClients,omitempty"` + StargateConfig *StargateConfig `protobuf:"bytes,5,opt,name=stargateConfig,proto3" json:"stargateConfig,omitempty"` + Disabled bool `protobuf:"varint,6,opt,name=disabled,proto3" json:"disabled,omitempty"` + Versions string `protobuf:"bytes,8,opt,name=versions,proto3" json:"versions,omitempty"` + AdditionalLabels map[string]string `protobuf:"bytes,10,rep,name=additionalLabels,proto3" json:"additionalLabels,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + AdditionalAnnotations map[string]string `protobuf:"bytes,11,rep,name=additionalAnnotations,proto3" json:"additionalAnnotations,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + Modules []*Module `protobuf:"bytes,12,rep,name=modules,proto3" json:"modules,omitempty"` + ExpectedStatus string `protobuf:"bytes,13,opt,name=expectedStatus,proto3" json:"expectedStatus,omitempty"` + UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,14,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } -func (x *DisabledStack) Reset() { - *x = DisabledStack{} - mi := &file_agent_proto_msgTypes[14] +func (x *Stack) Reset() { + *x = Stack{} + mi := &file_agent_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *DisabledStack) String() string { +func (x *Stack) String() string { return protoimpl.X.MessageStringOf(x) } -func (*DisabledStack) ProtoMessage() {} +func (*Stack) ProtoMessage() {} -func (x *DisabledStack) ProtoReflect() protoreflect.Message { - mi := &file_agent_proto_msgTypes[14] +func (x *Stack) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_msgTypes[18] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1118,42 +934,119 @@ func (x *DisabledStack) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use DisabledStack.ProtoReflect.Descriptor instead. -func (*DisabledStack) Descriptor() ([]byte, []int) { - return file_agent_proto_rawDescGZIP(), []int{14} +// Deprecated: Use Stack.ProtoReflect.Descriptor instead. +func (*Stack) Descriptor() ([]byte, []int) { + return file_agent_proto_rawDescGZIP(), []int{18} } -func (x *DisabledStack) GetClusterName() string { +func (x *Stack) GetClusterName() string { if x != nil { return x.ClusterName } return "" } -type EnabledStack struct { - state protoimpl.MessageState `protogen:"open.v1"` - ClusterName string `protobuf:"bytes,1,opt,name=clusterName,proto3" json:"clusterName,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache +func (x *Stack) GetSeed() string { + if x != nil { + return x.Seed + } + return "" } -func (x *EnabledStack) Reset() { - *x = EnabledStack{} - mi := &file_agent_proto_msgTypes[15] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) +func (x *Stack) GetAuthConfig() *AuthConfig { + if x != nil { + return x.AuthConfig + } + return nil } -func (x *EnabledStack) String() string { - return protoimpl.X.MessageStringOf(x) +func (x *Stack) GetStaticClients() []*AuthClient { + if x != nil { + return x.StaticClients + } + return nil } -func (*EnabledStack) ProtoMessage() {} - -func (x *EnabledStack) ProtoReflect() protoreflect.Message { - mi := &file_agent_proto_msgTypes[15] +func (x *Stack) GetStargateConfig() *StargateConfig { if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + return x.StargateConfig + } + return nil +} + +func (x *Stack) GetDisabled() bool { + if x != nil { + return x.Disabled + } + return false +} + +func (x *Stack) GetVersions() string { + if x != nil { + return x.Versions + } + return "" +} + +func (x *Stack) GetAdditionalLabels() map[string]string { + if x != nil { + return x.AdditionalLabels + } + return nil +} + +func (x *Stack) GetAdditionalAnnotations() map[string]string { + if x != nil { + return x.AdditionalAnnotations + } + return nil +} + +func (x *Stack) GetModules() []*Module { + if x != nil { + return x.Modules + } + return nil +} + +func (x *Stack) GetExpectedStatus() string { + if x != nil { + return x.ExpectedStatus + } + return "" +} + +func (x *Stack) GetUpdatedAt() *timestamppb.Timestamp { + if x != nil { + return x.UpdatedAt + } + return nil +} + +type Module struct { + state protoimpl.MessageState `protogen:"open.v1"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Module) Reset() { + *x = Module{} + mi := &file_agent_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Module) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Module) ProtoMessage() {} + +func (x *Module) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_msgTypes[19] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } @@ -1162,42 +1055,41 @@ func (x *EnabledStack) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use EnabledStack.ProtoReflect.Descriptor instead. -func (*EnabledStack) Descriptor() ([]byte, []int) { - return file_agent_proto_rawDescGZIP(), []int{15} +// Deprecated: Use Module.ProtoReflect.Descriptor instead. +func (*Module) Descriptor() ([]byte, []int) { + return file_agent_proto_rawDescGZIP(), []int{19} } -func (x *EnabledStack) GetClusterName() string { +func (x *Module) GetName() string { if x != nil { - return x.ClusterName + return x.Name } return "" } -type AuthConfig struct { +type VersionKind struct { state protoimpl.MessageState `protogen:"open.v1"` - ClientId string `protobuf:"bytes,1,opt,name=clientId,proto3" json:"clientId,omitempty"` - ClientSecret string `protobuf:"bytes,2,opt,name=clientSecret,proto3" json:"clientSecret,omitempty"` - Issuer string `protobuf:"bytes,3,opt,name=issuer,proto3" json:"issuer,omitempty"` + Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"` + Kind string `protobuf:"bytes,2,opt,name=kind,proto3" json:"kind,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *AuthConfig) Reset() { - *x = AuthConfig{} - mi := &file_agent_proto_msgTypes[16] +func (x *VersionKind) Reset() { + *x = VersionKind{} + mi := &file_agent_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *AuthConfig) String() string { +func (x *VersionKind) String() string { return protoimpl.X.MessageStringOf(x) } -func (*AuthConfig) ProtoMessage() {} +func (*VersionKind) ProtoMessage() {} -func (x *AuthConfig) ProtoReflect() protoreflect.Message { - mi := &file_agent_proto_msgTypes[16] +func (x *VersionKind) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_msgTypes[20] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1208,55 +1100,1014 @@ func (x *AuthConfig) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use AuthConfig.ProtoReflect.Descriptor instead. -func (*AuthConfig) Descriptor() ([]byte, []int) { - return file_agent_proto_rawDescGZIP(), []int{16} +// Deprecated: Use VersionKind.ProtoReflect.Descriptor instead. +func (*VersionKind) Descriptor() ([]byte, []int) { + return file_agent_proto_rawDescGZIP(), []int{20} } -func (x *AuthConfig) GetClientId() string { +func (x *VersionKind) GetVersion() string { if x != nil { - return x.ClientId + return x.Version } return "" } -func (x *AuthConfig) GetClientSecret() string { +func (x *VersionKind) GetKind() string { if x != nil { - return x.ClientSecret + return x.Kind + } + return "" +} + +type ModuleStatusChanged struct { + state protoimpl.MessageState `protogen:"open.v1"` + ClusterName string `protobuf:"bytes,1,opt,name=clusterName,proto3" json:"clusterName,omitempty"` + Status *structpb.Struct `protobuf:"bytes,2,opt,name=status,proto3" json:"status,omitempty"` + Vk *VersionKind `protobuf:"bytes,3,opt,name=vk,proto3" json:"vk,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ModuleStatusChanged) Reset() { + *x = ModuleStatusChanged{} + mi := &file_agent_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ModuleStatusChanged) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ModuleStatusChanged) ProtoMessage() {} + +func (x *ModuleStatusChanged) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_msgTypes[21] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ModuleStatusChanged.ProtoReflect.Descriptor instead. +func (*ModuleStatusChanged) Descriptor() ([]byte, []int) { + return file_agent_proto_rawDescGZIP(), []int{21} +} + +func (x *ModuleStatusChanged) GetClusterName() string { + if x != nil { + return x.ClusterName + } + return "" +} + +func (x *ModuleStatusChanged) GetStatus() *structpb.Struct { + if x != nil { + return x.Status + } + return nil +} + +func (x *ModuleStatusChanged) GetVk() *VersionKind { + if x != nil { + return x.Vk + } + return nil +} + +type ModuleDeleted struct { + state protoimpl.MessageState `protogen:"open.v1"` + ClusterName string `protobuf:"bytes,1,opt,name=clusterName,proto3" json:"clusterName,omitempty"` + Vk *VersionKind `protobuf:"bytes,2,opt,name=vk,proto3" json:"vk,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ModuleDeleted) Reset() { + *x = ModuleDeleted{} + mi := &file_agent_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ModuleDeleted) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ModuleDeleted) ProtoMessage() {} + +func (x *ModuleDeleted) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_msgTypes[22] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ModuleDeleted.ProtoReflect.Descriptor instead. +func (*ModuleDeleted) Descriptor() ([]byte, []int) { + return file_agent_proto_rawDescGZIP(), []int{22} +} + +func (x *ModuleDeleted) GetClusterName() string { + if x != nil { + return x.ClusterName } return "" } -func (x *AuthConfig) GetIssuer() string { - if x != nil { - return x.Issuer - } - return "" -} +func (x *ModuleDeleted) GetVk() *VersionKind { + if x != nil { + return x.Vk + } + return nil +} + +type StatusChanged struct { + state protoimpl.MessageState `protogen:"open.v1"` + ClusterName string `protobuf:"bytes,1,opt,name=clusterName,proto3" json:"clusterName,omitempty"` + Status StackStatus `protobuf:"varint,2,opt,name=status,proto3,enum=server.StackStatus" json:"status,omitempty"` + Statuses *structpb.Struct `protobuf:"bytes,3,opt,name=statuses,proto3" json:"statuses,omitempty"` + Vk *VersionKind `protobuf:"bytes,4,opt,name=vk,proto3" json:"vk,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *StatusChanged) Reset() { + *x = StatusChanged{} + mi := &file_agent_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *StatusChanged) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StatusChanged) ProtoMessage() {} + +func (x *StatusChanged) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_msgTypes[23] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StatusChanged.ProtoReflect.Descriptor instead. +func (*StatusChanged) Descriptor() ([]byte, []int) { + return file_agent_proto_rawDescGZIP(), []int{23} +} + +func (x *StatusChanged) GetClusterName() string { + if x != nil { + return x.ClusterName + } + return "" +} + +func (x *StatusChanged) GetStatus() StackStatus { + if x != nil { + return x.Status + } + return StackStatus_Progressing +} + +func (x *StatusChanged) GetStatuses() *structpb.Struct { + if x != nil { + return x.Statuses + } + return nil +} + +func (x *StatusChanged) GetVk() *VersionKind { + if x != nil { + return x.Vk + } + return nil +} + +type StargateConfig struct { + state protoimpl.MessageState `protogen:"open.v1"` + Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"` + Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` + DisableTLS bool `protobuf:"varint,3,opt,name=disableTLS,proto3" json:"disableTLS,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *StargateConfig) Reset() { + *x = StargateConfig{} + mi := &file_agent_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *StargateConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StargateConfig) ProtoMessage() {} + +func (x *StargateConfig) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_msgTypes[24] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StargateConfig.ProtoReflect.Descriptor instead. +func (*StargateConfig) Descriptor() ([]byte, []int) { + return file_agent_proto_rawDescGZIP(), []int{24} +} + +func (x *StargateConfig) GetEnabled() bool { + if x != nil { + return x.Enabled + } + return false +} + +func (x *StargateConfig) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +func (x *StargateConfig) GetDisableTLS() bool { + if x != nil { + return x.DisableTLS + } + return false +} + +type DeletedStack struct { + state protoimpl.MessageState `protogen:"open.v1"` + ClusterName string `protobuf:"bytes,1,opt,name=clusterName,proto3" json:"clusterName,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeletedStack) Reset() { + *x = DeletedStack{} + mi := &file_agent_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeletedStack) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeletedStack) ProtoMessage() {} + +func (x *DeletedStack) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_msgTypes[25] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeletedStack.ProtoReflect.Descriptor instead. +func (*DeletedStack) Descriptor() ([]byte, []int) { + return file_agent_proto_rawDescGZIP(), []int{25} +} + +func (x *DeletedStack) GetClusterName() string { + if x != nil { + return x.ClusterName + } + return "" +} + +type AuthConfig struct { + state protoimpl.MessageState `protogen:"open.v1"` + ClientId string `protobuf:"bytes,1,opt,name=clientId,proto3" json:"clientId,omitempty"` + ClientSecret string `protobuf:"bytes,2,opt,name=clientSecret,proto3" json:"clientSecret,omitempty"` + Issuer string `protobuf:"bytes,3,opt,name=issuer,proto3" json:"issuer,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AuthConfig) Reset() { + *x = AuthConfig{} + mi := &file_agent_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AuthConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AuthConfig) ProtoMessage() {} + +func (x *AuthConfig) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_msgTypes[26] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AuthConfig.ProtoReflect.Descriptor instead. +func (*AuthConfig) Descriptor() ([]byte, []int) { + return file_agent_proto_rawDescGZIP(), []int{26} +} + +func (x *AuthConfig) GetClientId() string { + if x != nil { + return x.ClientId + } + return "" +} + +func (x *AuthConfig) GetClientSecret() string { + if x != nil { + return x.ClientSecret + } + return "" +} + +func (x *AuthConfig) GetIssuer() string { + if x != nil { + return x.Issuer + } + return "" +} + +type AuthClient struct { + state protoimpl.MessageState `protogen:"open.v1"` + Public bool `protobuf:"varint,1,opt,name=public,proto3" json:"public,omitempty"` + Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AuthClient) Reset() { + *x = AuthClient{} + mi := &file_agent_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AuthClient) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AuthClient) ProtoMessage() {} + +func (x *AuthClient) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_msgTypes[27] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AuthClient.ProtoReflect.Descriptor instead. +func (*AuthClient) Descriptor() ([]byte, []int) { + return file_agent_proto_rawDescGZIP(), []int{27} +} + +func (x *AuthClient) GetPublic() bool { + if x != nil { + return x.Public + } + return false +} + +func (x *AuthClient) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +type AddedVersion struct { + state protoimpl.MessageState `protogen:"open.v1"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Versions map[string]string `protobuf:"bytes,2,rep,name=versions,proto3" json:"versions,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + Deprecated bool `protobuf:"varint,3,opt,name=deprecated,proto3" json:"deprecated,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AddedVersion) Reset() { + *x = AddedVersion{} + mi := &file_agent_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AddedVersion) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddedVersion) ProtoMessage() {} + +func (x *AddedVersion) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_msgTypes[28] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddedVersion.ProtoReflect.Descriptor instead. +func (*AddedVersion) Descriptor() ([]byte, []int) { + return file_agent_proto_rawDescGZIP(), []int{28} +} + +func (x *AddedVersion) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *AddedVersion) GetVersions() map[string]string { + if x != nil { + return x.Versions + } + return nil +} + +func (x *AddedVersion) GetDeprecated() bool { + if x != nil { + return x.Deprecated + } + return false +} + +type UpdatedVersion struct { + state protoimpl.MessageState `protogen:"open.v1"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Versions map[string]string `protobuf:"bytes,2,rep,name=versions,proto3" json:"versions,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + Deprecated bool `protobuf:"varint,3,opt,name=deprecated,proto3" json:"deprecated,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpdatedVersion) Reset() { + *x = UpdatedVersion{} + mi := &file_agent_proto_msgTypes[29] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdatedVersion) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdatedVersion) ProtoMessage() {} + +func (x *UpdatedVersion) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_msgTypes[29] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdatedVersion.ProtoReflect.Descriptor instead. +func (*UpdatedVersion) Descriptor() ([]byte, []int) { + return file_agent_proto_rawDescGZIP(), []int{29} +} + +func (x *UpdatedVersion) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *UpdatedVersion) GetVersions() map[string]string { + if x != nil { + return x.Versions + } + return nil +} + +func (x *UpdatedVersion) GetDeprecated() bool { + if x != nil { + return x.Deprecated + } + return false +} + +type DeletedVersion struct { + state protoimpl.MessageState `protogen:"open.v1"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeletedVersion) Reset() { + *x = DeletedVersion{} + mi := &file_agent_proto_msgTypes[30] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeletedVersion) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeletedVersion) ProtoMessage() {} + +func (x *DeletedVersion) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_msgTypes[30] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeletedVersion.ProtoReflect.Descriptor instead. +func (*DeletedVersion) Descriptor() ([]byte, []int) { + return file_agent_proto_rawDescGZIP(), []int{30} +} + +func (x *DeletedVersion) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +type ConnectRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Tags map[string]string `protobuf:"bytes,2,rep,name=tags,proto3" json:"tags,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + BaseUrl string `protobuf:"bytes,3,opt,name=baseUrl,proto3" json:"baseUrl,omitempty"` + Production bool `protobuf:"varint,4,opt,name=production,proto3" json:"production,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ConnectRequest) Reset() { + *x = ConnectRequest{} + mi := &file_agent_proto_msgTypes[31] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ConnectRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ConnectRequest) ProtoMessage() {} + +func (x *ConnectRequest) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_msgTypes[31] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ConnectRequest.ProtoReflect.Descriptor instead. +func (*ConnectRequest) Descriptor() ([]byte, []int) { + return file_agent_proto_rawDescGZIP(), []int{31} +} + +func (x *ConnectRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *ConnectRequest) GetTags() map[string]string { + if x != nil { + return x.Tags + } + return nil +} + +func (x *ConnectRequest) GetBaseUrl() string { + if x != nil { + return x.BaseUrl + } + return "" +} + +func (x *ConnectRequest) GetProduction() bool { + if x != nil { + return x.Production + } + return false +} + +type Order struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Message: + // + // *Order_Connected + // *Order_ExistingStack + // *Order_DeletedStack + // *Order_Ping + // *Order_DisabledStack + // *Order_EnabledStack + Message isOrder_Message `protobuf_oneof:"message"` + Metadata map[string]string `protobuf:"bytes,8,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Order) Reset() { + *x = Order{} + mi := &file_agent_proto_msgTypes[32] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Order) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Order) ProtoMessage() {} + +func (x *Order) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_msgTypes[32] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Order.ProtoReflect.Descriptor instead. +func (*Order) Descriptor() ([]byte, []int) { + return file_agent_proto_rawDescGZIP(), []int{32} +} + +func (x *Order) GetMessage() isOrder_Message { + if x != nil { + return x.Message + } + return nil +} + +func (x *Order) GetConnected() *Connected { + if x != nil { + if x, ok := x.Message.(*Order_Connected); ok { + return x.Connected + } + } + return nil +} + +func (x *Order) GetExistingStack() *Stack { + if x != nil { + if x, ok := x.Message.(*Order_ExistingStack); ok { + return x.ExistingStack + } + } + return nil +} + +func (x *Order) GetDeletedStack() *DeletedStack { + if x != nil { + if x, ok := x.Message.(*Order_DeletedStack); ok { + return x.DeletedStack + } + } + return nil +} + +func (x *Order) GetPing() *Ping { + if x != nil { + if x, ok := x.Message.(*Order_Ping); ok { + return x.Ping + } + } + return nil +} + +func (x *Order) GetDisabledStack() *DisabledStack { + if x != nil { + if x, ok := x.Message.(*Order_DisabledStack); ok { + return x.DisabledStack + } + } + return nil +} + +func (x *Order) GetEnabledStack() *EnabledStack { + if x != nil { + if x, ok := x.Message.(*Order_EnabledStack); ok { + return x.EnabledStack + } + } + return nil +} + +func (x *Order) GetMetadata() map[string]string { + if x != nil { + return x.Metadata + } + return nil +} + +type isOrder_Message interface { + isOrder_Message() +} + +type Order_Connected struct { + Connected *Connected `protobuf:"bytes,1,opt,name=connected,proto3,oneof"` +} + +type Order_ExistingStack struct { + ExistingStack *Stack `protobuf:"bytes,2,opt,name=existingStack,proto3,oneof"` +} + +type Order_DeletedStack struct { + DeletedStack *DeletedStack `protobuf:"bytes,3,opt,name=deletedStack,proto3,oneof"` +} + +type Order_Ping struct { + Ping *Ping `protobuf:"bytes,4,opt,name=ping,proto3,oneof"` +} + +type Order_DisabledStack struct { + DisabledStack *DisabledStack `protobuf:"bytes,6,opt,name=disabledStack,proto3,oneof"` +} + +type Order_EnabledStack struct { + EnabledStack *EnabledStack `protobuf:"bytes,7,opt,name=enabledStack,proto3,oneof"` +} + +func (*Order_Connected) isOrder_Message() {} + +func (*Order_ExistingStack) isOrder_Message() {} + +func (*Order_DeletedStack) isOrder_Message() {} + +func (*Order_Ping) isOrder_Message() {} + +func (*Order_DisabledStack) isOrder_Message() {} + +func (*Order_EnabledStack) isOrder_Message() {} + +type Message struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Message: + // + // *Message_StatusChanged + // *Message_Pong + // *Message_AddedVersion + // *Message_DeletedVersion + // *Message_UpdatedVersion + // *Message_ModuleStatusChanged + // *Message_ModuleDeleted + // *Message_StackDeleted + Message isMessage_Message `protobuf_oneof:"message"` + Metadata map[string]string `protobuf:"bytes,9,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Message) Reset() { + *x = Message{} + mi := &file_agent_proto_msgTypes[33] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Message) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Message) ProtoMessage() {} + +func (x *Message) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_msgTypes[33] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Message.ProtoReflect.Descriptor instead. +func (*Message) Descriptor() ([]byte, []int) { + return file_agent_proto_rawDescGZIP(), []int{33} +} + +func (x *Message) GetMessage() isMessage_Message { + if x != nil { + return x.Message + } + return nil +} + +func (x *Message) GetStatusChanged() *StatusChanged { + if x != nil { + if x, ok := x.Message.(*Message_StatusChanged); ok { + return x.StatusChanged + } + } + return nil +} + +func (x *Message) GetPong() *Pong { + if x != nil { + if x, ok := x.Message.(*Message_Pong); ok { + return x.Pong + } + } + return nil +} + +func (x *Message) GetAddedVersion() *AddedVersion { + if x != nil { + if x, ok := x.Message.(*Message_AddedVersion); ok { + return x.AddedVersion + } + } + return nil +} + +func (x *Message) GetDeletedVersion() *DeletedVersion { + if x != nil { + if x, ok := x.Message.(*Message_DeletedVersion); ok { + return x.DeletedVersion + } + } + return nil +} + +func (x *Message) GetUpdatedVersion() *UpdatedVersion { + if x != nil { + if x, ok := x.Message.(*Message_UpdatedVersion); ok { + return x.UpdatedVersion + } + } + return nil +} + +func (x *Message) GetModuleStatusChanged() *ModuleStatusChanged { + if x != nil { + if x, ok := x.Message.(*Message_ModuleStatusChanged); ok { + return x.ModuleStatusChanged + } + } + return nil +} + +func (x *Message) GetModuleDeleted() *ModuleDeleted { + if x != nil { + if x, ok := x.Message.(*Message_ModuleDeleted); ok { + return x.ModuleDeleted + } + } + return nil +} + +func (x *Message) GetStackDeleted() *DeletedStack { + if x != nil { + if x, ok := x.Message.(*Message_StackDeleted); ok { + return x.StackDeleted + } + } + return nil +} + +func (x *Message) GetMetadata() map[string]string { + if x != nil { + return x.Metadata + } + return nil +} + +type isMessage_Message interface { + isMessage_Message() +} + +type Message_StatusChanged struct { + StatusChanged *StatusChanged `protobuf:"bytes,1,opt,name=statusChanged,proto3,oneof"` +} + +type Message_Pong struct { + Pong *Pong `protobuf:"bytes,2,opt,name=pong,proto3,oneof"` +} + +type Message_AddedVersion struct { + AddedVersion *AddedVersion `protobuf:"bytes,3,opt,name=addedVersion,proto3,oneof"` +} + +type Message_DeletedVersion struct { + DeletedVersion *DeletedVersion `protobuf:"bytes,4,opt,name=deletedVersion,proto3,oneof"` +} + +type Message_UpdatedVersion struct { + UpdatedVersion *UpdatedVersion `protobuf:"bytes,5,opt,name=updatedVersion,proto3,oneof"` +} + +type Message_ModuleStatusChanged struct { + ModuleStatusChanged *ModuleStatusChanged `protobuf:"bytes,6,opt,name=moduleStatusChanged,proto3,oneof"` +} + +type Message_ModuleDeleted struct { + ModuleDeleted *ModuleDeleted `protobuf:"bytes,7,opt,name=moduleDeleted,proto3,oneof"` +} + +type Message_StackDeleted struct { + StackDeleted *DeletedStack `protobuf:"bytes,8,opt,name=stackDeleted,proto3,oneof"` +} + +func (*Message_StatusChanged) isMessage_Message() {} + +func (*Message_Pong) isMessage_Message() {} + +func (*Message_AddedVersion) isMessage_Message() {} + +func (*Message_DeletedVersion) isMessage_Message() {} + +func (*Message_UpdatedVersion) isMessage_Message() {} + +func (*Message_ModuleStatusChanged) isMessage_Message() {} + +func (*Message_ModuleDeleted) isMessage_Message() {} + +func (*Message_StackDeleted) isMessage_Message() {} -type AuthClient struct { +type Connected struct { state protoimpl.MessageState `protogen:"open.v1"` - Public bool `protobuf:"varint,1,opt,name=public,proto3" json:"public,omitempty"` - Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *AuthClient) Reset() { - *x = AuthClient{} - mi := &file_agent_proto_msgTypes[17] +func (x *Connected) Reset() { + *x = Connected{} + mi := &file_agent_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *AuthClient) String() string { +func (x *Connected) String() string { return protoimpl.X.MessageStringOf(x) } -func (*AuthClient) ProtoMessage() {} +func (*Connected) ProtoMessage() {} -func (x *AuthClient) ProtoReflect() protoreflect.Message { - mi := &file_agent_proto_msgTypes[17] +func (x *Connected) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_msgTypes[34] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1267,49 +2118,32 @@ func (x *AuthClient) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use AuthClient.ProtoReflect.Descriptor instead. -func (*AuthClient) Descriptor() ([]byte, []int) { - return file_agent_proto_rawDescGZIP(), []int{17} -} - -func (x *AuthClient) GetPublic() bool { - if x != nil { - return x.Public - } - return false -} - -func (x *AuthClient) GetId() string { - if x != nil { - return x.Id - } - return "" +// Deprecated: Use Connected.ProtoReflect.Descriptor instead. +func (*Connected) Descriptor() ([]byte, []int) { + return file_agent_proto_rawDescGZIP(), []int{34} } -type AddedVersion struct { +type Ping struct { state protoimpl.MessageState `protogen:"open.v1"` - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - Versions map[string]string `protobuf:"bytes,2,rep,name=versions,proto3" json:"versions,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - Deprecated bool `protobuf:"varint,3,opt,name=deprecated,proto3" json:"deprecated,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *AddedVersion) Reset() { - *x = AddedVersion{} - mi := &file_agent_proto_msgTypes[18] +func (x *Ping) Reset() { + *x = Ping{} + mi := &file_agent_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *AddedVersion) String() string { +func (x *Ping) String() string { return protoimpl.X.MessageStringOf(x) } -func (*AddedVersion) ProtoMessage() {} +func (*Ping) ProtoMessage() {} -func (x *AddedVersion) ProtoReflect() protoreflect.Message { - mi := &file_agent_proto_msgTypes[18] +func (x *Ping) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_msgTypes[35] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1320,56 +2154,69 @@ func (x *AddedVersion) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use AddedVersion.ProtoReflect.Descriptor instead. -func (*AddedVersion) Descriptor() ([]byte, []int) { - return file_agent_proto_rawDescGZIP(), []int{18} +// Deprecated: Use Ping.ProtoReflect.Descriptor instead. +func (*Ping) Descriptor() ([]byte, []int) { + return file_agent_proto_rawDescGZIP(), []int{35} } -func (x *AddedVersion) GetName() string { - if x != nil { - return x.Name - } - return "" +type Pong struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } -func (x *AddedVersion) GetVersions() map[string]string { - if x != nil { - return x.Versions - } - return nil +func (x *Pong) Reset() { + *x = Pong{} + mi := &file_agent_proto_msgTypes[36] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } -func (x *AddedVersion) GetDeprecated() bool { +func (x *Pong) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Pong) ProtoMessage() {} + +func (x *Pong) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_msgTypes[36] if x != nil { - return x.Deprecated + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms } - return false + return mi.MessageOf(x) } -type UpdatedVersion struct { +// Deprecated: Use Pong.ProtoReflect.Descriptor instead. +func (*Pong) Descriptor() ([]byte, []int) { + return file_agent_proto_rawDescGZIP(), []int{36} +} + +type DisabledStack struct { state protoimpl.MessageState `protogen:"open.v1"` - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - Versions map[string]string `protobuf:"bytes,2,rep,name=versions,proto3" json:"versions,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - Deprecated bool `protobuf:"varint,3,opt,name=deprecated,proto3" json:"deprecated,omitempty"` + ClusterName string `protobuf:"bytes,1,opt,name=clusterName,proto3" json:"clusterName,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *UpdatedVersion) Reset() { - *x = UpdatedVersion{} - mi := &file_agent_proto_msgTypes[19] +func (x *DisabledStack) Reset() { + *x = DisabledStack{} + mi := &file_agent_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *UpdatedVersion) String() string { +func (x *DisabledStack) String() string { return protoimpl.X.MessageStringOf(x) } -func (*UpdatedVersion) ProtoMessage() {} +func (*DisabledStack) ProtoMessage() {} -func (x *UpdatedVersion) ProtoReflect() protoreflect.Message { - mi := &file_agent_proto_msgTypes[19] +func (x *DisabledStack) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_msgTypes[37] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1380,54 +2227,40 @@ func (x *UpdatedVersion) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use UpdatedVersion.ProtoReflect.Descriptor instead. -func (*UpdatedVersion) Descriptor() ([]byte, []int) { - return file_agent_proto_rawDescGZIP(), []int{19} +// Deprecated: Use DisabledStack.ProtoReflect.Descriptor instead. +func (*DisabledStack) Descriptor() ([]byte, []int) { + return file_agent_proto_rawDescGZIP(), []int{37} } -func (x *UpdatedVersion) GetName() string { +func (x *DisabledStack) GetClusterName() string { if x != nil { - return x.Name + return x.ClusterName } return "" } -func (x *UpdatedVersion) GetVersions() map[string]string { - if x != nil { - return x.Versions - } - return nil -} - -func (x *UpdatedVersion) GetDeprecated() bool { - if x != nil { - return x.Deprecated - } - return false -} - -type DeletedVersion struct { +type EnabledStack struct { state protoimpl.MessageState `protogen:"open.v1"` - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + ClusterName string `protobuf:"bytes,1,opt,name=clusterName,proto3" json:"clusterName,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *DeletedVersion) Reset() { - *x = DeletedVersion{} - mi := &file_agent_proto_msgTypes[20] +func (x *EnabledStack) Reset() { + *x = EnabledStack{} + mi := &file_agent_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *DeletedVersion) String() string { +func (x *EnabledStack) String() string { return protoimpl.X.MessageStringOf(x) } -func (*DeletedVersion) ProtoMessage() {} +func (*EnabledStack) ProtoMessage() {} -func (x *DeletedVersion) ProtoReflect() protoreflect.Message { - mi := &file_agent_proto_msgTypes[20] +func (x *EnabledStack) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_msgTypes[38] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1438,14 +2271,14 @@ func (x *DeletedVersion) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use DeletedVersion.ProtoReflect.Descriptor instead. -func (*DeletedVersion) Descriptor() ([]byte, []int) { - return file_agent_proto_rawDescGZIP(), []int{20} +// Deprecated: Use EnabledStack.ProtoReflect.Descriptor instead. +func (*EnabledStack) Descriptor() ([]byte, []int) { + return file_agent_proto_rawDescGZIP(), []int{38} } -func (x *DeletedVersion) GetName() string { +func (x *EnabledStack) GetClusterName() string { if x != nil { - return x.Name + return x.ClusterName } return "" } @@ -1454,46 +2287,54 @@ var File_agent_proto protoreflect.FileDescriptor const file_agent_proto_rawDesc = "" + "\n" + - "\vagent.proto\x12\x06server\x1a\x1cgoogle/protobuf/struct.proto\"\xc9\x01\n" + - "\x0eConnectRequest\x12\x0e\n" + - "\x02id\x18\x01 \x01(\tR\x02id\x124\n" + - "\x04tags\x18\x02 \x03(\v2 .server.ConnectRequest.TagsEntryR\x04tags\x12\x18\n" + - "\abaseUrl\x18\x03 \x01(\tR\abaseUrl\x12\x1e\n" + + "\vagent.proto\x12\x06server\x1a\x1cgoogle/protobuf/struct.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"e\n" + + "\x11ListStacksRequest\x12\x1b\n" + + "\tregion_id\x18\x01 \x01(\tR\bregionId\x12\x1b\n" + + "\tpage_size\x18\x02 \x01(\x05R\bpageSize\x12\x16\n" + + "\x06cursor\x18\x03 \x01(\tR\x06cursor\"w\n" + + "\x12ListStacksResponse\x12%\n" + + "\x06stacks\x18\x01 \x03(\v2\r.server.StackR\x06stacks\x12\x1f\n" + + "\vnext_cursor\x18\x02 \x01(\tR\n" + + "nextCursor\x12\x19\n" + + "\bhas_more\x18\x03 \x01(\bR\ahasMore\"X\n" + + "\x18ReportStackStatusRequest\x12<\n" + + "\x0estatus_changed\x18\x01 \x01(\v2\x15.server.StatusChangedR\rstatusChanged\"\x1b\n" + + "\x19ReportStackStatusResponse\"V\n" + + "\x19ReportStackDeletedRequest\x129\n" + + "\rstack_deleted\x18\x01 \x01(\v2\x14.server.DeletedStackR\fstackDeleted\"\x1c\n" + + "\x1aReportStackDeletedResponse\"l\n" + + "\x19ReportModuleStatusRequest\x12O\n" + + "\x15module_status_changed\x18\x01 \x01(\v2\x1b.server.ModuleStatusChangedR\x13moduleStatusChanged\"\x1c\n" + + "\x1aReportModuleStatusResponse\"Z\n" + + "\x1aReportModuleDeletedRequest\x12<\n" + + "\x0emodule_deleted\x18\x01 \x01(\v2\x15.server.ModuleDeletedR\rmoduleDeleted\"\x1d\n" + + "\x1bReportModuleDeletedResponse\"\xcf\x01\n" + + "\x14UpsertVersionRequest\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12F\n" + + "\bversions\x18\x02 \x03(\v2*.server.UpsertVersionRequest.VersionsEntryR\bversions\x12\x1e\n" + "\n" + - "production\x18\x04 \x01(\bR\n" + - "production\x1a7\n" + - "\tTagsEntry\x12\x10\n" + - "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + - "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xd3\x03\n" + - "\x05Order\x121\n" + - "\tconnected\x18\x01 \x01(\v2\x11.server.ConnectedH\x00R\tconnected\x125\n" + - "\rexistingStack\x18\x02 \x01(\v2\r.server.StackH\x00R\rexistingStack\x12:\n" + - "\fdeletedStack\x18\x03 \x01(\v2\x14.server.DeletedStackH\x00R\fdeletedStack\x12\"\n" + - "\x04ping\x18\x04 \x01(\v2\f.server.PingH\x00R\x04ping\x12=\n" + - "\rdisabledStack\x18\x06 \x01(\v2\x15.server.DisabledStackH\x00R\rdisabledStack\x12:\n" + - "\fenabledStack\x18\a \x01(\v2\x14.server.EnabledStackH\x00R\fenabledStack\x127\n" + - "\bmetadata\x18\b \x03(\v2\x1b.server.Order.MetadataEntryR\bmetadata\x1a;\n" + - "\rMetadataEntry\x12\x10\n" + - "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + - "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01B\t\n" + - "\amessageJ\x04\b\x05\x10\x06\"\xfb\x04\n" + - "\aMessage\x12=\n" + - "\rstatusChanged\x18\x01 \x01(\v2\x15.server.StatusChangedH\x00R\rstatusChanged\x12\"\n" + - "\x04pong\x18\x02 \x01(\v2\f.server.PongH\x00R\x04pong\x12:\n" + - "\faddedVersion\x18\x03 \x01(\v2\x14.server.AddedVersionH\x00R\faddedVersion\x12@\n" + - "\x0edeletedVersion\x18\x04 \x01(\v2\x16.server.DeletedVersionH\x00R\x0edeletedVersion\x12@\n" + - "\x0eupdatedVersion\x18\x05 \x01(\v2\x16.server.UpdatedVersionH\x00R\x0eupdatedVersion\x12O\n" + - "\x13moduleStatusChanged\x18\x06 \x01(\v2\x1b.server.ModuleStatusChangedH\x00R\x13moduleStatusChanged\x12=\n" + - "\rmoduleDeleted\x18\a \x01(\v2\x15.server.ModuleDeletedH\x00R\rmoduleDeleted\x12:\n" + - "\fstackDeleted\x18\b \x01(\v2\x14.server.DeletedStackH\x00R\fstackDeleted\x129\n" + - "\bmetadata\x18\t \x03(\v2\x1d.server.Message.MetadataEntryR\bmetadata\x1a;\n" + - "\rMetadataEntry\x12\x10\n" + + "deprecated\x18\x03 \x01(\bR\n" + + "deprecated\x1a;\n" + + "\rVersionsEntry\x12\x10\n" + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + - "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01B\t\n" + - "\amessage\"\v\n" + - "\tConnected\"\x06\n" + - "\x04Ping\"\x06\n" + - "\x04Pong\"\x99\x05\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\x17\n" + + "\x15UpsertVersionResponse\"*\n" + + "\x14DeleteVersionRequest\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\"\x17\n" + + "\x15DeleteVersionResponse\"\xf4\x01\n" + + "\x10HeartbeatRequest\x12\x1b\n" + + "\tregion_id\x18\x01 \x01(\tR\bregionId\x12\x19\n" + + "\bbase_url\x18\x02 \x01(\tR\abaseUrl\x120\n" + + "\x14additional_base_urls\x18\x03 \x03(\tR\x12additionalBaseUrls\x12\x18\n" + + "\aversion\x18\x04 \x01(\tR\aversion\x12\x1e\n" + + "\n" + + "production\x18\x05 \x01(\bR\n" + + "production\x12\"\n" + + "\fcapabilities\x18\x06 \x03(\tR\fcapabilities\x12\x18\n" + + "\amodules\x18\a \x03(\tR\amodules\"\x13\n" + + "\x11HeartbeatResponse\"\x13\n" + + "\x11DisconnectRequest\"\x14\n" + + "\x12DisconnectResponse\"\xfc\x05\n" + "\x05Stack\x12 \n" + "\vclusterName\x18\x01 \x01(\tR\vclusterName\x12\x12\n" + "\x04seed\x18\x02 \x01(\tR\x04seed\x122\n" + @@ -1507,7 +2348,10 @@ const file_agent_proto_rawDesc = "" + "\x10additionalLabels\x18\n" + " \x03(\v2#.server.Stack.AdditionalLabelsEntryR\x10additionalLabels\x12^\n" + "\x15additionalAnnotations\x18\v \x03(\v2(.server.Stack.AdditionalAnnotationsEntryR\x15additionalAnnotations\x12(\n" + - "\amodules\x18\f \x03(\v2\x0e.server.ModuleR\amodules\x1aC\n" + + "\amodules\x18\f \x03(\v2\x0e.server.ModuleR\amodules\x12&\n" + + "\x0eexpectedStatus\x18\r \x01(\tR\x0eexpectedStatus\x129\n" + + "\n" + + "updated_at\x18\x0e \x01(\v2\x1a.google.protobuf.TimestampR\tupdatedAt\x1aC\n" + "\x15AdditionalLabelsEntry\x12\x10\n" + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\x1aH\n" + @@ -1539,10 +2383,6 @@ const file_agent_proto_rawDesc = "" + "disableTLS\x18\x03 \x01(\bR\n" + "disableTLS\"0\n" + "\fDeletedStack\x12 \n" + - "\vclusterName\x18\x01 \x01(\tR\vclusterName\"1\n" + - "\rDisabledStack\x12 \n" + - "\vclusterName\x18\x01 \x01(\tR\vclusterName\"0\n" + - "\fEnabledStack\x12 \n" + "\vclusterName\x18\x01 \x01(\tR\vclusterName\"d\n" + "\n" + "AuthConfig\x12\x1a\n" + @@ -1572,14 +2412,69 @@ const file_agent_proto_rawDesc = "" + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"$\n" + "\x0eDeletedVersion\x12\x12\n" + - "\x04name\x18\x01 \x01(\tR\x04name*D\n" + + "\x04name\x18\x01 \x01(\tR\x04name\"\xc9\x01\n" + + "\x0eConnectRequest\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\x124\n" + + "\x04tags\x18\x02 \x03(\v2 .server.ConnectRequest.TagsEntryR\x04tags\x12\x18\n" + + "\abaseUrl\x18\x03 \x01(\tR\abaseUrl\x12\x1e\n" + + "\n" + + "production\x18\x04 \x01(\bR\n" + + "production\x1a7\n" + + "\tTagsEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xd3\x03\n" + + "\x05Order\x121\n" + + "\tconnected\x18\x01 \x01(\v2\x11.server.ConnectedH\x00R\tconnected\x125\n" + + "\rexistingStack\x18\x02 \x01(\v2\r.server.StackH\x00R\rexistingStack\x12:\n" + + "\fdeletedStack\x18\x03 \x01(\v2\x14.server.DeletedStackH\x00R\fdeletedStack\x12\"\n" + + "\x04ping\x18\x04 \x01(\v2\f.server.PingH\x00R\x04ping\x12=\n" + + "\rdisabledStack\x18\x06 \x01(\v2\x15.server.DisabledStackH\x00R\rdisabledStack\x12:\n" + + "\fenabledStack\x18\a \x01(\v2\x14.server.EnabledStackH\x00R\fenabledStack\x127\n" + + "\bmetadata\x18\b \x03(\v2\x1b.server.Order.MetadataEntryR\bmetadata\x1a;\n" + + "\rMetadataEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01B\t\n" + + "\amessageJ\x04\b\x05\x10\x06\"\xfb\x04\n" + + "\aMessage\x12=\n" + + "\rstatusChanged\x18\x01 \x01(\v2\x15.server.StatusChangedH\x00R\rstatusChanged\x12\"\n" + + "\x04pong\x18\x02 \x01(\v2\f.server.PongH\x00R\x04pong\x12:\n" + + "\faddedVersion\x18\x03 \x01(\v2\x14.server.AddedVersionH\x00R\faddedVersion\x12@\n" + + "\x0edeletedVersion\x18\x04 \x01(\v2\x16.server.DeletedVersionH\x00R\x0edeletedVersion\x12@\n" + + "\x0eupdatedVersion\x18\x05 \x01(\v2\x16.server.UpdatedVersionH\x00R\x0eupdatedVersion\x12O\n" + + "\x13moduleStatusChanged\x18\x06 \x01(\v2\x1b.server.ModuleStatusChangedH\x00R\x13moduleStatusChanged\x12=\n" + + "\rmoduleDeleted\x18\a \x01(\v2\x15.server.ModuleDeletedH\x00R\rmoduleDeleted\x12:\n" + + "\fstackDeleted\x18\b \x01(\v2\x14.server.DeletedStackH\x00R\fstackDeleted\x129\n" + + "\bmetadata\x18\t \x03(\v2\x1d.server.Message.MetadataEntryR\bmetadata\x1a;\n" + + "\rMetadataEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01B\t\n" + + "\amessage\"\v\n" + + "\tConnected\"\x06\n" + + "\x04Ping\"\x06\n" + + "\x04Pong\"1\n" + + "\rDisabledStack\x12 \n" + + "\vclusterName\x18\x01 \x01(\tR\vclusterName\"0\n" + + "\fEnabledStack\x12 \n" + + "\vclusterName\x18\x01 \x01(\tR\vclusterName*D\n" + "\vStackStatus\x12\x0f\n" + "\vProgressing\x10\x00\x12\t\n" + "\x05Ready\x10\x01\x12\v\n" + "\aDeleted\x10\x02\x12\f\n" + "\bDisabled\x10\x0326\n" + "\x06Server\x12,\n" + - "\x04Join\x12\x0f.server.Message\x1a\r.server.Order\"\x00(\x010\x01B:Z8github.com/formancehq/membership/internal/grpc/generatedb\x06proto3" + "\x04Join\x12\x0f.server.Message\x1a\r.server.Order\"\x00(\x010\x012\xea\x05\n" + + "\fAgentService\x12C\n" + + "\n" + + "ListStacks\x12\x19.server.ListStacksRequest\x1a\x1a.server.ListStacksResponse\x12X\n" + + "\x11ReportStackStatus\x12 .server.ReportStackStatusRequest\x1a!.server.ReportStackStatusResponse\x12[\n" + + "\x12ReportStackDeleted\x12!.server.ReportStackDeletedRequest\x1a\".server.ReportStackDeletedResponse\x12[\n" + + "\x12ReportModuleStatus\x12!.server.ReportModuleStatusRequest\x1a\".server.ReportModuleStatusResponse\x12^\n" + + "\x13ReportModuleDeleted\x12\".server.ReportModuleDeletedRequest\x1a#.server.ReportModuleDeletedResponse\x12L\n" + + "\rUpsertVersion\x12\x1c.server.UpsertVersionRequest\x1a\x1d.server.UpsertVersionResponse\x12L\n" + + "\rDeleteVersion\x12\x1c.server.DeleteVersionRequest\x1a\x1d.server.DeleteVersionResponse\x12@\n" + + "\tHeartbeat\x12\x18.server.HeartbeatRequest\x1a\x19.server.HeartbeatResponse\x12C\n" + + "\n" + + "Disconnect\x12\x19.server.DisconnectRequest\x1a\x1a.server.DisconnectResponseB:Z8github.com/formancehq/membership/internal/grpc/generatedb\x06proto3" var ( file_agent_proto_rawDescOnce sync.Once @@ -1594,78 +2489,123 @@ func file_agent_proto_rawDescGZIP() []byte { } var file_agent_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_agent_proto_msgTypes = make([]protoimpl.MessageInfo, 28) +var file_agent_proto_msgTypes = make([]protoimpl.MessageInfo, 47) var file_agent_proto_goTypes = []any{ - (StackStatus)(0), // 0: server.StackStatus - (*ConnectRequest)(nil), // 1: server.ConnectRequest - (*Order)(nil), // 2: server.Order - (*Message)(nil), // 3: server.Message - (*Connected)(nil), // 4: server.Connected - (*Ping)(nil), // 5: server.Ping - (*Pong)(nil), // 6: server.Pong - (*Stack)(nil), // 7: server.Stack - (*Module)(nil), // 8: server.Module - (*VersionKind)(nil), // 9: server.VersionKind - (*ModuleStatusChanged)(nil), // 10: server.ModuleStatusChanged - (*ModuleDeleted)(nil), // 11: server.ModuleDeleted - (*StatusChanged)(nil), // 12: server.StatusChanged - (*StargateConfig)(nil), // 13: server.StargateConfig - (*DeletedStack)(nil), // 14: server.DeletedStack - (*DisabledStack)(nil), // 15: server.DisabledStack - (*EnabledStack)(nil), // 16: server.EnabledStack - (*AuthConfig)(nil), // 17: server.AuthConfig - (*AuthClient)(nil), // 18: server.AuthClient - (*AddedVersion)(nil), // 19: server.AddedVersion - (*UpdatedVersion)(nil), // 20: server.UpdatedVersion - (*DeletedVersion)(nil), // 21: server.DeletedVersion - nil, // 22: server.ConnectRequest.TagsEntry - nil, // 23: server.Order.MetadataEntry - nil, // 24: server.Message.MetadataEntry - nil, // 25: server.Stack.AdditionalLabelsEntry - nil, // 26: server.Stack.AdditionalAnnotationsEntry - nil, // 27: server.AddedVersion.VersionsEntry - nil, // 28: server.UpdatedVersion.VersionsEntry - (*structpb.Struct)(nil), // 29: google.protobuf.Struct + (StackStatus)(0), // 0: server.StackStatus + (*ListStacksRequest)(nil), // 1: server.ListStacksRequest + (*ListStacksResponse)(nil), // 2: server.ListStacksResponse + (*ReportStackStatusRequest)(nil), // 3: server.ReportStackStatusRequest + (*ReportStackStatusResponse)(nil), // 4: server.ReportStackStatusResponse + (*ReportStackDeletedRequest)(nil), // 5: server.ReportStackDeletedRequest + (*ReportStackDeletedResponse)(nil), // 6: server.ReportStackDeletedResponse + (*ReportModuleStatusRequest)(nil), // 7: server.ReportModuleStatusRequest + (*ReportModuleStatusResponse)(nil), // 8: server.ReportModuleStatusResponse + (*ReportModuleDeletedRequest)(nil), // 9: server.ReportModuleDeletedRequest + (*ReportModuleDeletedResponse)(nil), // 10: server.ReportModuleDeletedResponse + (*UpsertVersionRequest)(nil), // 11: server.UpsertVersionRequest + (*UpsertVersionResponse)(nil), // 12: server.UpsertVersionResponse + (*DeleteVersionRequest)(nil), // 13: server.DeleteVersionRequest + (*DeleteVersionResponse)(nil), // 14: server.DeleteVersionResponse + (*HeartbeatRequest)(nil), // 15: server.HeartbeatRequest + (*HeartbeatResponse)(nil), // 16: server.HeartbeatResponse + (*DisconnectRequest)(nil), // 17: server.DisconnectRequest + (*DisconnectResponse)(nil), // 18: server.DisconnectResponse + (*Stack)(nil), // 19: server.Stack + (*Module)(nil), // 20: server.Module + (*VersionKind)(nil), // 21: server.VersionKind + (*ModuleStatusChanged)(nil), // 22: server.ModuleStatusChanged + (*ModuleDeleted)(nil), // 23: server.ModuleDeleted + (*StatusChanged)(nil), // 24: server.StatusChanged + (*StargateConfig)(nil), // 25: server.StargateConfig + (*DeletedStack)(nil), // 26: server.DeletedStack + (*AuthConfig)(nil), // 27: server.AuthConfig + (*AuthClient)(nil), // 28: server.AuthClient + (*AddedVersion)(nil), // 29: server.AddedVersion + (*UpdatedVersion)(nil), // 30: server.UpdatedVersion + (*DeletedVersion)(nil), // 31: server.DeletedVersion + (*ConnectRequest)(nil), // 32: server.ConnectRequest + (*Order)(nil), // 33: server.Order + (*Message)(nil), // 34: server.Message + (*Connected)(nil), // 35: server.Connected + (*Ping)(nil), // 36: server.Ping + (*Pong)(nil), // 37: server.Pong + (*DisabledStack)(nil), // 38: server.DisabledStack + (*EnabledStack)(nil), // 39: server.EnabledStack + nil, // 40: server.UpsertVersionRequest.VersionsEntry + nil, // 41: server.Stack.AdditionalLabelsEntry + nil, // 42: server.Stack.AdditionalAnnotationsEntry + nil, // 43: server.AddedVersion.VersionsEntry + nil, // 44: server.UpdatedVersion.VersionsEntry + nil, // 45: server.ConnectRequest.TagsEntry + nil, // 46: server.Order.MetadataEntry + nil, // 47: server.Message.MetadataEntry + (*timestamppb.Timestamp)(nil), // 48: google.protobuf.Timestamp + (*structpb.Struct)(nil), // 49: google.protobuf.Struct } var file_agent_proto_depIdxs = []int32{ - 22, // 0: server.ConnectRequest.tags:type_name -> server.ConnectRequest.TagsEntry - 4, // 1: server.Order.connected:type_name -> server.Connected - 7, // 2: server.Order.existingStack:type_name -> server.Stack - 14, // 3: server.Order.deletedStack:type_name -> server.DeletedStack - 5, // 4: server.Order.ping:type_name -> server.Ping - 15, // 5: server.Order.disabledStack:type_name -> server.DisabledStack - 16, // 6: server.Order.enabledStack:type_name -> server.EnabledStack - 23, // 7: server.Order.metadata:type_name -> server.Order.MetadataEntry - 12, // 8: server.Message.statusChanged:type_name -> server.StatusChanged - 6, // 9: server.Message.pong:type_name -> server.Pong - 19, // 10: server.Message.addedVersion:type_name -> server.AddedVersion - 21, // 11: server.Message.deletedVersion:type_name -> server.DeletedVersion - 20, // 12: server.Message.updatedVersion:type_name -> server.UpdatedVersion - 10, // 13: server.Message.moduleStatusChanged:type_name -> server.ModuleStatusChanged - 11, // 14: server.Message.moduleDeleted:type_name -> server.ModuleDeleted - 14, // 15: server.Message.stackDeleted:type_name -> server.DeletedStack - 24, // 16: server.Message.metadata:type_name -> server.Message.MetadataEntry - 17, // 17: server.Stack.authConfig:type_name -> server.AuthConfig - 18, // 18: server.Stack.staticClients:type_name -> server.AuthClient - 13, // 19: server.Stack.stargateConfig:type_name -> server.StargateConfig - 25, // 20: server.Stack.additionalLabels:type_name -> server.Stack.AdditionalLabelsEntry - 26, // 21: server.Stack.additionalAnnotations:type_name -> server.Stack.AdditionalAnnotationsEntry - 8, // 22: server.Stack.modules:type_name -> server.Module - 29, // 23: server.ModuleStatusChanged.status:type_name -> google.protobuf.Struct - 9, // 24: server.ModuleStatusChanged.vk:type_name -> server.VersionKind - 9, // 25: server.ModuleDeleted.vk:type_name -> server.VersionKind - 0, // 26: server.StatusChanged.status:type_name -> server.StackStatus - 29, // 27: server.StatusChanged.statuses:type_name -> google.protobuf.Struct - 9, // 28: server.StatusChanged.vk:type_name -> server.VersionKind - 27, // 29: server.AddedVersion.versions:type_name -> server.AddedVersion.VersionsEntry - 28, // 30: server.UpdatedVersion.versions:type_name -> server.UpdatedVersion.VersionsEntry - 3, // 31: server.Server.Join:input_type -> server.Message - 2, // 32: server.Server.Join:output_type -> server.Order - 32, // [32:33] is the sub-list for method output_type - 31, // [31:32] is the sub-list for method input_type - 31, // [31:31] is the sub-list for extension type_name - 31, // [31:31] is the sub-list for extension extendee - 0, // [0:31] is the sub-list for field type_name + 19, // 0: server.ListStacksResponse.stacks:type_name -> server.Stack + 24, // 1: server.ReportStackStatusRequest.status_changed:type_name -> server.StatusChanged + 26, // 2: server.ReportStackDeletedRequest.stack_deleted:type_name -> server.DeletedStack + 22, // 3: server.ReportModuleStatusRequest.module_status_changed:type_name -> server.ModuleStatusChanged + 23, // 4: server.ReportModuleDeletedRequest.module_deleted:type_name -> server.ModuleDeleted + 40, // 5: server.UpsertVersionRequest.versions:type_name -> server.UpsertVersionRequest.VersionsEntry + 27, // 6: server.Stack.authConfig:type_name -> server.AuthConfig + 28, // 7: server.Stack.staticClients:type_name -> server.AuthClient + 25, // 8: server.Stack.stargateConfig:type_name -> server.StargateConfig + 41, // 9: server.Stack.additionalLabels:type_name -> server.Stack.AdditionalLabelsEntry + 42, // 10: server.Stack.additionalAnnotations:type_name -> server.Stack.AdditionalAnnotationsEntry + 20, // 11: server.Stack.modules:type_name -> server.Module + 48, // 12: server.Stack.updated_at:type_name -> google.protobuf.Timestamp + 49, // 13: server.ModuleStatusChanged.status:type_name -> google.protobuf.Struct + 21, // 14: server.ModuleStatusChanged.vk:type_name -> server.VersionKind + 21, // 15: server.ModuleDeleted.vk:type_name -> server.VersionKind + 0, // 16: server.StatusChanged.status:type_name -> server.StackStatus + 49, // 17: server.StatusChanged.statuses:type_name -> google.protobuf.Struct + 21, // 18: server.StatusChanged.vk:type_name -> server.VersionKind + 43, // 19: server.AddedVersion.versions:type_name -> server.AddedVersion.VersionsEntry + 44, // 20: server.UpdatedVersion.versions:type_name -> server.UpdatedVersion.VersionsEntry + 45, // 21: server.ConnectRequest.tags:type_name -> server.ConnectRequest.TagsEntry + 35, // 22: server.Order.connected:type_name -> server.Connected + 19, // 23: server.Order.existingStack:type_name -> server.Stack + 26, // 24: server.Order.deletedStack:type_name -> server.DeletedStack + 36, // 25: server.Order.ping:type_name -> server.Ping + 38, // 26: server.Order.disabledStack:type_name -> server.DisabledStack + 39, // 27: server.Order.enabledStack:type_name -> server.EnabledStack + 46, // 28: server.Order.metadata:type_name -> server.Order.MetadataEntry + 24, // 29: server.Message.statusChanged:type_name -> server.StatusChanged + 37, // 30: server.Message.pong:type_name -> server.Pong + 29, // 31: server.Message.addedVersion:type_name -> server.AddedVersion + 31, // 32: server.Message.deletedVersion:type_name -> server.DeletedVersion + 30, // 33: server.Message.updatedVersion:type_name -> server.UpdatedVersion + 22, // 34: server.Message.moduleStatusChanged:type_name -> server.ModuleStatusChanged + 23, // 35: server.Message.moduleDeleted:type_name -> server.ModuleDeleted + 26, // 36: server.Message.stackDeleted:type_name -> server.DeletedStack + 47, // 37: server.Message.metadata:type_name -> server.Message.MetadataEntry + 34, // 38: server.Server.Join:input_type -> server.Message + 1, // 39: server.AgentService.ListStacks:input_type -> server.ListStacksRequest + 3, // 40: server.AgentService.ReportStackStatus:input_type -> server.ReportStackStatusRequest + 5, // 41: server.AgentService.ReportStackDeleted:input_type -> server.ReportStackDeletedRequest + 7, // 42: server.AgentService.ReportModuleStatus:input_type -> server.ReportModuleStatusRequest + 9, // 43: server.AgentService.ReportModuleDeleted:input_type -> server.ReportModuleDeletedRequest + 11, // 44: server.AgentService.UpsertVersion:input_type -> server.UpsertVersionRequest + 13, // 45: server.AgentService.DeleteVersion:input_type -> server.DeleteVersionRequest + 15, // 46: server.AgentService.Heartbeat:input_type -> server.HeartbeatRequest + 17, // 47: server.AgentService.Disconnect:input_type -> server.DisconnectRequest + 33, // 48: server.Server.Join:output_type -> server.Order + 2, // 49: server.AgentService.ListStacks:output_type -> server.ListStacksResponse + 4, // 50: server.AgentService.ReportStackStatus:output_type -> server.ReportStackStatusResponse + 6, // 51: server.AgentService.ReportStackDeleted:output_type -> server.ReportStackDeletedResponse + 8, // 52: server.AgentService.ReportModuleStatus:output_type -> server.ReportModuleStatusResponse + 10, // 53: server.AgentService.ReportModuleDeleted:output_type -> server.ReportModuleDeletedResponse + 12, // 54: server.AgentService.UpsertVersion:output_type -> server.UpsertVersionResponse + 14, // 55: server.AgentService.DeleteVersion:output_type -> server.DeleteVersionResponse + 16, // 56: server.AgentService.Heartbeat:output_type -> server.HeartbeatResponse + 18, // 57: server.AgentService.Disconnect:output_type -> server.DisconnectResponse + 48, // [48:58] is the sub-list for method output_type + 38, // [38:48] is the sub-list for method input_type + 38, // [38:38] is the sub-list for extension type_name + 38, // [38:38] is the sub-list for extension extendee + 0, // [0:38] is the sub-list for field type_name } func init() { file_agent_proto_init() } @@ -1673,7 +2613,7 @@ func file_agent_proto_init() { if File_agent_proto != nil { return } - file_agent_proto_msgTypes[1].OneofWrappers = []any{ + file_agent_proto_msgTypes[32].OneofWrappers = []any{ (*Order_Connected)(nil), (*Order_ExistingStack)(nil), (*Order_DeletedStack)(nil), @@ -1681,7 +2621,7 @@ func file_agent_proto_init() { (*Order_DisabledStack)(nil), (*Order_EnabledStack)(nil), } - file_agent_proto_msgTypes[2].OneofWrappers = []any{ + file_agent_proto_msgTypes[33].OneofWrappers = []any{ (*Message_StatusChanged)(nil), (*Message_Pong)(nil), (*Message_AddedVersion)(nil), @@ -1697,9 +2637,9 @@ func file_agent_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_agent_proto_rawDesc), len(file_agent_proto_rawDesc)), NumEnums: 1, - NumMessages: 28, + NumMessages: 47, NumExtensions: 0, - NumServices: 1, + NumServices: 2, }, GoTypes: file_agent_proto_goTypes, DependencyIndexes: file_agent_proto_depIdxs, diff --git a/internal/generated/agent_grpc.pb.go b/internal/generated/agent_grpc.pb.go index d08fce0..5000727 100644 --- a/internal/generated/agent_grpc.pb.go +++ b/internal/generated/agent_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.5.1 -// - protoc v5.29.4 +// - protoc-gen-go-grpc v1.6.2 +// - protoc v7.35.0 // source: agent.proto package generated @@ -25,6 +25,12 @@ const ( // ServerClient is the client API for Server 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. +// +// Legacy bidirectional streaming agent service. +// Kept alongside AgentService for ~3 months to support old agent binaries that +// haven't yet migrated to the pull model. Sunset target: 2026-09-09. New +// agents must use AgentService. Membership-api keeps Server registered behind +// a feature flag. type ServerClient interface { Join(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[Message, Order], error) } @@ -53,6 +59,12 @@ type Server_JoinClient = grpc.BidiStreamingClient[Message, Order] // ServerServer is the server API for Server service. // All implementations must embed UnimplementedServerServer // for forward compatibility. +// +// Legacy bidirectional streaming agent service. +// Kept alongside AgentService for ~3 months to support old agent binaries that +// haven't yet migrated to the pull model. Sunset target: 2026-09-09. New +// agents must use AgentService. Membership-api keeps Server registered behind +// a feature flag. type ServerServer interface { Join(grpc.BidiStreamingServer[Message, Order]) error mustEmbedUnimplementedServerServer() @@ -66,7 +78,7 @@ type ServerServer interface { type UnimplementedServerServer struct{} func (UnimplementedServerServer) Join(grpc.BidiStreamingServer[Message, Order]) error { - return status.Errorf(codes.Unimplemented, "method Join not implemented") + return status.Error(codes.Unimplemented, "method Join not implemented") } func (UnimplementedServerServer) mustEmbedUnimplementedServerServer() {} func (UnimplementedServerServer) testEmbeddedByValue() {} @@ -79,7 +91,7 @@ type UnsafeServerServer interface { } func RegisterServerServer(s grpc.ServiceRegistrar, srv ServerServer) { - // If the following call pancis, it indicates UnimplementedServerServer was + // If the following call panics, it indicates UnimplementedServerServer was // embedded by pointer and is nil. This will cause panics if an // unimplemented method is ever invoked, so we test this at initialization // time to prevent it from happening at runtime later due to I/O. @@ -113,3 +125,423 @@ var Server_ServiceDesc = grpc.ServiceDesc{ }, Metadata: "agent.proto", } + +const ( + AgentService_ListStacks_FullMethodName = "/server.AgentService/ListStacks" + AgentService_ReportStackStatus_FullMethodName = "/server.AgentService/ReportStackStatus" + AgentService_ReportStackDeleted_FullMethodName = "/server.AgentService/ReportStackDeleted" + AgentService_ReportModuleStatus_FullMethodName = "/server.AgentService/ReportModuleStatus" + AgentService_ReportModuleDeleted_FullMethodName = "/server.AgentService/ReportModuleDeleted" + AgentService_UpsertVersion_FullMethodName = "/server.AgentService/UpsertVersion" + AgentService_DeleteVersion_FullMethodName = "/server.AgentService/DeleteVersion" + AgentService_Heartbeat_FullMethodName = "/server.AgentService/Heartbeat" + AgentService_Disconnect_FullMethodName = "/server.AgentService/Disconnect" +) + +// AgentServiceClient is the client API for AgentService 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. +// +// Pull-based agent service. The agent polls for stacks and reports status via unary RPCs. +type AgentServiceClient interface { + // Agent pulls stacks that need syncing, paginated by (updated_at, id) cursor + ListStacks(ctx context.Context, in *ListStacksRequest, opts ...grpc.CallOption) (*ListStacksResponse, error) + // Agent reports observed state back to membership + ReportStackStatus(ctx context.Context, in *ReportStackStatusRequest, opts ...grpc.CallOption) (*ReportStackStatusResponse, error) + ReportStackDeleted(ctx context.Context, in *ReportStackDeletedRequest, opts ...grpc.CallOption) (*ReportStackDeletedResponse, error) + ReportModuleStatus(ctx context.Context, in *ReportModuleStatusRequest, opts ...grpc.CallOption) (*ReportModuleStatusResponse, error) + ReportModuleDeleted(ctx context.Context, in *ReportModuleDeletedRequest, opts ...grpc.CallOption) (*ReportModuleDeletedResponse, error) + // Version management + UpsertVersion(ctx context.Context, in *UpsertVersionRequest, opts ...grpc.CallOption) (*UpsertVersionResponse, error) + DeleteVersion(ctx context.Context, in *DeleteVersionRequest, opts ...grpc.CallOption) (*DeleteVersionResponse, error) + // Agent heartbeat (replaces ping/pong) + Heartbeat(ctx context.Context, in *HeartbeatRequest, opts ...grpc.CallOption) (*HeartbeatResponse, error) + // Graceful disconnect — marks the region as inactive + Disconnect(ctx context.Context, in *DisconnectRequest, opts ...grpc.CallOption) (*DisconnectResponse, error) +} + +type agentServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewAgentServiceClient(cc grpc.ClientConnInterface) AgentServiceClient { + return &agentServiceClient{cc} +} + +func (c *agentServiceClient) ListStacks(ctx context.Context, in *ListStacksRequest, opts ...grpc.CallOption) (*ListStacksResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ListStacksResponse) + err := c.cc.Invoke(ctx, AgentService_ListStacks_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *agentServiceClient) ReportStackStatus(ctx context.Context, in *ReportStackStatusRequest, opts ...grpc.CallOption) (*ReportStackStatusResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ReportStackStatusResponse) + err := c.cc.Invoke(ctx, AgentService_ReportStackStatus_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *agentServiceClient) ReportStackDeleted(ctx context.Context, in *ReportStackDeletedRequest, opts ...grpc.CallOption) (*ReportStackDeletedResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ReportStackDeletedResponse) + err := c.cc.Invoke(ctx, AgentService_ReportStackDeleted_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *agentServiceClient) ReportModuleStatus(ctx context.Context, in *ReportModuleStatusRequest, opts ...grpc.CallOption) (*ReportModuleStatusResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ReportModuleStatusResponse) + err := c.cc.Invoke(ctx, AgentService_ReportModuleStatus_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *agentServiceClient) ReportModuleDeleted(ctx context.Context, in *ReportModuleDeletedRequest, opts ...grpc.CallOption) (*ReportModuleDeletedResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ReportModuleDeletedResponse) + err := c.cc.Invoke(ctx, AgentService_ReportModuleDeleted_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *agentServiceClient) UpsertVersion(ctx context.Context, in *UpsertVersionRequest, opts ...grpc.CallOption) (*UpsertVersionResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UpsertVersionResponse) + err := c.cc.Invoke(ctx, AgentService_UpsertVersion_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *agentServiceClient) DeleteVersion(ctx context.Context, in *DeleteVersionRequest, opts ...grpc.CallOption) (*DeleteVersionResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DeleteVersionResponse) + err := c.cc.Invoke(ctx, AgentService_DeleteVersion_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *agentServiceClient) Heartbeat(ctx context.Context, in *HeartbeatRequest, opts ...grpc.CallOption) (*HeartbeatResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(HeartbeatResponse) + err := c.cc.Invoke(ctx, AgentService_Heartbeat_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *agentServiceClient) Disconnect(ctx context.Context, in *DisconnectRequest, opts ...grpc.CallOption) (*DisconnectResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DisconnectResponse) + err := c.cc.Invoke(ctx, AgentService_Disconnect_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// AgentServiceServer is the server API for AgentService service. +// All implementations must embed UnimplementedAgentServiceServer +// for forward compatibility. +// +// Pull-based agent service. The agent polls for stacks and reports status via unary RPCs. +type AgentServiceServer interface { + // Agent pulls stacks that need syncing, paginated by (updated_at, id) cursor + ListStacks(context.Context, *ListStacksRequest) (*ListStacksResponse, error) + // Agent reports observed state back to membership + ReportStackStatus(context.Context, *ReportStackStatusRequest) (*ReportStackStatusResponse, error) + ReportStackDeleted(context.Context, *ReportStackDeletedRequest) (*ReportStackDeletedResponse, error) + ReportModuleStatus(context.Context, *ReportModuleStatusRequest) (*ReportModuleStatusResponse, error) + ReportModuleDeleted(context.Context, *ReportModuleDeletedRequest) (*ReportModuleDeletedResponse, error) + // Version management + UpsertVersion(context.Context, *UpsertVersionRequest) (*UpsertVersionResponse, error) + DeleteVersion(context.Context, *DeleteVersionRequest) (*DeleteVersionResponse, error) + // Agent heartbeat (replaces ping/pong) + Heartbeat(context.Context, *HeartbeatRequest) (*HeartbeatResponse, error) + // Graceful disconnect — marks the region as inactive + Disconnect(context.Context, *DisconnectRequest) (*DisconnectResponse, error) + mustEmbedUnimplementedAgentServiceServer() +} + +// UnimplementedAgentServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedAgentServiceServer struct{} + +func (UnimplementedAgentServiceServer) ListStacks(context.Context, *ListStacksRequest) (*ListStacksResponse, error) { + return nil, status.Error(codes.Unimplemented, "method ListStacks not implemented") +} +func (UnimplementedAgentServiceServer) ReportStackStatus(context.Context, *ReportStackStatusRequest) (*ReportStackStatusResponse, error) { + return nil, status.Error(codes.Unimplemented, "method ReportStackStatus not implemented") +} +func (UnimplementedAgentServiceServer) ReportStackDeleted(context.Context, *ReportStackDeletedRequest) (*ReportStackDeletedResponse, error) { + return nil, status.Error(codes.Unimplemented, "method ReportStackDeleted not implemented") +} +func (UnimplementedAgentServiceServer) ReportModuleStatus(context.Context, *ReportModuleStatusRequest) (*ReportModuleStatusResponse, error) { + return nil, status.Error(codes.Unimplemented, "method ReportModuleStatus not implemented") +} +func (UnimplementedAgentServiceServer) ReportModuleDeleted(context.Context, *ReportModuleDeletedRequest) (*ReportModuleDeletedResponse, error) { + return nil, status.Error(codes.Unimplemented, "method ReportModuleDeleted not implemented") +} +func (UnimplementedAgentServiceServer) UpsertVersion(context.Context, *UpsertVersionRequest) (*UpsertVersionResponse, error) { + return nil, status.Error(codes.Unimplemented, "method UpsertVersion not implemented") +} +func (UnimplementedAgentServiceServer) DeleteVersion(context.Context, *DeleteVersionRequest) (*DeleteVersionResponse, error) { + return nil, status.Error(codes.Unimplemented, "method DeleteVersion not implemented") +} +func (UnimplementedAgentServiceServer) Heartbeat(context.Context, *HeartbeatRequest) (*HeartbeatResponse, error) { + return nil, status.Error(codes.Unimplemented, "method Heartbeat not implemented") +} +func (UnimplementedAgentServiceServer) Disconnect(context.Context, *DisconnectRequest) (*DisconnectResponse, error) { + return nil, status.Error(codes.Unimplemented, "method Disconnect not implemented") +} +func (UnimplementedAgentServiceServer) mustEmbedUnimplementedAgentServiceServer() {} +func (UnimplementedAgentServiceServer) testEmbeddedByValue() {} + +// UnsafeAgentServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to AgentServiceServer will +// result in compilation errors. +type UnsafeAgentServiceServer interface { + mustEmbedUnimplementedAgentServiceServer() +} + +func RegisterAgentServiceServer(s grpc.ServiceRegistrar, srv AgentServiceServer) { + // If the following call panics, it indicates UnimplementedAgentServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&AgentService_ServiceDesc, srv) +} + +func _AgentService_ListStacks_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListStacksRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AgentServiceServer).ListStacks(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AgentService_ListStacks_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AgentServiceServer).ListStacks(ctx, req.(*ListStacksRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AgentService_ReportStackStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ReportStackStatusRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AgentServiceServer).ReportStackStatus(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AgentService_ReportStackStatus_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AgentServiceServer).ReportStackStatus(ctx, req.(*ReportStackStatusRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AgentService_ReportStackDeleted_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ReportStackDeletedRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AgentServiceServer).ReportStackDeleted(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AgentService_ReportStackDeleted_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AgentServiceServer).ReportStackDeleted(ctx, req.(*ReportStackDeletedRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AgentService_ReportModuleStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ReportModuleStatusRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AgentServiceServer).ReportModuleStatus(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AgentService_ReportModuleStatus_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AgentServiceServer).ReportModuleStatus(ctx, req.(*ReportModuleStatusRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AgentService_ReportModuleDeleted_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ReportModuleDeletedRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AgentServiceServer).ReportModuleDeleted(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AgentService_ReportModuleDeleted_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AgentServiceServer).ReportModuleDeleted(ctx, req.(*ReportModuleDeletedRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AgentService_UpsertVersion_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpsertVersionRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AgentServiceServer).UpsertVersion(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AgentService_UpsertVersion_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AgentServiceServer).UpsertVersion(ctx, req.(*UpsertVersionRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AgentService_DeleteVersion_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteVersionRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AgentServiceServer).DeleteVersion(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AgentService_DeleteVersion_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AgentServiceServer).DeleteVersion(ctx, req.(*DeleteVersionRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AgentService_Heartbeat_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(HeartbeatRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AgentServiceServer).Heartbeat(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AgentService_Heartbeat_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AgentServiceServer).Heartbeat(ctx, req.(*HeartbeatRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AgentService_Disconnect_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DisconnectRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AgentServiceServer).Disconnect(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AgentService_Disconnect_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AgentServiceServer).Disconnect(ctx, req.(*DisconnectRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// AgentService_ServiceDesc is the grpc.ServiceDesc for AgentService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var AgentService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "server.AgentService", + HandlerType: (*AgentServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "ListStacks", + Handler: _AgentService_ListStacks_Handler, + }, + { + MethodName: "ReportStackStatus", + Handler: _AgentService_ReportStackStatus_Handler, + }, + { + MethodName: "ReportStackDeleted", + Handler: _AgentService_ReportStackDeleted_Handler, + }, + { + MethodName: "ReportModuleStatus", + Handler: _AgentService_ReportModuleStatus_Handler, + }, + { + MethodName: "ReportModuleDeleted", + Handler: _AgentService_ReportModuleDeleted_Handler, + }, + { + MethodName: "UpsertVersion", + Handler: _AgentService_UpsertVersion_Handler, + }, + { + MethodName: "DeleteVersion", + Handler: _AgentService_DeleteVersion_Handler, + }, + { + MethodName: "Heartbeat", + Handler: _AgentService_Heartbeat_Handler, + }, + { + MethodName: "Disconnect", + Handler: _AgentService_Disconnect_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "agent.proto", +} diff --git a/internal/grpcclient/connection_adapter.go b/internal/grpcclient/connection_adapter.go deleted file mode 100644 index a1ba998..0000000 --- a/internal/grpcclient/connection_adapter.go +++ /dev/null @@ -1,104 +0,0 @@ -package grpcclient - -import ( - "context" - "fmt" - "reflect" - - "github.com/formancehq/stack/components/agent/internal/generated" - "github.com/formancehq/stack/components/agent/pkg/tracing" - "go.opentelemetry.io/otel" - "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/trace" -) - -var tracer = otel.Tracer("cmd.formance.grpc") - -//go:generate mockgen -source=connection_adapter.go -destination=connection_generated.go -package grpcclient . Connection -type Connection interface { - CloseSend() error - Send(*generated.Message) error - Recv() (*generated.Order, error) -} - -//go:generate mockgen -source=connection_adapter.go -destination=connection_generated.go -package grpcclient . ConnectionAdapter -type ConnectionAdapter interface { - CloseSend(context.Context) error - - Send(context.Context, *generated.Message) error - Recv(context.Context) (*generated.Order, error) -} - -type DefaultConnection struct { - Connection -} - -var _ ConnectionAdapter = (*DefaultConnection)(nil) - -func (c *DefaultConnection) Send(_ context.Context, msg *generated.Message) error { - return c.Connection.Send(msg) -} - -func (c *DefaultConnection) Recv(_ context.Context) (*generated.Order, error) { - return c.Connection.Recv() -} - -func (c *DefaultConnection) CloseSend(_ context.Context) error { - return c.Connection.CloseSend() -} - -func NewDefaultConnection(conn Connection) *DefaultConnection { - return &DefaultConnection{ - Connection: conn, - } -} - -type ConnectionWithTrace struct { - Debug bool - Connection -} - -func NewConnectionWithTrace(conn Connection, debug bool) *ConnectionWithTrace { - return &ConnectionWithTrace{ - Connection: conn, - Debug: debug, - } -} - -func (c *ConnectionWithTrace) Send(ctx context.Context, msg *generated.Message) error { - return tracing.TraceError(ctx, tracer, "Send", func(ctx context.Context) error { - span := trace.SpanFromContext(ctx) - name := reflect.TypeOf(msg.Message).Elem().Name() - span.SetAttributes(attribute.String("grpc.message.type", name)) - if c.Debug { - span.SetAttributes(attribute.String("grpc.message.raw", fmt.Sprintf("%v", msg.String()))) - } - - InjectOtelCtxInMessage(ctx, msg) - return c.Connection.Send(msg) - }) -} - -func (c *ConnectionWithTrace) Recv(ctx context.Context) (*generated.Order, error) { - msg, err := c.Connection.Recv() - if err != nil { - return nil, err - } - ctx = ExtractOtelCtxFromMessage(ctx, msg) - return tracing.Trace(ctx, tracer, "Recv", func(ctx context.Context) (*generated.Order, error) { - span := trace.SpanFromContext(ctx) - name := reflect.TypeOf(msg.Message).Elem().Name() - span.SetAttributes(attribute.String("grpc.message.type", name)) - - if c.Debug { - span.SetAttributes(attribute.String("grpc.message.raw", fmt.Sprintf("%v", msg.String()))) - } - return msg, err - }) -} - -func (c *ConnectionWithTrace) CloseSend(ctx context.Context) error { - return tracing.TraceError(ctx, tracer, "CloseSend", func(ctx context.Context) error { - return c.Connection.CloseSend() - }) -} diff --git a/internal/grpcclient/connection_generated.go b/internal/grpcclient/connection_generated.go deleted file mode 100644 index c72d10e..0000000 --- a/internal/grpcclient/connection_generated.go +++ /dev/null @@ -1,152 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: connection_adapter.go -// -// Generated by this command: -// -// mockgen -source=connection_adapter.go -destination=connection_generated.go -package grpcclient . ConnectionAdapter -// - -// Package grpcclient is a generated GoMock package. -package grpcclient - -import ( - context "context" - reflect "reflect" - - generated "github.com/formancehq/stack/components/agent/internal/generated" - gomock "go.uber.org/mock/gomock" -) - -// MockConnection is a mock of Connection interface. -type MockConnection struct { - ctrl *gomock.Controller - recorder *MockConnectionMockRecorder - isgomock struct{} -} - -// MockConnectionMockRecorder is the mock recorder for MockConnection. -type MockConnectionMockRecorder struct { - mock *MockConnection -} - -// NewMockConnection creates a new mock instance. -func NewMockConnection(ctrl *gomock.Controller) *MockConnection { - mock := &MockConnection{ctrl: ctrl} - mock.recorder = &MockConnectionMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockConnection) EXPECT() *MockConnectionMockRecorder { - return m.recorder -} - -// CloseSend mocks base method. -func (m *MockConnection) CloseSend() error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CloseSend") - ret0, _ := ret[0].(error) - return ret0 -} - -// CloseSend indicates an expected call of CloseSend. -func (mr *MockConnectionMockRecorder) CloseSend() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CloseSend", reflect.TypeOf((*MockConnection)(nil).CloseSend)) -} - -// Recv mocks base method. -func (m *MockConnection) Recv() (*generated.Order, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Recv") - ret0, _ := ret[0].(*generated.Order) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Recv indicates an expected call of Recv. -func (mr *MockConnectionMockRecorder) Recv() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Recv", reflect.TypeOf((*MockConnection)(nil).Recv)) -} - -// Send mocks base method. -func (m *MockConnection) Send(arg0 *generated.Message) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Send", arg0) - ret0, _ := ret[0].(error) - return ret0 -} - -// Send indicates an expected call of Send. -func (mr *MockConnectionMockRecorder) Send(arg0 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Send", reflect.TypeOf((*MockConnection)(nil).Send), arg0) -} - -// MockConnectionAdapter is a mock of ConnectionAdapter interface. -type MockConnectionAdapter struct { - ctrl *gomock.Controller - recorder *MockConnectionAdapterMockRecorder - isgomock struct{} -} - -// MockConnectionAdapterMockRecorder is the mock recorder for MockConnectionAdapter. -type MockConnectionAdapterMockRecorder struct { - mock *MockConnectionAdapter -} - -// NewMockConnectionAdapter creates a new mock instance. -func NewMockConnectionAdapter(ctrl *gomock.Controller) *MockConnectionAdapter { - mock := &MockConnectionAdapter{ctrl: ctrl} - mock.recorder = &MockConnectionAdapterMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockConnectionAdapter) EXPECT() *MockConnectionAdapterMockRecorder { - return m.recorder -} - -// CloseSend mocks base method. -func (m *MockConnectionAdapter) CloseSend(arg0 context.Context) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CloseSend", arg0) - ret0, _ := ret[0].(error) - return ret0 -} - -// CloseSend indicates an expected call of CloseSend. -func (mr *MockConnectionAdapterMockRecorder) CloseSend(arg0 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CloseSend", reflect.TypeOf((*MockConnectionAdapter)(nil).CloseSend), arg0) -} - -// Recv mocks base method. -func (m *MockConnectionAdapter) Recv(arg0 context.Context) (*generated.Order, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Recv", arg0) - ret0, _ := ret[0].(*generated.Order) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Recv indicates an expected call of Recv. -func (mr *MockConnectionAdapterMockRecorder) Recv(arg0 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Recv", reflect.TypeOf((*MockConnectionAdapter)(nil).Recv), arg0) -} - -// Send mocks base method. -func (m *MockConnectionAdapter) Send(arg0 context.Context, arg1 *generated.Message) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Send", arg0, arg1) - ret0, _ := ret[0].(error) - return ret0 -} - -// Send indicates an expected call of Send. -func (mr *MockConnectionAdapterMockRecorder) Send(arg0, arg1 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Send", reflect.TypeOf((*MockConnectionAdapter)(nil).Send), arg0, arg1) -} diff --git a/internal/grpcclient/tracing.go b/internal/grpcclient/tracing.go deleted file mode 100644 index 855b82e..0000000 --- a/internal/grpcclient/tracing.go +++ /dev/null @@ -1,53 +0,0 @@ -package grpcclient - -import ( - "context" - "encoding/json" - - "github.com/formancehq/go-libs/v2/logging" - "github.com/formancehq/stack/components/agent/internal/generated" - "go.opentelemetry.io/otel" - - "go.opentelemetry.io/otel/propagation" -) - -const ( - OtelCtx = "_otelCtx" -) - -func ExtractOtelCtxFromMessage(ctx context.Context, order *generated.Order) context.Context { - if header, ok := order.Metadata[OtelCtx]; !ok || ok && header == "" { - logging.FromContext(ctx).Errorf("otel context not found") - return ctx - } - - carrier := propagation.MapCarrier{} - if err := json.Unmarshal([]byte(order.Metadata[OtelCtx]), &carrier); err == nil { - ctx = otel.GetTextMapPropagator().Extract(ctx, carrier) - logging.FromContext(ctx).Debug("otel context extracted") - return ctx - } - - logging.FromContext(ctx).Error("cannot extract otel context") - return ctx -} - -func NewMsg(ctx context.Context) *generated.Message { - metadata := make(map[string]string) - message := &generated.Message{ - Metadata: metadata, - } - InjectOtelCtxInMessage(ctx, message) - return message -} - -func InjectOtelCtxInMessage(ctx context.Context, order *generated.Message) { - carrier := propagation.MapCarrier{} - otel.GetTextMapPropagator().Inject(ctx, carrier) - otelContext, _ := json.Marshal(carrier) - - if order.Metadata == nil { - order.Metadata = make(map[string]string) - } - order.Metadata[OtelCtx] = string(otelContext) -} diff --git a/internal/informer_modules.go b/internal/informer_modules.go index 77ed2aa..cb35c5e 100644 --- a/internal/informer_modules.go +++ b/internal/informer_modules.go @@ -1,6 +1,7 @@ package internal import ( + "context" "reflect" "github.com/formancehq/go-libs/v2/logging" @@ -10,24 +11,25 @@ import ( "k8s.io/client-go/tools/cache" ) -func fromUnstructuredToModuleStatusChanged(unstructuredModule *unstructured.Unstructured, status *structpb.Struct) *generated.Message { - return &generated.Message{ - Message: &generated.Message_ModuleStatusChanged{ - ModuleStatusChanged: &generated.ModuleStatusChanged{ - ClusterName: unstructuredModule.GetName(), - Vk: &generated.VersionKind{ - Version: unstructuredModule.GetObjectKind().GroupVersionKind().Version, - Kind: unstructuredModule.GetObjectKind().GroupVersionKind().Kind, - }, - Status: status, - }, - }, +func versionKindFromUnstructured(u *unstructured.Unstructured) *generated.VersionKind { + return &generated.VersionKind{ + Version: u.GetObjectKind().GroupVersionKind().Version, + Kind: u.GetObjectKind().GroupVersionKind().Kind, } } type ModuleEventHandler struct { - logger logging.Logger - client MembershipClient + ctx context.Context + logger logging.Logger + reporter MembershipReporter +} + +func (h *ModuleEventHandler) sendModuleStatus(clusterName string, vk *generated.VersionKind, status *structpb.Struct) error { + if err := h.reporter.ReportModuleStatus(h.ctx, clusterName, vk, status); err != nil { + h.logger.Errorf("Unable to send module status to server: %s", err) + return err + } + return nil } func (h *ModuleEventHandler) AddFunc(obj interface{}) { @@ -45,8 +47,8 @@ func (h *ModuleEventHandler) AddFunc(obj interface{}) { return } - message := fromUnstructuredToModuleStatusChanged(unstructuredModule, status) - if err := h.client.Send(message); err != nil { + vk := versionKindFromUnstructured(unstructuredModule) + if err := h.sendModuleStatus(unstructuredModule.GetName(), vk, status); err != nil { logger.Errorf("Unable to send message module added: %s", err) return } @@ -75,8 +77,8 @@ func (h *ModuleEventHandler) UpdateFunc(oldObj, newObj any) { return } - message := fromUnstructuredToModuleStatusChanged(newVersions, newStatus) - if err := h.client.Send(message); err != nil { + vk := versionKindFromUnstructured(newVersions) + if err := h.sendModuleStatus(newVersions.GetName(), vk, newStatus); err != nil { logger.Errorf("Unable to send message module update: %s", err) return } @@ -88,27 +90,19 @@ func (h *ModuleEventHandler) DeleteFunc(obj interface{}) { unstructuredModule := obj.(*unstructured.Unstructured) logger := h.logger.WithField("func", "Delete").WithField("module", unstructuredModule.GetName()) - if err := h.client.Send(&generated.Message{ - Message: &generated.Message_ModuleDeleted{ - ModuleDeleted: &generated.ModuleDeleted{ - ClusterName: unstructuredModule.GetName(), - Vk: &generated.VersionKind{ - Version: unstructuredModule.GetObjectKind().GroupVersionKind().Version, - Kind: unstructuredModule.GetObjectKind().GroupVersionKind().Kind, - }, - }, - }, - }); err != nil { + vk := versionKindFromUnstructured(unstructuredModule) + if err := h.reporter.ReportModuleDeleted(h.ctx, unstructuredModule.GetName(), vk); err != nil { logger.Errorf("Unable to send message module deleted: %s", err) return } logger.Infof("Detect module '%s' deleted", unstructuredModule.GetName()) } -func NewModuleEventHandler(logger logging.Logger, membershipClient MembershipClient) cache.ResourceEventHandlerFuncs { +func NewModuleEventHandler(ctx context.Context, logger logging.Logger, reporter MembershipReporter) cache.ResourceEventHandlerFuncs { moduleEventHandler := &ModuleEventHandler{ - logger: logger, - client: membershipClient, + ctx: ctx, + logger: logger, + reporter: reporter, } return cache.ResourceEventHandlerFuncs{ diff --git a/internal/informer_modules_test.go b/internal/informer_modules_test.go index e87b58d..ca87aa2 100644 --- a/internal/informer_modules_test.go +++ b/internal/informer_modules_test.go @@ -1,6 +1,7 @@ package internal_test import ( + "context" "encoding/json" "testing" @@ -10,7 +11,6 @@ import ( "github.com/formancehq/stack/components/agent/internal" "github.com/google/uuid" "github.com/stretchr/testify/require" - "go.uber.org/mock/gomock" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" ) @@ -107,9 +107,8 @@ func TestRestrictModuleStatus(t *testing.T) { func TestModuleAddFunc(t *testing.T) { t.Parallel() - ctrl := gomock.NewController(t) - membershipClientMock := internal.NewMockMembershipClient(ctrl) - resourceInformer := internal.NewModuleEventHandler(logging.Testing(), membershipClientMock) + reporter := internal.NewMembershipReporterMock() + resourceInformer := internal.NewModuleEventHandler(context.Background(), logging.Testing(), reporter) module := &unstructured.Unstructured{ Object: map[string]interface{}{ @@ -122,17 +121,17 @@ func TestModuleAddFunc(t *testing.T) { }, } - membershipClientMock.EXPECT().Send(gomock.Any()) resourceInformer.AddFunc(module) - require.True(t, ctrl.Satisfied()) + events := reporter.GetEvents() + require.Len(t, events, 1) + require.Equal(t, "ModuleStatus", events[0].Type) } func TestModuleDelete(t *testing.T) { t.Parallel() - ctrl := gomock.NewController(t) - membershipClientMock := internal.NewMockMembershipClient(ctrl) - resourceInformer := internal.NewModuleEventHandler(logging.Testing(), membershipClientMock) + reporter := internal.NewMembershipReporterMock() + resourceInformer := internal.NewModuleEventHandler(context.Background(), logging.Testing(), reporter) module := &unstructured.Unstructured{ Object: map[string]interface{}{ @@ -145,16 +144,17 @@ func TestModuleDelete(t *testing.T) { }, } - membershipClientMock.EXPECT().Send(gomock.Any()) resourceInformer.DeleteFunc(module) - require.True(t, ctrl.Satisfied()) + + events := reporter.GetEvents() + require.Len(t, events, 1) + require.Equal(t, "ModuleDeleted", events[0].Type) } func TestModuleUpdateStatusNil(t *testing.T) { t.Parallel() - ctrl := gomock.NewController(t) - membershipClientMock := internal.NewMockMembershipClient(ctrl) - resourceInformer := internal.NewModuleEventHandler(logging.Testing(), membershipClientMock) + reporter := internal.NewMembershipReporterMock() + resourceInformer := internal.NewModuleEventHandler(context.Background(), logging.Testing(), reporter) oldModule := &unstructured.Unstructured{ Object: map[string]interface{}{ @@ -173,9 +173,11 @@ func TestModuleUpdateStatusNil(t *testing.T) { } resourceInformer.UpdateFunc(oldModule, newModule) - require.True(t, ctrl.Satisfied()) + events := reporter.GetEvents() + require.Empty(t, events) } + func TestModuleUpdateStatusChanged(t *testing.T) { type testCase struct { @@ -194,9 +196,8 @@ func TestModuleUpdateStatusChanged(t *testing.T) { tc := tc t.Run("test", func(t *testing.T) { t.Parallel() - ctrl := gomock.NewController(t) - membershipClientMock := internal.NewMockMembershipClient(ctrl) - resourceInformer := internal.NewModuleEventHandler(logging.Testing(), membershipClientMock) + reporter := internal.NewMembershipReporterMock() + resourceInformer := internal.NewModuleEventHandler(context.Background(), logging.Testing(), reporter) oldModule := &unstructured.Unstructured{ Object: map[string]interface{}{ @@ -219,11 +220,16 @@ func TestModuleUpdateStatusChanged(t *testing.T) { }, }, } + + resourceInformer.UpdateFunc(oldModule, newModule) + + events := reporter.GetEvents() if tc.isReady != tc.wasReady { - membershipClientMock.EXPECT().Send(gomock.Any()) + require.Len(t, events, 1) + require.Equal(t, "ModuleStatus", events[0].Type) + } else { + require.Empty(t, events) } - resourceInformer.UpdateFunc(oldModule, newModule) - require.True(t, ctrl.Satisfied()) }) } diff --git a/internal/informer_stacks.go b/internal/informer_stacks.go index 01f3739..8a7f42b 100644 --- a/internal/informer_stacks.go +++ b/internal/informer_stacks.go @@ -1,29 +1,23 @@ package internal import ( + "context" "reflect" "github.com/formancehq/go-libs/v2/logging" - "github.com/formancehq/stack/components/agent/internal/generated" "google.golang.org/protobuf/types/known/structpb" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/client-go/tools/cache" ) type StackEventHandler struct { - logger logging.Logger - client MembershipClient + ctx context.Context + logger logging.Logger + reporter MembershipReporter } func (h *StackEventHandler) sendStatus(stackName string, status *structpb.Struct) error { - if err := h.client.Send(&generated.Message{ - Message: &generated.Message_StatusChanged{ - StatusChanged: &generated.StatusChanged{ - ClusterName: stackName, - Statuses: status, - }, - }, - }); err != nil { + if err := h.reporter.ReportStackStatus(h.ctx, stackName, status); err != nil { h.logger.Errorf("Unable to send stack status to server: %s", err) return err } @@ -96,23 +90,18 @@ func (h *StackEventHandler) DeleteFunc(obj interface{}) { stack := obj.(*unstructured.Unstructured) logger := h.logger.WithField("func", "Delete").WithField("stack", stack.GetName()) - if err := h.client.Send(&generated.Message{ - Message: &generated.Message_StackDeleted{ - StackDeleted: &generated.DeletedStack{ - ClusterName: stack.GetName(), - }, - }, - }); err != nil { + if err := h.reporter.ReportStackDeleted(h.ctx, stack.GetName()); err != nil { logger.Errorf("Unable to send stack delete to server: %s", err) return } logger.Infof("Stack '%s' deleted", stack.GetName()) } -func NewStackEventHandler(logger logging.Logger, membershipClient MembershipClient) cache.ResourceEventHandlerFuncs { +func NewStackEventHandler(ctx context.Context, logger logging.Logger, reporter MembershipReporter) cache.ResourceEventHandlerFuncs { stackEventHandler := &StackEventHandler{ - logger: logger, - client: membershipClient, + ctx: ctx, + logger: logger, + reporter: reporter, } return cache.ResourceEventHandlerFuncs{ diff --git a/internal/informer_stacks_test.go b/internal/informer_stacks_test.go index 870c678..0a34429 100644 --- a/internal/informer_stacks_test.go +++ b/internal/informer_stacks_test.go @@ -1,6 +1,7 @@ package internal_test import ( + "context" "fmt" "testing" @@ -9,7 +10,6 @@ import ( "github.com/formancehq/stack/components/agent/internal" "github.com/google/uuid" "github.com/stretchr/testify/require" - "go.uber.org/mock/gomock" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" @@ -17,9 +17,8 @@ import ( func TestDeleteFunc(t *testing.T) { t.Parallel() - ctrl := gomock.NewController(t) - membershipClientMock := internal.NewMockMembershipClient(ctrl) - resourceInformer := internal.NewStackEventHandler(logging.Testing(), membershipClientMock) + reporter := internal.NewMembershipReporterMock() + resourceInformer := internal.NewStackEventHandler(context.Background(), logging.Testing(), reporter) stack := &v1beta1.Stack{ ObjectMeta: v1.ObjectMeta{ @@ -27,7 +26,6 @@ func TestDeleteFunc(t *testing.T) { }, } - membershipClientMock.EXPECT().Send(gomock.Any()) unstructuredStack, err := runtime.DefaultUnstructuredConverter.ToUnstructured(stack) if err != nil { t.Fatalf("failed to convert stack to unstructured: %v", err) @@ -37,14 +35,16 @@ func TestDeleteFunc(t *testing.T) { Object: unstructuredStack, }) - require.True(t, ctrl.Satisfied()) + events := reporter.GetEvents() + require.Len(t, events, 1) + require.Equal(t, "StackDeleted", events[0].Type) + require.Equal(t, stack.Name, events[0].ClusterName) } func TestAddStack(t *testing.T) { t.Parallel() - ctrl := gomock.NewController(t) - membershipClientMock := internal.NewMockMembershipClient(ctrl) - resourceInformer := internal.NewStackEventHandler(logging.Testing(), membershipClientMock) + reporter := internal.NewMembershipReporterMock() + resourceInformer := internal.NewStackEventHandler(context.Background(), logging.Testing(), reporter) stack := &v1beta1.Stack{ ObjectMeta: v1.ObjectMeta{ @@ -55,7 +55,6 @@ func TestAddStack(t *testing.T) { }, } - membershipClientMock.EXPECT().Send(gomock.Any()) unstructuredStack, err := runtime.DefaultUnstructuredConverter.ToUnstructured(stack) if err != nil { t.Fatalf("failed to convert stack to unstructured: %v", err) @@ -64,7 +63,9 @@ func TestAddStack(t *testing.T) { Object: unstructuredStack, }) - require.True(t, ctrl.Satisfied()) + events := reporter.GetEvents() + require.Len(t, events, 1) + require.Equal(t, "StackStatus", events[0].Type) } // We are watching .Status and .Spec fields of the stack resource. @@ -100,9 +101,8 @@ func TestUpdateStatus(t *testing.T) { t.Run(fmt.Sprintf("isReady: %t isDisabled: %t wasReady: %t wasDisabled: %t", tc.isReady, tc.isDisabled, tc.wasReady, tc.wasDisabled), func(t *testing.T) { t.Parallel() - ctrl := gomock.NewController(t) - membershipClientMock := internal.NewMockMembershipClient(ctrl) - resourceInformer := internal.NewStackEventHandler(logging.Testing(), membershipClientMock) + reporter := internal.NewMembershipReporterMock() + resourceInformer := internal.NewStackEventHandler(context.Background(), logging.Testing(), reporter) oldStack := &v1beta1.Stack{ ObjectMeta: v1.ObjectMeta{ @@ -122,9 +122,7 @@ func TestUpdateStatus(t *testing.T) { newStack.Status.Ready = tc.isReady newStack.Spec.Disabled = tc.isDisabled - if tc.isReady != tc.wasReady || tc.isDisabled != tc.wasDisabled { - membershipClientMock.EXPECT().Send(gomock.Any()) - } + expectCall := tc.isReady != tc.wasReady || tc.isDisabled != tc.wasDisabled unstructuredOldStack, err := runtime.DefaultUnstructuredConverter.ToUnstructured(oldStack) if err != nil { @@ -141,7 +139,13 @@ func TestUpdateStatus(t *testing.T) { Object: unstructuredNewStack, }) - require.True(t, ctrl.Satisfied()) + events := reporter.GetEvents() + if expectCall { + require.Len(t, events, 1) + require.Equal(t, "StackStatus", events[0].Type) + } else { + require.Empty(t, events) + } }) } } diff --git a/internal/informer_versions.go b/internal/informer_versions.go index 1ce4e49..5059d86 100644 --- a/internal/informer_versions.go +++ b/internal/informer_versions.go @@ -1,11 +1,11 @@ package internal import ( + "context" "reflect" "github.com/formancehq/go-libs/v2/logging" "github.com/formancehq/operator/v3/api/formance.com/v1beta1" - "github.com/formancehq/stack/components/agent/internal/generated" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/tools/cache" @@ -22,22 +22,19 @@ func convertUnstructured[T client.Object](v any) T { return t } -func VersionsEventHandler(logger logging.Logger, membershipClient MembershipClient) cache.ResourceEventHandler { +func VersionsEventHandler(ctx context.Context, logger logging.Logger, reporter MembershipReporter) cache.ResourceEventHandler { return cache.ResourceEventHandlerFuncs{ AddFunc: func(obj interface{}) { version := convertUnstructured[*v1beta1.Versions](obj) logger.Infof("Detect versions '%s' added", version.Name) - if err := membershipClient.Send(&generated.Message{ - Message: &generated.Message_AddedVersion{ - AddedVersion: &generated.AddedVersion{ - Name: version.Name, - Versions: version.Spec, - Deprecated: version.Annotations["formance.com/deprecated"] == "true", - }, - }, - }); err != nil { + if err := reporter.UpsertVersion( + ctx, + version.Name, + version.Spec, + version.Annotations["formance.com/deprecated"] == "true", + ); err != nil { logger.Errorf("Unable to send version update: %s", err) } }, @@ -51,15 +48,12 @@ func VersionsEventHandler(logger logging.Logger, membershipClient MembershipClie } logger.Infof("Detect versions '%s' modified", newVersions.Name) - if err := membershipClient.Send(&generated.Message{ - Message: &generated.Message_UpdatedVersion{ - UpdatedVersion: &generated.UpdatedVersion{ - Name: newVersions.Name, - Versions: newVersions.Spec, - Deprecated: newVersions.Annotations["formance.com/deprecated"] == "true", - }, - }, - }); err != nil { + if err := reporter.UpsertVersion( + ctx, + newVersions.Name, + newVersions.Spec, + newVersions.Annotations["formance.com/deprecated"] == "true", + ); err != nil { logger.Errorf("Unable to send version update: %s", err) } }, @@ -67,13 +61,7 @@ func VersionsEventHandler(logger logging.Logger, membershipClient MembershipClie version := convertUnstructured[*v1beta1.Versions](obj) logger.Infof("Detect versions '%s' as deleted", version.Name) - if err := membershipClient.Send(&generated.Message{ - Message: &generated.Message_DeletedVersion{ - DeletedVersion: &generated.DeletedVersion{ - Name: version.Name, - }, - }, - }); err != nil { + if err := reporter.DeleteVersion(ctx, version.Name); err != nil { logger.Errorf("Unable to send version update: %s", err) } }, diff --git a/internal/membership_client.go b/internal/membership_client.go deleted file mode 100644 index 6a3db2e..0000000 --- a/internal/membership_client.go +++ /dev/null @@ -1,250 +0,0 @@ -package internal - -import ( - "context" - "io" - "strconv" - "time" - - "github.com/formancehq/go-libs/v2/logging" - "github.com/formancehq/stack/components/agent/internal/generated" - "github.com/formancehq/stack/components/agent/internal/grpcclient" - - "github.com/pkg/errors" - "google.golang.org/grpc" - "google.golang.org/grpc/metadata" -) - -const ( - metadataID = "id" - metadataBaseUrl = "baseUrl" - metadataAdditionalBaseUrls = "additionalBaseUrls" - metadataProduction = "production" - metadataOutdated = "outdated" - metadataVersion = "version" - metadataCapabilities = "capabilities" - - capabilityEE = "EE" - capabilityModuleList = "MODULE_LIST" -) - -type membershipClient struct { - modules []string - eeModules []string - - clientInfo ClientInfo - stopChan chan chan error - stopped chan struct{} - - joinContext context.Context - joinCancel func() - - authenticator Authenticator - - orders chan *generated.Order - opts []grpc.DialOption - - address string - - messages chan *generated.Message -} - -func (c *membershipClient) connectMetadata(ctx context.Context) (metadata.MD, error) { - - md, err := c.authenticator.authenticate(ctx) - if err != nil { - return nil, errors.Wrap(err, "authenticating client") - } - - md.Append(metadataID, c.clientInfo.ID) - md.Append(metadataBaseUrl, c.clientInfo.BaseUrl.String()) - md.Append(metadataAdditionalBaseUrls, c.clientInfo.AdditionalBaseURLs...) - md.Append(metadataProduction, strconv.FormatBool(c.clientInfo.Production)) - md.Append(metadataOutdated, strconv.FormatBool(c.clientInfo.Outdated)) - md.Append(metadataVersion, c.clientInfo.Version) - md.Append(metadataCapabilities, capabilityEE, capabilityModuleList) - md.Append(capabilityModuleList, c.modules...) - md.Append(capabilityEE, c.eeModules...) - return md, nil -} - -func LoggingClientStreamInterceptor(l logging.Logger) grpc.StreamClientInterceptor { - return func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) { - logging.FromContext(ctx). - Infof("Starting stream") - return streamer(logging.ContextWithLogger(ctx, l), desc, cc, method, opts...) - } -} - -func (c *membershipClient) connect(ctx context.Context) (generated.Server_JoinClient, error) { - logging.FromContext(ctx).WithFields(map[string]any{ - "id": c.clientInfo.ID, - }).Infof("Establish connection to server") - c.joinContext, c.joinCancel = context.WithCancel(ctx) - - opts := append(c.opts, - grpc.WithChainStreamInterceptor( - LoggingClientStreamInterceptor(logging.FromContext(ctx)), - ), - ) - conn, err := grpc.NewClient(c.address, opts...) - if err != nil { - return nil, err - } - - serverClient := generated.NewServerClient(conn) - - md, err := c.connectMetadata(ctx) - if err != nil { - return nil, err - } - connectContext := metadata.NewOutgoingContext(c.joinContext, md) - joinClient, err := serverClient.Join(connectContext) - if err != nil { - return nil, err - } - - return joinClient, nil -} - -func (c *membershipClient) Send(message *generated.Message) error { - select { - case <-c.stopped: - return errors.New("stopped") - case c.messages <- message: - return nil - } -} - -func (c *membershipClient) sendPong(ctx context.Context, client grpcclient.ConnectionAdapter) { - if err := client.Send(ctx, &generated.Message{ - Message: &generated.Message_Pong{ - Pong: &generated.Pong{}, - }, - }); err != nil { - logging.FromContext(ctx).Errorf("Unable to send pong to server: %s", err) - if errors.Is(err, io.EOF) { - panic(err) - } - } -} - -func (c *membershipClient) Start(ctx context.Context, client grpcclient.ConnectionAdapter) error { - - var ( - errCh = make(chan error, 1) - ) - go func() { - for { - msg, err := client.Recv(ctx) - if err != nil { - if err == io.EOF { - select { - case <-c.stopped: - default: - errCh <- err - } - return - } - errCh <- err - return - } - - if msg.GetPing() != nil { - c.sendPong(ctx, client) - continue - } - - select { - case c.orders <- msg: - case <-ctx.Done(): - return - } - } - }() - go func() { - for { - select { - case <-time.After(5 * time.Second): - c.sendPong(ctx, client) - case <-ctx.Done(): - return - } - } - }() - - for { - select { - case <-ctx.Done(): - return ctx.Err() - case ch := <-c.stopChan: - close(c.stopped) - if err := client.CloseSend(ctx); err != nil { - ch <- err - //nolint:nilerr - return nil - } - c.joinCancel() - - // Drain messages - for { - _, err := client.Recv(ctx) - if err != nil { - break - } - } - - ch <- nil - return nil - case msg := <-c.messages: - if err := client.Send(ctx, msg); err != nil { - panic(err) - } - <-time.After(50 * time.Millisecond) - case err := <-errCh: - logging.FromContext(ctx).Errorf("Stream closed with error: %s", err) - return err - } - } -} - -func (c *membershipClient) Stop(ctx context.Context) error { - ch := make(chan error) - select { - case <-ctx.Done(): - return ctx.Err() - case c.stopChan <- ch: - select { - case <-ctx.Done(): - return ctx.Err() - case err := <-ch: - return err - } - } -} - -func (c *membershipClient) Orders() chan *generated.Order { - return c.orders -} - -func NewMembershipClient( - authenticator Authenticator, - clientInfo ClientInfo, - address string, - modules modules, - eeModules eeModules, - opts ...grpc.DialOption, -) *membershipClient { - return &membershipClient{ - stopChan: make(chan chan error), - authenticator: authenticator, - clientInfo: clientInfo, - opts: opts, - address: address, - orders: make(chan *generated.Order), - messages: make(chan *generated.Message), - stopped: make(chan struct{}), - modules: modules.Singular(), - eeModules: eeModules.Singular(), - } -} diff --git a/internal/membership_client_generated.go b/internal/membership_client_generated.go deleted file mode 100644 index 47716a5..0000000 --- a/internal/membership_client_generated.go +++ /dev/null @@ -1,69 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: membership_listener.go -// -// Generated by this command: -// -// mockgen -source=membership_listener.go -destination=membership_client_generated.go -package=internal . MembershipClient -// - -// Package internal is a generated GoMock package. -package internal - -import ( - reflect "reflect" - - generated "github.com/formancehq/stack/components/agent/internal/generated" - gomock "go.uber.org/mock/gomock" -) - -// MockMembershipClient is a mock of MembershipClient interface. -type MockMembershipClient struct { - ctrl *gomock.Controller - recorder *MockMembershipClientMockRecorder - isgomock struct{} -} - -// MockMembershipClientMockRecorder is the mock recorder for MockMembershipClient. -type MockMembershipClientMockRecorder struct { - mock *MockMembershipClient -} - -// NewMockMembershipClient creates a new mock instance. -func NewMockMembershipClient(ctrl *gomock.Controller) *MockMembershipClient { - mock := &MockMembershipClient{ctrl: ctrl} - mock.recorder = &MockMembershipClientMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockMembershipClient) EXPECT() *MockMembershipClientMockRecorder { - return m.recorder -} - -// Orders mocks base method. -func (m *MockMembershipClient) Orders() chan *generated.Order { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Orders") - ret0, _ := ret[0].(chan *generated.Order) - return ret0 -} - -// Orders indicates an expected call of Orders. -func (mr *MockMembershipClientMockRecorder) Orders() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Orders", reflect.TypeOf((*MockMembershipClient)(nil).Orders)) -} - -// Send mocks base method. -func (m *MockMembershipClient) Send(message *generated.Message) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Send", message) - ret0, _ := ret[0].(error) - return ret0 -} - -// Send indicates an expected call of Send. -func (mr *MockMembershipClientMockRecorder) Send(message any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Send", reflect.TypeOf((*MockMembershipClient)(nil).Send), message) -} diff --git a/internal/membership_listener.go b/internal/membership_listener.go index 7821534..72f3eee 100644 --- a/internal/membership_listener.go +++ b/internal/membership_listener.go @@ -1,4 +1,3 @@ -//nolint:nosnakecase package internal import ( @@ -9,19 +8,15 @@ import ( "reflect" "slices" "strings" - "sync" - "go.opentelemetry.io/otel/attribute" v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/selection" - "github.com/alitto/pond" "github.com/formancehq/go-libs/v2/collectionutils" "github.com/formancehq/go-libs/v2/logging" "github.com/formancehq/operator/v3/api/formance.com/v1beta1" "github.com/formancehq/stack/components/agent/internal/generated" - "github.com/formancehq/stack/components/agent/internal/grpcclient" "github.com/pkg/errors" "k8s.io/apimachinery/pkg/api/equality" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -33,40 +28,6 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" ) -//go:generate mockgen -source=membership_listener.go -destination=membership_client_generated.go -package=internal . MembershipClient -type MembershipClient interface { - Orders() chan *generated.Order - Send(message *generated.Message) error -} - -type MembershipClientMock struct { - mu sync.Mutex - orders chan *generated.Order - messages []*generated.Message -} - -func (m *MembershipClientMock) Orders() chan *generated.Order { - return m.orders -} - -func (m *MembershipClientMock) Send(message *generated.Message) error { - m.mu.Lock() - defer m.mu.Unlock() - - m.messages = append(m.messages, message) - return nil -} - -func (m *MembershipClientMock) GetMessages() []*generated.Message { - return m.messages -} - -func NewMembershipClientMock() *MembershipClientMock { - return &MembershipClientMock{ - orders: make(chan *generated.Order), - } -} - type ClientInfo struct { ID string BaseUrl *url.URL @@ -77,78 +38,16 @@ type ClientInfo struct { Version string } -type membershipListener struct { +type MembershipListener struct { clientInfo ClientInfo client K8SClient + reporter MembershipReporter - restMapper meta.RESTMapper - membershipClient MembershipClient - modules modules - wp *pond.WorkerPool + restMapper meta.RESTMapper + modules modules } -func (c *membershipListener) Start(ctx context.Context) { - defer c.wp.StopAndWait() - for { - select { - case msg, ok := <-c.membershipClient.Orders(): - if !ok { - return - } - - c.wp.Submit(func() { - ctx = grpcclient.ExtractOtelCtxFromMessage(ctx, msg) - - ctx, span := tracer.Start(ctx, "NewOrder") - defer span.End() - - logger := logging.FromContext(ctx). - WithField("traceId", span.SpanContext().TraceID()). - WithField("spanId", span.SpanContext().SpanID()) - logger.Infof("Got message from membership: %T", msg.GetMessage()) - - switch msg := msg.Message.(type) { - case *generated.Order_ExistingStack: - logger = logger.WithField("stack", msg.ExistingStack.ClusterName) - ctx = logging.ContextWithLogger(ctx, logger) - - span.SetName("SyncExistingStack") - span.SetAttributes(attribute.String("stack", msg.ExistingStack.ClusterName)) - - c.syncExistingStack(ctx, msg.ExistingStack) - case *generated.Order_DeletedStack: - logger = logger.WithField("stack", msg.DeletedStack.ClusterName) - ctx = logging.ContextWithLogger(ctx, logger) - - span.SetName("DeleteStack") - span.SetAttributes(attribute.String("stack", msg.DeletedStack.ClusterName)) - - c.deleteStack(ctx, msg.DeletedStack) - case *generated.Order_DisabledStack: - logger = logger.WithField("stack", msg.DisabledStack.ClusterName) - ctx = logging.ContextWithLogger(ctx, logger) - - span.SetName("DisableStack") - span.SetAttributes(attribute.String("stack", msg.DisabledStack.ClusterName)) - - c.disableStack(ctx, msg.DisabledStack) - case *generated.Order_EnabledStack: - logger = logger.WithField("stack", msg.EnabledStack.ClusterName) - ctx = logging.ContextWithLogger(ctx, logger) - - span.SetName("EnableStack") - span.SetAttributes(attribute.String("stack", msg.EnabledStack.ClusterName)) - - c.enableStack(ctx, msg.EnabledStack) - } - }) - case <-ctx.Done(): - return - } - } -} - -func (c *membershipListener) syncExistingStack(ctx context.Context, membershipStack *generated.Stack) { +func (c *MembershipListener) SyncExistingStack(ctx context.Context, membershipStack *generated.Stack) { versions := membershipStack.Versions if versions == "" { versions = "default" @@ -175,7 +74,7 @@ func (c *membershipListener) syncExistingStack(ctx context.Context, membershipSt logging.FromContext(ctx).Infof("Stack %s updated cluster side", stack.GetName()) } -func (c *membershipListener) generateMetadata(membershipStack *generated.Stack) map[string]any { +func (c *MembershipListener) generateMetadata(membershipStack *generated.Stack) map[string]any { additionalLabels := map[string]any{} for key, value := range membershipStack.AdditionalLabels { additionalLabels["formance.com/"+key] = value @@ -192,7 +91,7 @@ func (c *membershipListener) generateMetadata(membershipStack *generated.Stack) } } -func (c *membershipListener) syncModules(ctx context.Context, metadata map[string]any, stack *unstructured.Unstructured, membershipStack *generated.Stack) { +func (c *MembershipListener) syncModules(ctx context.Context, metadata map[string]any, stack *unstructured.Unstructured, membershipStack *generated.Stack) { expectedModules := collectionutils.Map(membershipStack.Modules, func(module *generated.Module) string { return strings.ToLower(module.Name) }) @@ -270,13 +169,13 @@ func (c *membershipListener) syncModules(ctx context.Context, metadata map[strin } } -func (c *membershipListener) deleteModule(ctx context.Context, logger logging.Logger, resource string, stackName string) error { +func (c *MembershipListener) deleteModule(ctx context.Context, logger logging.Logger, resource string, stackName string) error { logger.Debugf("Deleting module %s", resource) return c.client.EnsureNotExistsBySelector(ctx, resource, stackLabels(stackName)) } -func (c *membershipListener) syncStargate(ctx context.Context, metadata map[string]any, stack *unstructured.Unstructured, membershipStack *generated.Stack) { +func (c *MembershipListener) syncStargate(ctx context.Context, metadata map[string]any, stack *unstructured.Unstructured, membershipStack *generated.Stack) { logger := logging.FromContext(ctx).WithField("stack", stack.GetName()) if membershipStack.StargateConfig != nil && membershipStack.StargateConfig.Enabled { parts := strings.Split(stack.GetName(), "-") @@ -311,7 +210,7 @@ func (c *membershipListener) syncStargate(ctx context.Context, metadata map[stri } } -func (c *membershipListener) syncAuthClients(ctx context.Context, metadata map[string]any, stack *unstructured.Unstructured, staticClients []*generated.AuthClient) { +func (c *MembershipListener) syncAuthClients(ctx context.Context, metadata map[string]any, stack *unstructured.Unstructured, staticClients []*generated.AuthClient) { expectedAuthClients := make([]*unstructured.Unstructured, 0) for _, client := range staticClients { authClient, err := c.createOrUpdateStackDependency(ctx, fmt.Sprintf("%s-%s", stack.GetName(), client.Id), stack.GetName(), @@ -352,17 +251,11 @@ func (c *membershipListener) syncAuthClients(ctx context.Context, metadata map[s } } -func (c *membershipListener) deleteStack(ctx context.Context, stack *generated.DeletedStack) { +func (c *MembershipListener) DeleteStack(ctx context.Context, stack *generated.DeletedStack) { logger := logging.FromContext(ctx).WithField("func", "Delete").WithField("stack", stack.ClusterName) if err := c.client.Delete(ctx, "Stacks", stack.ClusterName); err != nil { if apierrors.IsNotFound(err) { - if err := c.membershipClient.Send(&generated.Message{ - Message: &generated.Message_StackDeleted{ - StackDeleted: &generated.DeletedStack{ - ClusterName: stack.ClusterName, - }, - }, - }); err != nil { + if err := c.reporter.ReportStackDeleted(ctx, stack.ClusterName); err != nil { logger.Errorf("Unable to send stack delete to server: %s", err) return } @@ -376,25 +269,25 @@ func (c *membershipListener) deleteStack(ctx context.Context, stack *generated.D logger.Infof("Stack %s deleted", stack.ClusterName) } -func (c *membershipListener) disableStack(ctx context.Context, stack *generated.DisabledStack) { - if err := c.client.Patch(ctx, "Stacks", stack.ClusterName, []byte(`{"spec": {"disabled": true}}`)); err != nil { +func (c *MembershipListener) DisableStack(ctx context.Context, clusterName string) { + if err := c.client.Patch(ctx, "Stacks", clusterName, []byte(`{"spec": {"disabled": true}}`)); err != nil { logging.FromContext(ctx).Errorf("Disabling cluster side: %s", err) return } - logging.FromContext(ctx).Infof("Stack %s disabled", stack.ClusterName) + logging.FromContext(ctx).Infof("Stack %s disabled", clusterName) } -func (c *membershipListener) enableStack(ctx context.Context, stack *generated.EnabledStack) { - if err := c.client.Patch(ctx, "Stacks", stack.ClusterName, []byte(`{"spec": {"disabled": false}}`)); err != nil { - logging.FromContext(ctx).Errorf("Disabling cluster side: %s", err) +func (c *MembershipListener) EnableStack(ctx context.Context, clusterName string) { + if err := c.client.Patch(ctx, "Stacks", clusterName, []byte(`{"spec": {"disabled": false}}`)); err != nil { + logging.FromContext(ctx).Errorf("Enabling cluster side: %s", err) return } - logging.FromContext(ctx).Infof("Stack %s enabled", stack.ClusterName) + logging.FromContext(ctx).Infof("Stack %s enabled", clusterName) } -func (c *membershipListener) createOrUpdate(ctx context.Context, gvk schema.GroupVersionKind, name string, stackName string, owner *metav1.OwnerReference, content map[string]any) (*unstructured.Unstructured, error) { +func (c *MembershipListener) createOrUpdate(ctx context.Context, gvk schema.GroupVersionKind, name string, stackName string, owner *metav1.OwnerReference, content map[string]any) (*unstructured.Unstructured, error) { logger := logging.FromContext(ctx).WithFields(map[string]any{ "gvk": gvk, @@ -459,7 +352,7 @@ func (c *membershipListener) createOrUpdate(ctx context.Context, gvk schema.Grou return u, nil } -func (c *membershipListener) createOrUpdateStackDependency( +func (c *MembershipListener) createOrUpdateStackDependency( ctx context.Context, name string, stackName string, @@ -485,16 +378,15 @@ func NewMembershipListener( client K8SClient, clientInfo ClientInfo, mapper meta.RESTMapper, - membershipClient MembershipClient, + reporter MembershipReporter, modules modules, -) *membershipListener { - return &membershipListener{ - client: client, - clientInfo: clientInfo, - restMapper: mapper, - membershipClient: membershipClient, - wp: pond.New(5, 5), - modules: modules, +) *MembershipListener { + return &MembershipListener{ + client: client, + clientInfo: clientInfo, + restMapper: mapper, + reporter: reporter, + modules: modules, } } diff --git a/internal/membership_listener_test.go b/internal/membership_listener_test.go index d19d2a6..00a051b 100644 --- a/internal/membership_listener_test.go +++ b/internal/membership_listener_test.go @@ -117,9 +117,9 @@ func TestDeleteModule(t *testing.T) { require.NoError(t, err) require.NoError(t, testConfig.client.Post().Resource(resources.Resource.Resource).Body(&recon).Do(ctx).Error()) - orders := NewMembershipClientMock() + reporter := NewMembershipReporterMock() - membershipListener := NewMembershipListener(NewDefaultK8SClient(testConfig.client), ClientInfo{}, testConfig.mapper, orders, []v1apis.CustomResourceDefinition{}) + membershipListener := NewMembershipListener(NewDefaultK8SClient(testConfig.client), ClientInfo{}, testConfig.mapper, reporter, []v1apis.CustomResourceDefinition{}) if tc.withLabels { require.NoError(t, membershipListener.deleteModule(ctx, logging.Testing(), resources.Resource.Resource, stackName)) @@ -176,7 +176,8 @@ func TestSyncAuthClients(t *testing.T) { } test(t, func(ctx context.Context, tc *testConfig) { t.Parallel() - listener := NewMembershipListener(NewDefaultK8SClient(tc.client), ClientInfo{}, tc.mapper, NewMembershipClientMock(), []v1apis.CustomResourceDefinition{}) + reporter := NewMembershipReporterMock() + listener := NewMembershipListener(NewDefaultK8SClient(tc.client), ClientInfo{}, tc.mapper, reporter, []v1apis.CustomResourceDefinition{}) stackName := uuid.NewString() + "-" + rand(4) stackuid := uuid.NewString() @@ -233,7 +234,8 @@ func TestSyncStargate(t *testing.T) { t.Run(fmt.Sprintf("%s enabled=%t", t.Name(), tcase.enabled), func(t *testing.T) { test(t, func(ctx context.Context, tc *testConfig) { t.Parallel() - listener := NewMembershipListener(NewDefaultK8SClient(tc.client), ClientInfo{}, tc.mapper, NewMembershipClientMock(), []v1apis.CustomResourceDefinition{}) + reporter := NewMembershipReporterMock() + listener := NewMembershipListener(NewDefaultK8SClient(tc.client), ClientInfo{}, tc.mapper, reporter, []v1apis.CustomResourceDefinition{}) stackName := uuid.NewString() + "-" + rand(4) stackuid := uuid.NewString() @@ -288,18 +290,16 @@ func TestSyncStargate(t *testing.T) { func TestDeleteStackNotExisting(t *testing.T) { test(t, func(ctx context.Context, tc *testConfig) { t.Parallel() - mock := NewMembershipClientMock() - listener := NewMembershipListener(NewDefaultK8SClient(tc.client), ClientInfo{}, tc.mapper, mock, []v1apis.CustomResourceDefinition{}) - listener.deleteStack(ctx, &generated.DeletedStack{ + reporter := NewMembershipReporterMock() + listener := NewMembershipListener(NewDefaultK8SClient(tc.client), ClientInfo{}, tc.mapper, reporter, []v1apis.CustomResourceDefinition{}) + listener.DeleteStack(ctx, &generated.DeletedStack{ ClusterName: "non-existing-stack", }) - messages := mock.GetMessages() - require.Len(t, messages, 1) + events := reporter.GetEvents() + require.Len(t, events, 1) - message, ok := messages[0].Message.(*generated.Message_StackDeleted) - require.True(t, ok) - - require.Equal(t, "non-existing-stack", message.StackDeleted.ClusterName) + require.Equal(t, "StackDeleted", events[0].Type) + require.Equal(t, "non-existing-stack", events[0].ClusterName) }) } diff --git a/internal/membership_reporter.go b/internal/membership_reporter.go new file mode 100644 index 0000000..b6df469 --- /dev/null +++ b/internal/membership_reporter.go @@ -0,0 +1,84 @@ +package internal + +import ( + "context" + + "github.com/formancehq/stack/components/agent/internal/generated" + "google.golang.org/protobuf/types/known/structpb" +) + +// MembershipReporter reports observed K8s state back to membership via unary RPCs. +type MembershipReporter interface { + ReportStackStatus(ctx context.Context, clusterName string, statuses *structpb.Struct) error + ReportStackDeleted(ctx context.Context, clusterName string) error + ReportModuleStatus(ctx context.Context, clusterName string, vk *generated.VersionKind, status *structpb.Struct) error + ReportModuleDeleted(ctx context.Context, clusterName string, vk *generated.VersionKind) error + UpsertVersion(ctx context.Context, name string, versions map[string]string, deprecated bool) error + DeleteVersion(ctx context.Context, name string) error +} + +type membershipReporter struct { + client generated.AgentServiceClient +} + +func (r *membershipReporter) ReportStackStatus(ctx context.Context, clusterName string, statuses *structpb.Struct) error { + _, err := r.client.ReportStackStatus(ctx, &generated.ReportStackStatusRequest{ + StatusChanged: &generated.StatusChanged{ + ClusterName: clusterName, + Statuses: statuses, + }, + }) + return err +} + +func (r *membershipReporter) ReportStackDeleted(ctx context.Context, clusterName string) error { + _, err := r.client.ReportStackDeleted(ctx, &generated.ReportStackDeletedRequest{ + StackDeleted: &generated.DeletedStack{ + ClusterName: clusterName, + }, + }) + return err +} + +func (r *membershipReporter) ReportModuleStatus(ctx context.Context, clusterName string, vk *generated.VersionKind, status *structpb.Struct) error { + _, err := r.client.ReportModuleStatus(ctx, &generated.ReportModuleStatusRequest{ + ModuleStatusChanged: &generated.ModuleStatusChanged{ + ClusterName: clusterName, + Vk: vk, + Status: status, + }, + }) + return err +} + +func (r *membershipReporter) ReportModuleDeleted(ctx context.Context, clusterName string, vk *generated.VersionKind) error { + _, err := r.client.ReportModuleDeleted(ctx, &generated.ReportModuleDeletedRequest{ + ModuleDeleted: &generated.ModuleDeleted{ + ClusterName: clusterName, + Vk: vk, + }, + }) + return err +} + +func (r *membershipReporter) UpsertVersion(ctx context.Context, name string, versions map[string]string, deprecated bool) error { + _, err := r.client.UpsertVersion(ctx, &generated.UpsertVersionRequest{ + Name: name, + Versions: versions, + Deprecated: deprecated, + }) + return err +} + +func (r *membershipReporter) DeleteVersion(ctx context.Context, name string) error { + _, err := r.client.DeleteVersion(ctx, &generated.DeleteVersionRequest{ + Name: name, + }) + return err +} + +func NewMembershipReporter(client generated.AgentServiceClient) MembershipReporter { + return &membershipReporter{ + client: client, + } +} diff --git a/internal/membership_reporter_mock.go b/internal/membership_reporter_mock.go new file mode 100644 index 0000000..431b9f0 --- /dev/null +++ b/internal/membership_reporter_mock.go @@ -0,0 +1,111 @@ +package internal + +import ( + "context" + "sync" + + "github.com/formancehq/stack/components/agent/internal/generated" + "google.golang.org/protobuf/types/known/structpb" +) + +// ReportedEvent represents an event captured by the mock reporter for test assertions. +type ReportedEvent struct { + Type string + ClusterName string + Statuses *structpb.Struct + Vk *generated.VersionKind + Status *structpb.Struct + Name string + Versions map[string]string + Deprecated bool +} + +type MembershipReporterMock struct { + mu sync.Mutex + events []ReportedEvent +} + +func (m *MembershipReporterMock) ReportStackStatus(_ context.Context, clusterName string, statuses *structpb.Struct) error { + m.mu.Lock() + defer m.mu.Unlock() + + m.events = append(m.events, ReportedEvent{ + Type: "StackStatus", + ClusterName: clusterName, + Statuses: statuses, + }) + return nil +} + +func (m *MembershipReporterMock) ReportStackDeleted(_ context.Context, clusterName string) error { + m.mu.Lock() + defer m.mu.Unlock() + + m.events = append(m.events, ReportedEvent{ + Type: "StackDeleted", + ClusterName: clusterName, + }) + return nil +} + +func (m *MembershipReporterMock) ReportModuleStatus(_ context.Context, clusterName string, vk *generated.VersionKind, status *structpb.Struct) error { + m.mu.Lock() + defer m.mu.Unlock() + + m.events = append(m.events, ReportedEvent{ + Type: "ModuleStatus", + ClusterName: clusterName, + Vk: vk, + Status: status, + }) + return nil +} + +func (m *MembershipReporterMock) ReportModuleDeleted(_ context.Context, clusterName string, vk *generated.VersionKind) error { + m.mu.Lock() + defer m.mu.Unlock() + + m.events = append(m.events, ReportedEvent{ + Type: "ModuleDeleted", + ClusterName: clusterName, + Vk: vk, + }) + return nil +} + +func (m *MembershipReporterMock) UpsertVersion(_ context.Context, name string, versions map[string]string, deprecated bool) error { + m.mu.Lock() + defer m.mu.Unlock() + + m.events = append(m.events, ReportedEvent{ + Type: "UpsertVersion", + Name: name, + Versions: versions, + Deprecated: deprecated, + }) + return nil +} + +func (m *MembershipReporterMock) DeleteVersion(_ context.Context, name string) error { + m.mu.Lock() + defer m.mu.Unlock() + + m.events = append(m.events, ReportedEvent{ + Type: "DeleteVersion", + Name: name, + }) + return nil +} + +func (m *MembershipReporterMock) GetEvents() []ReportedEvent { + m.mu.Lock() + defer m.mu.Unlock() + + result := make([]ReportedEvent, len(m.events)) + copy(result, m.events) + return result +} + +func NewMembershipReporterMock() *MembershipReporterMock { + return &MembershipReporterMock{} +} diff --git a/internal/module.go b/internal/module.go index d2a5424..362c228 100644 --- a/internal/module.go +++ b/internal/module.go @@ -9,7 +9,7 @@ import ( "github.com/formancehq/go-libs/v2/collectionutils" "github.com/formancehq/go-libs/v2/logging" "github.com/formancehq/operator/v3/api/formance.com/v1beta1" - "github.com/formancehq/stack/components/agent/internal/grpcclient" + "github.com/formancehq/stack/components/agent/internal/generated" "github.com/pkg/errors" "go.uber.org/fx" "google.golang.org/grpc" @@ -80,26 +80,26 @@ func createInformer(factory dynamicinformer.DynamicSharedInformerFactory, resour return nil } -func CreateVersionsInformer(factory dynamicinformer.DynamicSharedInformerFactory, - logger logging.Logger, client MembershipClient) error { +func CreateVersionsInformer(ctx context.Context, factory dynamicinformer.DynamicSharedInformerFactory, + logger logging.Logger, reporter MembershipReporter) error { logger = logger.WithFields(map[string]any{ "component": "versions", }) logger.Info("Creating informer") - return createInformer(factory, "versions", VersionsEventHandler(logger, client)) + return createInformer(factory, "versions", VersionsEventHandler(ctx, logger, reporter)) } -func CreateStacksInformer(factory dynamicinformer.DynamicSharedInformerFactory, - logger logging.Logger, client MembershipClient) error { +func CreateStacksInformer(ctx context.Context, factory dynamicinformer.DynamicSharedInformerFactory, + logger logging.Logger, reporter MembershipReporter) error { logger = logger.WithFields(map[string]any{ "component": "stacks", }) logger.Info("Creating informer") - return createInformer(factory, "stacks", NewStackEventHandler(logger, client)) + return createInformer(factory, "stacks", NewStackEventHandler(ctx, logger, reporter)) } -func CreateModulesInformers(factory dynamicinformer.DynamicSharedInformerFactory, - restMapper meta.RESTMapper, logger logging.Logger, client MembershipClient) error { +func CreateModulesInformers(ctx context.Context, factory dynamicinformer.DynamicSharedInformerFactory, + restMapper meta.RESTMapper, logger logging.Logger, reporter MembershipReporter) error { for gvk, rtype := range scheme.Scheme.AllKnownTypes() { object := reflect.New(rtype).Interface() @@ -118,7 +118,7 @@ func CreateModulesInformers(factory dynamicinformer.DynamicSharedInformerFactory }) logger.Info("Creating informer") - if err := createInformer(factory, restMapping.Resource.Resource, NewModuleEventHandler(logger, client)); err != nil { + if err := createInformer(factory, restMapping.Resource.Resource, NewModuleEventHandler(ctx, logger, reporter)); err != nil { return err } } @@ -205,41 +205,32 @@ func RetrieveModuleList(ctx context.Context, config *rest.Config) (modules, eeMo return modules, eeModules, nil } -func runMembershipClient(lc fx.Lifecycle, debug bool, membershipClient *membershipClient, logger logging.Logger, config *rest.Config) { +func runPollingClient(lc fx.Lifecycle, pollingClient *pollingClient, conn *grpc.ClientConn, agentClient generated.AgentServiceClient, logger logging.Logger) { lc.Append(fx.Hook{ OnStart: func(ctx context.Context) error { - client, err := membershipClient.connect(logging.ContextWithLogger(ctx, logger)) - if err != nil { - return err - } - clientWithTrace := grpcclient.NewConnectionWithTrace(client, debug) - go func() { - if err := membershipClient.Start(logging.ContextWithLogger(ctx, logger), clientWithTrace); err != nil { + if err := pollingClient.Start(logging.ContextWithLogger(ctx, logger)); err != nil { + logger.Errorf("Polling client stopped with error: %s", err) panic(err) } }() return nil }, - OnStop: membershipClient.Stop, - }) -} - -func runMembershipListener(lc fx.Lifecycle, client *membershipListener, logger logging.Logger) { - lc.Append(fx.Hook{ - OnStart: func(ctx context.Context) error { - go client.Start(logging.ContextWithLogger(ctx, logger)) - return nil + OnStop: func(ctx context.Context) error { + if _, err := agentClient.Disconnect(ctx, &generated.DisconnectRequest{}); err != nil { + logger.Errorf("Disconnect RPC failed: %s", err) + } + return conn.Close() }, }) } func NewModule( - debug bool, serverAddress string, authenticator Authenticator, clientInfo ClientInfo, resyncPeriod time.Duration, + pollInterval time.Duration, opts ...grpc.DialOption, ) fx.Option { return fx.Options( @@ -254,20 +245,36 @@ func NewModule( }), fx.Provide(RetrieveModuleList), fx.Provide(CreateRestMapper), - fx.Provide(func(modules modules, eeModules eeModules) *membershipClient { - return NewMembershipClient(authenticator, clientInfo, serverAddress, modules, eeModules, opts...) + // Create gRPC connection and AgentService client + fx.Provide(func(modules modules, eeModules eeModules) (*grpc.ClientConn, error) { + allOpts := make([]grpc.DialOption, len(opts)) + copy(allOpts, opts) + allOpts = append(allOpts, + grpc.WithChainUnaryInterceptor( + MetadataUnaryInterceptor(authenticator, clientInfo, modules, eeModules), + ), + ) + return grpc.NewClient(serverAddress, allOpts...) }), - fx.Provide(func(membershipClient *membershipClient) MembershipClient { - return membershipClient + fx.Provide(func(conn *grpc.ClientConn) generated.AgentServiceClient { + return generated.NewAgentServiceClient(conn) + }), + fx.Provide(func(client generated.AgentServiceClient) MembershipReporter { + return NewMembershipReporter(client) }), fx.Provide(NewMembershipListener), + fx.Provide(func( + agentClient generated.AgentServiceClient, + reconciler *MembershipListener, + k8sClient K8SClient, + modules modules, + ) *pollingClient { + return NewPollingClient(agentClient, reconciler, k8sClient, clientInfo, modules, pollInterval) + }), fx.Invoke(CreateVersionsInformer), fx.Invoke(CreateStacksInformer), fx.Invoke(CreateModulesInformers), - fx.Invoke(func(lc fx.Lifecycle, membershipClient *membershipClient, logger logging.Logger, config *rest.Config) { - runMembershipClient(lc, debug, membershipClient, logger, config) - }), - fx.Invoke(runMembershipListener), + fx.Invoke(runPollingClient), fx.Invoke(runInformers), ) } diff --git a/internal/polling_client.go b/internal/polling_client.go new file mode 100644 index 0000000..6c5e7bd --- /dev/null +++ b/internal/polling_client.go @@ -0,0 +1,238 @@ +package internal + +import ( + "context" + "time" + + "github.com/formancehq/go-libs/v2/logging" + "github.com/formancehq/stack/components/agent/internal/generated" + "golang.org/x/sync/errgroup" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/selection" +) + +const ( + defaultPageSize = 100 + heartbeatInterval = 30 * time.Second + expectedStatusDel = "deleted" +) + +type pollingClient struct { + agentClient generated.AgentServiceClient + reconciler *MembershipListener + k8sClient K8SClient + clientInfo ClientInfo + modules modules + pollInterval time.Duration + cursor string // persistent cursor across polls + fullSyncDone bool // tracks whether first full sync with orphan cleanup succeeded +} + +func (p *pollingClient) Start(ctx context.Context) error { + g, ctx := errgroup.WithContext(ctx) + + // Heartbeat goroutine + g.Go(func() error { + return p.runHeartbeat(ctx) + }) + + // Poll loop goroutine + g.Go(func() error { + return p.runPollLoop(ctx) + }) + + return g.Wait() +} + +func (p *pollingClient) runHeartbeat(ctx context.Context) error { + logger := logging.FromContext(ctx) + + hbBackoff := heartbeatInterval + maxBackoff := heartbeatInterval * 16 + + // Send initial heartbeat immediately + if err := p.sendHeartbeat(ctx); err != nil { + logger.Errorf("Initial heartbeat failed: %s", err) + hbBackoff = min(hbBackoff*2, maxBackoff) + } + + ticker := time.NewTicker(hbBackoff) + defer ticker.Stop() + + for { + select { + case <-ctx.Done(): + return ctx.Err() + case <-ticker.C: + if err := p.sendHeartbeat(ctx); err != nil { + logger.Errorf("Heartbeat failed: %s", err) + hbBackoff = min(hbBackoff*2, maxBackoff) + } else { + hbBackoff = heartbeatInterval + } + ticker.Reset(hbBackoff) + } + } +} + +func (p *pollingClient) sendHeartbeat(ctx context.Context) error { + _, err := p.agentClient.Heartbeat(ctx, &generated.HeartbeatRequest{ + RegionId: p.clientInfo.ID, + BaseUrl: p.clientInfo.BaseUrl.String(), + AdditionalBaseUrls: p.clientInfo.AdditionalBaseURLs, + Version: p.clientInfo.Version, + Production: p.clientInfo.Production, + Capabilities: []string{capabilityEE, capabilityModuleList}, + Modules: p.modules.Singular(), + }) + return err +} + +func (p *pollingClient) runPollLoop(ctx context.Context) error { + logger := logging.FromContext(ctx) + + pollBackoff := p.pollInterval + maxBackoff := p.pollInterval * 16 + + // First poll: full sync with orphan cleanup + if err := p.poll(ctx, !p.fullSyncDone); err != nil { + logger.Errorf("Initial poll failed: %s", err) + pollBackoff = min(pollBackoff*2, maxBackoff) + } else { + pollBackoff = p.pollInterval + } + + ticker := time.NewTicker(pollBackoff) + defer ticker.Stop() + + for { + select { + case <-ctx.Done(): + return ctx.Err() + case <-ticker.C: + if err := p.poll(ctx, !p.fullSyncDone); err != nil { + logger.Errorf("Poll failed: %s", err) + pollBackoff = min(pollBackoff*2, maxBackoff) + } else { + pollBackoff = p.pollInterval + } + ticker.Reset(pollBackoff) + } + } +} + +func (p *pollingClient) poll(ctx context.Context, isFullSync bool) error { + logger := logging.FromContext(ctx) + logger.Infof("Polling membership for stack changes (cursor=%q, fullSync=%t)", p.cursor, isFullSync) + + // Collect all stacks from this poll for orphan detection + var allStackNames map[string]struct{} + if isFullSync { + allStackNames = make(map[string]struct{}) + } + + cursor := p.cursor + for { + resp, err := p.agentClient.ListStacks(ctx, &generated.ListStacksRequest{ + RegionId: p.clientInfo.ID, + PageSize: defaultPageSize, + Cursor: cursor, + }) + if err != nil { + return err + } + + for _, stack := range resp.GetStacks() { + logger := logger.WithField("stack", stack.ClusterName) + ctx := logging.ContextWithLogger(ctx, logger) + + if isFullSync { + allStackNames[stack.ClusterName] = struct{}{} + } + + p.reconcileStack(ctx, stack) + } + + if !resp.GetHasMore() { + // Only update cursor if the server returned one. + // An empty cursor means no results — keep the previous cursor + // to avoid re-scanning from the beginning. + if next := resp.GetNextCursor(); next != "" { + p.cursor = next + } + break + } + cursor = resp.GetNextCursor() + } + + // Orphan cleanup on full sync + if isFullSync { + p.cleanupOrphans(ctx, allStackNames) + p.fullSyncDone = true + } + + return nil +} + +func (p *pollingClient) reconcileStack(ctx context.Context, stack *generated.Stack) { + logger := logging.FromContext(ctx) + + if stack.GetExpectedStatus() == expectedStatusDel { + logger.Infof("Stack %s expected to be deleted, deleting", stack.ClusterName) + p.reconciler.DeleteStack(ctx, &generated.DeletedStack{ + ClusterName: stack.ClusterName, + }) + return + } + + // SyncExistingStack handles both active and disabled stacks (disabled: true in spec) + logger.Infof("Syncing existing stack %s (disabled=%t)", stack.ClusterName, stack.GetDisabled()) + p.reconciler.SyncExistingStack(ctx, stack) +} + +func (p *pollingClient) cleanupOrphans(ctx context.Context, knownStacks map[string]struct{}) { + logger := logging.FromContext(ctx) + logger.Infof("Running orphan cleanup, known stacks: %d", len(knownStacks)) + + // List all K8s stacks with the agent label + agentLabel, err := labels.NewRequirement("formance.com/created-by-agent", selection.Equals, []string{"true"}) + if err != nil { + logger.Errorf("Failed to create label requirement: %s", err) + return + } + + selector := labels.NewSelector().Add(*agentLabel) + k8sStacks, err := p.k8sClient.List(ctx, "Stacks", selector) + if err != nil { + logger.Errorf("Failed to list K8s stacks for orphan cleanup: %s", err) + return + } + + for _, k8sStack := range k8sStacks { + name := k8sStack.GetName() + if _, known := knownStacks[name]; !known { + logger.Infof("Cleaning up orphan stack %s", name) + if err := p.k8sClient.Delete(ctx, "Stacks", name); err != nil { + logger.Errorf("Failed to delete orphan stack %s: %s", name, err) + } + } + } +} + +func NewPollingClient( + agentClient generated.AgentServiceClient, + reconciler *MembershipListener, + k8sClient K8SClient, + clientInfo ClientInfo, + modules modules, + pollInterval time.Duration, +) *pollingClient { + return &pollingClient{ + agentClient: agentClient, + reconciler: reconciler, + k8sClient: k8sClient, + clientInfo: clientInfo, + modules: modules, + pollInterval: pollInterval, + } +} diff --git a/internal/tracer.go b/internal/tracer.go deleted file mode 100644 index a208380..0000000 --- a/internal/tracer.go +++ /dev/null @@ -1,7 +0,0 @@ -package internal - -import "go.opentelemetry.io/otel" - -var ( - tracer = otel.Tracer("com.formance.agent") -) diff --git a/pkg/tracing/tracing.go b/pkg/tracing/tracing.go deleted file mode 100644 index d11e1aa..0000000 --- a/pkg/tracing/tracing.go +++ /dev/null @@ -1,51 +0,0 @@ -package tracing - -import ( - "context" - - "go.opentelemetry.io/otel/codes" - "go.opentelemetry.io/otel/trace" -) - -func TraceTuple[K, V any](ctx context.Context, tracer trace.Tracer, name string, fn func(ctx context.Context) (K, V, error), opts ...trace.SpanStartOption) (K, V, error) { - ctx, trace := tracer.Start(ctx, name, opts...) - defer trace.End() - - var k K - var v V - k, v, err := fn(ctx) - if err != nil { - trace.RecordError(err) - trace.SetStatus(codes.Error, err.Error()) - return k, v, err - } - - return k, v, nil -} - -func Trace[RET any](ctx context.Context, tracer trace.Tracer, name string, fn func(ctx context.Context) (RET, error), opts ...trace.SpanStartOption) (RET, error) { - ctx, trace := tracer.Start(ctx, name, opts...) - defer trace.End() - - var zeroRet RET - ret, err := fn(ctx) - if err != nil { - trace.RecordError(err) - trace.SetStatus(codes.Error, err.Error()) - return zeroRet, err - } - - return ret, nil -} - -func TraceError(ctx context.Context, tracer trace.Tracer, name string, fn func(ctx context.Context) error, opts ...trace.SpanStartOption) error { - ctx, trace := tracer.Start(ctx, name, opts...) - defer trace.End() - - if err := fn(ctx); err != nil { - trace.RecordError(err) - trace.SetStatus(codes.Error, err.Error()) - return err - } - return nil -} diff --git a/tests/informer_stacks_test.go b/tests/informer_stacks_test.go index 1b155a0..3e1d273 100644 --- a/tests/informer_stacks_test.go +++ b/tests/informer_stacks_test.go @@ -8,7 +8,6 @@ import ( "github.com/formancehq/go-libs/v2/logging" "github.com/formancehq/operator/v3/api/formance.com/v1beta1" "github.com/formancehq/stack/components/agent/internal" - "github.com/formancehq/stack/components/agent/internal/generated" "github.com/google/uuid" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -19,16 +18,16 @@ import ( var _ = Describe("Stacks informer", func() { var ( - membershipClientMock *internal.MembershipClientMock - startListener func() + reporterMock *internal.MembershipReporterMock + startListener func() ) BeforeEach(func() { - membershipClientMock = internal.NewMembershipClientMock() + reporterMock = internal.NewMembershipReporterMock() dynamicClient, err := dynamic.NewForConfig(restConfig) Expect(err).To(Succeed()) factory := internal.NewDynamicSharedInformerFactory(dynamicClient, 5*time.Minute) - Expect(internal.CreateStacksInformer(factory, logging.Testing(), membershipClientMock)).To(Succeed()) + Expect(internal.CreateStacksInformer(context.Background(), factory, logging.Testing(), reporterMock)).To(Succeed()) startListener = func() { stopCh := make(chan struct{}) factory.Start(stopCh) @@ -83,20 +82,19 @@ var _ = Describe("Stacks informer", func() { Do(context.Background()).Error()).To(Succeed()) }) }) - It("Should have sent a Status_Changed", func() { - Eventually(func() []*generated.Message { - for _, message := range membershipClientMock.GetMessages() { - if message.GetStatusChanged() != nil { - if _, ok := message.GetStatusChanged().GetStatuses().Fields["ready"]; ok { - isReady := message.GetStatusChanged().GetStatuses().Fields["ready"].GetBoolValue() - if isReady { - return membershipClientMock.GetMessages() + It("Should have sent a StackStatus with ready=true", func() { + Eventually(func() bool { + for _, event := range reporterMock.GetEvents() { + if event.Type == "StackStatus" && event.Statuses != nil { + if readyVal, ok := event.Statuses.Fields["ready"]; ok { + if readyVal.GetBoolValue() { + return true } } } } - return nil - }).ShouldNot(BeEmpty()) + return false + }).Should(BeTrue()) }) When("The stack is ready", func() { BeforeEach(func() { @@ -115,20 +113,19 @@ var _ = Describe("Stacks informer", func() { Do(context.Background()). Error()).To(Succeed()) }) - It("Should have sent a Status_Changed", func() { - Eventually(func() []*generated.Message { - for _, message := range membershipClientMock.GetMessages() { - if message.GetStatusChanged() != nil { - if _, ok := message.GetStatusChanged().GetStatuses().Fields["ready"]; ok { - isReady := message.GetStatusChanged().GetStatuses().Fields["ready"].GetBoolValue() - if isReady { - return membershipClientMock.GetMessages() + It("Should have sent a StackStatus with ready=true", func() { + Eventually(func() bool { + for _, event := range reporterMock.GetEvents() { + if event.Type == "StackStatus" && event.Statuses != nil { + if readyVal, ok := event.Statuses.Fields["ready"]; ok { + if readyVal.GetBoolValue() { + return true } } } } - return nil - }).ShouldNot(BeEmpty()) + return false + }).Should(BeTrue()) }) }) When("the stack is re-enabled", func() { @@ -166,20 +163,19 @@ var _ = Describe("Stacks informer", func() { Error()).To(Succeed()) }) }) - It("should have sent a Status_Changed", func() { - Eventually(func() []*generated.Message { - for _, message := range membershipClientMock.GetMessages() { - if message.GetStatusChanged() != nil { - if _, ok := message.GetStatusChanged().GetStatuses().Fields["ready"]; ok { - isReady := message.GetStatusChanged().GetStatuses().Fields["ready"].GetBoolValue() - if !isReady { - return membershipClientMock.GetMessages() + It("should have sent a StackStatus with ready=false", func() { + Eventually(func() bool { + for _, event := range reporterMock.GetEvents() { + if event.Type == "StackStatus" && event.Statuses != nil { + if readyVal, ok := event.Statuses.Fields["ready"]; ok { + if !readyVal.GetBoolValue() { + return true } } } } - return []*generated.Message{} - }).ShouldNot(BeEmpty()) + return false + }).Should(BeTrue()) }) When("the stack is reconcilled", func() { BeforeEach(func() { @@ -202,20 +198,19 @@ var _ = Describe("Stacks informer", func() { Error()).To(Succeed()) }) }) - It("should have sent a Status_Changed", func() { - Eventually(func() []*generated.Message { - for _, message := range membershipClientMock.GetMessages() { - if message.GetStatusChanged() != nil { - if _, ok := message.GetStatusChanged().GetStatuses().Fields["ready"]; ok { - isReady := message.GetStatusChanged().GetStatuses().Fields["ready"].GetBoolValue() - if isReady { - return membershipClientMock.GetMessages() + It("should have sent a StackStatus with ready=true", func() { + Eventually(func() bool { + for _, event := range reporterMock.GetEvents() { + if event.Type == "StackStatus" && event.Statuses != nil { + if readyVal, ok := event.Statuses.Fields["ready"]; ok { + if readyVal.GetBoolValue() { + return true } } } } - return nil - }).ShouldNot(BeEmpty()) + return false + }).Should(BeTrue()) }) }) }) @@ -261,20 +256,19 @@ var _ = Describe("Stacks informer", func() { Name(stack.Name). Do(context.Background()).Error()).To(Succeed()) }) - It("should have sent a Status_Changed", func() { - Eventually(func() []*generated.Message { - for _, message := range membershipClientMock.GetMessages() { - if message.GetStatusChanged() != nil && message.GetStatusChanged().Status == generated.StackStatus_Progressing && stack.Name == message.GetStatusChanged().ClusterName { - if _, ok := message.GetStatusChanged().GetStatuses().Fields["ready"]; ok { - isReady := message.GetStatusChanged().GetStatuses().Fields["ready"].GetBoolValue() - if !isReady { - return membershipClientMock.GetMessages() + It("should have sent a StackStatus with ready=false", func() { + Eventually(func() bool { + for _, event := range reporterMock.GetEvents() { + if event.Type == "StackStatus" && event.ClusterName == stack.Name && event.Statuses != nil { + if readyVal, ok := event.Statuses.Fields["ready"]; ok { + if !readyVal.GetBoolValue() { + return true } } } } - return nil - }).ShouldNot(BeEmpty()) + return false + }).Should(BeTrue()) }) When("all stack dependent are ready", func() { BeforeEach(func() { @@ -296,20 +290,19 @@ var _ = Describe("Stacks informer", func() { Error()).To(Succeed()) }) }) - It("should have sent a Status_Ready", func() { - Eventually(func() []*generated.Message { - for _, message := range membershipClientMock.GetMessages() { - if message.GetStatusChanged() != nil { - if _, ok := message.GetStatusChanged().GetStatuses().Fields["ready"]; ok { - isReady := message.GetStatusChanged().GetStatuses().Fields["ready"].GetBoolValue() - if isReady { - return membershipClientMock.GetMessages() + It("should have sent a StackStatus with ready=true", func() { + Eventually(func() bool { + for _, event := range reporterMock.GetEvents() { + if event.Type == "StackStatus" && event.Statuses != nil { + if readyVal, ok := event.Statuses.Fields["ready"]; ok { + if readyVal.GetBoolValue() { + return true } } } } - return nil - }).ShouldNot(BeEmpty()) + return false + }).Should(BeTrue()) }) }) }) @@ -329,20 +322,25 @@ var _ = Describe("Stacks informer", func() { startListener() + // Wait for the informer cache to sync and see the stack before deleting. + // A newly created stack may not have a status yet, so the AddFunc won't + // emit a StackStatus event. We wait briefly for the informer cache to sync. + time.Sleep(2 * time.Second) + Expect(k8sClient.Delete(). Resource("Stacks"). Name(stack.Name). Do(context.Background()).Error()).To(Succeed()) }) - It("should have sent a Stack_Deleted", func() { - Eventually(func() []*generated.Message { - for _, message := range membershipClientMock.GetMessages() { - if message.GetStackDeleted() != nil && message.GetStackDeleted().ClusterName == stack.Name { - return membershipClientMock.GetMessages() + It("should have sent a StackDeleted", func() { + Eventually(func() bool { + for _, event := range reporterMock.GetEvents() { + if event.Type == "StackDeleted" && event.ClusterName == stack.Name { + return true } } - return nil - }).ShouldNot(BeEmpty()) + return false + }).Should(BeTrue()) }) }) }) diff --git a/tests/informers_modules_test.go b/tests/informers_modules_test.go index 79f5ffc..f0b39bf 100644 --- a/tests/informers_modules_test.go +++ b/tests/informers_modules_test.go @@ -23,13 +23,13 @@ import ( var _ = Describe("Informer modules", func() { var ( - membershipClientMock *internal.MembershipClientMock - restMapper meta.RESTMapper - err error + reporterMock *internal.MembershipReporterMock + restMapper meta.RESTMapper + err error ) BeforeEach(func() { - membershipClientMock = internal.NewMembershipClientMock() + reporterMock = internal.NewMembershipReporterMock() restMapper, err = internal.CreateRestMapper(restConfig, logging.Testing()) Expect(err).ToNot(HaveOccurred()) }) @@ -128,7 +128,7 @@ var _ = Describe("Informer modules", func() { dynamicClient, err := dynamic.NewForConfig(restConfig) Expect(err).ToNot(HaveOccurred()) factory := internal.NewDynamicSharedInformerFactory(dynamicClient, 5*time.Minute) - Expect(internal.CreateModulesInformers(factory, restMapper, logging.Testing(), membershipClientMock)).ToNot(HaveOccurred()) + Expect(internal.CreateModulesInformers(context.Background(), factory, restMapper, logging.Testing(), reporterMock)).ToNot(HaveOccurred()) stopCh := make(chan struct{}) factory.Start(stopCh) @@ -136,23 +136,24 @@ var _ = Describe("Informer modules", func() { close(stopCh) }) }) - It("Should have sent ModuleStatusChanged", func() { + It("Should have sent ModuleStatus events", func() { for gvk, module := range modules { By(fmt.Sprintf("Checking the module %s", gvk.Kind), func() { Eventually(func(g Gomega) bool { - for _, message := range membershipClientMock.GetMessages() { - if msg := message.GetModuleStatusChanged(); msg != nil && - msg.Vk.Kind == gvk.Kind && - msg.Vk.Version == gvk.Version && - msg.ClusterName == module.GetName() { + for _, event := range reporterMock.GetEvents() { + if event.Type == "ModuleStatus" && + event.Vk != nil && + event.Vk.Kind == gvk.Kind && + event.Vk.Version == gvk.Version && + event.ClusterName == module.GetName() { status, _, _ := unstructured.NestedMap(module.Object, "status") - g.Expect(msg.Status.AsMap()["info"]).ToNot(BeNil()) - g.Expect(msg.Status.AsMap()["ready"]).To(BeFalse()) + g.Expect(event.Status.AsMap()["info"]).ToNot(BeNil()) + g.Expect(event.Status.AsMap()["ready"]).To(BeFalse()) for k, value := range status { - g.Expect(msg.Status.AsMap()[k]).To(Equal(value)) + g.Expect(event.Status.AsMap()[k]).To(Equal(value)) } return true } @@ -178,11 +179,12 @@ var _ = Describe("Informer modules", func() { It("Should have sent ModuleDeleted", func() { By(fmt.Sprintf("Checking message received for %s", moduleDeleted.GetKind()), func() { Eventually(func(g Gomega) bool { - for _, message := range membershipClientMock.GetMessages() { - if msg := message.GetModuleDeleted(); msg != nil && - msg.Vk.Kind == moduleDeleted.GetKind() && - msg.Vk.Version == strings.Split(moduleDeleted.GetAPIVersion(), "/")[1] && - msg.ClusterName == moduleDeleted.GetName() { + for _, event := range reporterMock.GetEvents() { + if event.Type == "ModuleDeleted" && + event.Vk != nil && + event.Vk.Kind == moduleDeleted.GetKind() && + event.Vk.Version == strings.Split(moduleDeleted.GetAPIVersion(), "/")[1] && + event.ClusterName == moduleDeleted.GetName() { return true } } diff --git a/tests/membership_listener_test.go b/tests/membership_listener_test.go index 87be402..e9b11c1 100644 --- a/tests/membership_listener_test.go +++ b/tests/membership_listener_test.go @@ -25,31 +25,20 @@ import ( var _ = Describe("Membership listener", func() { var ( - membershipClient *internal.MembershipClientMock - clientInfo internal.ClientInfo - ctx = logging.TestingContext() + reporter *internal.MembershipReporterMock + listener *internal.MembershipListener + clientInfo internal.ClientInfo + ctx = logging.TestingContext() ) BeforeEach(func() { - membershipClient = internal.NewMembershipClientMock() + reporter = internal.NewMembershipReporterMock() clientInfo = internal.ClientInfo{ BaseUrl: &url.URL{}, } modules, _, err := internal.RetrieveModuleList(ctx, restConfig) Expect(err).To(BeNil()) - listener := internal.NewMembershipListener(internal.NewDefaultK8SClient(k8sClient), clientInfo, mapper, membershipClient, modules) - done := make(chan struct{}) - DeferCleanup(func() { - <-done - }) - go func() { - defer close(done) - listener.Start(context.Background()) - }() - - DeferCleanup(func() { - close(membershipClient.Orders()) - }) + listener = internal.NewMembershipListener(internal.NewDefaultK8SClient(k8sClient), clientInfo, mapper, reporter, modules) }) Context("When sending an existing stack from membership", func() { var ( @@ -79,7 +68,7 @@ var _ = Describe("Membership listener", func() { Expect(k8sClient.Post().Resource("AuthClients").Body(client).Do(context.Background()).Error()).To(BeNil()) }) - By("Creating a stack", func() { + By("Syncing the stack", func() { modules := make([]*generated.Module, 0) for gvk, rtype := range scheme.Scheme.AllKnownTypes() { object := reflect.New(rtype).Interface() @@ -124,13 +113,13 @@ var _ = Describe("Membership listener", func() { Public: true, }, }, - Modules: modules, - } - membershipClient.Orders() <- &generated.Order{ - Message: &generated.Order_ExistingStack{ - ExistingStack: membershipStack, - }, + Modules: modules, + ExpectedStatus: "active", } + + // Directly call SyncExistingStack instead of sending over channel + listener.SyncExistingStack(ctx, membershipStack) + stack = &v1beta1.Stack{} Eventually(func() error { return LoadResource("Stacks", membershipStack.ClusterName, stack) @@ -240,11 +229,8 @@ var _ = Describe("Membership listener", func() { return !exist }) - membershipClient.Orders() <- &generated.Order{ - Message: &generated.Order_ExistingStack{ - ExistingStack: membershipStack, - }, - } + // Directly call SyncExistingStack instead of sending over channel + listener.SyncExistingStack(ctx, membershipStack) }) It("modules should be removed", func() { for moduleName := range modulesToRemove { @@ -257,13 +243,8 @@ var _ = Describe("Membership listener", func() { }) Context("then when disabling the stack", func() { BeforeEach(func() { - membershipClient.Orders() <- &generated.Order{ - Message: &generated.Order_DisabledStack{ - DisabledStack: &generated.DisabledStack{ - ClusterName: membershipStack.ClusterName, - }, - }, - } + // Directly call DisableStack instead of sending over channel + listener.DisableStack(ctx, membershipStack.ClusterName) }) shouldBeDisabled := func() { stack := &v1beta1.Stack{} @@ -276,13 +257,8 @@ var _ = Describe("Membership listener", func() { Context("Then re enabling the stack", func() { BeforeEach(func() { shouldBeDisabled() - membershipClient.Orders() <- &generated.Order{ - Message: &generated.Order_EnabledStack{ - EnabledStack: &generated.EnabledStack{ - ClusterName: membershipStack.ClusterName, - }, - }, - } + // Directly call EnableStack instead of sending over channel + listener.EnableStack(ctx, membershipStack.ClusterName) }) It("Should enable the stack on the cluster", func() { stack := &v1beta1.Stack{}