diff --git a/pkg/app/piped/livestatereporter/ecs/report.go b/pkg/app/piped/livestatereporter/ecs/report.go new file mode 100644 index 0000000000..ab1a9bfca1 --- /dev/null +++ b/pkg/app/piped/livestatereporter/ecs/report.go @@ -0,0 +1,132 @@ +// Copyright 2024 The PipeCD Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ecs + +import ( + "context" + "fmt" + "time" + + "github.com/pipe-cd/pipecd/pkg/app/piped/livestatestore/ecs" + "github.com/pipe-cd/pipecd/pkg/app/server/service/pipedservice" + "github.com/pipe-cd/pipecd/pkg/config" + "github.com/pipe-cd/pipecd/pkg/model" + "go.uber.org/zap" + "google.golang.org/grpc" +) + +type applicationLister interface { + ListByPlatformProvider(name string) []*model.Application +} + +type apiClient interface { + ReportApplicationLiveState(ctx context.Context, req *pipedservice.ReportApplicationLiveStateRequest, opts ...grpc.CallOption) (*pipedservice.ReportApplicationLiveStateResponse, error) + ReportApplicationLiveStateEvents(ctx context.Context, req *pipedservice.ReportApplicationLiveStateEventsRequest, opts ...grpc.CallOption) (*pipedservice.ReportApplicationLiveStateEventsResponse, error) +} + +type Reporter interface { + Run(ctx context.Context) error + ProviderName() string +} + +type reporter struct { + provider config.PipedPlatformProvider + appLister applicationLister + stateGetter ecs.Getter + apiClient apiClient + snapshotFlushInterval time.Duration + logger *zap.Logger + + snapshotVersions map[string]model.ApplicationLiveStateVersion +} + +func NewReporter(cp config.PipedPlatformProvider, appLister applicationLister, stateGetter ecs.Getter, apiClient apiClient, logger *zap.Logger) Reporter { + logger = logger.Named("ecs-reporter").With( + zap.String("platform-provider", cp.Name), + ) + return &reporter{ + provider: cp, + appLister: appLister, + stateGetter: stateGetter, + apiClient: apiClient, + snapshotFlushInterval: time.Minute, + logger: logger, + snapshotVersions: make(map[string]model.ApplicationLiveStateVersion), + } +} + +func (r *reporter) Run(ctx context.Context) error { + r.logger.Info("start running app live state reporter") + + r.logger.Info("waiting for livestatestore to be ready") + if err := r.stateGetter.WaitForReady(ctx, 10*time.Minute); err != nil { + r.logger.Error("livestatestore was unable to be ready in time", zap.Error(err)) + return err + } + + snapshotTicker := time.NewTicker(r.snapshotFlushInterval) + defer snapshotTicker.Stop() + + for { + select { + case <-snapshotTicker.C: + r.flushSnapshots(ctx) + + case <-ctx.Done(): + r.logger.Info("app live state reporter has been stopped") + return nil + } + } +} + +func (r *reporter) ProviderName() string { + return r.provider.Name +} + +func (r *reporter) flushSnapshots(ctx context.Context) { + apps := r.appLister.ListByPlatformProvider(r.provider.Name) + for _, app := range apps { + state, ok := r.stateGetter.GetState(app.Id) + if !ok { + r.logger.Info(fmt.Sprintf("no app state of ecs application %s to report", app.Id)) + continue + } + + snapshot := &model.ApplicationLiveStateSnapshot{ + ApplicationId: app.Id, + PipedId: app.PipedId, + ProjectId: app.ProjectId, + Kind: app.Kind, + Ecs: &model.ECSApplicationLiveState{ + Resources: state.Resources, + }, + Version: &state.Version, + } + snapshot.DetermineAppHealthStatus() + req := &pipedservice.ReportApplicationLiveStateRequest{ + Snapshot: snapshot, + } + + if _, err := r.apiClient.ReportApplicationLiveState(ctx, req); err != nil { + r.logger.Error("failed to report application live state", + zap.String("application-id", app.Id), + zap.Error(err), + ) + continue + } + r.snapshotVersions[app.Id] = state.Version + r.logger.Info(fmt.Sprintf("successfully reported application live state for application: %s", app.Id)) + } +} diff --git a/pkg/app/piped/livestatereporter/reporter.go b/pkg/app/piped/livestatereporter/reporter.go index 2f2ffc45f6..2db806a8b3 100644 --- a/pkg/app/piped/livestatereporter/reporter.go +++ b/pkg/app/piped/livestatereporter/reporter.go @@ -26,6 +26,7 @@ import ( "google.golang.org/grpc" "github.com/pipe-cd/pipecd/pkg/app/piped/livestatereporter/cloudrun" + "github.com/pipe-cd/pipecd/pkg/app/piped/livestatereporter/ecs" "github.com/pipe-cd/pipecd/pkg/app/piped/livestatereporter/kubernetes" "github.com/pipe-cd/pipecd/pkg/app/piped/livestatestore" "github.com/pipe-cd/pipecd/pkg/app/server/service/pipedservice" @@ -79,6 +80,13 @@ func NewReporter(appLister applicationLister, stateGetter livestatestore.Getter, continue } r.reporters = append(r.reporters, cloudrun.NewReporter(cp, appLister, sg, apiClient, logger)) + case model.PlatformProviderECS: + sg, ok := stateGetter.ECSGetter(cp.Name) + if !ok { + r.logger.Error(fmt.Sprintf(errFmt, cp.Name)) + continue + } + r.reporters = append(r.reporters, ecs.NewReporter(cp, appLister, sg, apiClient, logger)) } } diff --git a/pkg/app/piped/livestatestore/ecs/ecs.go b/pkg/app/piped/livestatestore/ecs/ecs.go new file mode 100644 index 0000000000..581d2f878c --- /dev/null +++ b/pkg/app/piped/livestatestore/ecs/ecs.go @@ -0,0 +1,118 @@ +// Copyright 2024 The PipeCD Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ecs + +import ( + "context" + "time" + + "go.uber.org/zap" + + provider "github.com/pipe-cd/pipecd/pkg/app/piped/platformprovider/ecs" + "github.com/pipe-cd/pipecd/pkg/config" + "github.com/pipe-cd/pipecd/pkg/model" +) + +type Store struct { + store *store + logger *zap.Logger + interval time.Duration + firstSyncedCh chan error +} + +type Getter interface { + GetECSManifests(appID string) (provider.ECSManifests, bool) + GetState(appID string) (State, bool) + + WaitForReady(ctx context.Context, timeout time.Duration) error +} + +type State struct { + Resources []*model.ECSResourceState + Version model.ApplicationLiveStateVersion +} + +func NewStore(cfg *config.PlatformProviderECSConfig, platformProvider string, logger *zap.Logger) (*Store, error) { + logger = logger.Named("ecs"). + With(zap.String("platform-provider", platformProvider)) + + client, err := provider.DefaultRegistry().Client(platformProvider, cfg, logger) + if err != nil { + return nil, err + } + + store := &Store{ + store: &store{ + client: client, + logger: logger.Named("store"), + }, + interval: 15 * time.Second, + logger: logger, + firstSyncedCh: make(chan error, 1), + } + + return store, nil +} + +func (s *Store) Run(ctx context.Context) error { + s.logger.Info("start running ecs app state store") + + tick := time.NewTicker(s.interval) + defer tick.Stop() + + // Run the first sync of ECS resources. + if err := s.store.run(ctx); err != nil { + s.firstSyncedCh <- err + return err + } + + s.logger.Info("successfully ran the first sync of all ecs resources") + close(s.firstSyncedCh) + + for { + select { + case <-ctx.Done(): + s.logger.Info("ecs app state store has been stopped") + return nil + + case <-tick.C: + if err := s.store.run(ctx); err != nil { + s.logger.Error("failed to sync ecs resources", zap.Error(err)) + continue + } + s.logger.Info("successfully synced all ecs resources") + } + } +} + +func (s *Store) GetECSManifests(appID string) (provider.ECSManifests, bool) { + return s.store.getECSManifests(appID) +} + +func (s *Store) GetState(appID string) (State, bool) { + return s.store.getState(appID) +} + +func (s *Store) WaitForReady(ctx context.Context, timeout time.Duration) error { + ctx, cancel := context.WithTimeout(ctx, timeout) + defer cancel() + + select { + case <-ctx.Done(): + return nil + case err := <-s.firstSyncedCh: + return err + } +} diff --git a/pkg/app/piped/livestatestore/ecs/store.go b/pkg/app/piped/livestatestore/ecs/store.go index 95a63ebdc7..1bffeb6c8e 100644 --- a/pkg/app/piped/livestatestore/ecs/store.go +++ b/pkg/app/piped/livestatestore/ecs/store.go @@ -16,36 +16,133 @@ package ecs import ( "context" + "fmt" + "sync/atomic" + "time" + "github.com/aws/aws-sdk-go-v2/service/ecs/types" "go.uber.org/zap" - "github.com/pipe-cd/pipecd/pkg/config" + provider "github.com/pipe-cd/pipecd/pkg/app/piped/platformprovider/ecs" "github.com/pipe-cd/pipecd/pkg/model" ) -type applicationLister interface { - List() []*model.Application +type store struct { + apps atomic.Value + logger *zap.Logger + client provider.Client } -type Store struct { - logger *zap.Logger +type app struct { + // ServiceDefinition and its primary taskset's TaskDefinition. + ecsManifests provider.ECSManifests + + // States of services, tasksets, and tasks. + // NOTE: Standalone tasks are NOT included yet. + states []*model.ECSResourceState + version model.ApplicationLiveStateVersion +} + +func (s *store) run(ctx context.Context) error { + apps := map[string]app{} + now := time.Now() + version := model.ApplicationLiveStateVersion{ + Timestamp: now.Unix(), + } + + clusters, err := s.client.ListClusters(ctx) + if err != nil { + return fmt.Errorf("failed to fetch ECS clusters: %w", err) + } + + for _, cluster := range clusters { + services, err := s.client.GetServices(ctx, cluster) + if err != nil { + return fmt.Errorf("failed to fetch ECS services of cluster %s: %w", cluster, err) + } + + for _, service := range services { + taskSetTasks := make(map[string][]*types.Task, len(service.TaskSets)) + var primaryTaskDef *types.TaskDefinition + for _, taskSet := range service.TaskSets { + if *taskSet.Status == "PRIMARY" { + primaryTaskDef, err = s.client.GetTaskDefinition(ctx, *taskSet.TaskDefinition) + if err != nil { + return fmt.Errorf("failed to fetch ECS task definition %s: %w", *taskSet.TaskDefinition, err) + } + } + + tasks, err := s.client.GetTaskSetTasks(ctx, taskSet) + if err != nil { + return fmt.Errorf("failed to fetch ECS tasks of task set %s: %w", *taskSet.TaskSetArn, err) + } + taskSetTasks[*taskSet.TaskSetArn] = tasks + } + + // Use the application ID tag as the key. + appId := "" + for _, tag := range service.Tags { + if *tag.Key == provider.LabelApplication { + appId = *tag.Value + break + } + } + if appId == "" { + // Skip a service which is not managed by PipeCD. + continue + } + + apps[appId] = app{ + ecsManifests: provider.ECSManifests{ + ServiceDefinition: service, + TaskDefinition: primaryTaskDef, + }, + states: provider.MakeServiceResourceStates(service, taskSetTasks), + version: version, + } + } + } + + s.apps.Store(apps) + + return nil } -type Getter interface { +func (s *store) loadApps() map[string]app { + apps := s.apps.Load() + if apps == nil { + return nil + } + return apps.(map[string]app) } -func NewStore(cfg *config.PlatformProviderECSConfig, platformProvider string, appLister applicationLister, logger *zap.Logger) *Store { - logger = logger.Named("ecs"). - With(zap.String("platform-provider", platformProvider)) +func (s *store) getECSManifests(appID string) (provider.ECSManifests, bool) { + apps := s.loadApps() + if apps == nil { + return provider.ECSManifests{}, false + } - return &Store{ - logger: logger, + app, ok := apps[appID] + if !ok { + return provider.ECSManifests{}, false } + + return app.ecsManifests, true } -func (s *Store) Run(ctx context.Context) error { - s.logger.Info("start running ecs app state store") +func (s *store) getState(appID string) (State, bool) { + apps := s.loadApps() + if apps == nil { + return State{}, false + } + + app, ok := apps[appID] + if !ok { + return State{}, false + } - s.logger.Info("ecs app state store has been stopped") - return nil + return State{ + Resources: app.states, + Version: app.version, + }, true } diff --git a/pkg/app/piped/livestatestore/livestatestore.go b/pkg/app/piped/livestatestore/livestatestore.go index 325028db05..09fba739ad 100644 --- a/pkg/app/piped/livestatestore/livestatestore.go +++ b/pkg/app/piped/livestatestore/livestatestore.go @@ -41,7 +41,7 @@ type applicationLister interface { type Getter interface { CloudRunGetter(platformProvider string) (cloudrun.Getter, bool) - ECSRunGetter(platformProvider string) (ecs.Getter, bool) + ECSGetter(platformProvider string) (ecs.Getter, bool) KubernetesGetter(platformProvider string) (kubernetes.Getter, bool) LambdaGetter(platformProvider string) (lambda.Getter, bool) TerraformGetter(platformProvider string) (terraform.Getter, bool) @@ -72,6 +72,7 @@ type lambdaStore interface { type ecsStore interface { Run(ctx context.Context) error + ecs.Getter } // store manages a list of particular stores for all cloud providers. @@ -126,7 +127,11 @@ func NewStore(ctx context.Context, cfg *config.PipedSpec, appLister applicationL s.lambdaStores[cp.Name] = store case model.PlatformProviderECS: - store := ecs.NewStore(cp.ECSConfig, cp.Name, appLister, logger) + store, err := ecs.NewStore(cp.ECSConfig, cp.Name, logger) + if err != nil { + logger.Error("failed to create a new ecs's livestatestore", zap.Error(err)) + continue + } s.ecsStores[cp.Name] = store } } @@ -192,7 +197,7 @@ func (s *store) CloudRunGetter(platformProvider string) (cloudrun.Getter, bool) return ks, ok } -func (s *store) ECSRunGetter(platformProvider string) (ecs.Getter, bool) { +func (s *store) ECSGetter(platformProvider string) (ecs.Getter, bool) { ks, ok := s.ecsStores[platformProvider] return ks, ok } diff --git a/pkg/app/piped/platformprovider/ecs/client.go b/pkg/app/piped/platformprovider/ecs/client.go index 178dca1f4b..0caebdc2bb 100644 --- a/pkg/app/piped/platformprovider/ecs/client.go +++ b/pkg/app/piped/platformprovider/ecs/client.go @@ -166,6 +166,17 @@ func (c *client) UpdateService(ctx context.Context, service types.Service) (*typ return output.Service, nil } +func (c *client) GetTaskDefinition(ctx context.Context, taskDefinitionArn string) (*types.TaskDefinition, error) { + input := &ecs.DescribeTaskDefinitionInput{ + TaskDefinition: aws.String(taskDefinitionArn), + } + output, err := c.ecsClient.DescribeTaskDefinition(ctx, input) + if err != nil { + return nil, fmt.Errorf("failed to get ECS task definition %s: %w", taskDefinitionArn, err) + } + return output.TaskDefinition, nil +} + func (c *client) RegisterTaskDefinition(ctx context.Context, taskDefinition types.TaskDefinition) (*types.TaskDefinition, error) { input := &ecs.RegisterTaskDefinitionInput{ Family: taskDefinition.Family, @@ -526,3 +537,105 @@ func (c *client) TagResource(ctx context.Context, resourceArn string, tags []typ } return nil } + +func (c *client) ListClusters(ctx context.Context) ([]string, error) { + in := &ecs.ListClustersInput{ + MaxResults: aws.Int32(100), + } + clusters := []string{} + for { + out, err := c.ecsClient.ListClusters(ctx, in) + if err != nil { + return nil, fmt.Errorf("failed to list ECS clusters: %w", err) + } + clusters = append(clusters, out.ClusterArns...) + if out.NextToken == nil { + return clusters, nil + } + in.NextToken = out.NextToken + } +} + +func (c *client) GetServices(ctx context.Context, clusterName string) ([]*types.Service, error) { + listIn := &ecs.ListServicesInput{ + Cluster: aws.String(clusterName), + MaxResults: aws.Int32(100), + } + var serviceArns []string + for { + listOut, err := c.ecsClient.ListServices(ctx, listIn) + if err != nil { + return nil, fmt.Errorf("failed to list services of cluster %s: %w", clusterName, err) + } + serviceArns = append(serviceArns, listOut.ServiceArns...) + if listOut.NextToken == nil { + break + } + listIn.NextToken = listOut.NextToken + } + + if len(serviceArns) == 0 { + return []*types.Service{}, nil + } + + services := make([]*types.Service, 0, len(serviceArns)) + // Split serviceArns into chunks of 10 to avoid the limitation in a single request of DescribeServices. + for i := 0; i < len(serviceArns); i += 10 { + end := i + 10 + if end > len(serviceArns) { + end = len(serviceArns) + } + describeIn := &ecs.DescribeServicesInput{ + Cluster: aws.String(clusterName), + Services: serviceArns[i:end], + Include: []types.ServiceField{types.ServiceFieldTags}, + } + describeOut, err := c.ecsClient.DescribeServices(ctx, describeIn) + if err != nil { + return nil, fmt.Errorf("failed to describe services: %w", err) + } + + for i := range describeOut.Services { + services = append(services, &describeOut.Services[i]) + } + } + + return services, nil +} + +func (c *client) GetTaskSetTasks(ctx context.Context, taskSet types.TaskSet) ([]*types.Task, error) { + listIn := &ecs.ListTasksInput{ + Cluster: taskSet.ClusterArn, + // Service tasks have the deployment ID, which is the same as taskSet's ID, as `startedBy` field. + StartedBy: taskSet.Id, + } + listOut, err := c.ecsClient.ListTasks(ctx, listIn) + if err != nil { + return nil, fmt.Errorf("failed to list tasks of task set %s: %w", *taskSet.TaskSetArn, err) + } + + taskArns := listOut.TaskArns + tasks := make([]*types.Task, 0, len(taskArns)) + // Split taskArns into chunks of 100 to avoid the limitation in a single request of DescribeTasks. + for i := 0; i < len(taskArns); i += 100 { + end := i + 100 + if end > len(taskArns) { + end = len(taskArns) + } + + describeIn := &ecs.DescribeTasksInput{ + Cluster: taskSet.ClusterArn, + Tasks: listOut.TaskArns[i:end], + } + out, err := c.ecsClient.DescribeTasks(ctx, describeIn) + if err != nil { + return nil, fmt.Errorf("failed to describe tasks: %w", err) + } + + for i := range out.Tasks { + tasks = append(tasks, &out.Tasks[i]) + } + } + + return tasks, nil +} diff --git a/pkg/app/piped/platformprovider/ecs/ecs.go b/pkg/app/piped/platformprovider/ecs/ecs.go index 927d716b0e..1f8918badb 100644 --- a/pkg/app/piped/platformprovider/ecs/ecs.go +++ b/pkg/app/piped/platformprovider/ecs/ecs.go @@ -42,13 +42,17 @@ type Client interface { } type ECS interface { + ListClusters(ctx context.Context) ([]string, error) ServiceExists(ctx context.Context, clusterName string, servicesName string) (bool, error) CreateService(ctx context.Context, service types.Service) (*types.Service, error) UpdateService(ctx context.Context, service types.Service) (*types.Service, error) PruneServiceTasks(ctx context.Context, service types.Service) error WaitServiceStable(ctx context.Context, service types.Service) error + GetServices(ctx context.Context, clusterName string) ([]*types.Service, error) + GetTaskDefinition(ctx context.Context, taskDefinitionArn string) (*types.TaskDefinition, error) RegisterTaskDefinition(ctx context.Context, taskDefinition types.TaskDefinition) (*types.TaskDefinition, error) RunTask(ctx context.Context, taskDefinition types.TaskDefinition, clusterArn string, launchType string, awsVpcConfiguration *config.ECSVpcConfiguration, tags []types.Tag) error + GetTaskSetTasks(ctx context.Context, taskSet types.TaskSet) ([]*types.Task, error) GetServiceTaskSets(ctx context.Context, service types.Service) ([]*types.TaskSet, error) CreateTaskSet(ctx context.Context, service types.Service, taskDefinition types.TaskDefinition, targetGroup *types.LoadBalancer, scale int) (*types.TaskSet, error) DeleteTaskSet(ctx context.Context, taskSet types.TaskSet) error diff --git a/pkg/app/piped/platformprovider/ecs/state.go b/pkg/app/piped/platformprovider/ecs/state.go new file mode 100644 index 0000000000..0beb79c3f6 --- /dev/null +++ b/pkg/app/piped/platformprovider/ecs/state.go @@ -0,0 +1,128 @@ +// Copyright 2024 The PipeCD Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ecs + +import ( + "fmt" + "strings" + + "github.com/aws/aws-sdk-go-v2/service/ecs/types" + "github.com/pipe-cd/pipecd/pkg/model" +) + +// MakeServiceResourceStates creates ECSResourceStates of Service, TaskSets, and Tasks. +// `taskSetTasks` is a map of TaskSetArn to Tasks. +func MakeServiceResourceStates(service *types.Service, taskSetTasks map[string][]*types.Task) []*model.ECSResourceState { + states := []*model.ECSResourceState{} + + states = append(states, makeServiceResourceState(service)) + + for _, taskSet := range service.TaskSets { + states = append(states, makeTaskSetResourceState(&taskSet)) + + for _, task := range taskSetTasks[*taskSet.TaskSetArn] { + states = append(states, makeTaskResourceState(task, *taskSet.TaskSetArn)) + } + } + return states +} + +func makeServiceResourceState(service *types.Service) *model.ECSResourceState { + var healthStatus model.ECSResourceState_HealthStatus + switch *service.Status { + case "ACTIVE": + healthStatus = model.ECSResourceState_HEALTHY + case "DRAINING", "INACTIVE": + healthStatus = model.ECSResourceState_OTHER + default: + healthStatus = model.ECSResourceState_UNKNOWN + } + + createdAt := service.CreatedAt.Unix() + return &model.ECSResourceState{ + Id: *service.ServiceArn, + OwnerIds: []string{*service.ClusterArn}, + ParentIds: []string{*service.ClusterArn}, + Name: *service.ServiceName, + + Kind: "Service", + + HealthStatus: healthStatus, + HealthDescription: fmt.Sprintf("Service's status is %s", *service.Status), + + CreatedAt: createdAt, + // We use CreatedAt for UpdatedAt although Service is not immutable because Service does not have UpdatedAt field. + UpdatedAt: createdAt, + } +} + +func makeTaskSetResourceState(taskSet *types.TaskSet) *model.ECSResourceState { + var healthStatus model.ECSResourceState_HealthStatus + switch *taskSet.Status { + case "PRIMARY", "ACTIVE": + healthStatus = model.ECSResourceState_HEALTHY + case "DRAINING": + healthStatus = model.ECSResourceState_OTHER + default: + healthStatus = model.ECSResourceState_UNKNOWN + } + + return &model.ECSResourceState{ + Id: *taskSet.TaskSetArn, + OwnerIds: []string{*taskSet.ServiceArn}, + ParentIds: []string{*taskSet.ServiceArn}, + Name: *taskSet.Id, + + Kind: "TaskSet", + + HealthStatus: healthStatus, + HealthDescription: fmt.Sprintf("TaskSet's status is %s", *taskSet.Status), + + CreatedAt: taskSet.CreatedAt.Unix(), + UpdatedAt: taskSet.UpdatedAt.Unix(), + } +} + +// `parentArn`: Specify taskSet's arn for service tasks, and specify cluster's arn for standalone tasks. +func makeTaskResourceState(task *types.Task, parentArn string) *model.ECSResourceState { + var healthStatus model.ECSResourceState_HealthStatus + switch task.HealthStatus { + case types.HealthStatusHealthy: + healthStatus = model.ECSResourceState_HEALTHY + case types.HealthStatusUnhealthy: + healthStatus = model.ECSResourceState_OTHER + default: + healthStatus = model.ECSResourceState_UNKNOWN + } + + taskArnParts := strings.Split(*task.TaskArn, "/") + taskId := taskArnParts[len(taskArnParts)-1] + + createdAt := task.CreatedAt.Unix() + return &model.ECSResourceState{ + Id: *task.TaskArn, + OwnerIds: []string{parentArn}, + ParentIds: []string{parentArn}, + Name: taskId, + + Kind: "Task", + + HealthStatus: healthStatus, + HealthDescription: fmt.Sprintf("Task's last status is %s and the health status is %s", *task.LastStatus, task.HealthStatus), + + CreatedAt: createdAt, + UpdatedAt: createdAt, // Task is immutable, so updatedAt is the same as createdAt. + } +} diff --git a/pkg/app/piped/platformprovider/ecs/state_test.go b/pkg/app/piped/platformprovider/ecs/state_test.go new file mode 100644 index 0000000000..cb934368ba --- /dev/null +++ b/pkg/app/piped/platformprovider/ecs/state_test.go @@ -0,0 +1,207 @@ +// Copyright 2024 The PipeCD Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ecs + +import ( + "fmt" + "testing" + "time" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ecs/types" + "github.com/stretchr/testify/assert" + + "github.com/pipe-cd/pipecd/pkg/model" +) + +func TestMakeServiceResourceState(t *testing.T) { + t.Parallel() + + testcases := []struct { + title string + status string + expectedStatus model.ECSResourceState_HealthStatus + }{ + { + title: "active is healthy", + status: "ACTIVE", + expectedStatus: model.ECSResourceState_HEALTHY, + }, + { + title: "draining is other", + status: "DRAINING", + expectedStatus: model.ECSResourceState_OTHER, + }, + { + title: "inactive is other", + status: "INACTIVE", + expectedStatus: model.ECSResourceState_OTHER, + }, + { + title: "else is unknown", + status: "dummy-status", + expectedStatus: model.ECSResourceState_UNKNOWN, + }, + } + + for _, tc := range testcases { + tc := tc + t.Run(tc.title, func(t *testing.T) { + t.Parallel() + service := &types.Service{ + Status: &tc.status, + // Folowing fields are required to avoid nil pointer panic. + ServiceArn: aws.String("test-service-arn"), + ClusterArn: aws.String("test-cluster-arn"), + ServiceName: aws.String("test-service-name"), + CreatedAt: aws.Time(time.Now()), + } + state := makeServiceResourceState(service) + + expected := &model.ECSResourceState{ + Id: "test-service-arn", + OwnerIds: []string{"test-cluster-arn"}, + ParentIds: []string{"test-cluster-arn"}, + Name: "test-service-name", + Kind: "Service", + HealthStatus: tc.expectedStatus, + HealthDescription: fmt.Sprintf("Service's status is %s", tc.status), + CreatedAt: service.CreatedAt.Unix(), + UpdatedAt: service.CreatedAt.Unix(), + } + + assert.Equal(t, expected, state) + }) + } +} + +func TestMakeTaskSetResourceState(t *testing.T) { + t.Parallel() + + testcases := []struct { + title string + status string + expectedStatus model.ECSResourceState_HealthStatus + }{ + { + title: "primary is healthy", + status: "PRIMARY", + expectedStatus: model.ECSResourceState_HEALTHY, + }, + { + title: "active is healthy", + status: "ACTIVE", + expectedStatus: model.ECSResourceState_HEALTHY, + }, + { + title: "draining is other", + status: "DRAINING", + expectedStatus: model.ECSResourceState_OTHER, + }, + { + title: "else is unknown", + status: "dummy-status", + expectedStatus: model.ECSResourceState_UNKNOWN, + }, + } + + for _, tc := range testcases { + tc := tc + t.Run(tc.title, func(t *testing.T) { + t.Parallel() + now := time.Now() + taskSet := &types.TaskSet{ + Status: &tc.status, + // Folowing fields are required to avoid nil pointer panic. + TaskSetArn: aws.String("test-task-set-arn"), + Id: aws.String("test-task-set-id"), + ServiceArn: aws.String("test-service-arn"), + CreatedAt: aws.Time(now), + UpdatedAt: aws.Time(now), + } + state := makeTaskSetResourceState(taskSet) + + expected := &model.ECSResourceState{ + Id: "test-task-set-arn", + OwnerIds: []string{"test-service-arn"}, + ParentIds: []string{"test-service-arn"}, + Name: "test-task-set-id", + Kind: "TaskSet", + HealthStatus: tc.expectedStatus, + HealthDescription: fmt.Sprintf("TaskSet's status is %s", tc.status), + CreatedAt: now.Unix(), + UpdatedAt: now.Unix(), + } + + assert.Equal(t, expected, state) + }) + } +} + +func TestMakeTaskResourceState(t *testing.T) { + t.Parallel() + + testcases := []struct { + title string + healthStatus types.HealthStatus + expectedStatus model.ECSResourceState_HealthStatus + }{ + { + title: "healthy", + healthStatus: types.HealthStatusHealthy, + expectedStatus: model.ECSResourceState_HEALTHY, + }, + { + title: "unhealthy", + healthStatus: types.HealthStatusUnhealthy, + expectedStatus: model.ECSResourceState_OTHER, + }, + { + title: "unknown", + healthStatus: types.HealthStatusUnknown, + expectedStatus: model.ECSResourceState_UNKNOWN, + }, + } + + for _, tc := range testcases { + tc := tc + t.Run(tc.title, func(t *testing.T) { + t.Parallel() + now := time.Now() + task := &types.Task{ + HealthStatus: tc.healthStatus, + // Folowing fields are required to avoid nil pointer panic. + LastStatus: aws.String("test-last-status"), + TaskArn: aws.String("arn:aws:ecs:region:account-id:task/test-cluster/test-task-id"), + CreatedAt: aws.Time(now), + } + state := makeTaskResourceState(task, "test-cluster-arn") + + expected := &model.ECSResourceState{ + Id: "arn:aws:ecs:region:account-id:task/test-cluster/test-task-id", + OwnerIds: []string{"test-cluster-arn"}, + ParentIds: []string{"test-cluster-arn"}, + Name: "test-task-id", + Kind: "Task", + HealthStatus: tc.expectedStatus, + HealthDescription: fmt.Sprintf("Task's last status is test-last-status and the health status is %s", string(tc.healthStatus)), + CreatedAt: now.Unix(), + UpdatedAt: now.Unix(), + } + + assert.Equal(t, expected, state) + }) + } +} diff --git a/pkg/model/application_live_state.go b/pkg/model/application_live_state.go index 40d17fce3f..57cd9d09b2 100644 --- a/pkg/model/application_live_state.go +++ b/pkg/model/application_live_state.go @@ -67,6 +67,8 @@ func (s *ApplicationLiveStateSnapshot) DetermineAppHealthStatus() { s.determineKubernetesAppHealthStatus() case ApplicationKind_CLOUDRUN: s.determineCloudRunAppHealthStatus() + case ApplicationKind_ECS: + s.determineECSAppHealthStatus() } } @@ -103,3 +105,22 @@ func (s *ApplicationLiveStateSnapshot) determineCloudRunAppHealthStatus() { } s.HealthStatus = ApplicationLiveStateSnapshot_HEALTHY } + +func (s *ApplicationLiveStateSnapshot) determineECSAppHealthStatus() { + app := s.Ecs + if app == nil { + return + } + for _, r := range app.Resources { + if r.HealthStatus == ECSResourceState_OTHER { + s.HealthStatus = ApplicationLiveStateSnapshot_OTHER + return + } + + if r.HealthStatus == ECSResourceState_UNKNOWN { + s.HealthStatus = ApplicationLiveStateSnapshot_UNKNOWN + return + } + } + s.HealthStatus = ApplicationLiveStateSnapshot_HEALTHY +} diff --git a/pkg/model/application_live_state.pb.go b/pkg/model/application_live_state.pb.go index 26a0df37c4..8d7643dcae 100644 --- a/pkg/model/application_live_state.pb.go +++ b/pkg/model/application_live_state.pb.go @@ -130,7 +130,7 @@ func (x KubernetesResourceState_HealthStatus) Number() protoreflect.EnumNumber { // Deprecated: Use KubernetesResourceState_HealthStatus.Descriptor instead. func (KubernetesResourceState_HealthStatus) EnumDescriptor() ([]byte, []int) { - return file_pkg_model_application_live_state_proto_rawDescGZIP(), []int{6, 0} + return file_pkg_model_application_live_state_proto_rawDescGZIP(), []int{7, 0} } type KubernetesResourceStateEvent_Type int32 @@ -176,7 +176,7 @@ func (x KubernetesResourceStateEvent_Type) Number() protoreflect.EnumNumber { // Deprecated: Use KubernetesResourceStateEvent_Type.Descriptor instead. func (KubernetesResourceStateEvent_Type) EnumDescriptor() ([]byte, []int) { - return file_pkg_model_application_live_state_proto_rawDescGZIP(), []int{7, 0} + return file_pkg_model_application_live_state_proto_rawDescGZIP(), []int{8, 0} } type CloudRunResourceState_HealthStatus int32 @@ -225,7 +225,56 @@ func (x CloudRunResourceState_HealthStatus) Number() protoreflect.EnumNumber { // Deprecated: Use CloudRunResourceState_HealthStatus.Descriptor instead. func (CloudRunResourceState_HealthStatus) EnumDescriptor() ([]byte, []int) { - return file_pkg_model_application_live_state_proto_rawDescGZIP(), []int{8, 0} + return file_pkg_model_application_live_state_proto_rawDescGZIP(), []int{9, 0} +} + +type ECSResourceState_HealthStatus int32 + +const ( + ECSResourceState_UNKNOWN ECSResourceState_HealthStatus = 0 + ECSResourceState_HEALTHY ECSResourceState_HealthStatus = 1 + ECSResourceState_OTHER ECSResourceState_HealthStatus = 2 +) + +// Enum value maps for ECSResourceState_HealthStatus. +var ( + ECSResourceState_HealthStatus_name = map[int32]string{ + 0: "UNKNOWN", + 1: "HEALTHY", + 2: "OTHER", + } + ECSResourceState_HealthStatus_value = map[string]int32{ + "UNKNOWN": 0, + "HEALTHY": 1, + "OTHER": 2, + } +) + +func (x ECSResourceState_HealthStatus) Enum() *ECSResourceState_HealthStatus { + p := new(ECSResourceState_HealthStatus) + *p = x + return p +} + +func (x ECSResourceState_HealthStatus) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ECSResourceState_HealthStatus) Descriptor() protoreflect.EnumDescriptor { + return file_pkg_model_application_live_state_proto_enumTypes[4].Descriptor() +} + +func (ECSResourceState_HealthStatus) Type() protoreflect.EnumType { + return &file_pkg_model_application_live_state_proto_enumTypes[4] +} + +func (x ECSResourceState_HealthStatus) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ECSResourceState_HealthStatus.Descriptor instead. +func (ECSResourceState_HealthStatus) EnumDescriptor() ([]byte, []int) { + return file_pkg_model_application_live_state_proto_rawDescGZIP(), []int{10, 0} } // ApplicationLiveStateSnapshot represents the full live state information of an application @@ -244,6 +293,7 @@ type ApplicationLiveStateSnapshot struct { Terraform *TerraformApplicationLiveState `protobuf:"bytes,11,opt,name=terraform,proto3" json:"terraform,omitempty"` Cloudrun *CloudRunApplicationLiveState `protobuf:"bytes,12,opt,name=cloudrun,proto3" json:"cloudrun,omitempty"` Lambda *LambdaApplicationLiveState `protobuf:"bytes,13,opt,name=lambda,proto3" json:"lambda,omitempty"` + Ecs *ECSApplicationLiveState `protobuf:"bytes,14,opt,name=ecs,proto3" json:"ecs,omitempty"` Version *ApplicationLiveStateVersion `protobuf:"bytes,15,opt,name=version,proto3" json:"version,omitempty"` } @@ -342,6 +392,13 @@ func (x *ApplicationLiveStateSnapshot) GetLambda() *LambdaApplicationLiveState { return nil } +func (x *ApplicationLiveStateSnapshot) GetEcs() *ECSApplicationLiveState { + if x != nil { + return x.Ecs + } + return nil +} + func (x *ApplicationLiveStateSnapshot) GetVersion() *ApplicationLiveStateVersion { if x != nil { return x.Version @@ -538,6 +595,53 @@ func (x *CloudRunApplicationLiveState) GetResources() []*CloudRunResourceState { return nil } +type ECSApplicationLiveState struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Resources []*ECSResourceState `protobuf:"bytes,1,rep,name=resources,proto3" json:"resources,omitempty"` +} + +func (x *ECSApplicationLiveState) Reset() { + *x = ECSApplicationLiveState{} + if protoimpl.UnsafeEnabled { + mi := &file_pkg_model_application_live_state_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ECSApplicationLiveState) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ECSApplicationLiveState) ProtoMessage() {} + +func (x *ECSApplicationLiveState) ProtoReflect() protoreflect.Message { + mi := &file_pkg_model_application_live_state_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ECSApplicationLiveState.ProtoReflect.Descriptor instead. +func (*ECSApplicationLiveState) Descriptor() ([]byte, []int) { + return file_pkg_model_application_live_state_proto_rawDescGZIP(), []int{5} +} + +func (x *ECSApplicationLiveState) GetResources() []*ECSResourceState { + if x != nil { + return x.Resources + } + return nil +} + type LambdaApplicationLiveState struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -547,7 +651,7 @@ type LambdaApplicationLiveState struct { func (x *LambdaApplicationLiveState) Reset() { *x = LambdaApplicationLiveState{} if protoimpl.UnsafeEnabled { - mi := &file_pkg_model_application_live_state_proto_msgTypes[5] + mi := &file_pkg_model_application_live_state_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -560,7 +664,7 @@ func (x *LambdaApplicationLiveState) String() string { func (*LambdaApplicationLiveState) ProtoMessage() {} func (x *LambdaApplicationLiveState) ProtoReflect() protoreflect.Message { - mi := &file_pkg_model_application_live_state_proto_msgTypes[5] + mi := &file_pkg_model_application_live_state_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -573,7 +677,7 @@ func (x *LambdaApplicationLiveState) ProtoReflect() protoreflect.Message { // Deprecated: Use LambdaApplicationLiveState.ProtoReflect.Descriptor instead. func (*LambdaApplicationLiveState) Descriptor() ([]byte, []int) { - return file_pkg_model_application_live_state_proto_rawDescGZIP(), []int{5} + return file_pkg_model_application_live_state_proto_rawDescGZIP(), []int{6} } // KubernetesResourceState represents the state of a single kubernetes resource object. @@ -609,7 +713,7 @@ type KubernetesResourceState struct { func (x *KubernetesResourceState) Reset() { *x = KubernetesResourceState{} if protoimpl.UnsafeEnabled { - mi := &file_pkg_model_application_live_state_proto_msgTypes[6] + mi := &file_pkg_model_application_live_state_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -622,7 +726,7 @@ func (x *KubernetesResourceState) String() string { func (*KubernetesResourceState) ProtoMessage() {} func (x *KubernetesResourceState) ProtoReflect() protoreflect.Message { - mi := &file_pkg_model_application_live_state_proto_msgTypes[6] + mi := &file_pkg_model_application_live_state_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -635,7 +739,7 @@ func (x *KubernetesResourceState) ProtoReflect() protoreflect.Message { // Deprecated: Use KubernetesResourceState.ProtoReflect.Descriptor instead. func (*KubernetesResourceState) Descriptor() ([]byte, []int) { - return file_pkg_model_application_live_state_proto_rawDescGZIP(), []int{6} + return file_pkg_model_application_live_state_proto_rawDescGZIP(), []int{7} } func (x *KubernetesResourceState) GetId() string { @@ -732,7 +836,7 @@ type KubernetesResourceStateEvent struct { func (x *KubernetesResourceStateEvent) Reset() { *x = KubernetesResourceStateEvent{} if protoimpl.UnsafeEnabled { - mi := &file_pkg_model_application_live_state_proto_msgTypes[7] + mi := &file_pkg_model_application_live_state_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -745,7 +849,7 @@ func (x *KubernetesResourceStateEvent) String() string { func (*KubernetesResourceStateEvent) ProtoMessage() {} func (x *KubernetesResourceStateEvent) ProtoReflect() protoreflect.Message { - mi := &file_pkg_model_application_live_state_proto_msgTypes[7] + mi := &file_pkg_model_application_live_state_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -758,7 +862,7 @@ func (x *KubernetesResourceStateEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use KubernetesResourceStateEvent.ProtoReflect.Descriptor instead. func (*KubernetesResourceStateEvent) Descriptor() ([]byte, []int) { - return file_pkg_model_application_live_state_proto_rawDescGZIP(), []int{7} + return file_pkg_model_application_live_state_proto_rawDescGZIP(), []int{8} } func (x *KubernetesResourceStateEvent) GetId() string { @@ -836,7 +940,7 @@ type CloudRunResourceState struct { func (x *CloudRunResourceState) Reset() { *x = CloudRunResourceState{} if protoimpl.UnsafeEnabled { - mi := &file_pkg_model_application_live_state_proto_msgTypes[8] + mi := &file_pkg_model_application_live_state_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -849,7 +953,7 @@ func (x *CloudRunResourceState) String() string { func (*CloudRunResourceState) ProtoMessage() {} func (x *CloudRunResourceState) ProtoReflect() protoreflect.Message { - mi := &file_pkg_model_application_live_state_proto_msgTypes[8] + mi := &file_pkg_model_application_live_state_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -862,7 +966,7 @@ func (x *CloudRunResourceState) ProtoReflect() protoreflect.Message { // Deprecated: Use CloudRunResourceState.ProtoReflect.Descriptor instead. func (*CloudRunResourceState) Descriptor() ([]byte, []int) { - return file_pkg_model_application_live_state_proto_rawDescGZIP(), []int{8} + return file_pkg_model_application_live_state_proto_rawDescGZIP(), []int{9} } func (x *CloudRunResourceState) GetId() string { @@ -942,6 +1046,126 @@ func (x *CloudRunResourceState) GetUpdatedAt() int64 { return 0 } +// ECSResourceState represents the state of an ECS service resource. +type ECSResourceState struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The arn of the ECS resource. + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + // The sorted list of unique IDs of the owners that depended by this resource. + // The owner is another resource that created and managing this resource. + OwnerIds []string `protobuf:"bytes,2,rep,name=owner_ids,json=ownerIds,proto3" json:"owner_ids,omitempty"` + // The sorted list of unique IDs of the parents. + ParentIds []string `protobuf:"bytes,3,rep,name=parent_ids,json=parentIds,proto3" json:"parent_ids,omitempty"` + // The unique name for the type of resource. + Name string `protobuf:"bytes,4,opt,name=name,proto3" json:"name,omitempty"` + // The kind of this resource. e.g. Service, TaskSet, Task. + Kind string `protobuf:"bytes,5,opt,name=kind,proto3" json:"kind,omitempty"` + HealthStatus ECSResourceState_HealthStatus `protobuf:"varint,6,opt,name=health_status,json=healthStatus,proto3,enum=model.ECSResourceState_HealthStatus" json:"health_status,omitempty"` + HealthDescription string `protobuf:"bytes,7,opt,name=health_description,json=healthDescription,proto3" json:"health_description,omitempty"` + // The timestamp when this resource was created. + CreatedAt int64 `protobuf:"varint,8,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` + // The timestamp of the last time when this resource was updated. + UpdatedAt int64 `protobuf:"varint,9,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"` +} + +func (x *ECSResourceState) Reset() { + *x = ECSResourceState{} + if protoimpl.UnsafeEnabled { + mi := &file_pkg_model_application_live_state_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ECSResourceState) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ECSResourceState) ProtoMessage() {} + +func (x *ECSResourceState) ProtoReflect() protoreflect.Message { + mi := &file_pkg_model_application_live_state_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ECSResourceState.ProtoReflect.Descriptor instead. +func (*ECSResourceState) Descriptor() ([]byte, []int) { + return file_pkg_model_application_live_state_proto_rawDescGZIP(), []int{10} +} + +func (x *ECSResourceState) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *ECSResourceState) GetOwnerIds() []string { + if x != nil { + return x.OwnerIds + } + return nil +} + +func (x *ECSResourceState) GetParentIds() []string { + if x != nil { + return x.ParentIds + } + return nil +} + +func (x *ECSResourceState) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *ECSResourceState) GetKind() string { + if x != nil { + return x.Kind + } + return "" +} + +func (x *ECSResourceState) GetHealthStatus() ECSResourceState_HealthStatus { + if x != nil { + return x.HealthStatus + } + return ECSResourceState_UNKNOWN +} + +func (x *ECSResourceState) GetHealthDescription() string { + if x != nil { + return x.HealthDescription + } + return "" +} + +func (x *ECSResourceState) GetCreatedAt() int64 { + if x != nil { + return x.CreatedAt + } + return 0 +} + +func (x *ECSResourceState) GetUpdatedAt() int64 { + if x != nil { + return x.UpdatedAt + } + return 0 +} + var File_pkg_model_application_live_state_proto protoreflect.FileDescriptor var file_pkg_model_application_live_state_proto_rawDesc = []byte{ @@ -951,7 +1175,7 @@ var file_pkg_model_application_live_state_proto_rawDesc = []byte{ 0x17, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x16, 0x70, 0x6b, 0x67, 0x2f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x22, 0xa5, 0x05, 0x0a, 0x1c, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x22, 0xd7, 0x05, 0x0a, 0x1c, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x76, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x2e, 0x0a, 0x0e, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, @@ -985,130 +1209,165 @@ var file_pkg_model_application_live_state_proto_rawDesc = []byte{ 0x12, 0x39, 0x0a, 0x06, 0x6c, 0x61, 0x6d, 0x62, 0x64, 0x61, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x4c, 0x61, 0x6d, 0x62, 0x64, 0x61, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x76, 0x65, 0x53, 0x74, - 0x61, 0x74, 0x65, 0x52, 0x06, 0x6c, 0x61, 0x6d, 0x62, 0x64, 0x61, 0x12, 0x46, 0x0a, 0x07, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x6d, - 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x4c, 0x69, 0x76, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x22, 0x2d, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a, - 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x48, 0x45, - 0x41, 0x4c, 0x54, 0x48, 0x59, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x4f, 0x54, 0x48, 0x45, 0x52, - 0x10, 0x02, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x22, 0x63, 0x0a, 0x1b, 0x41, 0x70, 0x70, 0x6c, - 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x76, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, - 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x22, - 0x02, 0x20, 0x00, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1d, - 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x42, 0x07, 0xfa, - 0x42, 0x04, 0x22, 0x02, 0x28, 0x00, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x5e, 0x0a, - 0x1e, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x41, 0x70, 0x70, 0x6c, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x76, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, - 0x3c, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x4b, 0x75, 0x62, 0x65, 0x72, - 0x6e, 0x65, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, - 0x74, 0x65, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x22, 0x1f, 0x0a, - 0x1d, 0x54, 0x65, 0x72, 0x72, 0x61, 0x66, 0x6f, 0x72, 0x6d, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x76, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, 0x5a, - 0x0a, 0x1c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x52, 0x75, 0x6e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x76, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x3a, - 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x1c, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x52, - 0x75, 0x6e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, - 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x22, 0x1c, 0x0a, 0x1a, 0x4c, 0x61, - 0x6d, 0x62, 0x64, 0x61, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4c, - 0x69, 0x76, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, 0x80, 0x04, 0x0a, 0x17, 0x4b, 0x75, 0x62, + 0x61, 0x74, 0x65, 0x52, 0x06, 0x6c, 0x61, 0x6d, 0x62, 0x64, 0x61, 0x12, 0x30, 0x0a, 0x03, 0x65, + 0x63, 0x73, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, + 0x2e, 0x45, 0x43, 0x53, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4c, + 0x69, 0x76, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x03, 0x65, 0x63, 0x73, 0x12, 0x46, 0x0a, + 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, + 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x4c, 0x69, 0x76, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x07, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x2d, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, + 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, + 0x48, 0x45, 0x41, 0x4c, 0x54, 0x48, 0x59, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x4f, 0x54, 0x48, + 0x45, 0x52, 0x10, 0x02, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x22, 0x63, 0x0a, 0x1b, 0x41, 0x70, + 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x76, 0x65, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x09, 0x74, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x42, 0x07, 0xfa, 0x42, + 0x04, 0x22, 0x02, 0x20, 0x00, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x12, 0x1d, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x42, + 0x07, 0xfa, 0x42, 0x04, 0x22, 0x02, 0x28, 0x00, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, + 0x5e, 0x0a, 0x1e, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x41, 0x70, 0x70, + 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x76, 0x65, 0x53, 0x74, 0x61, 0x74, + 0x65, 0x12, 0x3c, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, - 0x74, 0x61, 0x74, 0x65, 0x12, 0x17, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1b, 0x0a, - 0x09, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, - 0x52, 0x08, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, - 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, - 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x73, 0x12, 0x1b, 0x0a, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, - 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x0b, 0x61, 0x70, 0x69, 0x5f, 0x76, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, - 0x72, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x61, 0x70, 0x69, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x12, 0x1b, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, - 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x1c, 0x0a, - 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x5a, 0x0a, 0x0d, 0x68, - 0x65, 0x61, 0x6c, 0x74, 0x68, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x08, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x2b, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x4b, 0x75, 0x62, 0x65, 0x72, - 0x6e, 0x65, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, - 0x74, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x42, - 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0c, 0x68, 0x65, 0x61, 0x6c, 0x74, - 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x2d, 0x0a, 0x12, 0x68, 0x65, 0x61, 0x6c, 0x74, - 0x68, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x11, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x44, 0x65, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x26, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x64, 0x5f, 0x61, 0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x03, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x22, - 0x02, 0x20, 0x00, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x26, - 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x0f, 0x20, 0x01, - 0x28, 0x03, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x22, 0x02, 0x20, 0x00, 0x52, 0x09, 0x75, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0x33, 0x0a, 0x0c, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, - 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, - 0x4e, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x48, 0x45, 0x41, 0x4c, 0x54, 0x48, 0x59, 0x10, 0x01, - 0x12, 0x09, 0x0a, 0x05, 0x4f, 0x54, 0x48, 0x45, 0x52, 0x10, 0x02, 0x22, 0x99, 0x03, 0x0a, 0x1c, + 0x74, 0x61, 0x74, 0x65, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x22, + 0x1f, 0x0a, 0x1d, 0x54, 0x65, 0x72, 0x72, 0x61, 0x66, 0x6f, 0x72, 0x6d, 0x41, 0x70, 0x70, 0x6c, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x76, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, + 0x22, 0x5a, 0x0a, 0x1c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x52, 0x75, 0x6e, 0x41, 0x70, 0x70, 0x6c, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x76, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, + 0x12, 0x3a, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x43, 0x6c, 0x6f, 0x75, + 0x64, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, + 0x65, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x22, 0x50, 0x0a, 0x17, + 0x45, 0x43, 0x53, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, + 0x76, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x35, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x6d, 0x6f, 0x64, + 0x65, 0x6c, 0x2e, 0x45, 0x43, 0x53, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, + 0x61, 0x74, 0x65, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x22, 0x1c, + 0x0a, 0x1a, 0x4c, 0x61, 0x6d, 0x62, 0x64, 0x61, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x76, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, 0x80, 0x04, 0x0a, + 0x17, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x17, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x02, 0x69, + 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, 0x1d, + 0x0a, 0x0a, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x09, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x73, 0x12, 0x1b, 0x0a, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, + 0x72, 0x02, 0x10, 0x01, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x0b, 0x61, 0x70, + 0x69, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x61, 0x70, 0x69, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x04, 0x6b, 0x69, 0x6e, + 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, + 0x5a, 0x0a, 0x0d, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2b, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x4b, + 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0c, 0x68, + 0x65, 0x61, 0x6c, 0x74, 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x2d, 0x0a, 0x12, 0x68, + 0x65, 0x61, 0x6c, 0x74, 0x68, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x44, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x26, 0x0a, 0x0a, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x03, 0x42, 0x07, + 0xfa, 0x42, 0x04, 0x22, 0x02, 0x20, 0x00, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, + 0x41, 0x74, 0x12, 0x26, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, + 0x18, 0x0f, 0x20, 0x01, 0x28, 0x03, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x22, 0x02, 0x20, 0x00, 0x52, + 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0x33, 0x0a, 0x0c, 0x48, 0x65, + 0x61, 0x6c, 0x74, 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, + 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x48, 0x45, 0x41, 0x4c, 0x54, + 0x48, 0x59, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x4f, 0x54, 0x48, 0x45, 0x52, 0x10, 0x02, 0x22, + 0x99, 0x03, 0x0a, 0x1c, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x12, 0x17, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, + 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x02, 0x69, 0x64, 0x12, 0x2e, 0x0a, 0x0e, 0x61, 0x70, 0x70, + 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x0d, 0x61, 0x70, 0x70, 0x6c, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x46, 0x0a, 0x04, 0x74, 0x79, 0x70, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x28, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x17, 0x0a, 0x02, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, - 0x01, 0x52, 0x02, 0x69, 0x64, 0x12, 0x2e, 0x0a, 0x0e, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, - 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x0d, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x46, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0e, 0x32, 0x28, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x4b, 0x75, 0x62, 0x65, - 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, - 0x61, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x42, 0x08, 0xfa, - 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x3e, 0x0a, - 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6d, - 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x42, 0x08, 0xfa, 0x42, - 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x57, 0x0a, - 0x10, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, - 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x76, 0x65, 0x53, - 0x74, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x08, 0xfa, 0x42, 0x05, - 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0f, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x26, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x64, 0x5f, 0x61, 0x74, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x03, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x22, - 0x02, 0x20, 0x00, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0x27, - 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x0e, 0x41, 0x44, 0x44, 0x5f, 0x4f, 0x52, - 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, - 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x02, 0x22, 0xfc, 0x03, 0x0a, 0x15, 0x43, 0x6c, 0x6f, 0x75, + 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x54, 0x79, 0x70, + 0x65, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x04, 0x74, 0x79, 0x70, + 0x65, 0x12, 0x3e, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1e, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, + 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, + 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, + 0x65, 0x12, 0x57, 0x0a, 0x10, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x5f, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x6d, 0x6f, + 0x64, 0x65, 0x6c, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4c, + 0x69, 0x76, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, + 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0f, 0x73, 0x6e, 0x61, 0x70, 0x73, + 0x68, 0x6f, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x26, 0x0a, 0x0a, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x03, 0x42, 0x07, + 0xfa, 0x42, 0x04, 0x22, 0x02, 0x20, 0x00, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, + 0x41, 0x74, 0x22, 0x27, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x0e, 0x41, 0x44, + 0x44, 0x5f, 0x4f, 0x52, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0b, + 0x0a, 0x07, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x02, 0x22, 0xfc, 0x03, 0x0a, 0x15, + 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x17, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1b, + 0x0a, 0x09, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x08, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x70, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x09, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x73, 0x12, 0x1b, 0x0a, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, + 0x01, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x0b, 0x61, 0x70, 0x69, 0x5f, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, + 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x61, 0x70, 0x69, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x12, 0x1b, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x1c, + 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x58, 0x0a, 0x0d, + 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x08, 0x20, + 0x01, 0x28, 0x0e, 0x32, 0x29, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, - 0x65, 0x12, 0x17, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, - 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x6f, 0x77, - 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x6f, - 0x77, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x72, 0x65, 0x6e, - 0x74, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x70, 0x61, 0x72, - 0x65, 0x6e, 0x74, 0x49, 0x64, 0x73, 0x12, 0x1b, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x0b, 0x61, 0x70, 0x69, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, - 0x01, 0x52, 0x0a, 0x61, 0x70, 0x69, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, - 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, - 0x72, 0x02, 0x10, 0x01, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, - 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, - 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x58, 0x0a, 0x0d, 0x68, 0x65, 0x61, 0x6c, - 0x74, 0x68, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, - 0x29, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x52, 0x75, 0x6e, - 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x48, 0x65, - 0x61, 0x6c, 0x74, 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, - 0x01, 0x02, 0x10, 0x01, 0x52, 0x0c, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x12, 0x2d, 0x0a, 0x12, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x5f, 0x64, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, - 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x26, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, - 0x0e, 0x20, 0x01, 0x28, 0x03, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x22, 0x02, 0x20, 0x00, 0x52, 0x09, - 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x26, 0x0a, 0x0a, 0x75, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x03, 0x42, 0x07, 0xfa, - 0x42, 0x04, 0x22, 0x02, 0x20, 0x00, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, - 0x74, 0x22, 0x33, 0x0a, 0x0c, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0b, - 0x0a, 0x07, 0x48, 0x45, 0x41, 0x4c, 0x54, 0x48, 0x59, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x4f, - 0x54, 0x48, 0x45, 0x52, 0x10, 0x02, 0x42, 0x25, 0x5a, 0x23, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, - 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x69, 0x70, 0x65, 0x2d, 0x63, 0x64, 0x2f, 0x70, 0x69, 0x70, - 0x65, 0x63, 0x64, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x42, 0x08, + 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0c, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x2d, 0x0a, 0x12, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, + 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x11, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x26, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, + 0x5f, 0x61, 0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x03, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x22, 0x02, + 0x20, 0x00, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x26, 0x0a, + 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x0f, 0x20, 0x01, 0x28, + 0x03, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x22, 0x02, 0x20, 0x00, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0x33, 0x0a, 0x0c, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, + 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x48, 0x45, 0x41, 0x4c, 0x54, 0x48, 0x59, 0x10, 0x01, 0x12, + 0x09, 0x0a, 0x05, 0x4f, 0x54, 0x48, 0x45, 0x52, 0x10, 0x02, 0x22, 0xaa, 0x03, 0x0a, 0x10, 0x45, + 0x43, 0x53, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, + 0x17, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, + 0x72, 0x02, 0x10, 0x01, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x6f, 0x77, 0x6e, 0x65, + 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x6f, 0x77, 0x6e, + 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, + 0x69, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x70, 0x61, 0x72, 0x65, 0x6e, + 0x74, 0x49, 0x64, 0x73, 0x12, 0x1b, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x12, 0x1b, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x53, + 0x0a, 0x0d, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x24, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x45, 0x43, + 0x53, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x48, + 0x65, 0x61, 0x6c, 0x74, 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, + 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0c, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x12, 0x2d, 0x0a, 0x12, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x5f, 0x64, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x11, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x26, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x22, 0x02, 0x20, 0x00, 0x52, + 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x26, 0x0a, 0x0a, 0x75, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x42, 0x07, + 0xfa, 0x42, 0x04, 0x22, 0x02, 0x20, 0x00, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, + 0x41, 0x74, 0x22, 0x33, 0x0a, 0x0c, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, + 0x0b, 0x0a, 0x07, 0x48, 0x45, 0x41, 0x4c, 0x54, 0x48, 0x59, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, + 0x4f, 0x54, 0x48, 0x45, 0x52, 0x10, 0x02, 0x42, 0x25, 0x5a, 0x23, 0x67, 0x69, 0x74, 0x68, 0x75, + 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x69, 0x70, 0x65, 0x2d, 0x63, 0x64, 0x2f, 0x70, 0x69, + 0x70, 0x65, 0x63, 0x64, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1123,44 +1382,50 @@ func file_pkg_model_application_live_state_proto_rawDescGZIP() []byte { return file_pkg_model_application_live_state_proto_rawDescData } -var file_pkg_model_application_live_state_proto_enumTypes = make([]protoimpl.EnumInfo, 4) -var file_pkg_model_application_live_state_proto_msgTypes = make([]protoimpl.MessageInfo, 9) +var file_pkg_model_application_live_state_proto_enumTypes = make([]protoimpl.EnumInfo, 5) +var file_pkg_model_application_live_state_proto_msgTypes = make([]protoimpl.MessageInfo, 11) var file_pkg_model_application_live_state_proto_goTypes = []interface{}{ (ApplicationLiveStateSnapshot_Status)(0), // 0: model.ApplicationLiveStateSnapshot.Status (KubernetesResourceState_HealthStatus)(0), // 1: model.KubernetesResourceState.HealthStatus (KubernetesResourceStateEvent_Type)(0), // 2: model.KubernetesResourceStateEvent.Type (CloudRunResourceState_HealthStatus)(0), // 3: model.CloudRunResourceState.HealthStatus - (*ApplicationLiveStateSnapshot)(nil), // 4: model.ApplicationLiveStateSnapshot - (*ApplicationLiveStateVersion)(nil), // 5: model.ApplicationLiveStateVersion - (*KubernetesApplicationLiveState)(nil), // 6: model.KubernetesApplicationLiveState - (*TerraformApplicationLiveState)(nil), // 7: model.TerraformApplicationLiveState - (*CloudRunApplicationLiveState)(nil), // 8: model.CloudRunApplicationLiveState - (*LambdaApplicationLiveState)(nil), // 9: model.LambdaApplicationLiveState - (*KubernetesResourceState)(nil), // 10: model.KubernetesResourceState - (*KubernetesResourceStateEvent)(nil), // 11: model.KubernetesResourceStateEvent - (*CloudRunResourceState)(nil), // 12: model.CloudRunResourceState - (ApplicationKind)(0), // 13: model.ApplicationKind + (ECSResourceState_HealthStatus)(0), // 4: model.ECSResourceState.HealthStatus + (*ApplicationLiveStateSnapshot)(nil), // 5: model.ApplicationLiveStateSnapshot + (*ApplicationLiveStateVersion)(nil), // 6: model.ApplicationLiveStateVersion + (*KubernetesApplicationLiveState)(nil), // 7: model.KubernetesApplicationLiveState + (*TerraformApplicationLiveState)(nil), // 8: model.TerraformApplicationLiveState + (*CloudRunApplicationLiveState)(nil), // 9: model.CloudRunApplicationLiveState + (*ECSApplicationLiveState)(nil), // 10: model.ECSApplicationLiveState + (*LambdaApplicationLiveState)(nil), // 11: model.LambdaApplicationLiveState + (*KubernetesResourceState)(nil), // 12: model.KubernetesResourceState + (*KubernetesResourceStateEvent)(nil), // 13: model.KubernetesResourceStateEvent + (*CloudRunResourceState)(nil), // 14: model.CloudRunResourceState + (*ECSResourceState)(nil), // 15: model.ECSResourceState + (ApplicationKind)(0), // 16: model.ApplicationKind } var file_pkg_model_application_live_state_proto_depIdxs = []int32{ - 13, // 0: model.ApplicationLiveStateSnapshot.kind:type_name -> model.ApplicationKind + 16, // 0: model.ApplicationLiveStateSnapshot.kind:type_name -> model.ApplicationKind 0, // 1: model.ApplicationLiveStateSnapshot.health_status:type_name -> model.ApplicationLiveStateSnapshot.Status - 6, // 2: model.ApplicationLiveStateSnapshot.kubernetes:type_name -> model.KubernetesApplicationLiveState - 7, // 3: model.ApplicationLiveStateSnapshot.terraform:type_name -> model.TerraformApplicationLiveState - 8, // 4: model.ApplicationLiveStateSnapshot.cloudrun:type_name -> model.CloudRunApplicationLiveState - 9, // 5: model.ApplicationLiveStateSnapshot.lambda:type_name -> model.LambdaApplicationLiveState - 5, // 6: model.ApplicationLiveStateSnapshot.version:type_name -> model.ApplicationLiveStateVersion - 10, // 7: model.KubernetesApplicationLiveState.resources:type_name -> model.KubernetesResourceState - 12, // 8: model.CloudRunApplicationLiveState.resources:type_name -> model.CloudRunResourceState - 1, // 9: model.KubernetesResourceState.health_status:type_name -> model.KubernetesResourceState.HealthStatus - 2, // 10: model.KubernetesResourceStateEvent.type:type_name -> model.KubernetesResourceStateEvent.Type - 10, // 11: model.KubernetesResourceStateEvent.state:type_name -> model.KubernetesResourceState - 5, // 12: model.KubernetesResourceStateEvent.snapshot_version:type_name -> model.ApplicationLiveStateVersion - 3, // 13: model.CloudRunResourceState.health_status:type_name -> model.CloudRunResourceState.HealthStatus - 14, // [14:14] is the sub-list for method output_type - 14, // [14:14] is the sub-list for method input_type - 14, // [14:14] is the sub-list for extension type_name - 14, // [14:14] is the sub-list for extension extendee - 0, // [0:14] is the sub-list for field type_name + 7, // 2: model.ApplicationLiveStateSnapshot.kubernetes:type_name -> model.KubernetesApplicationLiveState + 8, // 3: model.ApplicationLiveStateSnapshot.terraform:type_name -> model.TerraformApplicationLiveState + 9, // 4: model.ApplicationLiveStateSnapshot.cloudrun:type_name -> model.CloudRunApplicationLiveState + 11, // 5: model.ApplicationLiveStateSnapshot.lambda:type_name -> model.LambdaApplicationLiveState + 10, // 6: model.ApplicationLiveStateSnapshot.ecs:type_name -> model.ECSApplicationLiveState + 6, // 7: model.ApplicationLiveStateSnapshot.version:type_name -> model.ApplicationLiveStateVersion + 12, // 8: model.KubernetesApplicationLiveState.resources:type_name -> model.KubernetesResourceState + 14, // 9: model.CloudRunApplicationLiveState.resources:type_name -> model.CloudRunResourceState + 15, // 10: model.ECSApplicationLiveState.resources:type_name -> model.ECSResourceState + 1, // 11: model.KubernetesResourceState.health_status:type_name -> model.KubernetesResourceState.HealthStatus + 2, // 12: model.KubernetesResourceStateEvent.type:type_name -> model.KubernetesResourceStateEvent.Type + 12, // 13: model.KubernetesResourceStateEvent.state:type_name -> model.KubernetesResourceState + 6, // 14: model.KubernetesResourceStateEvent.snapshot_version:type_name -> model.ApplicationLiveStateVersion + 3, // 15: model.CloudRunResourceState.health_status:type_name -> model.CloudRunResourceState.HealthStatus + 4, // 16: model.ECSResourceState.health_status:type_name -> model.ECSResourceState.HealthStatus + 17, // [17:17] is the sub-list for method output_type + 17, // [17:17] is the sub-list for method input_type + 17, // [17:17] is the sub-list for extension type_name + 17, // [17:17] is the sub-list for extension extendee + 0, // [0:17] is the sub-list for field type_name } func init() { file_pkg_model_application_live_state_proto_init() } @@ -1231,7 +1496,7 @@ func file_pkg_model_application_live_state_proto_init() { } } file_pkg_model_application_live_state_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*LambdaApplicationLiveState); i { + switch v := v.(*ECSApplicationLiveState); i { case 0: return &v.state case 1: @@ -1243,7 +1508,7 @@ func file_pkg_model_application_live_state_proto_init() { } } file_pkg_model_application_live_state_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*KubernetesResourceState); i { + switch v := v.(*LambdaApplicationLiveState); i { case 0: return &v.state case 1: @@ -1255,7 +1520,7 @@ func file_pkg_model_application_live_state_proto_init() { } } file_pkg_model_application_live_state_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*KubernetesResourceStateEvent); i { + switch v := v.(*KubernetesResourceState); i { case 0: return &v.state case 1: @@ -1267,6 +1532,18 @@ func file_pkg_model_application_live_state_proto_init() { } } file_pkg_model_application_live_state_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*KubernetesResourceStateEvent); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_pkg_model_application_live_state_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CloudRunResourceState); i { case 0: return &v.state @@ -1278,14 +1555,26 @@ func file_pkg_model_application_live_state_proto_init() { return nil } } + file_pkg_model_application_live_state_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ECSResourceState); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_pkg_model_application_live_state_proto_rawDesc, - NumEnums: 4, - NumMessages: 9, + NumEnums: 5, + NumMessages: 11, NumExtensions: 0, NumServices: 0, }, diff --git a/pkg/model/application_live_state.pb.validate.go b/pkg/model/application_live_state.pb.validate.go index be705577c8..4c636f7f75 100644 --- a/pkg/model/application_live_state.pb.validate.go +++ b/pkg/model/application_live_state.pb.validate.go @@ -219,6 +219,35 @@ func (m *ApplicationLiveStateSnapshot) validate(all bool) error { } } + if all { + switch v := interface{}(m.GetEcs()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, ApplicationLiveStateSnapshotValidationError{ + field: "Ecs", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, ApplicationLiveStateSnapshotValidationError{ + field: "Ecs", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetEcs()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return ApplicationLiveStateSnapshotValidationError{ + field: "Ecs", + reason: "embedded message failed validation", + cause: err, + } + } + } + if m.GetVersion() == nil { err := ApplicationLiveStateSnapshotValidationError{ field: "Version", @@ -842,6 +871,142 @@ var _ interface { ErrorName() string } = CloudRunApplicationLiveStateValidationError{} +// Validate checks the field values on ECSApplicationLiveState with the rules +// defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *ECSApplicationLiveState) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on ECSApplicationLiveState with the +// rules defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// ECSApplicationLiveStateMultiError, or nil if none found. +func (m *ECSApplicationLiveState) ValidateAll() error { + return m.validate(true) +} + +func (m *ECSApplicationLiveState) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + for idx, item := range m.GetResources() { + _, _ = idx, item + + if all { + switch v := interface{}(item).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, ECSApplicationLiveStateValidationError{ + field: fmt.Sprintf("Resources[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, ECSApplicationLiveStateValidationError{ + field: fmt.Sprintf("Resources[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(item).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return ECSApplicationLiveStateValidationError{ + field: fmt.Sprintf("Resources[%v]", idx), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + + if len(errors) > 0 { + return ECSApplicationLiveStateMultiError(errors) + } + + return nil +} + +// ECSApplicationLiveStateMultiError is an error wrapping multiple validation +// errors returned by ECSApplicationLiveState.ValidateAll() if the designated +// constraints aren't met. +type ECSApplicationLiveStateMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m ECSApplicationLiveStateMultiError) Error() string { + var msgs []string + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m ECSApplicationLiveStateMultiError) AllErrors() []error { return m } + +// ECSApplicationLiveStateValidationError is the validation error returned by +// ECSApplicationLiveState.Validate if the designated constraints aren't met. +type ECSApplicationLiveStateValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e ECSApplicationLiveStateValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e ECSApplicationLiveStateValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e ECSApplicationLiveStateValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e ECSApplicationLiveStateValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e ECSApplicationLiveStateValidationError) ErrorName() string { + return "ECSApplicationLiveStateValidationError" +} + +// Error satisfies the builtin error interface +func (e ECSApplicationLiveStateValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sECSApplicationLiveState.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = ECSApplicationLiveStateValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = ECSApplicationLiveStateValidationError{} + // Validate checks the field values on LambdaApplicationLiveState with the // rules defined in the proto definition for this message. If any rules are // violated, the first error encountered is returned, or nil if there are no violations. @@ -1536,3 +1701,171 @@ var _ interface { Cause() error ErrorName() string } = CloudRunResourceStateValidationError{} + +// Validate checks the field values on ECSResourceState with the rules defined +// in the proto definition for this message. If any rules are violated, the +// first error encountered is returned, or nil if there are no violations. +func (m *ECSResourceState) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on ECSResourceState with the rules +// defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// ECSResourceStateMultiError, or nil if none found. +func (m *ECSResourceState) ValidateAll() error { + return m.validate(true) +} + +func (m *ECSResourceState) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if utf8.RuneCountInString(m.GetId()) < 1 { + err := ECSResourceStateValidationError{ + field: "Id", + reason: "value length must be at least 1 runes", + } + if !all { + return err + } + errors = append(errors, err) + } + + if utf8.RuneCountInString(m.GetName()) < 1 { + err := ECSResourceStateValidationError{ + field: "Name", + reason: "value length must be at least 1 runes", + } + if !all { + return err + } + errors = append(errors, err) + } + + if utf8.RuneCountInString(m.GetKind()) < 1 { + err := ECSResourceStateValidationError{ + field: "Kind", + reason: "value length must be at least 1 runes", + } + if !all { + return err + } + errors = append(errors, err) + } + + if _, ok := ECSResourceState_HealthStatus_name[int32(m.GetHealthStatus())]; !ok { + err := ECSResourceStateValidationError{ + field: "HealthStatus", + reason: "value must be one of the defined enum values", + } + if !all { + return err + } + errors = append(errors, err) + } + + // no validation rules for HealthDescription + + if m.GetCreatedAt() <= 0 { + err := ECSResourceStateValidationError{ + field: "CreatedAt", + reason: "value must be greater than 0", + } + if !all { + return err + } + errors = append(errors, err) + } + + if m.GetUpdatedAt() <= 0 { + err := ECSResourceStateValidationError{ + field: "UpdatedAt", + reason: "value must be greater than 0", + } + if !all { + return err + } + errors = append(errors, err) + } + + if len(errors) > 0 { + return ECSResourceStateMultiError(errors) + } + + return nil +} + +// ECSResourceStateMultiError is an error wrapping multiple validation errors +// returned by ECSResourceState.ValidateAll() if the designated constraints +// aren't met. +type ECSResourceStateMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m ECSResourceStateMultiError) Error() string { + var msgs []string + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m ECSResourceStateMultiError) AllErrors() []error { return m } + +// ECSResourceStateValidationError is the validation error returned by +// ECSResourceState.Validate if the designated constraints aren't met. +type ECSResourceStateValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e ECSResourceStateValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e ECSResourceStateValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e ECSResourceStateValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e ECSResourceStateValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e ECSResourceStateValidationError) ErrorName() string { return "ECSResourceStateValidationError" } + +// Error satisfies the builtin error interface +func (e ECSResourceStateValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sECSResourceState.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = ECSResourceStateValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = ECSResourceStateValidationError{} diff --git a/pkg/model/application_live_state.proto b/pkg/model/application_live_state.proto index 155895b816..0108a70ca0 100644 --- a/pkg/model/application_live_state.proto +++ b/pkg/model/application_live_state.proto @@ -40,6 +40,7 @@ message ApplicationLiveStateSnapshot { TerraformApplicationLiveState terraform = 11; CloudRunApplicationLiveState cloudrun = 12; LambdaApplicationLiveState lambda = 13; + ECSApplicationLiveState ecs = 14; ApplicationLiveStateVersion version = 15 [(validate.rules).message.required = true]; } @@ -62,6 +63,10 @@ message CloudRunApplicationLiveState { repeated CloudRunResourceState resources = 1; } +message ECSApplicationLiveState{ + repeated ECSResourceState resources = 1; +} + message LambdaApplicationLiveState { } @@ -149,3 +154,32 @@ message CloudRunResourceState { // The timestamp of the last time when this resource was updated. int64 updated_at = 15 [(validate.rules).int64.gt = 0]; } + +// ECSResourceState represents the state of an ECS service resource. +message ECSResourceState { + enum HealthStatus { + UNKNOWN = 0; + HEALTHY = 1; + OTHER = 2; + } + + // The arn of the ECS resource. + string id = 1 [(validate.rules).string.min_len = 1]; + // The sorted list of unique IDs of the owners that depended by this resource. + // The owner is another resource that created and managing this resource. + repeated string owner_ids = 2; + // The sorted list of unique IDs of the parents. + repeated string parent_ids = 3; + // The unique name for the type of resource. + string name = 4 [(validate.rules).string.min_len = 1]; + // The kind of this resource. e.g. Service, TaskSet, Task. + string kind = 5 [(validate.rules).string.min_len = 1]; + + HealthStatus health_status = 6 [(validate.rules).enum.defined_only = true]; + string health_description = 7; + + // The timestamp when this resource was created. + int64 created_at = 8 [(validate.rules).int64.gt = 0]; + // The timestamp of the last time when this resource was updated. + int64 updated_at = 9 [(validate.rules).int64.gt = 0]; +} diff --git a/pkg/model/application_live_state_test.go b/pkg/model/application_live_state_test.go index fba26eab2d..340c4ca279 100644 --- a/pkg/model/application_live_state_test.go +++ b/pkg/model/application_live_state_test.go @@ -100,6 +100,29 @@ func TestApplicationLiveStateSnapshot_DetermineAppHealthStatus(t *testing.T) { }, want: ApplicationLiveStateSnapshot_UNKNOWN, }, + { + name: "ecs: healthy", + snapshot: &ApplicationLiveStateSnapshot{ + Kind: ApplicationKind_ECS, + Ecs: &ECSApplicationLiveState{ + Resources: []*ECSResourceState{{HealthStatus: ECSResourceState_HEALTHY}}, + }, + }, + want: ApplicationLiveStateSnapshot_HEALTHY, + }, + { + name: "ecs: unhealthy", + snapshot: &ApplicationLiveStateSnapshot{ + Kind: ApplicationKind_ECS, + Ecs: &ECSApplicationLiveState{ + Resources: []*ECSResourceState{ + {HealthStatus: ECSResourceState_HEALTHY}, + {HealthStatus: ECSResourceState_OTHER}, + }, + }, + }, + want: ApplicationLiveStateSnapshot_OTHER, + }, { name: "ecs: unknown", snapshot: &ApplicationLiveStateSnapshot{ diff --git a/web/model/application_live_state_pb.d.ts b/web/model/application_live_state_pb.d.ts index 5de73f49eb..af17e275e3 100644 --- a/web/model/application_live_state_pb.d.ts +++ b/web/model/application_live_state_pb.d.ts @@ -40,6 +40,11 @@ export class ApplicationLiveStateSnapshot extends jspb.Message { hasLambda(): boolean; clearLambda(): ApplicationLiveStateSnapshot; + getEcs(): ECSApplicationLiveState | undefined; + setEcs(value?: ECSApplicationLiveState): ApplicationLiveStateSnapshot; + hasEcs(): boolean; + clearEcs(): ApplicationLiveStateSnapshot; + getVersion(): ApplicationLiveStateVersion | undefined; setVersion(value?: ApplicationLiveStateVersion): ApplicationLiveStateSnapshot; hasVersion(): boolean; @@ -64,6 +69,7 @@ export namespace ApplicationLiveStateSnapshot { terraform?: TerraformApplicationLiveState.AsObject, cloudrun?: CloudRunApplicationLiveState.AsObject, lambda?: LambdaApplicationLiveState.AsObject, + ecs?: ECSApplicationLiveState.AsObject, version?: ApplicationLiveStateVersion.AsObject, } @@ -150,6 +156,26 @@ export namespace CloudRunApplicationLiveState { } } +export class ECSApplicationLiveState extends jspb.Message { + getResourcesList(): Array; + setResourcesList(value: Array): ECSApplicationLiveState; + clearResourcesList(): ECSApplicationLiveState; + addResources(value?: ECSResourceState, index?: number): ECSResourceState; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): ECSApplicationLiveState.AsObject; + static toObject(includeInstance: boolean, msg: ECSApplicationLiveState): ECSApplicationLiveState.AsObject; + static serializeBinaryToWriter(message: ECSApplicationLiveState, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): ECSApplicationLiveState; + static deserializeBinaryFromReader(message: ECSApplicationLiveState, reader: jspb.BinaryReader): ECSApplicationLiveState; +} + +export namespace ECSApplicationLiveState { + export type AsObject = { + resourcesList: Array, + } +} + export class LambdaApplicationLiveState extends jspb.Message { serializeBinary(): Uint8Array; toObject(includeInstance?: boolean): LambdaApplicationLiveState.AsObject; @@ -347,3 +373,63 @@ export namespace CloudRunResourceState { } } +export class ECSResourceState extends jspb.Message { + getId(): string; + setId(value: string): ECSResourceState; + + getOwnerIdsList(): Array; + setOwnerIdsList(value: Array): ECSResourceState; + clearOwnerIdsList(): ECSResourceState; + addOwnerIds(value: string, index?: number): ECSResourceState; + + getParentIdsList(): Array; + setParentIdsList(value: Array): ECSResourceState; + clearParentIdsList(): ECSResourceState; + addParentIds(value: string, index?: number): ECSResourceState; + + getName(): string; + setName(value: string): ECSResourceState; + + getKind(): string; + setKind(value: string): ECSResourceState; + + getHealthStatus(): ECSResourceState.HealthStatus; + setHealthStatus(value: ECSResourceState.HealthStatus): ECSResourceState; + + getHealthDescription(): string; + setHealthDescription(value: string): ECSResourceState; + + getCreatedAt(): number; + setCreatedAt(value: number): ECSResourceState; + + getUpdatedAt(): number; + setUpdatedAt(value: number): ECSResourceState; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): ECSResourceState.AsObject; + static toObject(includeInstance: boolean, msg: ECSResourceState): ECSResourceState.AsObject; + static serializeBinaryToWriter(message: ECSResourceState, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): ECSResourceState; + static deserializeBinaryFromReader(message: ECSResourceState, reader: jspb.BinaryReader): ECSResourceState; +} + +export namespace ECSResourceState { + export type AsObject = { + id: string, + ownerIdsList: Array, + parentIdsList: Array, + name: string, + kind: string, + healthStatus: ECSResourceState.HealthStatus, + healthDescription: string, + createdAt: number, + updatedAt: number, + } + + export enum HealthStatus { + UNKNOWN = 0, + HEALTHY = 1, + OTHER = 2, + } +} + diff --git a/web/model/application_live_state_pb.js b/web/model/application_live_state_pb.js index 1ae106e2a5..f27ee1d108 100644 --- a/web/model/application_live_state_pb.js +++ b/web/model/application_live_state_pb.js @@ -31,6 +31,9 @@ goog.exportSymbol('proto.model.ApplicationLiveStateVersion', null, global); goog.exportSymbol('proto.model.CloudRunApplicationLiveState', null, global); goog.exportSymbol('proto.model.CloudRunResourceState', null, global); goog.exportSymbol('proto.model.CloudRunResourceState.HealthStatus', null, global); +goog.exportSymbol('proto.model.ECSApplicationLiveState', null, global); +goog.exportSymbol('proto.model.ECSResourceState', null, global); +goog.exportSymbol('proto.model.ECSResourceState.HealthStatus', null, global); goog.exportSymbol('proto.model.KubernetesApplicationLiveState', null, global); goog.exportSymbol('proto.model.KubernetesResourceState', null, global); goog.exportSymbol('proto.model.KubernetesResourceState.HealthStatus', null, global); @@ -143,6 +146,27 @@ if (goog.DEBUG && !COMPILED) { */ proto.model.CloudRunApplicationLiveState.displayName = 'proto.model.CloudRunApplicationLiveState'; } +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.model.ECSApplicationLiveState = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, proto.model.ECSApplicationLiveState.repeatedFields_, null); +}; +goog.inherits(proto.model.ECSApplicationLiveState, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.model.ECSApplicationLiveState.displayName = 'proto.model.ECSApplicationLiveState'; +} /** * Generated by JsPbCodeGenerator. * @param {Array=} opt_data Optional initial data array, typically from a @@ -227,6 +251,27 @@ if (goog.DEBUG && !COMPILED) { */ proto.model.CloudRunResourceState.displayName = 'proto.model.CloudRunResourceState'; } +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.model.ECSResourceState = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, proto.model.ECSResourceState.repeatedFields_, null); +}; +goog.inherits(proto.model.ECSResourceState, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.model.ECSResourceState.displayName = 'proto.model.ECSResourceState'; +} @@ -268,6 +313,7 @@ proto.model.ApplicationLiveStateSnapshot.toObject = function(includeInstance, ms terraform: (f = msg.getTerraform()) && proto.model.TerraformApplicationLiveState.toObject(includeInstance, f), cloudrun: (f = msg.getCloudrun()) && proto.model.CloudRunApplicationLiveState.toObject(includeInstance, f), lambda: (f = msg.getLambda()) && proto.model.LambdaApplicationLiveState.toObject(includeInstance, f), + ecs: (f = msg.getEcs()) && proto.model.ECSApplicationLiveState.toObject(includeInstance, f), version: (f = msg.getVersion()) && proto.model.ApplicationLiveStateVersion.toObject(includeInstance, f) }; @@ -345,6 +391,11 @@ proto.model.ApplicationLiveStateSnapshot.deserializeBinaryFromReader = function( reader.readMessage(value,proto.model.LambdaApplicationLiveState.deserializeBinaryFromReader); msg.setLambda(value); break; + case 14: + var value = new proto.model.ECSApplicationLiveState; + reader.readMessage(value,proto.model.ECSApplicationLiveState.deserializeBinaryFromReader); + msg.setEcs(value); + break; case 15: var value = new proto.model.ApplicationLiveStateVersion; reader.readMessage(value,proto.model.ApplicationLiveStateVersion.deserializeBinaryFromReader); @@ -446,6 +497,14 @@ proto.model.ApplicationLiveStateSnapshot.serializeBinaryToWriter = function(mess proto.model.LambdaApplicationLiveState.serializeBinaryToWriter ); } + f = message.getEcs(); + if (f != null) { + writer.writeMessage( + 14, + f, + proto.model.ECSApplicationLiveState.serializeBinaryToWriter + ); + } f = message.getVersion(); if (f != null) { writer.writeMessage( @@ -704,6 +763,43 @@ proto.model.ApplicationLiveStateSnapshot.prototype.hasLambda = function() { }; +/** + * optional ECSApplicationLiveState ecs = 14; + * @return {?proto.model.ECSApplicationLiveState} + */ +proto.model.ApplicationLiveStateSnapshot.prototype.getEcs = function() { + return /** @type{?proto.model.ECSApplicationLiveState} */ ( + jspb.Message.getWrapperField(this, proto.model.ECSApplicationLiveState, 14)); +}; + + +/** + * @param {?proto.model.ECSApplicationLiveState|undefined} value + * @return {!proto.model.ApplicationLiveStateSnapshot} returns this +*/ +proto.model.ApplicationLiveStateSnapshot.prototype.setEcs = function(value) { + return jspb.Message.setWrapperField(this, 14, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.model.ApplicationLiveStateSnapshot} returns this + */ +proto.model.ApplicationLiveStateSnapshot.prototype.clearEcs = function() { + return this.setEcs(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.model.ApplicationLiveStateSnapshot.prototype.hasEcs = function() { + return jspb.Message.getField(this, 14) != null; +}; + + /** * optional ApplicationLiveStateVersion version = 15; * @return {?proto.model.ApplicationLiveStateVersion} @@ -1323,6 +1419,166 @@ proto.model.CloudRunApplicationLiveState.prototype.clearResourcesList = function +/** + * List of repeated fields within this message type. + * @private {!Array} + * @const + */ +proto.model.ECSApplicationLiveState.repeatedFields_ = [1]; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.model.ECSApplicationLiveState.prototype.toObject = function(opt_includeInstance) { + return proto.model.ECSApplicationLiveState.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.model.ECSApplicationLiveState} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.model.ECSApplicationLiveState.toObject = function(includeInstance, msg) { + var f, obj = { + resourcesList: jspb.Message.toObjectList(msg.getResourcesList(), + proto.model.ECSResourceState.toObject, includeInstance) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.model.ECSApplicationLiveState} + */ +proto.model.ECSApplicationLiveState.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.model.ECSApplicationLiveState; + return proto.model.ECSApplicationLiveState.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.model.ECSApplicationLiveState} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.model.ECSApplicationLiveState} + */ +proto.model.ECSApplicationLiveState.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.model.ECSResourceState; + reader.readMessage(value,proto.model.ECSResourceState.deserializeBinaryFromReader); + msg.addResources(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.model.ECSApplicationLiveState.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.model.ECSApplicationLiveState.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.model.ECSApplicationLiveState} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.model.ECSApplicationLiveState.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getResourcesList(); + if (f.length > 0) { + writer.writeRepeatedMessage( + 1, + f, + proto.model.ECSResourceState.serializeBinaryToWriter + ); + } +}; + + +/** + * repeated ECSResourceState resources = 1; + * @return {!Array} + */ +proto.model.ECSApplicationLiveState.prototype.getResourcesList = function() { + return /** @type{!Array} */ ( + jspb.Message.getRepeatedWrapperField(this, proto.model.ECSResourceState, 1)); +}; + + +/** + * @param {!Array} value + * @return {!proto.model.ECSApplicationLiveState} returns this +*/ +proto.model.ECSApplicationLiveState.prototype.setResourcesList = function(value) { + return jspb.Message.setRepeatedWrapperField(this, 1, value); +}; + + +/** + * @param {!proto.model.ECSResourceState=} opt_value + * @param {number=} opt_index + * @return {!proto.model.ECSResourceState} + */ +proto.model.ECSApplicationLiveState.prototype.addResources = function(opt_value, opt_index) { + return jspb.Message.addToRepeatedWrapperField(this, 1, opt_value, proto.model.ECSResourceState, opt_index); +}; + + +/** + * Clears the list making it empty but non-null. + * @return {!proto.model.ECSApplicationLiveState} returns this + */ +proto.model.ECSApplicationLiveState.prototype.clearResourcesList = function() { + return this.setResourcesList([]); +}; + + + if (jspb.Message.GENERATE_TO_OBJECT) { @@ -2721,4 +2977,428 @@ proto.model.CloudRunResourceState.prototype.setUpdatedAt = function(value) { }; + +/** + * List of repeated fields within this message type. + * @private {!Array} + * @const + */ +proto.model.ECSResourceState.repeatedFields_ = [2,3]; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.model.ECSResourceState.prototype.toObject = function(opt_includeInstance) { + return proto.model.ECSResourceState.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.model.ECSResourceState} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.model.ECSResourceState.toObject = function(includeInstance, msg) { + var f, obj = { + id: jspb.Message.getFieldWithDefault(msg, 1, ""), + ownerIdsList: (f = jspb.Message.getRepeatedField(msg, 2)) == null ? undefined : f, + parentIdsList: (f = jspb.Message.getRepeatedField(msg, 3)) == null ? undefined : f, + name: jspb.Message.getFieldWithDefault(msg, 4, ""), + kind: jspb.Message.getFieldWithDefault(msg, 5, ""), + healthStatus: jspb.Message.getFieldWithDefault(msg, 6, 0), + healthDescription: jspb.Message.getFieldWithDefault(msg, 7, ""), + createdAt: jspb.Message.getFieldWithDefault(msg, 8, 0), + updatedAt: jspb.Message.getFieldWithDefault(msg, 9, 0) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.model.ECSResourceState} + */ +proto.model.ECSResourceState.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.model.ECSResourceState; + return proto.model.ECSResourceState.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.model.ECSResourceState} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.model.ECSResourceState} + */ +proto.model.ECSResourceState.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {string} */ (reader.readString()); + msg.setId(value); + break; + case 2: + var value = /** @type {string} */ (reader.readString()); + msg.addOwnerIds(value); + break; + case 3: + var value = /** @type {string} */ (reader.readString()); + msg.addParentIds(value); + break; + case 4: + var value = /** @type {string} */ (reader.readString()); + msg.setName(value); + break; + case 5: + var value = /** @type {string} */ (reader.readString()); + msg.setKind(value); + break; + case 6: + var value = /** @type {!proto.model.ECSResourceState.HealthStatus} */ (reader.readEnum()); + msg.setHealthStatus(value); + break; + case 7: + var value = /** @type {string} */ (reader.readString()); + msg.setHealthDescription(value); + break; + case 8: + var value = /** @type {number} */ (reader.readInt64()); + msg.setCreatedAt(value); + break; + case 9: + var value = /** @type {number} */ (reader.readInt64()); + msg.setUpdatedAt(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.model.ECSResourceState.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.model.ECSResourceState.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.model.ECSResourceState} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.model.ECSResourceState.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getId(); + if (f.length > 0) { + writer.writeString( + 1, + f + ); + } + f = message.getOwnerIdsList(); + if (f.length > 0) { + writer.writeRepeatedString( + 2, + f + ); + } + f = message.getParentIdsList(); + if (f.length > 0) { + writer.writeRepeatedString( + 3, + f + ); + } + f = message.getName(); + if (f.length > 0) { + writer.writeString( + 4, + f + ); + } + f = message.getKind(); + if (f.length > 0) { + writer.writeString( + 5, + f + ); + } + f = message.getHealthStatus(); + if (f !== 0.0) { + writer.writeEnum( + 6, + f + ); + } + f = message.getHealthDescription(); + if (f.length > 0) { + writer.writeString( + 7, + f + ); + } + f = message.getCreatedAt(); + if (f !== 0) { + writer.writeInt64( + 8, + f + ); + } + f = message.getUpdatedAt(); + if (f !== 0) { + writer.writeInt64( + 9, + f + ); + } +}; + + +/** + * @enum {number} + */ +proto.model.ECSResourceState.HealthStatus = { + UNKNOWN: 0, + HEALTHY: 1, + OTHER: 2 +}; + +/** + * optional string id = 1; + * @return {string} + */ +proto.model.ECSResourceState.prototype.getId = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); +}; + + +/** + * @param {string} value + * @return {!proto.model.ECSResourceState} returns this + */ +proto.model.ECSResourceState.prototype.setId = function(value) { + return jspb.Message.setProto3StringField(this, 1, value); +}; + + +/** + * repeated string owner_ids = 2; + * @return {!Array} + */ +proto.model.ECSResourceState.prototype.getOwnerIdsList = function() { + return /** @type {!Array} */ (jspb.Message.getRepeatedField(this, 2)); +}; + + +/** + * @param {!Array} value + * @return {!proto.model.ECSResourceState} returns this + */ +proto.model.ECSResourceState.prototype.setOwnerIdsList = function(value) { + return jspb.Message.setField(this, 2, value || []); +}; + + +/** + * @param {string} value + * @param {number=} opt_index + * @return {!proto.model.ECSResourceState} returns this + */ +proto.model.ECSResourceState.prototype.addOwnerIds = function(value, opt_index) { + return jspb.Message.addToRepeatedField(this, 2, value, opt_index); +}; + + +/** + * Clears the list making it empty but non-null. + * @return {!proto.model.ECSResourceState} returns this + */ +proto.model.ECSResourceState.prototype.clearOwnerIdsList = function() { + return this.setOwnerIdsList([]); +}; + + +/** + * repeated string parent_ids = 3; + * @return {!Array} + */ +proto.model.ECSResourceState.prototype.getParentIdsList = function() { + return /** @type {!Array} */ (jspb.Message.getRepeatedField(this, 3)); +}; + + +/** + * @param {!Array} value + * @return {!proto.model.ECSResourceState} returns this + */ +proto.model.ECSResourceState.prototype.setParentIdsList = function(value) { + return jspb.Message.setField(this, 3, value || []); +}; + + +/** + * @param {string} value + * @param {number=} opt_index + * @return {!proto.model.ECSResourceState} returns this + */ +proto.model.ECSResourceState.prototype.addParentIds = function(value, opt_index) { + return jspb.Message.addToRepeatedField(this, 3, value, opt_index); +}; + + +/** + * Clears the list making it empty but non-null. + * @return {!proto.model.ECSResourceState} returns this + */ +proto.model.ECSResourceState.prototype.clearParentIdsList = function() { + return this.setParentIdsList([]); +}; + + +/** + * optional string name = 4; + * @return {string} + */ +proto.model.ECSResourceState.prototype.getName = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 4, "")); +}; + + +/** + * @param {string} value + * @return {!proto.model.ECSResourceState} returns this + */ +proto.model.ECSResourceState.prototype.setName = function(value) { + return jspb.Message.setProto3StringField(this, 4, value); +}; + + +/** + * optional string kind = 5; + * @return {string} + */ +proto.model.ECSResourceState.prototype.getKind = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 5, "")); +}; + + +/** + * @param {string} value + * @return {!proto.model.ECSResourceState} returns this + */ +proto.model.ECSResourceState.prototype.setKind = function(value) { + return jspb.Message.setProto3StringField(this, 5, value); +}; + + +/** + * optional HealthStatus health_status = 6; + * @return {!proto.model.ECSResourceState.HealthStatus} + */ +proto.model.ECSResourceState.prototype.getHealthStatus = function() { + return /** @type {!proto.model.ECSResourceState.HealthStatus} */ (jspb.Message.getFieldWithDefault(this, 6, 0)); +}; + + +/** + * @param {!proto.model.ECSResourceState.HealthStatus} value + * @return {!proto.model.ECSResourceState} returns this + */ +proto.model.ECSResourceState.prototype.setHealthStatus = function(value) { + return jspb.Message.setProto3EnumField(this, 6, value); +}; + + +/** + * optional string health_description = 7; + * @return {string} + */ +proto.model.ECSResourceState.prototype.getHealthDescription = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 7, "")); +}; + + +/** + * @param {string} value + * @return {!proto.model.ECSResourceState} returns this + */ +proto.model.ECSResourceState.prototype.setHealthDescription = function(value) { + return jspb.Message.setProto3StringField(this, 7, value); +}; + + +/** + * optional int64 created_at = 8; + * @return {number} + */ +proto.model.ECSResourceState.prototype.getCreatedAt = function() { + return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 8, 0)); +}; + + +/** + * @param {number} value + * @return {!proto.model.ECSResourceState} returns this + */ +proto.model.ECSResourceState.prototype.setCreatedAt = function(value) { + return jspb.Message.setProto3IntField(this, 8, value); +}; + + +/** + * optional int64 updated_at = 9; + * @return {number} + */ +proto.model.ECSResourceState.prototype.getUpdatedAt = function() { + return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 9, 0)); +}; + + +/** + * @param {number} value + * @return {!proto.model.ECSResourceState} returns this + */ +proto.model.ECSResourceState.prototype.setUpdatedAt = function(value) { + return jspb.Message.setProto3IntField(this, 9, value); +}; + + goog.object.extend(exports, proto.model);