diff --git a/astro-client/mutations.go b/astro-client/mutations.go index a22a20def..ce455d359 100644 --- a/astro-client/mutations.go +++ b/astro-client/mutations.go @@ -46,6 +46,7 @@ var ( dagDeployEnabled schedulerSize isHighAvailability + apiKeyOnlyDeployments cluster { id name @@ -91,6 +92,7 @@ var ( dagDeployEnabled schedulerSize isHighAvailability + apiKeyOnlyDeployments cluster { id name diff --git a/astro-client/queries.go b/astro-client/queries.go index 9c68df557..9d6c8ad70 100644 --- a/astro-client/queries.go +++ b/astro-client/queries.go @@ -20,6 +20,7 @@ var ( description releaseName dagDeployEnabled + apiKeyOnlyDeployments schedulerSize isHighAvailability cluster { diff --git a/astro-client/types.go b/astro-client/types.go index af726f53a..c202d2e38 100644 --- a/astro-client/types.go +++ b/astro-client/types.go @@ -49,24 +49,25 @@ type AuthUser struct { // Deployment defines structure of a astrohub response Deployment object type Deployment struct { - ID string `json:"id"` - Label string `json:"label"` - Description string `json:"description"` - WebserverStatus string `json:"webserverStatus"` - Status string `json:"status"` - ReleaseName string `json:"releaseName"` - Version string `json:"version"` - DagDeployEnabled bool `json:"dagDeployEnabled"` - AlertEmails []string `json:"alertEmails"` - Cluster Cluster `json:"cluster"` - Workspace Workspace `json:"workspace"` - RuntimeRelease RuntimeRelease `json:"runtimeRelease"` - DeploymentSpec DeploymentSpec `json:"deploymentSpec"` - SchedulerSize string `json:"schedulerSize"` - IsHighAvailability bool `json:"isHighAvailability"` - WorkerQueues []WorkerQueue `json:"workerQueues"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` + ID string `json:"id"` + Label string `json:"label"` + Description string `json:"description"` + WebserverStatus string `json:"webserverStatus"` + Status string `json:"status"` + ReleaseName string `json:"releaseName"` + Version string `json:"version"` + DagDeployEnabled bool `json:"dagDeployEnabled"` + APIKeyOnlyDeployments bool `json:"apiKeyOnlyDeployments"` + AlertEmails []string `json:"alertEmails"` + Cluster Cluster `json:"cluster"` + Workspace Workspace `json:"workspace"` + RuntimeRelease RuntimeRelease `json:"runtimeRelease"` + DeploymentSpec DeploymentSpec `json:"deploymentSpec"` + SchedulerSize string `json:"schedulerSize"` + IsHighAvailability bool `json:"isHighAvailability"` + WorkerQueues []WorkerQueue `json:"workerQueues"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` } // Cluster contains all components of an Astronomer Cluster @@ -338,6 +339,7 @@ type CreateDeploymentInput struct { WorkerQueues []WorkerQueue `json:"workerQueues"` IsHighAvailability bool `json:"isHighAvailability"` SchedulerSize string `json:"schedulerSize"` + APIKeyOnlyDeployments bool `json:"apiKeyOnlyDeployments"` } type DeploymentCreateSpec struct { @@ -346,15 +348,16 @@ type DeploymentCreateSpec struct { } type UpdateDeploymentInput struct { - ID string `json:"id"` - ClusterID string `json:"clusterId"` - Label string `json:"label"` - Description string `json:"description"` - DagDeployEnabled bool `json:"dagDeployEnabled"` - DeploymentSpec DeploymentCreateSpec `json:"deploymentSpec"` - IsHighAvailability bool `json:"isHighAvailability"` - SchedulerSize string `json:"schedulerSize"` - WorkerQueues []WorkerQueue `json:"workerQueues"` + ID string `json:"id"` + ClusterID string `json:"clusterId"` + Label string `json:"label"` + Description string `json:"description"` + DagDeployEnabled bool `json:"dagDeployEnabled"` + APIKeyOnlyDeployments bool `json:"apiKeyOnlyDeployments"` + DeploymentSpec DeploymentCreateSpec `json:"deploymentSpec"` + IsHighAvailability bool `json:"isHighAvailability"` + SchedulerSize string `json:"schedulerSize"` + WorkerQueues []WorkerQueue `json:"workerQueues"` } type DeleteDeploymentInput struct { diff --git a/cloud/deployment/deployment.go b/cloud/deployment/deployment.go index 2b8df0963..e5f4404c5 100644 --- a/cloud/deployment/deployment.go +++ b/cloud/deployment/deployment.go @@ -30,6 +30,7 @@ var ( ErrInvalidDeploymentKey = errors.New("invalid Deployment selected") ErrInvalidRegionKey = errors.New("invalid Region selected") errTimedOut = errors.New("timed out waiting for the deployment to become healthy") + ErrWrongEnforceInput = errors.New("the input to the `--enforce-cicd` flag") // Monkey patched to write unit tests createDeployment = Create CleanOutput = false @@ -53,7 +54,7 @@ func newTableOut() *printutil.Table { return &printutil.Table{ Padding: []int{30, 50, 10, 50, 10, 10, 10}, DynamicPadding: true, - Header: []string{"NAME", "NAMESPACE", "CLUSTER", "DEPLOYMENT ID", "RUNTIME VERSION", "DAG DEPLOY ENABLED"}, + Header: []string{"NAME", "NAMESPACE", "CLUSTER", "DEPLOYMENT ID", "RUNTIME VERSION", "DAG DEPLOY ENABLED", "CI-CD ENFORCEMENT"}, } } @@ -61,7 +62,7 @@ func newTableOutAll() *printutil.Table { return &printutil.Table{ Padding: []int{30, 50, 10, 50, 10, 10, 10}, DynamicPadding: true, - Header: []string{"NAME", "WORKSPACE", "NAMESPACE", "CLUSTER", "DEPLOYMENT ID", "RUNTIME VERSION", "DAG DEPLOY ENABLED"}, + Header: []string{"NAME", "WORKSPACE", "NAMESPACE", "CLUSTER", "DEPLOYMENT ID", "RUNTIME VERSION", "DAG DEPLOY ENABLED", "CI-CD ENFORCEMENT"}, } } @@ -95,9 +96,9 @@ func List(ws string, all bool, client astro.Client, out io.Writer) error { } if all { - tab.AddRow([]string{d.Label, d.Workspace.Label, releaseName, clusterName, d.ID, runtimeVersionText, strconv.FormatBool(d.DagDeployEnabled)}, false) + tab.AddRow([]string{d.Label, d.Workspace.Label, releaseName, clusterName, d.ID, runtimeVersionText, strconv.FormatBool(d.DagDeployEnabled), strconv.FormatBool(d.APIKeyOnlyDeployments)}, false) } else { - tab.AddRow([]string{d.Label, releaseName, clusterName, d.ID, runtimeVersionText, strconv.FormatBool(d.DagDeployEnabled)}, false) + tab.AddRow([]string{d.Label, releaseName, clusterName, d.ID, runtimeVersionText, strconv.FormatBool(d.DagDeployEnabled), strconv.FormatBool(d.APIKeyOnlyDeployments)}, false) } } @@ -154,7 +155,7 @@ func Logs(deploymentID, ws, deploymentName string, warnLogs, errorLogs, infoLogs return nil } -func Create(label, workspaceID, description, clusterID, runtimeVersion, dagDeploy, executor, cloudProvider, region, schedulerSize, highAvailability string, schedulerAU, schedulerReplicas int, client astro.Client, coreClient astrocore.CoreClient, waitForStatus bool) error { //nolint +func Create(label, workspaceID, description, clusterID, runtimeVersion, dagDeploy, executor, cloudProvider, region, schedulerSize, highAvailability string, schedulerAU, schedulerReplicas int, client astro.Client, coreClient astrocore.CoreClient, waitForStatus bool, enforceCD *bool) error { //nolint var organizationID string var currentWorkspace astro.Workspace var dagDeployEnabled bool @@ -271,6 +272,7 @@ func Create(label, workspaceID, description, clusterID, runtimeVersion, dagDeplo DagDeployEnabled: dagDeployEnabled, RuntimeReleaseVersion: runtimeVersion, DeploymentSpec: spec, + APIKeyOnlyDeployments: *enforceCD, } if organization.IsOrgHosted() { @@ -316,8 +318,7 @@ func createOutput(workspaceID string, d *astro.Deployment) error { clusterName = d.Cluster.Region releaseName = notApplicable } - tab.AddRow([]string{d.Label, releaseName, clusterName, d.ID, runtimeVersionText, strconv.FormatBool(d.DagDeployEnabled)}, false) - + tab.AddRow([]string{d.Label, releaseName, clusterName, d.ID, runtimeVersionText, strconv.FormatBool(d.DagDeployEnabled), strconv.FormatBool(d.APIKeyOnlyDeployments)}, false) deploymentURL, err := GetDeploymentURL(d.ID, workspaceID) if err != nil { return err @@ -569,7 +570,7 @@ func healthPoll(deploymentID, ws string, client astro.Client) error { } } -func Update(deploymentID, label, ws, description, deploymentName, dagDeploy, executor, schedulerSize, highAvailability string, schedulerAU, schedulerReplicas int, wQueueList []astro.WorkerQueue, forceDeploy bool, client astro.Client) error { //nolint +func Update(deploymentID, label, ws, description, deploymentName, dagDeploy, executor, schedulerSize, highAvailability string, schedulerAU, schedulerReplicas int, wQueueList []astro.WorkerQueue, forceDeploy bool, enforceCD *bool, client astro.Client) error { //nolint var queueCreateUpdate, confirmWithUser bool // get deployment currentDeployment, err := GetDeployment(ws, deploymentID, deploymentName, client, nil) @@ -623,6 +624,12 @@ func Update(deploymentID, label, ws, description, deploymentName, dagDeploy, exe deploymentUpdate.Description = currentDeployment.Description } + if enforceCD == nil { + deploymentUpdate.APIKeyOnlyDeployments = currentDeployment.APIKeyOnlyDeployments + } else { + deploymentUpdate.APIKeyOnlyDeployments = *enforceCD + } + if organization.IsOrgHosted() { if schedulerSize != "" { deploymentUpdate.SchedulerSize = schedulerSize @@ -702,7 +709,7 @@ func Update(deploymentID, label, ws, description, deploymentName, dagDeploy, exe clusterName = d.Cluster.Region releaseName = notApplicable } - tabDeployment.AddRow([]string{d.Label, releaseName, clusterName, d.ID, runtimeVersionText, strconv.FormatBool(d.DagDeployEnabled)}, false) + tabDeployment.AddRow([]string{d.Label, releaseName, clusterName, d.ID, runtimeVersionText, strconv.FormatBool(d.DagDeployEnabled), strconv.FormatBool(d.APIKeyOnlyDeployments)}, false) tabDeployment.SuccessMsg = "\n Successfully updated Deployment" tabDeployment.Print(os.Stdout) } @@ -874,9 +881,9 @@ func deploymentSelectionProcess(ws string, deployments []astro.Deployment, clien schedulerAU := configOption.Components.Scheduler.AU.Default schedulerReplicas := configOption.Components.Scheduler.Replicas.Default - + cicdEnforcement := false // walk user through creating a deployment - err = createDeployment("", ws, "", "", runtimeVersion, "disable", CeleryExecutor, "", "", "medium", "", schedulerAU, schedulerReplicas, client, coreClient, false) + err = createDeployment("", ws, "", "", runtimeVersion, "disable", CeleryExecutor, "", "", "medium", "", schedulerAU, schedulerReplicas, client, coreClient, false, &cicdEnforcement) if err != nil { return astro.Deployment{}, err } diff --git a/cloud/deployment/deployment_test.go b/cloud/deployment/deployment_test.go index 31388216d..0791818db 100644 --- a/cloud/deployment/deployment_test.go +++ b/cloud/deployment/deployment_test.go @@ -19,7 +19,11 @@ import ( "github.com/stretchr/testify/mock" ) -var errMock = errors.New("mock error") +var ( + enableCiCdEnforcement = true + disableCiCdEnforcement = false + errMock = errors.New("mock error") +) const ( org = "test-org-id" @@ -188,7 +192,7 @@ func TestGetDeployment(t *testing.T) { }, }, nil).Once() // mock createDeployment - createDeployment = func(label, workspaceID, description, clusterID, runtimeVersion, dagDeploy, executor, cloudProvider, region, schedulerSize, highAvailability string, schedulerAU, schedulerReplicas int, client astro.Client, coreClient astrocore.CoreClient, waitForStatus bool) error { + createDeployment = func(label, workspaceID, description, clusterID, runtimeVersion, dagDeploy, executor, cloudProvider, region, schedulerSize, highAvailability string, schedulerAU, schedulerReplicas int, client astro.Client, coreClient astrocore.CoreClient, waitForStatus bool, apiKeyOnlyDeployments *bool) error { return errMock } @@ -231,7 +235,7 @@ func TestGetDeployment(t *testing.T) { }, }, nil).Once() // mock createDeployment - createDeployment = func(label, workspaceID, description, clusterID, runtimeVersion, dagDeploy, executor, cloudProvider, region, schedulerSize, highAvailability string, schedulerAU, schedulerReplicas int, client astro.Client, coreClient astrocore.CoreClient, waitForStatus bool) error { + createDeployment = func(label, workspaceID, description, clusterID, runtimeVersion, dagDeploy, executor, cloudProvider, region, schedulerSize, highAvailability string, schedulerAU, schedulerReplicas int, client astro.Client, coreClient astrocore.CoreClient, waitForStatus bool, apiKeyOnlyDeployments *bool) error { return nil } mockClient.On("ListDeployments", org, ws).Return([]astro.Deployment{{ID: "test-id"}}, errMock).Once() @@ -274,7 +278,7 @@ func TestGetDeployment(t *testing.T) { }, }, nil).Once() // mock createDeployment - createDeployment = func(label, workspaceID, description, clusterID, runtimeVersion, dagDeploy, executor, cloudProvider, region, schedulerSize, highAvailability string, schedulerAU, schedulerReplicas int, client astro.Client, coreClient astrocore.CoreClient, waitForStatus bool) error { + createDeployment = func(label, workspaceID, description, clusterID, runtimeVersion, dagDeploy, executor, cloudProvider, region, schedulerSize, highAvailability string, schedulerAU, schedulerReplicas int, client astro.Client, coreClient astrocore.CoreClient, waitForStatus bool, apiKeyOnlyDeployments *bool) error { return nil } @@ -539,9 +543,44 @@ func TestCreate(t *testing.T) { defer testUtil.MockUserInput(t, "test-name")() - err := Create("", ws, "test-desc", csID, "4.2.5", dagDeploy, CeleryExecutor, "", "", "", "", 10, 3, mockClient, mockCoreClient, false) + err := Create("", ws, "test-desc", csID, "4.2.5", dagDeploy, CeleryExecutor, "", "", "", "", 10, 3, mockClient, mockCoreClient, false, &disableCiCdEnforcement) + assert.NoError(t, err) + mockClient.AssertExpectations(t) + }) + t.Run("success with enabling ci-cd enforcement", func(t *testing.T) { + mockClient.On("GetDeploymentConfig").Return(astro.DeploymentConfig{ + Components: astro.Components{ + Scheduler: astro.SchedulerConfig{ + AU: astro.AuConfig{ + Default: 5, + Limit: 24, + }, + Replicas: astro.ReplicasConfig{ + Default: 1, + Minimum: 1, + Limit: 4, + }, + }, + }, + RuntimeReleases: []astro.RuntimeRelease{ + { + Version: "4.2.5", + }, + }, + }, nil).Times(2) + deploymentCreateInput.APIKeyOnlyDeployments = true + defer func() { deploymentCreateInput.APIKeyOnlyDeployments = false }() + mockClient.On("ListWorkspaces", "test-org-id").Return([]astro.Workspace{{ID: ws, OrganizationID: "test-org-id"}}, nil).Once() + mockClient.On("ListClusters", "test-org-id").Return([]astro.Cluster{{ID: csID}}, nil).Once() + mockClient.On("CreateDeployment", &deploymentCreateInput).Return(astro.Deployment{ID: "test-id"}, nil).Once() + mockClient.On("ListDeployments", org, ws).Return([]astro.Deployment{{ID: "test-id"}}, nil).Once() + + defer testUtil.MockUserInput(t, "test-name")() + + err := Create("", ws, "test-desc", csID, "4.2.5", dagDeploy, "CeleryExecutor", "", "", "", "", 10, 3, mockClient, mockCoreClient, false, &enableCiCdEnforcement) assert.NoError(t, err) mockClient.AssertExpectations(t) + mockCoreClient.AssertExpectations(t) }) t.Run("success with cloud provider and region", func(t *testing.T) { ctx, err := context.GetCurrentContext() @@ -610,7 +649,7 @@ func TestCreate(t *testing.T) { defer testUtil.MockUserInput(t, "test-name")() - err = Create("", ws, "test-desc", "", "4.2.5", dagDeploy, "KubernetesExecutor", "gcp", region, "small", "enable", 10, 3, mockClient, mockCoreClient, false) + err = Create("", ws, "test-desc", "", "4.2.5", dagDeploy, "KubernetesExecutor", "gcp", region, "small", "enable", 10, 3, mockClient, mockCoreClient, false, &disableCiCdEnforcement) assert.NoError(t, err) ctx.SetContextKey("organization_product", "HYBRID") mockClient.AssertExpectations(t) @@ -699,7 +738,7 @@ func TestCreate(t *testing.T) { mockCoreClient.On("GetSharedClusterWithResponse", mock.Anything, getSharedClusterParams).Return(mockOKResponse, nil).Once() defer testUtil.MockUserInput(t, "1")() - err = Create("test-name", ws, "test-desc", "", "4.2.5", dagDeploy, "KubernetesExecutor", "gcp", "", "small", "enable", 10, 3, mockClient, mockCoreClient, false) + err = Create("test-name", ws, "test-desc", "", "4.2.5", dagDeploy, "KubernetesExecutor", "gcp", "", "small", "enable", 10, 3, mockClient, mockCoreClient, false, &disableCiCdEnforcement) assert.NoError(t, err) ctx.SetContextKey("organization_product", "HYBRID") mockClient.AssertExpectations(t) @@ -735,7 +774,7 @@ func TestCreate(t *testing.T) { defer testUtil.MockUserInput(t, "test-name")() - err := Create("", ws, "test-desc", csID, "4.2.5", dagDeploy, "KubeExecutor", "", "", "", "", 10, 3, mockClient, mockCoreClient, false) + err := Create("", ws, "test-desc", csID, "4.2.5", dagDeploy, "KubeExecutor", "", "", "", "", 10, 3, mockClient, mockCoreClient, false, &disableCiCdEnforcement) assert.NoError(t, err) mockClient.AssertExpectations(t) mockCoreClient.AssertExpectations(t) @@ -772,7 +811,7 @@ func TestCreate(t *testing.T) { tickNum = 2 mockClient.On("ListDeployments", org, ws).Return([]astro.Deployment{{ID: "test-id", Status: "UNHEALTHY"}}, nil).Once() mockClient.On("ListDeployments", org, ws).Return([]astro.Deployment{{ID: "test-id", Status: "HEALTHY"}}, nil).Once() - err := Create("", ws, "test-desc", csID, "4.2.5", dagDeploy, CeleryExecutor, "", "", "", "", 10, 3, mockClient, mockCoreClient, true) + err := Create("", ws, "test-desc", csID, "4.2.5", dagDeploy, CeleryExecutor, "", "", "", "", 10, 3, mockClient, mockCoreClient, true, &disableCiCdEnforcement) assert.NoError(t, err) mockClient.On("ListDeployments", org, ws).Return([]astro.Deployment{{}}, nil).Once() @@ -781,7 +820,7 @@ func TestCreate(t *testing.T) { // timeout timeoutNum = 1 - err = Create("", ws, "test-desc", csID, "4.2.5", dagDeploy, CeleryExecutor, "", "", "", "", 10, 3, mockClient, mockCoreClient, true) + err = Create("", ws, "test-desc", csID, "4.2.5", dagDeploy, CeleryExecutor, "", "", "", "", 10, 3, mockClient, mockCoreClient, true, &disableCiCdEnforcement) assert.ErrorIs(t, err, errTimedOut) mockClient.AssertExpectations(t) }) @@ -813,14 +852,14 @@ func TestCreate(t *testing.T) { defer testUtil.MockUserInput(t, "test-name")() - err := Create("", ws, "test-desc", csID, "4.2.5", dagDeploy, CeleryExecutor, "", "", "", "", 10, 3, mockClient, mockCoreClient, false) + err := Create("", ws, "test-desc", csID, "4.2.5", dagDeploy, CeleryExecutor, "", "", "", "", 10, 3, mockClient, mockCoreClient, false, &disableCiCdEnforcement) assert.ErrorIs(t, err, errMock) mockClient.AssertExpectations(t) }) t.Run("failed to validate resources", func(t *testing.T) { mockClient.On("GetDeploymentConfig").Return(astro.DeploymentConfig{}, errMock).Once() - err := Create("", ws, "test-desc", csID, "4.2.5", dagDeploy, CeleryExecutor, "", "", "", "", 10, 3, mockClient, mockCoreClient, false) + err := Create("", ws, "test-desc", csID, "4.2.5", dagDeploy, CeleryExecutor, "", "", "", "", 10, 3, mockClient, mockCoreClient, false, &disableCiCdEnforcement) assert.ErrorIs(t, err, errMock) mockClient.AssertExpectations(t) }) @@ -847,7 +886,7 @@ func TestCreate(t *testing.T) { }, nil).Times(2) mockClient.On("ListWorkspaces", "test-org-id").Return([]astro.Workspace{{ID: ws, OrganizationID: "test-org-id"}}, nil).Once() mockClient.On("ListClusters", "test-org-id").Return([]astro.Cluster{}, errMock).Once() - err := Create("test-name", ws, "test-desc", "invalid-cluster-id", "4.2.5", dagDeploy, CeleryExecutor, "", "", "", "", 10, 3, mockClient, mockCoreClient, false) + err := Create("test-name", ws, "test-desc", "invalid-cluster-id", "4.2.5", dagDeploy, CeleryExecutor, "", "", "", "", 10, 3, mockClient, mockCoreClient, false, &disableCiCdEnforcement) assert.ErrorIs(t, err, errMock) mockClient.AssertExpectations(t) }) @@ -872,7 +911,7 @@ func TestCreate(t *testing.T) { }, }, }, nil).Times(1) - err := Create("", ws, "test-desc", csID, "4.2.5", dagDeploy, CeleryExecutor, "", "", "", "", 10, 5, mockClient, mockCoreClient, false) + err := Create("", ws, "test-desc", csID, "4.2.5", dagDeploy, CeleryExecutor, "", "", "", "", 10, 5, mockClient, mockCoreClient, false, &disableCiCdEnforcement) assert.NoError(t, err) }) t.Run("list workspace failure", func(t *testing.T) { @@ -898,7 +937,7 @@ func TestCreate(t *testing.T) { }, nil).Times(2) mockClient.On("ListWorkspaces", "test-org-id").Return([]astro.Workspace{}, errMock).Once() - err := Create("", ws, "test-desc", csID, "4.2.5", dagDeploy, CeleryExecutor, "", "", "", "", 10, 3, mockClient, mockCoreClient, false) + err := Create("", ws, "test-desc", csID, "4.2.5", dagDeploy, CeleryExecutor, "", "", "", "", 10, 3, mockClient, mockCoreClient, false, &disableCiCdEnforcement) assert.ErrorIs(t, err, errMock) mockClient.AssertExpectations(t) }) @@ -925,7 +964,7 @@ func TestCreate(t *testing.T) { }, nil).Times(2) mockClient.On("ListWorkspaces", "test-org-id").Return([]astro.Workspace{{ID: ws, OrganizationID: "test-org-id"}}, nil).Once() - err := Create("", "test-invalid-id", "test-desc", csID, "4.2.5", dagDeploy, CeleryExecutor, "", "", "", "", 10, 3, mockClient, mockCoreClient, false) + err := Create("", "test-invalid-id", "test-desc", csID, "4.2.5", dagDeploy, CeleryExecutor, "", "", "", "", 10, 3, mockClient, mockCoreClient, false, &disableCiCdEnforcement) assert.Error(t, err) assert.Contains(t, err.Error(), "no workspaces with id") mockClient.AssertExpectations(t) @@ -992,7 +1031,7 @@ func TestCreate(t *testing.T) { defer testUtil.MockUserInput(t, "test-name")() - err = Create("", ws, "test-desc", csID, "4.2.5", dagDeploy, CeleryExecutor, "gcp", region, "", "", 10, 3, mockClient, mockCoreClient, false) + err = Create("", ws, "test-desc", csID, "4.2.5", dagDeploy, CeleryExecutor, "gcp", region, "", "", 10, 3, mockClient, mockCoreClient, false, &disableCiCdEnforcement) assert.NoError(t, err) ctx.SetContextKey("organization_product", "HYBRID") mockClient.AssertExpectations(t) @@ -1040,7 +1079,7 @@ func TestCreate(t *testing.T) { defer testUtil.MockUserInput(t, "test-name")() - err := Create("", ws, "test-desc", csID, "4.2.5", dagDeploy, CeleryExecutor, "", "", "", "", 0, 0, mockClient, mockCoreClient, false) + err := Create("", ws, "test-desc", csID, "4.2.5", dagDeploy, CeleryExecutor, "", "", "", "", 0, 0, mockClient, mockCoreClient, false, &disableCiCdEnforcement) assert.NoError(t, err) mockClient.AssertExpectations(t) }) @@ -1275,7 +1314,7 @@ func TestUpdate(t *testing.T) { defer func() { os.Stdin = stdin }() os.Stdin = r - err = Update("test-id", "", ws, "", "", "", CeleryExecutor, "", "", 0, 0, expectedQueue, false, mockClient) + err = Update("test-id", "", ws, "", "", "", CeleryExecutor, "", "", 0, 0, expectedQueue, false, nil, mockClient) assert.NoError(t, err) // mock os.Stdin @@ -1294,7 +1333,7 @@ func TestUpdate(t *testing.T) { defer func() { os.Stdin = stdin }() os.Stdin = r - err = Update("test-id", "test-label", ws, "test description", "", "", CeleryExecutor, "", "", 5, 3, []astro.WorkerQueue{}, false, mockClient) + err = Update("test-id", "test-label", ws, "test description", "", "", CeleryExecutor, "", "", 5, 3, []astro.WorkerQueue{}, false, nil, mockClient) assert.NoError(t, err) mockClient.AssertExpectations(t) }) @@ -1384,7 +1423,7 @@ func TestUpdate(t *testing.T) { defer func() { os.Stdin = stdin }() os.Stdin = r - err = Update("test-id", "", ws, "", "", "", CeleryExecutor, "medium", "enable", 0, 0, expectedQueue, false, mockClient) + err = Update("test-id", "", ws, "", "", "", CeleryExecutor, "medium", "enable", 0, 0, expectedQueue, false, nil, mockClient) assert.NoError(t, err) // mock os.Stdin @@ -1403,7 +1442,7 @@ func TestUpdate(t *testing.T) { defer func() { os.Stdin = stdin }() os.Stdin = r - err = Update("test-id", "test-label", ws, "test description", "", "", CeleryExecutor, "small", "disable", 5, 3, []astro.WorkerQueue{}, false, mockClient) + err = Update("test-id", "test-label", ws, "test description", "", "", CeleryExecutor, "small", "disable", 5, 3, []astro.WorkerQueue{}, false, nil, mockClient) assert.NoError(t, err) mockClient.AssertExpectations(t) }) @@ -1412,7 +1451,7 @@ func TestUpdate(t *testing.T) { mockClient.On("ListDeployments", org, ws).Return([]astro.Deployment{deploymentResp}, nil).Once() mockClient.On("GetDeploymentConfig").Return(astro.DeploymentConfig{}, errMock).Once() - err := Update("test-id", "test-label", ws, "test description", "", "", CeleryExecutor, "", "", 5, 3, []astro.WorkerQueue{}, false, mockClient) + err := Update("test-id", "test-label", ws, "test description", "", "", CeleryExecutor, "", "", 5, 3, []astro.WorkerQueue{}, false, nil, mockClient) assert.ErrorIs(t, err, errMock) mockClient.AssertExpectations(t) }) @@ -1469,7 +1508,7 @@ func TestUpdate(t *testing.T) { defer func() { os.Stdin = stdin }() os.Stdin = r - err = Update("test-id", "", ws, "", "", "", CeleryExecutor, "", "", 0, 0, expectedQueue, false, mockClient) + err = Update("test-id", "", ws, "", "", "", CeleryExecutor, "", "", 0, 0, expectedQueue, false, nil, mockClient) assert.NoError(t, err) mockClient.AssertExpectations(t) }) @@ -1477,7 +1516,7 @@ func TestUpdate(t *testing.T) { t.Run("list deployments failure", func(t *testing.T) { mockClient.On("ListDeployments", org, ws).Return([]astro.Deployment{}, errMock).Once() - err := Update("test-id", "test-label", ws, "test description", "", "", CeleryExecutor, "", "", 5, 3, []astro.WorkerQueue{}, false, mockClient) + err := Update("test-id", "test-label", ws, "test description", "", "", CeleryExecutor, "", "", 5, 3, []astro.WorkerQueue{}, false, nil, mockClient) assert.ErrorIs(t, err, errMock) mockClient.AssertExpectations(t) }) @@ -1501,10 +1540,10 @@ func TestUpdate(t *testing.T) { defer func() { os.Stdin = stdin }() os.Stdin = r - err = Update("", "test-label", ws, "test description", "", "", CeleryExecutor, "", "", 5, 3, []astro.WorkerQueue{}, false, mockClient) + err = Update("", "test-label", ws, "test description", "", "", CeleryExecutor, "", "", 5, 3, []astro.WorkerQueue{}, false, nil, mockClient) assert.ErrorIs(t, err, ErrInvalidDeploymentKey) - err = Update("test-invalid-id", "test-label", ws, "test description", "", "", CeleryExecutor, "", "", 5, 3, []astro.WorkerQueue{}, false, mockClient) + err = Update("test-invalid-id", "test-label", ws, "test description", "", "", CeleryExecutor, "", "", 5, 3, []astro.WorkerQueue{}, false, nil, mockClient) assert.ErrorIs(t, err, errInvalidDeployment) mockClient.AssertExpectations(t) }) @@ -1531,7 +1570,7 @@ func TestUpdate(t *testing.T) { }, }, nil).Times(1) mockClient.On("ListDeployments", org, ws).Return([]astro.Deployment{deploymentResp}, nil).Once() - err := Update("test-id", "test-label", ws, "test-description", "", "", CeleryExecutor, "", "", 10, 5, []astro.WorkerQueue{}, true, mockClient) + err := Update("test-id", "test-label", ws, "test-description", "", "", CeleryExecutor, "", "", 10, 5, []astro.WorkerQueue{}, true, nil, mockClient) assert.NoError(t, err) mockClient.AssertExpectations(t) }) @@ -1575,7 +1614,7 @@ func TestUpdate(t *testing.T) { defer func() { os.Stdin = stdin }() os.Stdin = r - err = Update("test-id", "test-label", ws, "test description", "", "", CeleryExecutor, "", "", 5, 3, []astro.WorkerQueue{}, false, mockClient) + err = Update("test-id", "test-label", ws, "test description", "", "", CeleryExecutor, "", "", 5, 3, []astro.WorkerQueue{}, false, nil, mockClient) assert.NoError(t, err) mockClient.AssertExpectations(t) }) @@ -1604,7 +1643,7 @@ func TestUpdate(t *testing.T) { mockClient.On("ListDeployments", org, ws).Return([]astro.Deployment{deploymentResp}, nil).Once() mockClient.On("UpdateDeployment", mock.Anything).Return(astro.Deployment{}, errMock).Once() - err := Update("test-id", "", ws, "", "", "", CeleryExecutor, "", "", 0, 0, []astro.WorkerQueue{}, true, mockClient) + err := Update("test-id", "", ws, "", "", "", CeleryExecutor, "", "", 0, 0, []astro.WorkerQueue{}, true, nil, mockClient) assert.ErrorIs(t, err, errMock) assert.NotContains(t, err.Error(), astro.AstronomerConnectionErrMsg) mockClient.AssertExpectations(t) @@ -1646,7 +1685,7 @@ func TestUpdate(t *testing.T) { mockClient.On("ListDeployments", org, ws).Return([]astro.Deployment{deploymentResp}, nil).Once() mockClient.On("UpdateDeployment", &deploymentUpdateInput).Return(astro.Deployment{ID: "test-id"}, nil).Once() - err := Update("test-id", "", ws, "", "", "enable", CeleryExecutor, "", "", 5, 3, []astro.WorkerQueue{}, true, mockClient) + err := Update("test-id", "", ws, "", "", "enable", CeleryExecutor, "", "", 5, 3, []astro.WorkerQueue{}, true, nil, mockClient) assert.NoError(t, err) mockClient.AssertExpectations(t) @@ -1682,7 +1721,7 @@ func TestUpdate(t *testing.T) { } mockClient.On("ListDeployments", org, ws).Return([]astro.Deployment{deploymentResp}, nil).Once() - err := Update("test-id", "", ws, "", "", "enable", CeleryExecutor, "", "", 5, 3, []astro.WorkerQueue{}, true, mockClient) + err := Update("test-id", "", ws, "", "", "enable", CeleryExecutor, "", "", 5, 3, []astro.WorkerQueue{}, true, nil, mockClient) assert.NoError(t, err) mockClient.AssertExpectations(t) @@ -1758,16 +1797,16 @@ func TestUpdate(t *testing.T) { // force is false so we will confirm with the user defer testUtil.MockUserInput(t, "y")() - err := Update("test-id", "", ws, "", "", "disable", CeleryExecutor, "", "", 5, 3, []astro.WorkerQueue{}, false, mockClient) + err := Update("test-id", "", ws, "", "", "disable", CeleryExecutor, "", "", 5, 3, []astro.WorkerQueue{}, false, nil, mockClient) assert.NoError(t, err) // force is false so we will confirm with the user defer testUtil.MockUserInput(t, "n")() - err = Update("test-id", "", ws, "", "", "disable", CeleryExecutor, "", "", 5, 3, []astro.WorkerQueue{}, false, mockClient) + err = Update("test-id", "", ws, "", "", "disable", CeleryExecutor, "", "", 5, 3, []astro.WorkerQueue{}, false, nil, mockClient) assert.NoError(t, err) // force is true so no confirmation is needed - err = Update("test-id", "", ws, "", "", "disable", CeleryExecutor, "", "", 5, 3, []astro.WorkerQueue{}, true, mockClient) + err = Update("test-id", "", ws, "", "", "disable", CeleryExecutor, "", "", 5, 3, []astro.WorkerQueue{}, true, nil, mockClient) assert.NoError(t, err) mockClient.AssertExpectations(t) }) @@ -1802,7 +1841,7 @@ func TestUpdate(t *testing.T) { } mockClient.On("ListDeployments", org, ws).Return([]astro.Deployment{deploymentResp}, nil).Once() - err := Update("test-id", "", ws, "", "", "disable", CeleryExecutor, "", "", 5, 3, []astro.WorkerQueue{}, true, mockClient) + err := Update("test-id", "", ws, "", "", "disable", CeleryExecutor, "", "", 5, 3, []astro.WorkerQueue{}, true, nil, mockClient) assert.NoError(t, err) mockClient.AssertExpectations(t) @@ -1876,7 +1915,7 @@ func TestUpdate(t *testing.T) { mockClient.On("UpdateDeployment", &deploymentUpdateInput).Return(astro.Deployment{ID: "test-id"}, nil).Once() defer testUtil.MockUserInput(t, "y")() - err := Update("test-id", "", ws, "", "", "", KubeExecutor, "", "", 5, 3, []astro.WorkerQueue{}, true, mockClient) + err := Update("test-id", "", ws, "", "", "", KubeExecutor, "", "", 5, 3, []astro.WorkerQueue{}, true, nil, mockClient) assert.NoError(t, err) mockClient.AssertExpectations(t) }) @@ -1949,7 +1988,7 @@ func TestUpdate(t *testing.T) { mockClient.On("UpdateDeployment", &deploymentUpdateInput).Return(astro.Deployment{ID: "test-id"}, nil).Once() defer testUtil.MockUserInput(t, "y")() - err := Update("test-id", "", ws, "", "", "", CeleryExecutor, "", "", 5, 3, []astro.WorkerQueue{}, true, mockClient) + err := Update("test-id", "", ws, "", "", "", CeleryExecutor, "", "", 5, 3, []astro.WorkerQueue{}, true, nil, mockClient) assert.NoError(t, err) mockClient.AssertExpectations(t) }) @@ -2008,7 +2047,7 @@ func TestUpdate(t *testing.T) { mockClient.On("ListDeployments", org, ws).Return([]astro.Deployment{deploymentResp}, nil).Once() defer testUtil.MockUserInput(t, "n")() - err := Update("test-id", "", ws, "", "", "", CeleryExecutor, "", "", 5, 3, []astro.WorkerQueue{}, false, mockClient) + err := Update("test-id", "", ws, "", "", "", CeleryExecutor, "", "", 5, 3, []astro.WorkerQueue{}, false, nil, mockClient) assert.NoError(t, err) mockClient.AssertExpectations(t) }) @@ -2042,7 +2081,7 @@ func TestUpdate(t *testing.T) { } mockClient.On("ListDeployments", org, ws).Return([]astro.Deployment{deploymentResp}, nil).Once() - err := Update("test-id", "", ws, "", "", "disable", CeleryExecutor, "", "", 5, 3, []astro.WorkerQueue{}, true, mockClient) + err := Update("test-id", "", ws, "", "", "disable", CeleryExecutor, "", "", 5, 3, []astro.WorkerQueue{}, true, nil, mockClient) assert.NoError(t, err) mockClient.AssertExpectations(t) @@ -2077,7 +2116,7 @@ func TestUpdate(t *testing.T) { } mockClient.On("ListDeployments", org, ws).Return([]astro.Deployment{deploymentResp}, nil).Once() - err := Update("test-id", "", ws, "", "", "disable", "", "", "", 5, 3, []astro.WorkerQueue{}, true, mockClient) + err := Update("test-id", "", ws, "", "", "disable", "", "", "", 5, 3, []astro.WorkerQueue{}, true, nil, mockClient) assert.NoError(t, err) mockClient.AssertExpectations(t) diff --git a/cloud/deployment/inspect/inspect.go b/cloud/deployment/inspect/inspect.go index b0758d8de..c430e826b 100644 --- a/cloud/deployment/inspect/inspect.go +++ b/cloud/deployment/inspect/inspect.go @@ -31,15 +31,16 @@ type deploymentMetadata struct { } type deploymentConfig struct { - Name string `mapstructure:"name" yaml:"name" json:"name"` - Description string `mapstructure:"description" yaml:"description" json:"description"` - RunTimeVersion string `mapstructure:"runtime_version" yaml:"runtime_version" json:"runtime_version"` - DagDeployEnabled bool `mapstructure:"dag_deploy_enabled" yaml:"dag_deploy_enabled" json:"dag_deploy_enabled"` - Executor string `mapstructure:"executor" yaml:"executor" json:"executor"` - SchedulerAU int `mapstructure:"scheduler_au" yaml:"scheduler_au" json:"scheduler_au"` - SchedulerCount int `mapstructure:"scheduler_count" yaml:"scheduler_count" json:"scheduler_count"` - ClusterName string `mapstructure:"cluster_name" yaml:"cluster_name" json:"cluster_name"` - WorkspaceName string `mapstructure:"workspace_name" yaml:"workspace_name" json:"workspace_name"` + Name string `mapstructure:"name" yaml:"name" json:"name"` + Description string `mapstructure:"description" yaml:"description" json:"description"` + RunTimeVersion string `mapstructure:"runtime_version" yaml:"runtime_version" json:"runtime_version"` + DagDeployEnabled bool `mapstructure:"dag_deploy_enabled" yaml:"dag_deploy_enabled" json:"dag_deploy_enabled"` + APIKeyOnlyDeployments bool `mapstructure:"ci_cd_enforcement" yaml:"ci_cd_enforcement" json:"ci_cd_enforcement"` + Executor string `mapstructure:"executor" yaml:"executor" json:"executor"` + SchedulerAU int `mapstructure:"scheduler_au" yaml:"scheduler_au" json:"scheduler_au"` + SchedulerCount int `mapstructure:"scheduler_count" yaml:"scheduler_count" json:"scheduler_count"` + ClusterName string `mapstructure:"cluster_name" yaml:"cluster_name" json:"cluster_name"` + WorkspaceName string `mapstructure:"workspace_name" yaml:"workspace_name" json:"workspace_name"` } type Workerq struct { @@ -168,6 +169,7 @@ func getDeploymentConfig(sourceDeployment *astro.Deployment) map[string]interfac "cluster_name": clusterName, "runtime_version": sourceDeployment.RuntimeRelease.Version, "dag_deploy_enabled": sourceDeployment.DagDeployEnabled, + "ci_cd_enforcement": sourceDeployment.APIKeyOnlyDeployments, "scheduler_au": sourceDeployment.DeploymentSpec.Scheduler.AU, "scheduler_count": sourceDeployment.DeploymentSpec.Scheduler.Replicas, "executor": sourceDeployment.DeploymentSpec.Executor, diff --git a/cloud/deployment/inspect/inspect_test.go b/cloud/deployment/inspect/inspect_test.go index 52ffb4e88..c1de57d03 100644 --- a/cloud/deployment/inspect/inspect_test.go +++ b/cloud/deployment/inspect/inspect_test.go @@ -732,8 +732,9 @@ func TestFormatPrintableDeployment(t *testing.T) { }, }, }, - DagDeployEnabled: true, - RuntimeRelease: astro.RuntimeRelease{Version: "6.0.0", AirflowVersion: "2.4.0"}, + DagDeployEnabled: true, + APIKeyOnlyDeployments: true, + RuntimeRelease: astro.RuntimeRelease{Version: "6.0.0", AirflowVersion: "2.4.0"}, DeploymentSpec: astro.DeploymentSpec{ Executor: "CeleryExecutor", Scheduler: astro.Scheduler{ @@ -839,6 +840,7 @@ func TestFormatPrintableDeployment(t *testing.T) { release_name: great-release-name airflow_version: 2.4.0 dag_deploy_enabled: true + ci_cd_enforcement: true status: UNHEALTHY created_at: 2022-11-17T13:25:55.275697-08:00 updated_at: 2022-11-17T13:25:55.275697-08:00 @@ -891,6 +893,7 @@ func TestFormatPrintableDeployment(t *testing.T) { description: description runtime_version: 6.0.0 dag_deploy_enabled: true + ci_cd_enforcement: true executor: CeleryExecutor scheduler_au: 5 scheduler_count: 3 @@ -983,6 +986,7 @@ func TestFormatPrintableDeployment(t *testing.T) { "release_name": "great-release-name", "airflow_version": "2.4.0", "dag_deploy_enabled": true, + "ci_cd_enforcement": true, "status": "UNHEALTHY", "created_at": "2022-11-17T12:26:45.362983-08:00", "updated_at": "2022-11-17T12:26:45.362983-08:00", @@ -1042,6 +1046,7 @@ func TestFormatPrintableDeployment(t *testing.T) { "description": "description", "runtime_version": "6.0.0", "dag_deploy_enabled": true, + "ci_cd_enforcement": true, "executor": "KubernetesExecutor", "scheduler_au": 5, "scheduler_count": 3, diff --git a/cloud/deployment/workerqueue/workerqueue.go b/cloud/deployment/workerqueue/workerqueue.go index e69a74201..8790b9579 100644 --- a/cloud/deployment/workerqueue/workerqueue.go +++ b/cloud/deployment/workerqueue/workerqueue.go @@ -124,7 +124,7 @@ func CreateOrUpdate(ws, deploymentID, deploymentName, name, action, workerType s } // update the deployment with the new list of worker queues - err = deployment.Update(requestedDeployment.ID, "", ws, "", "", "", "", "", "", 0, 0, listToCreate, true, client) + err = deployment.Update(requestedDeployment.ID, "", ws, "", "", "", "", "", "", 0, 0, listToCreate, true, nil, client) if err != nil { return err } @@ -365,7 +365,7 @@ func Delete(ws, deploymentID, deploymentName, name string, force bool, client as } } // update the deployment with the new list - err = deployment.Update(requestedDeployment.ID, "", ws, "", "", "", "", "", "", 0, 0, listToDelete, true, client) + err = deployment.Update(requestedDeployment.ID, "", ws, "", "", "", "", "", "", 0, 0, listToDelete, true, nil, client) if err != nil { return err } diff --git a/cmd/cloud/deployment.go b/cmd/cloud/deployment.go index fd8234167..c11a64a9d 100644 --- a/cmd/cloud/deployment.go +++ b/cmd/cloud/deployment.go @@ -50,6 +50,8 @@ var ( region string schedulerSize string highAvailability string + deploymentCreateEnforceCD bool + deploymentUpdateEnforceCD bool deploymentVariableListExample = ` # List a deployment's variables $ astro deployment variable list --deployment-id --key FOO @@ -147,6 +149,7 @@ func newDeploymentCreateCmd(out io.Writer) *cobra.Command { cmd.Flags().StringVarP(&inputFile, "deployment-file", "", "", "Location of file containing the deployment to create. File can be in either JSON or YAML format.") cmd.Flags().BoolVarP(&waitForStatus, "wait", "i", false, "Wait for the Deployment to become healthy before ending the command") cmd.Flags().BoolVarP(&cleanOutput, "clean-output", "", false, "clean output to only include inspect yaml or json file in any situation.") + cmd.Flags().BoolVarP(&deploymentCreateEnforceCD, "enforce-cicd", "", false, "Provide this flag means deploys to deployment must use an API Key or Token. This essentially forces Deploys to happen through CI/CD") if organization.IsOrgHosted() { cmd.Flags().StringVarP(&cloudProvider, "cloud-provider", "p", "gcp", "The Cloud Provider to use for the Deployment. Possible values can be gcp.") cmd.Flags().StringVarP(®ion, "region", "", "", "The Cloud Provider region to use for the deployment.") @@ -181,6 +184,7 @@ func newDeploymentUpdateCmd(out io.Writer) *cobra.Command { cmd.Flags().StringVarP(&deploymentName, "deployment-name", "", "", "Name of the deployment to update") cmd.Flags().StringVarP(&dagDeploy, "dag-deploy", "", "", "Enables DAG-only deploys for the deployment") cmd.Flags().BoolVarP(&cleanOutput, "clean-output", "c", false, "clean output to only include inspect yaml or json file in any situation.") + cmd.Flags().BoolVarP(&deploymentUpdateEnforceCD, "enforce-cicd", "", false, "Provide this flag means deploys to deployment must use an API Key or Token. This essentially forces Deploys to happen through CI/CD. Pass enforce-cicd=false to disable this feature") if organization.IsOrgHosted() { cmd.Flags().StringVarP(&schedulerSize, "scheduler-size", "", "", "The size of Scheduler for the Deployment. Possible values can be small, medium, large") cmd.Flags().StringVarP(&highAvailability, "high-availability", "a", "", "Enables High Availability for the Deployment") @@ -371,7 +375,7 @@ func deploymentCreate(cmd *cobra.Command, _ []string, out io.Writer) error { return fmt.Errorf("%s is %w", cloudProvider, errInvalidCloudProvider) } } - return deployment.Create(label, workspaceID, description, clusterID, runtimeVersion, dagDeploy, executor, cloudProvider, region, schedulerSize, highAvailability, schedulerAU, schedulerReplicas, astroClient, astroCoreClient, waitForStatus) + return deployment.Create(label, workspaceID, description, clusterID, runtimeVersion, dagDeploy, executor, cloudProvider, region, schedulerSize, highAvailability, schedulerAU, schedulerReplicas, astroClient, astroCoreClient, waitForStatus, &deploymentCreateEnforceCD) } func deploymentUpdate(cmd *cobra.Command, args []string, out io.Writer) error { @@ -413,7 +417,11 @@ func deploymentUpdate(cmd *cobra.Command, args []string, out io.Writer) error { deploymentID = args[0] } - return deployment.Update(deploymentID, label, ws, description, deploymentName, dagDeploy, executor, schedulerSize, highAvailability, updateSchedulerAU, updateSchedulerReplicas, []astro.WorkerQueue{}, forceUpdate, astroClient) + if !cmd.Flags().Changed("enforce-cicd") { + return deployment.Update(deploymentID, label, ws, description, deploymentName, dagDeploy, executor, schedulerSize, highAvailability, updateSchedulerAU, updateSchedulerReplicas, []astro.WorkerQueue{}, forceUpdate, nil, astroClient) + } + + return deployment.Update(deploymentID, label, ws, description, deploymentName, dagDeploy, executor, schedulerSize, highAvailability, updateSchedulerAU, updateSchedulerReplicas, []astro.WorkerQueue{}, forceUpdate, &deploymentUpdateEnforceCD, astroClient) } func deploymentDelete(cmd *cobra.Command, args []string) error { diff --git a/cmd/cloud/deployment_test.go b/cmd/cloud/deployment_test.go index 15e302b65..ce5bb2aa1 100644 --- a/cmd/cloud/deployment_test.go +++ b/cmd/cloud/deployment_test.go @@ -407,7 +407,8 @@ func TestDeploymentUpdate(t *testing.T) { Executor: "CeleryExecutor", Scheduler: astro.Scheduler{AU: 5, Replicas: 3}, }, - WorkerQueues: nil, + APIKeyOnlyDeployments: false, + WorkerQueues: nil, } mockClient := new(astro_mocks.Client) @@ -430,9 +431,9 @@ func TestDeploymentUpdate(t *testing.T) { Version: "4.2.5", }, }, - }, nil).Once() - mockClient.On("ListDeployments", mock.Anything, ws).Return([]astro.Deployment{deploymentResp}, nil).Once() - mockClient.On("UpdateDeployment", &deploymentUpdateInput).Return(astro.Deployment{ID: "test-id"}, nil).Once() + }, nil).Times(3) + mockClient.On("ListDeployments", mock.Anything, ws).Return([]astro.Deployment{deploymentResp}, nil).Times(3) + mockClient.On("UpdateDeployment", &deploymentUpdateInput).Return(astro.Deployment{ID: "test-id"}, nil).Times(3) astroClient = mockClient t.Run("updates the deployment successfully", func(t *testing.T) { @@ -440,6 +441,18 @@ func TestDeploymentUpdate(t *testing.T) { _, err := execDeploymentCmd(cmdArgs...) assert.NoError(t, err) }) + t.Run("updates the deployment successfully to enable ci-cd enforcement", func(t *testing.T) { + deploymentUpdateInput.APIKeyOnlyDeployments = true + cmdArgs := []string{"update", "test-id", "--name", "test-name", "--workspace-id", ws, "--force", "--enforce-cicd"} + _, err := execDeploymentCmd(cmdArgs...) + assert.NoError(t, err) + }) + t.Run("updates the deployment successfully to disable ci-cd enforcement", func(t *testing.T) { + deploymentUpdateInput.APIKeyOnlyDeployments = false + cmdArgs := []string{"update", "test-id", "--name", "test-name", "--workspace-id", ws, "--force", "--enforce-cicd=false"} + _, err := execDeploymentCmd(cmdArgs...) + assert.NoError(t, err) + }) t.Run("returns an error if dag-deploy has an incorrect value", func(t *testing.T) { cmdArgs := []string{"update", "test-id", "--name", "test-name", "--workspace-id", ws, "--force", "--dag-deploy", "some-value"} _, err := execDeploymentCmd(cmdArgs...)