diff --git a/cf-custom-resources/lib/env-controller.js b/cf-custom-resources/lib/env-controller.js index 2cb0d4c7c8e..d7912be992a 100644 --- a/cf-custom-resources/lib/env-controller.js +++ b/cf-custom-resources/lib/env-controller.js @@ -122,7 +122,11 @@ const controlEnv = async function ( (param) => !envSet.has(param) ); const exportedValues = getExportedValues(updatedEnvStack); - // Return if there are no parameter changes. + // If there are no changes in env-controller managed parameters, the custom + // resource may have been triggered because the env template is upgraded, + // and the service template is attempting to retrieve the latest Outputs + // from the env stack (see PR #3957). Return the updated Outputs instead + // of triggering an env-controller update of the environment. const shouldUpdateAliases = needUpdateAliases(envParams, workload, aliases); if ( parametersToRemove.length + parametersToAdd.length === 0 && @@ -314,7 +318,7 @@ const getExportedValues = function (stack) { const exportedValues = {}; stack.Outputs.forEach((output) => { if (ignoredEnvOutputs.has(output.OutputKey)) { - return + return; } exportedValues[output.OutputKey] = output.OutputValue; }); diff --git a/internal/pkg/cli/deploy/svc.go b/internal/pkg/cli/deploy/svc.go index c1e14aceefe..02e4fd12926 100644 --- a/internal/pkg/cli/deploy/svc.go +++ b/internal/pkg/cli/deploy/svc.go @@ -172,6 +172,7 @@ type workloadDeployer struct { endpointGetter endpointGetter spinner spinner templateFS template.Reader + envVersionGetter versionGetter // Cached variables. defaultSess *session.Session @@ -183,13 +184,14 @@ type workloadDeployer struct { // WorkloadDeployerInput is the input to for workloadDeployer constructor. type WorkloadDeployerInput struct { - SessionProvider *sessions.Provider - Name string - App *config.Application - Env *config.Environment - ImageTag string - Mft interface{} // Interpolated, applied, and unmarshaled manifest. - RawMft []byte // Content of the manifest file without any transformations. + SessionProvider *sessions.Provider + Name string + App *config.Application + Env *config.Environment + ImageTag string + Mft interface{} // Interpolated, applied, and unmarshaled manifest. + RawMft []byte // Content of the manifest file without any transformations. + EnvVersionGetter versionGetter } // newWorkloadDeployer is the constructor for workloadDeployer. @@ -269,6 +271,7 @@ func newWorkloadDeployer(in *WorkloadDeployerInput) (*workloadDeployer, error) { endpointGetter: envDescriber, spinner: termprogress.NewSpinner(log.DiagnosticWriter), templateFS: template.New(), + envVersionGetter: in.EnvVersionGetter, defaultSess: defaultSession, defaultSessWithEnvRegion: defaultSessEnvRegion, @@ -991,6 +994,10 @@ func (d *workloadDeployer) runtimeConfig(in *StackRuntimeConfiguration) (*stack. if err != nil { return nil, fmt.Errorf("get service discovery endpoint: %w", err) } + envVersion, err := d.envVersionGetter.Version() + if err != nil { + return nil, fmt.Errorf("get version of environment %q: %w", d.env.Name, err) + } if in.ImageDigest == nil { return &stack.RuntimeConfig{ AddonsTemplateURL: in.AddonsURL, @@ -1000,6 +1007,7 @@ func (d *workloadDeployer) runtimeConfig(in *StackRuntimeConfiguration) (*stack. AccountID: d.env.AccountID, Region: d.env.Region, CustomResourcesURL: in.CustomResourceURLs, + EnvVersion: envVersion, }, nil } return &stack.RuntimeConfig{ @@ -1015,6 +1023,7 @@ func (d *workloadDeployer) runtimeConfig(in *StackRuntimeConfiguration) (*stack. AccountID: d.env.AccountID, Region: d.env.Region, CustomResourcesURL: in.CustomResourceURLs, + EnvVersion: envVersion, }, nil } diff --git a/internal/pkg/cli/deploy/svc_test.go b/internal/pkg/cli/deploy/svc_test.go index 5daf16535fc..10a1cb0e6bf 100644 --- a/internal/pkg/cli/deploy/svc_test.go +++ b/internal/pkg/cli/deploy/svc_test.go @@ -45,7 +45,8 @@ type deployMocks struct { mockServiceForceUpdater *mocks.MockserviceForceUpdater mockAddons *mocks.MockstackBuilder mockUploader *mocks.Mockuploader - mockVersionGetter *mocks.MockversionGetter + mockAppVersionGetter *mocks.MockversionGetter + mockEnvVersionGetter *mocks.MockversionGetter mockFileReader *mocks.MockfileReader mockValidator *mocks.MockaliasCertValidator } @@ -431,6 +432,7 @@ func TestWorkloadDeployer_UploadArtifacts(t *testing.T) { }) } } + func TestWorkloadDeployer_DeployWorkload(t *testing.T) { mockError := errors.New("some error") const ( @@ -481,6 +483,16 @@ func TestWorkloadDeployer_DeployWorkload(t *testing.T) { }, wantErr: fmt.Errorf("get service discovery endpoint: some error"), }, + "fail to get env version": { + inEnvironment: &config.Environment{ + Name: mockEnvName, + }, + mock: func(m *deployMocks) { + m.mockEndpointGetter.EXPECT().ServiceDiscoveryEndpoint().Return("mockApp.local", nil) + m.mockEnvVersionGetter.EXPECT().Version().Return("", errors.New("some error")) + }, + wantErr: fmt.Errorf(`get version of environment "mockEnv": some error`), + }, "fail if alias is not specified with env has imported certs": { inEnvironment: &config.Environment{ Name: mockEnvName, @@ -496,6 +508,7 @@ func TestWorkloadDeployer_DeployWorkload(t *testing.T) { }, mock: func(m *deployMocks) { m.mockEndpointGetter.EXPECT().ServiceDiscoveryEndpoint().Return("mockApp.local", nil) + m.mockEnvVersionGetter.EXPECT().Version().Return("v1.42.0", nil) }, wantErr: fmt.Errorf("cannot deploy service mockWkld without http.alias to environment mockEnv with certificate imported"), }, @@ -525,6 +538,7 @@ func TestWorkloadDeployer_DeployWorkload(t *testing.T) { }, mock: func(m *deployMocks) { m.mockEndpointGetter.EXPECT().ServiceDiscoveryEndpoint().Return("mockApp.local", nil) + m.mockEnvVersionGetter.EXPECT().Version().Return("v1.42.0", nil) }, wantErr: fmt.Errorf("cannot specify alias hosted zones [mockHostedZone1 mockHostedZone2] when no certificates are imported in environment \"mockEnv\""), }, @@ -556,6 +570,7 @@ func TestWorkloadDeployer_DeployWorkload(t *testing.T) { }, mock: func(m *deployMocks) { m.mockEndpointGetter.EXPECT().ServiceDiscoveryEndpoint().Return("mockApp.local", nil) + m.mockEnvVersionGetter.EXPECT().Version().Return("v1.42.0", nil) }, wantErr: fmt.Errorf("cannot specify alias hosted zones when cdn is enabled in environment \"mockEnv\""), }, @@ -577,6 +592,7 @@ func TestWorkloadDeployer_DeployWorkload(t *testing.T) { }, mock: func(m *deployMocks) { m.mockEndpointGetter.EXPECT().ServiceDiscoveryEndpoint().Return("mockApp.local", nil) + m.mockEnvVersionGetter.EXPECT().Version().Return("v1.42.0", nil) m.mockValidator.EXPECT().ValidateCertAliases([]string{"example.com", "foobar.com"}, mockCertARNs).Return(mockError) }, wantErr: fmt.Errorf("validate aliases against the imported public ALB certificate for env mockEnv: some error"), @@ -600,6 +616,7 @@ func TestWorkloadDeployer_DeployWorkload(t *testing.T) { }, mock: func(m *deployMocks) { m.mockEndpointGetter.EXPECT().ServiceDiscoveryEndpoint().Return("mockApp.local", nil) + m.mockEnvVersionGetter.EXPECT().Version().Return("v1.42.0", nil) m.mockValidator.EXPECT().ValidateCertAliases([]string{"example.com", "foobar.com"}, mockCertARNs).Return(nil) m.mockValidator.EXPECT().ValidateCertAliases([]string{"example.com", "foobar.com"}, []string{mockCDNCertARN}).Return(mockError) }, @@ -618,6 +635,7 @@ func TestWorkloadDeployer_DeployWorkload(t *testing.T) { }, mock: func(m *deployMocks) { m.mockEndpointGetter.EXPECT().ServiceDiscoveryEndpoint().Return("mockApp.local", nil) + m.mockEnvVersionGetter.EXPECT().Version().Return("v1.42.0", nil) m.mockPublicCIDRBlocksGetter.EXPECT().PublicCIDRBlocks().Return(nil, errors.New("some error")) }, wantErr: fmt.Errorf("get public CIDR blocks information from the VPC of environment mockEnv: some error"), @@ -633,6 +651,7 @@ func TestWorkloadDeployer_DeployWorkload(t *testing.T) { }, mock: func(m *deployMocks) { m.mockEndpointGetter.EXPECT().ServiceDiscoveryEndpoint().Return("mockApp.local", nil) + m.mockEnvVersionGetter.EXPECT().Version().Return("v1.42.0", nil) }, wantErr: errors.New("cannot specify http.alias when application is not associated with a domain and env mockEnv doesn't import one or more certificates"), }, @@ -650,6 +669,7 @@ func TestWorkloadDeployer_DeployWorkload(t *testing.T) { }, mock: func(m *deployMocks) { m.mockEndpointGetter.EXPECT().ServiceDiscoveryEndpoint().Return("mockApp.local", nil) + m.mockEnvVersionGetter.EXPECT().Version().Return("v1.42.0", nil) }, wantErr: errors.New("cannot specify nlb.alias when application is not associated with a domain"), }, @@ -673,6 +693,7 @@ func TestWorkloadDeployer_DeployWorkload(t *testing.T) { }, mock: func(m *deployMocks) { m.mockEndpointGetter.EXPECT().ServiceDiscoveryEndpoint().Return("mockApp.local", nil) + m.mockEnvVersionGetter.EXPECT().Version().Return("v1.42.0", nil) m.mockValidator.EXPECT().ValidateCertAliases([]string{"mockAlias"}, mockCertARNs).Return(nil) }, wantErr: errors.New("cannot specify nlb.alias when env mockEnv imports one or more certificates"), @@ -688,8 +709,9 @@ func TestWorkloadDeployer_DeployWorkload(t *testing.T) { Domain: "mockDomain", }, mock: func(m *deployMocks) { - m.mockVersionGetter.EXPECT().Version().Return("", mockError) + m.mockAppVersionGetter.EXPECT().Version().Return("", mockError) m.mockEndpointGetter.EXPECT().ServiceDiscoveryEndpoint().Return("mockApp.local", nil) + m.mockEnvVersionGetter.EXPECT().Version().Return("v1.42.0", nil) }, wantErr: fmt.Errorf("get version for app %s: %w", mockAppName, mockError), }, @@ -704,8 +726,9 @@ func TestWorkloadDeployer_DeployWorkload(t *testing.T) { Domain: "mockDomain", }, mock: func(m *deployMocks) { - m.mockVersionGetter.EXPECT().Version().Return("v0.0.0", nil) + m.mockAppVersionGetter.EXPECT().Version().Return("v0.0.0", nil) m.mockEndpointGetter.EXPECT().ServiceDiscoveryEndpoint().Return("mockApp.local", nil) + m.mockEnvVersionGetter.EXPECT().Version().Return("v1.42.0", nil) }, wantErr: fmt.Errorf("alias is not compatible with application versions below %s", deploy.AliasLeastAppTemplateVersion), }, @@ -723,8 +746,9 @@ func TestWorkloadDeployer_DeployWorkload(t *testing.T) { Domain: "mockDomain", }, mock: func(m *deployMocks) { - m.mockVersionGetter.EXPECT().Version().Return("v0.0.0", nil) + m.mockAppVersionGetter.EXPECT().Version().Return("v0.0.0", nil) m.mockEndpointGetter.EXPECT().ServiceDiscoveryEndpoint().Return("mockApp.local", nil) + m.mockEnvVersionGetter.EXPECT().Version().Return("v1.42.0", nil) }, wantErr: fmt.Errorf("alias is not compatible with application versions below %s", deploy.AliasLeastAppTemplateVersion), }, @@ -741,8 +765,9 @@ func TestWorkloadDeployer_DeployWorkload(t *testing.T) { Domain: "mockDomain", }, mock: func(m *deployMocks) { - m.mockVersionGetter.EXPECT().Version().Return("v1.0.0", nil) + m.mockAppVersionGetter.EXPECT().Version().Return("v1.0.0", nil) m.mockEndpointGetter.EXPECT().ServiceDiscoveryEndpoint().Return("mockApp.local", nil) + m.mockEnvVersionGetter.EXPECT().Version().Return("v1.42.0", nil) }, wantErr: fmt.Errorf(`alias "v1.v2.mockDomain" is not supported in hosted zones managed by Copilot`), }, @@ -762,8 +787,9 @@ func TestWorkloadDeployer_DeployWorkload(t *testing.T) { Domain: "mockDomain", }, mock: func(m *deployMocks) { - m.mockVersionGetter.EXPECT().Version().Return("v1.0.0", nil) + m.mockAppVersionGetter.EXPECT().Version().Return("v1.0.0", nil) m.mockEndpointGetter.EXPECT().ServiceDiscoveryEndpoint().Return("mockApp.local", nil) + m.mockEnvVersionGetter.EXPECT().Version().Return("v1.42.0", nil) }, wantErr: fmt.Errorf(`alias "v1.v2.mockDomain" is not supported in hosted zones managed by Copilot`), }, @@ -777,6 +803,7 @@ func TestWorkloadDeployer_DeployWorkload(t *testing.T) { }, mock: func(m *deployMocks) { m.mockEndpointGetter.EXPECT().ServiceDiscoveryEndpoint().Return("mockApp.local", nil) + m.mockEnvVersionGetter.EXPECT().Version().Return("v1.42.0", nil) m.mockServiceDeployer.EXPECT().DeployService(gomock.Any(), "mockBucket", gomock.Any()).Return(errors.New("some error")) }, wantErr: fmt.Errorf("deploy service: some error"), @@ -791,6 +818,7 @@ func TestWorkloadDeployer_DeployWorkload(t *testing.T) { }, mock: func(m *deployMocks) { m.mockEndpointGetter.EXPECT().ServiceDiscoveryEndpoint().Return("mockApp.local", nil) + m.mockEnvVersionGetter.EXPECT().Version().Return("v1.42.0", nil) m.mockServiceDeployer.EXPECT().DeployService(gomock.Any(), "mockBucket", gomock.Any()).Return(cloudformation.NewMockErrChangeSetEmpty()) }, wantErr: fmt.Errorf("deploy service: change set with name mockChangeSet for stack mockStack has no changes"), @@ -806,6 +834,7 @@ func TestWorkloadDeployer_DeployWorkload(t *testing.T) { }, mock: func(m *deployMocks) { m.mockEndpointGetter.EXPECT().ServiceDiscoveryEndpoint().Return("mockApp.local", nil) + m.mockEnvVersionGetter.EXPECT().Version().Return("v1.42.0", nil) m.mockServiceDeployer.EXPECT().DeployService(gomock.Any(), "mockBucket", gomock.Any()). Return(nil) m.mockServiceForceUpdater.EXPECT().LastUpdatedAt(mockAppName, mockEnvName, mockName). @@ -824,6 +853,7 @@ func TestWorkloadDeployer_DeployWorkload(t *testing.T) { }, mock: func(m *deployMocks) { m.mockEndpointGetter.EXPECT().ServiceDiscoveryEndpoint().Return("mockApp.local", nil) + m.mockEnvVersionGetter.EXPECT().Version().Return("v1.42.0", nil) m.mockServiceDeployer.EXPECT().DeployService(gomock.Any(), "mockBucket", gomock.Any()). Return(nil) m.mockServiceForceUpdater.EXPECT().LastUpdatedAt(mockAppName, mockEnvName, mockName). @@ -841,6 +871,7 @@ func TestWorkloadDeployer_DeployWorkload(t *testing.T) { }, mock: func(m *deployMocks) { m.mockEndpointGetter.EXPECT().ServiceDiscoveryEndpoint().Return("mockApp.local", nil) + m.mockEnvVersionGetter.EXPECT().Version().Return("v1.42.0", nil) m.mockServiceDeployer.EXPECT().DeployService(gomock.Any(), "mockBucket", gomock.Any()). Return(cloudformation.NewMockErrChangeSetEmpty()) m.mockServiceForceUpdater.EXPECT().LastUpdatedAt(mockAppName, mockEnvName, mockName). @@ -862,6 +893,7 @@ func TestWorkloadDeployer_DeployWorkload(t *testing.T) { }, mock: func(m *deployMocks) { m.mockEndpointGetter.EXPECT().ServiceDiscoveryEndpoint().Return("mockApp.local", nil) + m.mockEnvVersionGetter.EXPECT().Version().Return("v1.42.0", nil) m.mockServiceDeployer.EXPECT().DeployService(gomock.Any(), "mockBucket", gomock.Any()). Return(cloudformation.NewMockErrChangeSetEmpty()) m.mockServiceForceUpdater.EXPECT().LastUpdatedAt(mockAppName, mockEnvName, mockName). @@ -887,6 +919,7 @@ func TestWorkloadDeployer_DeployWorkload(t *testing.T) { }, mock: func(m *deployMocks) { m.mockEndpointGetter.EXPECT().ServiceDiscoveryEndpoint().Return("mockApp.local", nil) + m.mockEnvVersionGetter.EXPECT().Version().Return("v1.42.0", nil) m.mockServiceDeployer.EXPECT().DeployService(gomock.Any(), "mockBucket", gomock.Any()).Return(nil) }, }, @@ -909,6 +942,7 @@ func TestWorkloadDeployer_DeployWorkload(t *testing.T) { }, mock: func(m *deployMocks) { m.mockEndpointGetter.EXPECT().ServiceDiscoveryEndpoint().Return("mockApp.local", nil) + m.mockEnvVersionGetter.EXPECT().Version().Return("v1.42.0", nil) m.mockValidator.EXPECT().ValidateCertAliases([]string{"example.com", "foobar.com"}, mockCertARNs).Return(nil) m.mockServiceDeployer.EXPECT().DeployService(gomock.Any(), "mockBucket", gomock.Any()).Return(nil) }, @@ -924,6 +958,7 @@ func TestWorkloadDeployer_DeployWorkload(t *testing.T) { }, mock: func(m *deployMocks) { m.mockEndpointGetter.EXPECT().ServiceDiscoveryEndpoint().Return("mockApp.local", nil) + m.mockEnvVersionGetter.EXPECT().Version().Return("v1.42.0", nil) m.mockServiceDeployer.EXPECT().DeployService(gomock.Any(), "mockBucket", gomock.Any()). Return(cloudformation.NewMockErrChangeSetEmpty()) m.mockServiceForceUpdater.EXPECT().LastUpdatedAt(mockAppName, mockEnvName, mockName). @@ -941,7 +976,8 @@ func TestWorkloadDeployer_DeployWorkload(t *testing.T) { defer ctrl.Finish() m := &deployMocks{ - mockVersionGetter: mocks.NewMockversionGetter(ctrl), + mockAppVersionGetter: mocks.NewMockversionGetter(ctrl), + mockEnvVersionGetter: mocks.NewMockversionGetter(ctrl), mockEndpointGetter: mocks.NewMockendpointGetter(ctrl), mockServiceDeployer: mocks.NewMockserviceDeployer(ctrl), mockServiceForceUpdater: mocks.NewMockserviceForceUpdater(ctrl), @@ -959,14 +995,15 @@ func TestWorkloadDeployer_DeployWorkload(t *testing.T) { deployer := lbWebSvcDeployer{ svcDeployer: &svcDeployer{ workloadDeployer: &workloadDeployer{ - name: mockName, - app: tc.inApp, - env: tc.inEnvironment, - envConfig: tc.inEnvironmentConfig(), - resources: mockResources, - deployer: m.mockServiceDeployer, - endpointGetter: m.mockEndpointGetter, - spinner: m.mockSpinner, + name: mockName, + app: tc.inApp, + env: tc.inEnvironment, + envConfig: tc.inEnvironmentConfig(), + resources: mockResources, + deployer: m.mockServiceDeployer, + endpointGetter: m.mockEndpointGetter, + spinner: m.mockSpinner, + envVersionGetter: m.mockEnvVersionGetter, }, newSvcUpdater: func(f func(*session.Session) serviceForceUpdater) serviceForceUpdater { return m.mockServiceForceUpdater @@ -975,7 +1012,7 @@ func TestWorkloadDeployer_DeployWorkload(t *testing.T) { return mockNowTime }, }, - appVersionGetter: m.mockVersionGetter, + appVersionGetter: m.mockAppVersionGetter, publicCIDRBlocksGetter: m.mockPublicCIDRBlocksGetter, newAliasCertValidator: func(region *string) aliasCertValidator { return m.mockValidator @@ -1021,8 +1058,9 @@ func TestWorkloadDeployer_DeployWorkload(t *testing.T) { } type deployRDSvcMocks struct { - mockVersionGetter *mocks.MockversionGetter - mockEndpointGetter *mocks.MockendpointGetter + mockAppVersionGetter *mocks.MockversionGetter + mockEnvVersionGetter *mocks.MockversionGetter + mockEndpointGetter *mocks.MockendpointGetter } func TestSvcDeployOpts_rdWebServiceStackConfiguration(t *testing.T) { @@ -1057,6 +1095,7 @@ func TestSvcDeployOpts_rdWebServiceStackConfiguration(t *testing.T) { }, mock: func(m *deployRDSvcMocks) { m.mockEndpointGetter.EXPECT().ServiceDiscoveryEndpoint().Return("mockApp.local", nil) + m.mockEnvVersionGetter.EXPECT().Version().Return("v1.42.0", nil) }, wantErr: errors.New("alias specified when application is not associated with a domain"), @@ -1072,8 +1111,9 @@ func TestSvcDeployOpts_rdWebServiceStackConfiguration(t *testing.T) { Domain: "mockDomain", }, mock: func(m *deployRDSvcMocks) { - m.mockVersionGetter.EXPECT().Version().Return("v1.0.0", nil) + m.mockAppVersionGetter.EXPECT().Version().Return("v1.0.0", nil) m.mockEndpointGetter.EXPECT().ServiceDiscoveryEndpoint().Return("mockApp.local", nil) + m.mockEnvVersionGetter.EXPECT().Version().Return("v1.42.0", nil) }, wantErr: fmt.Errorf("alias is not supported in hosted zones that are not managed by Copilot"), @@ -1089,8 +1129,9 @@ func TestSvcDeployOpts_rdWebServiceStackConfiguration(t *testing.T) { Domain: "mockDomain", }, mock: func(m *deployRDSvcMocks) { - m.mockVersionGetter.EXPECT().Version().Return("v1.0.0", nil) + m.mockAppVersionGetter.EXPECT().Version().Return("v1.0.0", nil) m.mockEndpointGetter.EXPECT().ServiceDiscoveryEndpoint().Return("mockApp.local", nil) + m.mockEnvVersionGetter.EXPECT().Version().Return("v1.42.0", nil) }, wantErr: fmt.Errorf("mockEnv.mockApp.mockDomain is an environment-level alias, which is not supported yet"), @@ -1106,8 +1147,9 @@ func TestSvcDeployOpts_rdWebServiceStackConfiguration(t *testing.T) { Domain: "mockDomain", }, mock: func(m *deployRDSvcMocks) { - m.mockVersionGetter.EXPECT().Version().Return("v1.0.0", nil) + m.mockAppVersionGetter.EXPECT().Version().Return("v1.0.0", nil) m.mockEndpointGetter.EXPECT().ServiceDiscoveryEndpoint().Return("mockApp.local", nil) + m.mockEnvVersionGetter.EXPECT().Version().Return("v1.42.0", nil) }, wantErr: fmt.Errorf("someSub.mockApp.mockDomain is an application-level alias, which is not supported yet"), @@ -1123,8 +1165,9 @@ func TestSvcDeployOpts_rdWebServiceStackConfiguration(t *testing.T) { Domain: "mockDomain", }, mock: func(m *deployRDSvcMocks) { - m.mockVersionGetter.EXPECT().Version().Return("v1.0.0", nil) + m.mockAppVersionGetter.EXPECT().Version().Return("v1.0.0", nil) m.mockEndpointGetter.EXPECT().ServiceDiscoveryEndpoint().Return("mockApp.local", nil) + m.mockEnvVersionGetter.EXPECT().Version().Return("v1.42.0", nil) }, wantErr: fmt.Errorf("mockDomain is a root domain alias, which is not supported yet"), @@ -1140,8 +1183,9 @@ func TestSvcDeployOpts_rdWebServiceStackConfiguration(t *testing.T) { Domain: "mockDomain", }, mock: func(m *deployRDSvcMocks) { - m.mockVersionGetter.EXPECT().Version().Return("v1.0.0", nil) + m.mockAppVersionGetter.EXPECT().Version().Return("v1.0.0", nil) m.mockEndpointGetter.EXPECT().ServiceDiscoveryEndpoint().Return("mockApp.local", nil) + m.mockEnvVersionGetter.EXPECT().Version().Return("v1.42.0", nil) }, wantAlias: "v1.mockDomain", }, @@ -1153,25 +1197,27 @@ func TestSvcDeployOpts_rdWebServiceStackConfiguration(t *testing.T) { defer ctrl.Finish() m := &deployRDSvcMocks{ - mockVersionGetter: mocks.NewMockversionGetter(ctrl), - mockEndpointGetter: mocks.NewMockendpointGetter(ctrl), + mockAppVersionGetter: mocks.NewMockversionGetter(ctrl), + mockEnvVersionGetter: mocks.NewMockversionGetter(ctrl), + mockEndpointGetter: mocks.NewMockendpointGetter(ctrl), } tc.mock(m) deployer := rdwsDeployer{ svcDeployer: &svcDeployer{ workloadDeployer: &workloadDeployer{ - name: mockName, - app: tc.inApp, - env: tc.inEnvironment, - resources: mockResources, - endpointGetter: m.mockEndpointGetter, + name: mockName, + app: tc.inApp, + env: tc.inEnvironment, + resources: mockResources, + endpointGetter: m.mockEndpointGetter, + envVersionGetter: m.mockEnvVersionGetter, }, newSvcUpdater: func(f func(*session.Session) serviceForceUpdater) serviceForceUpdater { return nil }, }, - appVersionGetter: m.mockVersionGetter, + appVersionGetter: m.mockAppVersionGetter, rdwsMft: &manifest.RequestDrivenWebService{ Workload: manifest.Workload{ Name: aws.String(mockName), @@ -1244,6 +1290,7 @@ func TestSvcDeployOpts_stackConfiguration_worker(t *testing.T) { }, mock: func(m *deployMocks) { m.mockEndpointGetter.EXPECT().ServiceDiscoveryEndpoint().Return("mockApp.local", nil) + m.mockEnvVersionGetter.EXPECT().Version().Return("v1.42.0", nil) m.mockSNSTopicsLister.EXPECT().ListSNSTopics(mockAppName, mockEnvName).Return(nil, mockError) }, wantErr: fmt.Errorf("get SNS topics for app mockApp and environment mockEnv: %w", mockError), @@ -1259,6 +1306,7 @@ func TestSvcDeployOpts_stackConfiguration_worker(t *testing.T) { }, mock: func(m *deployMocks) { m.mockEndpointGetter.EXPECT().ServiceDiscoveryEndpoint().Return("mockEnv.mockApp.local", nil) + m.mockEnvVersionGetter.EXPECT().Version().Return("v1.42.0", nil) m.mockSNSTopicsLister.EXPECT().ListSNSTopics(mockAppName, mockEnvName).Return([]deploy.Topic{ *topic, }, nil) @@ -1272,19 +1320,21 @@ func TestSvcDeployOpts_stackConfiguration_worker(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() m := &deployMocks{ - mockEndpointGetter: mocks.NewMockendpointGetter(ctrl), - mockSNSTopicsLister: mocks.NewMocksnsTopicsLister(ctrl), + mockEndpointGetter: mocks.NewMockendpointGetter(ctrl), + mockSNSTopicsLister: mocks.NewMocksnsTopicsLister(ctrl), + mockEnvVersionGetter: mocks.NewMockversionGetter(ctrl), } tc.mock(m) deployer := workerSvcDeployer{ svcDeployer: &svcDeployer{ workloadDeployer: &workloadDeployer{ - name: mockName, - app: tc.inApp, - env: tc.inEnvironment, - resources: mockResources, - endpointGetter: m.mockEndpointGetter, + name: mockName, + app: tc.inApp, + env: tc.inEnvironment, + resources: mockResources, + endpointGetter: m.mockEndpointGetter, + envVersionGetter: m.mockEnvVersionGetter, }, newSvcUpdater: func(f func(*session.Session) serviceForceUpdater) serviceForceUpdater { return nil @@ -1405,6 +1455,7 @@ func TestBackendSvcDeployer_stackConfiguration(t *testing.T) { Manifest: &manifest.BackendService{}, setupMocks: func(m *deployMocks) { m.mockEndpointGetter.EXPECT().ServiceDiscoveryEndpoint().Return(mockAppName+".local", nil) + m.mockEnvVersionGetter.EXPECT().Version().Return("v1.42.0", nil) }, }, "failure if alias configured, no env certs": { @@ -1427,6 +1478,7 @@ func TestBackendSvcDeployer_stackConfiguration(t *testing.T) { }, setupMocks: func(m *deployMocks) { m.mockEndpointGetter.EXPECT().ServiceDiscoveryEndpoint().Return(mockAppName+".local", nil) + m.mockEnvVersionGetter.EXPECT().Version().Return("v1.42.0", nil) }, expectedErr: `cannot specify "alias" in an environment without imported certs`, }, @@ -1455,6 +1507,7 @@ func TestBackendSvcDeployer_stackConfiguration(t *testing.T) { }, setupMocks: func(m *deployMocks) { m.mockEndpointGetter.EXPECT().ServiceDiscoveryEndpoint().Return(mockAppName+".local", nil) + m.mockEnvVersionGetter.EXPECT().Version().Return("v1.42.0", nil) m.mockValidator.EXPECT().ValidateCertAliases([]string{"go.dev"}, []string{"mockCertARN"}).Return(errors.New("some error")) }, expectedErr: "validate aliases against the imported certificate for env mock-env: some error", @@ -1484,6 +1537,7 @@ func TestBackendSvcDeployer_stackConfiguration(t *testing.T) { }, setupMocks: func(m *deployMocks) { m.mockEndpointGetter.EXPECT().ServiceDiscoveryEndpoint().Return(mockAppName+".local", nil) + m.mockEnvVersionGetter.EXPECT().Version().Return("v1.42.0", nil) m.mockValidator.EXPECT().ValidateCertAliases([]string{"go.dev"}, []string{"mockCertARN"}).Return(nil) }, }, @@ -1508,6 +1562,7 @@ func TestBackendSvcDeployer_stackConfiguration(t *testing.T) { }, setupMocks: func(m *deployMocks) { m.mockEndpointGetter.EXPECT().ServiceDiscoveryEndpoint().Return(mockAppName+".local", nil) + m.mockEnvVersionGetter.EXPECT().Version().Return("v1.42.0", nil) }, expectedErr: `cannot deploy service mock-svc without http.alias to environment mock-env with certificate imported`, }, @@ -1524,6 +1579,7 @@ func TestBackendSvcDeployer_stackConfiguration(t *testing.T) { Manifest: &manifest.BackendService{}, setupMocks: func(m *deployMocks) { m.mockEndpointGetter.EXPECT().ServiceDiscoveryEndpoint().Return(mockAppName+".local", nil) + m.mockEnvVersionGetter.EXPECT().Version().Return("v1.42.0", nil) }, }, } @@ -1534,8 +1590,9 @@ func TestBackendSvcDeployer_stackConfiguration(t *testing.T) { defer ctrl.Finish() m := &deployMocks{ - mockEndpointGetter: mocks.NewMockendpointGetter(ctrl), - mockValidator: mocks.NewMockaliasCertValidator(ctrl), + mockEndpointGetter: mocks.NewMockendpointGetter(ctrl), + mockValidator: mocks.NewMockaliasCertValidator(ctrl), + mockEnvVersionGetter: mocks.NewMockversionGetter(ctrl), } if tc.setupMocks != nil { tc.setupMocks(m) @@ -1548,11 +1605,12 @@ func TestBackendSvcDeployer_stackConfiguration(t *testing.T) { deployer := &backendSvcDeployer{ svcDeployer: &svcDeployer{ workloadDeployer: &workloadDeployer{ - name: mockSvcName, - app: tc.App, - env: tc.Env, - endpointGetter: m.mockEndpointGetter, - envConfig: tc.inEnvironmentConfig(), + name: mockSvcName, + app: tc.App, + env: tc.Env, + endpointGetter: m.mockEndpointGetter, + envConfig: tc.inEnvironmentConfig(), + envVersionGetter: m.mockEnvVersionGetter, }, newSvcUpdater: func(f func(*session.Session) serviceForceUpdater) serviceForceUpdater { return nil diff --git a/internal/pkg/cli/job_deploy.go b/internal/pkg/cli/job_deploy.go index 348ea7ec5ff..1038f4ca9cc 100644 --- a/internal/pkg/cli/job_deploy.go +++ b/internal/pkg/cli/job_deploy.go @@ -88,13 +88,14 @@ func newJobDeployer(o *deployJobOpts) (workloadDeployer, error) { } content := o.appliedDynamicMft.Manifest() in := deploy.WorkloadDeployerInput{ - SessionProvider: o.sessProvider, - Name: o.name, - App: o.targetApp, - Env: o.targetEnv, - ImageTag: o.imageTag, - Mft: content, - RawMft: raw, + SessionProvider: o.sessProvider, + Name: o.name, + App: o.targetApp, + Env: o.targetEnv, + ImageTag: o.imageTag, + Mft: content, + RawMft: raw, + EnvVersionGetter: o.envFeaturesDescriber, } var deployer workloadDeployer switch t := content.(type) { diff --git a/internal/pkg/cli/svc_deploy.go b/internal/pkg/cli/svc_deploy.go index bd28e81323b..c420049b187 100644 --- a/internal/pkg/cli/svc_deploy.go +++ b/internal/pkg/cli/svc_deploy.go @@ -118,13 +118,14 @@ func newSvcDeployer(o *deploySvcOpts) (workloadDeployer, error) { content := o.appliedDynamicMft.Manifest() var deployer workloadDeployer in := clideploy.WorkloadDeployerInput{ - SessionProvider: o.sessProvider, - Name: o.name, - App: targetApp, - Env: o.targetEnv, - ImageTag: o.imageTag, - Mft: content, - RawMft: raw, + SessionProvider: o.sessProvider, + Name: o.name, + App: targetApp, + Env: o.targetEnv, + ImageTag: o.imageTag, + Mft: content, + RawMft: raw, + EnvVersionGetter: o.envFeaturesDescriber, } switch t := content.(type) { case *manifest.LoadBalancedWebService: diff --git a/internal/pkg/cli/svc_deploy_test.go b/internal/pkg/cli/svc_deploy_test.go index 4b1e349bb47..a8a7f137e5e 100644 --- a/internal/pkg/cli/svc_deploy_test.go +++ b/internal/pkg/cli/svc_deploy_test.go @@ -217,6 +217,22 @@ func TestSvcDeployOpts_Execute(t *testing.T) { wantedError: fmt.Errorf("deploy service frontend to environment prod-iad: some error"), }, + "success with no recommendations": { + mock: func(m *deployMocks) { + m.mockWsReader.EXPECT().ReadWorkloadManifest(mockSvcName).Return([]byte(""), nil) + m.mockInterpolator.EXPECT().Interpolate("").Return("", nil) + m.mockMft = &mockWorkloadMft{ + mockRequiredEnvironmentFeatures: func() []string { + return []string{"mockFeature1"} + }, + } + m.mockEnvFeaturesDescriber.EXPECT().AvailableFeatures().Return([]string{"mockFeature1", "mockFeature2"}, nil) + m.mockEnvFeaturesDescriber.EXPECT().Version().Times(0) + m.mockDeployer.EXPECT().UploadArtifacts().Return(&deploy.UploadArtifactsOutput{}, nil) + m.mockDeployer.EXPECT().DeployWorkload(gomock.Any()).Return(nil, nil) + m.mockDeployer.EXPECT().IsServiceAvailableInRegion("").Return(false, nil) + }, + }, } for name, tc := range testCases { diff --git a/internal/pkg/cli/svc_package.go b/internal/pkg/cli/svc_package.go index f7e98c4add2..35a7705dbe2 100644 --- a/internal/pkg/cli/svc_package.go +++ b/internal/pkg/cli/svc_package.go @@ -120,13 +120,14 @@ func newWorkloadStackGenerator(o *packageSvcOpts) (workloadStackGenerator, error content := o.appliedDynamicMft.Manifest() var deployer workloadStackGenerator in := clideploy.WorkloadDeployerInput{ - SessionProvider: o.sessProvider, - Name: o.name, - App: targetApp, - Env: targetEnv, - ImageTag: o.tag, - Mft: content, - RawMft: raw, + SessionProvider: o.sessProvider, + Name: o.name, + App: targetApp, + Env: targetEnv, + ImageTag: o.tag, + Mft: content, + RawMft: raw, + EnvVersionGetter: o.envFeaturesDescriber, } switch t := content.(type) { case *manifest.LoadBalancedWebService: diff --git a/internal/pkg/deploy/cloudformation/stack/backend_svc.go b/internal/pkg/deploy/cloudformation/stack/backend_svc.go index 58d382e08a8..1982c909688 100644 --- a/internal/pkg/deploy/cloudformation/stack/backend_svc.go +++ b/internal/pkg/deploy/cloudformation/stack/backend_svc.go @@ -146,6 +146,7 @@ func (s *BackendService) Template() (string, error) { EnvName: s.env, WorkloadName: s.name, SerializedManifest: string(s.rawManifest), + EnvVersion: s.rc.EnvVersion, Variables: s.manifest.BackendServiceConfig.Variables, Secrets: convertSecrets(s.manifest.BackendServiceConfig.Secrets), diff --git a/internal/pkg/deploy/cloudformation/stack/backend_svc_test.go b/internal/pkg/deploy/cloudformation/stack/backend_svc_test.go index 0c3562af64a..85c3be45e04 100644 --- a/internal/pkg/deploy/cloudformation/stack/backend_svc_test.go +++ b/internal/pkg/deploy/cloudformation/stack/backend_svc_test.go @@ -561,6 +561,7 @@ func TestBackendService_TemplateAndParamsGeneration(t *testing.T) { Manifest: mft.(*manifest.BackendService), RuntimeConfig: RuntimeConfig{ ServiceDiscoveryEndpoint: fmt.Sprintf("%s.%s.local", envName, appName), + EnvVersion: "v1.42.0", }, }) require.NoError(t, err) diff --git a/internal/pkg/deploy/cloudformation/stack/lb_grpc_web_service_integration_test.go b/internal/pkg/deploy/cloudformation/stack/lb_grpc_web_service_integration_test.go index 1f06cb67aa9..b155a33033f 100644 --- a/internal/pkg/deploy/cloudformation/stack/lb_grpc_web_service_integration_test.go +++ b/internal/pkg/deploy/cloudformation/stack/lb_grpc_web_service_integration_test.go @@ -82,6 +82,7 @@ func TestGrpcLoadBalancedWebService_Template(t *testing.T) { ServiceDiscoveryEndpoint: svcDiscoveryEndpointName, AccountID: "123456789123", Region: "us-west-2", + EnvVersion: "v1.42.0", }, }) diff --git a/internal/pkg/deploy/cloudformation/stack/lb_network_web_service_integration_test.go b/internal/pkg/deploy/cloudformation/stack/lb_network_web_service_integration_test.go index 287495bd666..9f997e833ec 100644 --- a/internal/pkg/deploy/cloudformation/stack/lb_network_web_service_integration_test.go +++ b/internal/pkg/deploy/cloudformation/stack/lb_network_web_service_integration_test.go @@ -101,6 +101,7 @@ func TestNetworkLoadBalancedWebService_Template(t *testing.T) { ServiceDiscoveryEndpoint: svcDiscoveryEndpointName, AccountID: "123456789123", Region: "us-west-2", + EnvVersion: "v1.42.0", }, RootUserARN: "arn:aws:iam::123456789123:root", }, stack.WithNLB([]string{"10.0.0.0/24", "10.1.0.0/24"})) diff --git a/internal/pkg/deploy/cloudformation/stack/lb_web_service_integration_test.go b/internal/pkg/deploy/cloudformation/stack/lb_web_service_integration_test.go index ab0aa79c3b8..34042cac16c 100644 --- a/internal/pkg/deploy/cloudformation/stack/lb_web_service_integration_test.go +++ b/internal/pkg/deploy/cloudformation/stack/lb_web_service_integration_test.go @@ -102,6 +102,7 @@ func TestLoadBalancedWebService_Template(t *testing.T) { ServiceDiscoveryEndpoint: svcDiscoveryEndpointName, AccountID: "123456789123", Region: "us-west-2", + EnvVersion: "v1.42.0", }, }) tpl, err := serializer.Template() diff --git a/internal/pkg/deploy/cloudformation/stack/lb_web_svc.go b/internal/pkg/deploy/cloudformation/stack/lb_web_svc.go index fdf7ae4c695..4d6915a0845 100644 --- a/internal/pkg/deploy/cloudformation/stack/lb_web_svc.go +++ b/internal/pkg/deploy/cloudformation/stack/lb_web_svc.go @@ -190,6 +190,7 @@ func (s *LoadBalancedWebService) Template() (string, error) { EnvName: s.env, WorkloadName: s.name, SerializedManifest: string(s.rawManifest), + EnvVersion: s.rc.EnvVersion, Variables: s.manifest.TaskConfig.Variables, Secrets: convertSecrets(s.manifest.TaskConfig.Secrets), diff --git a/internal/pkg/deploy/cloudformation/stack/rd_web_svc.go b/internal/pkg/deploy/cloudformation/stack/rd_web_svc.go index b0c25e408ce..cf830830fdc 100644 --- a/internal/pkg/deploy/cloudformation/stack/rd_web_svc.go +++ b/internal/pkg/deploy/cloudformation/stack/rd_web_svc.go @@ -117,6 +117,7 @@ func (s *RequestDrivenWebService) Template() (string, error) { EnvName: s.env, WorkloadName: s.name, SerializedManifest: string(s.rawManifest), + EnvVersion: s.rc.EnvVersion, Variables: s.manifest.Variables, StartCommand: s.manifest.StartCommand, diff --git a/internal/pkg/deploy/cloudformation/stack/rd_web_svc_integration_test.go b/internal/pkg/deploy/cloudformation/stack/rd_web_svc_integration_test.go index 6addf90b64c..b283a19f707 100644 --- a/internal/pkg/deploy/cloudformation/stack/rd_web_svc_integration_test.go +++ b/internal/pkg/deploy/cloudformation/stack/rd_web_svc_integration_test.go @@ -74,8 +74,9 @@ func TestRDWS_Template(t *testing.T) { Env: tc.envName, Manifest: v, RuntimeConfig: stack.RuntimeConfig{ - AccountID: "123456789123", - Region: "us-west-2", + AccountID: "123456789123", + Region: "us-west-2", + EnvVersion: "v1.42.0", }, }) require.NoError(t, err, "create rdws serializer") diff --git a/internal/pkg/deploy/cloudformation/stack/scheduled_job.go b/internal/pkg/deploy/cloudformation/stack/scheduled_job.go index 058fed660a9..b6417a0db89 100644 --- a/internal/pkg/deploy/cloudformation/stack/scheduled_job.go +++ b/internal/pkg/deploy/cloudformation/stack/scheduled_job.go @@ -184,6 +184,7 @@ func (j *ScheduledJob) Template() (string, error) { ServiceDiscoveryEndpoint: j.rc.ServiceDiscoveryEndpoint, Publish: publishers, Platform: convertPlatform(j.manifest.Platform), + EnvVersion: j.rc.EnvVersion, CustomResources: crs, }) diff --git a/internal/pkg/deploy/cloudformation/stack/scheduled_job_integration_test.go b/internal/pkg/deploy/cloudformation/stack/scheduled_job_integration_test.go index 58fbaa3413a..8f40c48c9da 100644 --- a/internal/pkg/deploy/cloudformation/stack/scheduled_job_integration_test.go +++ b/internal/pkg/deploy/cloudformation/stack/scheduled_job_integration_test.go @@ -59,6 +59,7 @@ func TestScheduledJob_Template(t *testing.T) { Manifest: v, RuntimeConfig: stack.RuntimeConfig{ ServiceDiscoveryEndpoint: "test.my-app.local", + EnvVersion: "v1.42.0", }, }) diff --git a/internal/pkg/deploy/cloudformation/stack/stack_local_integration_test.go b/internal/pkg/deploy/cloudformation/stack/stack_local_integration_test.go index 9fbc20a2868..c935ba15dac 100644 --- a/internal/pkg/deploy/cloudformation/stack/stack_local_integration_test.go +++ b/internal/pkg/deploy/cloudformation/stack/stack_local_integration_test.go @@ -68,6 +68,7 @@ func Test_Stack_Local_Integration(t *testing.T) { RepoURL: imageURL, ImageTag: imageTag, }, + EnvVersion: "v1.42.0", }, }) require.NoError(t, err) diff --git a/internal/pkg/deploy/cloudformation/stack/testdata/workloads/backend/http-autoscaling-template.yml b/internal/pkg/deploy/cloudformation/stack/testdata/workloads/backend/http-autoscaling-template.yml index e226260b29a..f13140c8d49 100644 --- a/internal/pkg/deploy/cloudformation/stack/testdata/workloads/backend/http-autoscaling-template.yml +++ b/internal/pkg/deploy/cloudformation/stack/testdata/workloads/backend/http-autoscaling-template.yml @@ -560,6 +560,7 @@ Resources: Workload: !Ref WorkloadName EnvStack: !Sub "${AppName}-${EnvName}" Parameters: ["InternalALBWorkloads"] + EnvVersion: v1.42.0 EnvControllerFunction: Type: AWS::Lambda::Function Properties: diff --git a/internal/pkg/deploy/cloudformation/stack/testdata/workloads/backend/http-full-config-template.yml b/internal/pkg/deploy/cloudformation/stack/testdata/workloads/backend/http-full-config-template.yml index c842b30d7bf..b9a14e34184 100644 --- a/internal/pkg/deploy/cloudformation/stack/testdata/workloads/backend/http-full-config-template.yml +++ b/internal/pkg/deploy/cloudformation/stack/testdata/workloads/backend/http-full-config-template.yml @@ -449,6 +449,7 @@ Resources: Workload: !Ref WorkloadName EnvStack: !Sub "${AppName}-${EnvName}" Parameters: ["InternalALBWorkloads"] + EnvVersion: v1.42.0 EnvControllerFunction: Type: AWS::Lambda::Function Properties: diff --git a/internal/pkg/deploy/cloudformation/stack/testdata/workloads/backend/http-only-path-template.yml b/internal/pkg/deploy/cloudformation/stack/testdata/workloads/backend/http-only-path-template.yml index e124893d895..5a0cfc4f665 100644 --- a/internal/pkg/deploy/cloudformation/stack/testdata/workloads/backend/http-only-path-template.yml +++ b/internal/pkg/deploy/cloudformation/stack/testdata/workloads/backend/http-only-path-template.yml @@ -438,6 +438,7 @@ Resources: Workload: !Ref WorkloadName EnvStack: !Sub "${AppName}-${EnvName}" Parameters: ["InternalALBWorkloads"] + EnvVersion: v1.42.0 EnvControllerFunction: Type: AWS::Lambda::Function Properties: diff --git a/internal/pkg/deploy/cloudformation/stack/testdata/workloads/backend/https-path-alias-template.yml b/internal/pkg/deploy/cloudformation/stack/testdata/workloads/backend/https-path-alias-template.yml index 2fb10b595fe..1fe0e402771 100644 --- a/internal/pkg/deploy/cloudformation/stack/testdata/workloads/backend/https-path-alias-template.yml +++ b/internal/pkg/deploy/cloudformation/stack/testdata/workloads/backend/https-path-alias-template.yml @@ -427,6 +427,7 @@ Resources: Aliases: ["example.com", "foobar.com", "*.foobar.com"] EnvStack: !Sub '${AppName}-${EnvName}' Parameters: [InternalALBWorkloads] + EnvVersion: v1.42.0 EnvControllerFunction: Type: AWS::Lambda::Function Properties: diff --git a/internal/pkg/deploy/cloudformation/stack/testdata/workloads/backend/simple-template.yml b/internal/pkg/deploy/cloudformation/stack/testdata/workloads/backend/simple-template.yml index 0ed61c42a75..28dd81d3b68 100644 --- a/internal/pkg/deploy/cloudformation/stack/testdata/workloads/backend/simple-template.yml +++ b/internal/pkg/deploy/cloudformation/stack/testdata/workloads/backend/simple-template.yml @@ -315,6 +315,7 @@ Resources: Workload: !Ref WorkloadName EnvStack: !Sub "${AppName}-${EnvName}" Parameters: [] + EnvVersion: v1.42.0 EnvControllerFunction: Type: AWS::Lambda::Function Properties: diff --git a/internal/pkg/deploy/cloudformation/stack/testdata/workloads/job-test.stack.yml b/internal/pkg/deploy/cloudformation/stack/testdata/workloads/job-test.stack.yml index 28c2bb912c7..d0873375f64 100644 --- a/internal/pkg/deploy/cloudformation/stack/testdata/workloads/job-test.stack.yml +++ b/internal/pkg/deploy/cloudformation/stack/testdata/workloads/job-test.stack.yml @@ -53,6 +53,7 @@ Resources: EnvStack: !Sub '${AppName}-${EnvName}' Parameters: - EFSWorkloads + EnvVersion: v1.42.0 EnvControllerFunction: Type: AWS::Lambda::Function diff --git a/internal/pkg/deploy/cloudformation/stack/testdata/workloads/rdws-test.stack.yml b/internal/pkg/deploy/cloudformation/stack/testdata/workloads/rdws-test.stack.yml index 4154558dd61..3af85910bb7 100644 --- a/internal/pkg/deploy/cloudformation/stack/testdata/workloads/rdws-test.stack.yml +++ b/internal/pkg/deploy/cloudformation/stack/testdata/workloads/rdws-test.stack.yml @@ -209,6 +209,7 @@ Resources: Workload: !Ref WorkloadName EnvStack: !Sub '${AppName}-${EnvName}' Parameters: [NATWorkloads,] + EnvVersion: v1.42.0 EnvControllerFunction: Type: AWS::Lambda::Function diff --git a/internal/pkg/deploy/cloudformation/stack/testdata/workloads/svc-grpc-test.stack.yml b/internal/pkg/deploy/cloudformation/stack/testdata/workloads/svc-grpc-test.stack.yml index 5a791523708..59e33a9f4dd 100644 --- a/internal/pkg/deploy/cloudformation/stack/testdata/workloads/svc-grpc-test.stack.yml +++ b/internal/pkg/deploy/cloudformation/stack/testdata/workloads/svc-grpc-test.stack.yml @@ -353,6 +353,7 @@ Resources: # If a bucket URL is specified, that means the template exists. Aliases: ["example.com"] EnvStack: !Sub '${AppName}-${EnvName}' Parameters: [ALBWorkloads, Aliases] + EnvVersion: v1.42.0 EnvControllerFunction: Type: AWS::Lambda::Function Properties: diff --git a/internal/pkg/deploy/cloudformation/stack/testdata/workloads/svc-nlb-dev.stack.yml b/internal/pkg/deploy/cloudformation/stack/testdata/workloads/svc-nlb-dev.stack.yml index 4a907f4819d..667d5dc192c 100644 --- a/internal/pkg/deploy/cloudformation/stack/testdata/workloads/svc-nlb-dev.stack.yml +++ b/internal/pkg/deploy/cloudformation/stack/testdata/workloads/svc-nlb-dev.stack.yml @@ -230,6 +230,7 @@ Resources: # If a bucket URL is specified, that means the template exists. Workload: !Ref WorkloadName EnvStack: !Sub '${AppName}-${EnvName}' Parameters: [ALBWorkloads, Aliases] + EnvVersion: v1.42.0 EnvControllerFunction: Type: AWS::Lambda::Function Properties: diff --git a/internal/pkg/deploy/cloudformation/stack/testdata/workloads/svc-nlb-prod.stack.yml b/internal/pkg/deploy/cloudformation/stack/testdata/workloads/svc-nlb-prod.stack.yml index 68a902011cd..f949eda5dc6 100644 --- a/internal/pkg/deploy/cloudformation/stack/testdata/workloads/svc-nlb-prod.stack.yml +++ b/internal/pkg/deploy/cloudformation/stack/testdata/workloads/svc-nlb-prod.stack.yml @@ -236,6 +236,7 @@ Resources: # If a bucket URL is specified, that means the template exists. Workload: !Ref WorkloadName EnvStack: !Sub '${AppName}-${EnvName}' Parameters: [Aliases] + EnvVersion: v1.42.0 EnvControllerFunction: Type: AWS::Lambda::Function Properties: diff --git a/internal/pkg/deploy/cloudformation/stack/testdata/workloads/svc-nlb-test.stack.yml b/internal/pkg/deploy/cloudformation/stack/testdata/workloads/svc-nlb-test.stack.yml index 75c5b8cb848..5e16baba2ba 100644 --- a/internal/pkg/deploy/cloudformation/stack/testdata/workloads/svc-nlb-test.stack.yml +++ b/internal/pkg/deploy/cloudformation/stack/testdata/workloads/svc-nlb-test.stack.yml @@ -219,6 +219,7 @@ Resources: # If a bucket URL is specified, that means the template exists. Workload: !Ref WorkloadName EnvStack: !Sub '${AppName}-${EnvName}' Parameters: [Aliases] + EnvVersion: v1.42.0 EnvControllerFunction: Type: AWS::Lambda::Function Properties: diff --git a/internal/pkg/deploy/cloudformation/stack/testdata/workloads/svc-prod.stack.yml b/internal/pkg/deploy/cloudformation/stack/testdata/workloads/svc-prod.stack.yml index 026cc19adf0..80f8a7ecd61 100644 --- a/internal/pkg/deploy/cloudformation/stack/testdata/workloads/svc-prod.stack.yml +++ b/internal/pkg/deploy/cloudformation/stack/testdata/workloads/svc-prod.stack.yml @@ -436,6 +436,7 @@ Resources: # If a bucket URL is specified, that means the template exists. Aliases: ["example.com"] EnvStack: !Sub '${AppName}-${EnvName}' Parameters: [ALBWorkloads, Aliases] + EnvVersion: v1.42.0 EnvControllerFunction: Type: AWS::Lambda::Function Properties: diff --git a/internal/pkg/deploy/cloudformation/stack/testdata/workloads/svc-staging.stack.yml b/internal/pkg/deploy/cloudformation/stack/testdata/workloads/svc-staging.stack.yml index 2e78fe7b460..00087d231b3 100644 --- a/internal/pkg/deploy/cloudformation/stack/testdata/workloads/svc-staging.stack.yml +++ b/internal/pkg/deploy/cloudformation/stack/testdata/workloads/svc-staging.stack.yml @@ -242,6 +242,7 @@ Resources: # If a bucket URL is specified, that means the template exists. Aliases: ["example.com"] EnvStack: !Sub '${AppName}-${EnvName}' Parameters: [ALBWorkloads, Aliases] + EnvVersion: v1.42.0 EnvControllerFunction: Type: AWS::Lambda::Function Properties: diff --git a/internal/pkg/deploy/cloudformation/stack/testdata/workloads/svc-test.stack.yml b/internal/pkg/deploy/cloudformation/stack/testdata/workloads/svc-test.stack.yml index b831fd2a924..7479d45cbb1 100644 --- a/internal/pkg/deploy/cloudformation/stack/testdata/workloads/svc-test.stack.yml +++ b/internal/pkg/deploy/cloudformation/stack/testdata/workloads/svc-test.stack.yml @@ -353,6 +353,7 @@ Resources: # If a bucket URL is specified, that means the template exists. Aliases: ["example.com"] EnvStack: !Sub '${AppName}-${EnvName}' Parameters: [ALBWorkloads, Aliases] + EnvVersion: v1.42.0 EnvControllerFunction: Type: AWS::Lambda::Function Properties: diff --git a/internal/pkg/deploy/cloudformation/stack/testdata/workloads/windows-svc-test.stack.yml b/internal/pkg/deploy/cloudformation/stack/testdata/workloads/windows-svc-test.stack.yml index de559f31877..93d65a5a81a 100644 --- a/internal/pkg/deploy/cloudformation/stack/testdata/workloads/windows-svc-test.stack.yml +++ b/internal/pkg/deploy/cloudformation/stack/testdata/workloads/windows-svc-test.stack.yml @@ -224,6 +224,7 @@ Resources: # If a bucket URL is specified, that means the template exists. Workload: !Ref WorkloadName EnvStack: !Sub '${AppName}-${EnvName}' Parameters: [ALBWorkloads, Aliases] + EnvVersion: v1.42.0 EnvControllerFunction: Type: AWS::Lambda::Function Properties: diff --git a/internal/pkg/deploy/cloudformation/stack/testdata/workloads/worker-test.stack.yml b/internal/pkg/deploy/cloudformation/stack/testdata/workloads/worker-test.stack.yml index 5467b4ca155..cacf5dc368f 100644 --- a/internal/pkg/deploy/cloudformation/stack/testdata/workloads/worker-test.stack.yml +++ b/internal/pkg/deploy/cloudformation/stack/testdata/workloads/worker-test.stack.yml @@ -744,6 +744,7 @@ Resources: Workload: !Ref WorkloadName EnvStack: !Sub '${AppName}-${EnvName}' Parameters: [] + EnvVersion: v1.42.0 EnvControllerFunction: Type: AWS::Lambda::Function Properties: diff --git a/internal/pkg/deploy/cloudformation/stack/validate_template_integration_test.go b/internal/pkg/deploy/cloudformation/stack/validate_template_integration_test.go index 49cf510b8ef..9f9de2faa89 100644 --- a/internal/pkg/deploy/cloudformation/stack/validate_template_integration_test.go +++ b/internal/pkg/deploy/cloudformation/stack/validate_template_integration_test.go @@ -57,6 +57,7 @@ func TestAutoscalingIntegration_Validate(t *testing.T) { "DynamicDesiredCountFunction": "https://my-bucket.s3.us-west-2.amazonaws.com/code.zip", "RulePriorityFunction": "https://my-bucket.s3.us-west-2.amazonaws.com/code.zip", }, + EnvVersion: "v1.42.0", }, }) require.NoError(t, err) @@ -100,6 +101,7 @@ func TestScheduledJob_Validate(t *testing.T) { CustomResourcesURL: map[string]string{ "EnvControllerFunction": "https://my-bucket.s3.us-west-2.amazonaws.com/code.zip", }, + EnvVersion: "v1.42.0", }, }) diff --git a/internal/pkg/deploy/cloudformation/stack/windows_lb_web_service_integration_test.go b/internal/pkg/deploy/cloudformation/stack/windows_lb_web_service_integration_test.go index a5259ff5905..27772350716 100644 --- a/internal/pkg/deploy/cloudformation/stack/windows_lb_web_service_integration_test.go +++ b/internal/pkg/deploy/cloudformation/stack/windows_lb_web_service_integration_test.go @@ -68,6 +68,7 @@ func TestWindowsLoadBalancedWebService_Template(t *testing.T) { AccountID: "123456789123", Region: "us-west-2", ServiceDiscoveryEndpoint: svcDiscoveryEndpointName, + EnvVersion: "v1.42.0", }, }) diff --git a/internal/pkg/deploy/cloudformation/stack/worker_service_integration_test.go b/internal/pkg/deploy/cloudformation/stack/worker_service_integration_test.go index 3e35f17493c..1d50902d203 100644 --- a/internal/pkg/deploy/cloudformation/stack/worker_service_integration_test.go +++ b/internal/pkg/deploy/cloudformation/stack/worker_service_integration_test.go @@ -62,6 +62,7 @@ func TestWorkerService_Template(t *testing.T) { ServiceDiscoveryEndpoint: "test.my-app.local", AccountID: "123456789123", Region: "us-west-2", + EnvVersion: "v1.42.0", }, }) diff --git a/internal/pkg/deploy/cloudformation/stack/worker_svc.go b/internal/pkg/deploy/cloudformation/stack/worker_svc.go index 95cec0c478f..b06d20db95e 100644 --- a/internal/pkg/deploy/cloudformation/stack/worker_svc.go +++ b/internal/pkg/deploy/cloudformation/stack/worker_svc.go @@ -115,6 +115,7 @@ func (s *WorkerService) Template() (string, error) { EnvName: s.env, WorkloadName: s.name, SerializedManifest: string(s.rawManifest), + EnvVersion: s.rc.EnvVersion, Variables: s.manifest.WorkerServiceConfig.Variables, Secrets: convertSecrets(s.manifest.WorkerServiceConfig.Secrets), diff --git a/internal/pkg/deploy/cloudformation/stack/workload.go b/internal/pkg/deploy/cloudformation/stack/workload.go index 3098209544a..27a6dabff77 100644 --- a/internal/pkg/deploy/cloudformation/stack/workload.go +++ b/internal/pkg/deploy/cloudformation/stack/workload.go @@ -80,6 +80,7 @@ type RuntimeConfig struct { ServiceDiscoveryEndpoint string // Endpoint for the service discovery namespace in the environment. AccountID string Region string + EnvVersion string } // ECRImage represents configuration about the pushed ECR image that is needed to diff --git a/internal/pkg/template/templates/workloads/partials/cf/env-controller.yml b/internal/pkg/template/templates/workloads/partials/cf/env-controller.yml index 880a887a0b7..fbfe67a868d 100644 --- a/internal/pkg/template/templates/workloads/partials/cf/env-controller.yml +++ b/internal/pkg/template/templates/workloads/partials/cf/env-controller.yml @@ -10,6 +10,7 @@ EnvControllerAction: {{- end}} EnvStack: !Sub '${AppName}-${EnvName}' Parameters: {{ envControllerParams . }} + EnvVersion: {{.EnvVersion}} EnvControllerFunction: Type: AWS::Lambda::Function diff --git a/internal/pkg/template/workload.go b/internal/pkg/template/workload.go index ea924e61362..fc9cf8cfcad 100644 --- a/internal/pkg/template/workload.go +++ b/internal/pkg/template/workload.go @@ -484,6 +484,7 @@ type WorkloadOpts struct { EnvName string WorkloadName string SerializedManifest string // Raw manifest file used to deploy the workload. + EnvVersion string // Additional options that are common between **all** workload templates. Variables map[string]string