diff --git a/cmd/software/deploy.go b/cmd/software/deploy.go index 5cbb2e14b..a2ceb3a61 100644 --- a/cmd/software/deploy.go +++ b/cmd/software/deploy.go @@ -57,7 +57,7 @@ func NewDeployCmd() *cobra.Command { cmd.Flags().BoolVarP(&ignoreCacheDeploy, "no-cache", "", false, "Do not use cache when building container image") cmd.Flags().StringVar(&workspaceID, "workspace-id", "", "workspace assigned to deployment") if !context.IsCloudContext() && houston.VerifyVersionMatch(houstonVersion, houston.VersionRestrictions{GTE: "0.34.0"}) { - cmd.Flags().BoolVarP(&isDagOnlyDeploy, "dags", "", false, "Push only DAGs to your Deployment") + cmd.Flags().BoolVarP(&isDagOnlyDeploy, "dags", "d", false, "Push only DAGs to your Deployment") } return cmd } diff --git a/cmd/software/deployment.go b/cmd/software/deployment.go index 5451e5644..c1972da69 100644 --- a/cmd/software/deployment.go +++ b/cmd/software/deployment.go @@ -4,6 +4,7 @@ import ( "fmt" "io" + "github.com/astronomer/astro-cli/houston" "github.com/astronomer/astro-cli/pkg/input" "github.com/astronomer/astro-cli/software/deployment" "github.com/spf13/cobra" @@ -15,11 +16,18 @@ const ( kubernetesExecutorArg = "kubernetes" k8sExecutorArg = "k8s" - cliDeploymentHardDeletePrompt = "\nWarning: This action permanently deletes all data associated with this Deployment, including the database. You will not be able to recover it. Proceed with hard delete?" - deploymentTypeCmdMessage = "DAG Deployment mechanism: image, volume, git_sync, dag_deploy" + cliDeploymentHardDeletePrompt = "\nWarning: This action permanently deletes all data associated with this Deployment, including the database. You will not be able to recover it. Proceed with hard delete?" + deploymentTypeCmdMessage = "DAG Deployment mechanism: image, volume, git_sync, dag_deploy" + continueSubMsg = " for more details. Do you want to continue?" + CreateDeploymentWithTypeDagDeployPromptMsg = "\nthis is an experimental feature. Please use with caution. See the Software documentation at " + houston.DagDeployDocsLink + continueSubMsg + UpdateDeploymentTypeToDagDeployPromptMsg = "\nthis is an experimental feature. Please use with caution. Changing to a DAG-only Deployment will erase all of the currently deployed DAGs in this deployment. To keep running your DAGs, you must redeploy them to the deployment. See the Software documentation at " + houston.DagDeployDocsLink + continueSubMsg + UpdateDeploymentTypeFromDagDeployPromptMsg = "\nchanging from a DAG-only deployment will erase all of the currently deployed DAGs in this deployment. To keep running your DAGs, you must redeploy them to the deployment. See the Software documentation at " + houston.DeployViaCLIDocsLink + continueSubMsg + SkipUserPromptMsgForCreateDeployment = "Skip user confirmation prompt for creating a deployment with type: dag_deploy (experimental feature)" + SkipUserPromptMsgForUpdateDeployment = "Skip user confirmation prompt for updating the deployment type to/from dag_deploy (experimental feature)" ) var ( + skipPrompt bool allDeployments bool cancel bool hardDelete bool @@ -121,6 +129,8 @@ func newDeploymentCreateCmd(out io.Writer) *cobra.Command { }, } + cmd.Flags().BoolVarP(&skipPrompt, "force", "f", false, SkipUserPromptMsgForCreateDeployment) + var nfsMountDAGDeploymentEnabled, triggererEnabled, gitSyncDAGDeploymentEnabled, runtimeEnabled, dagOnlyDeployEnabled bool if appConfig != nil { nfsMountDAGDeploymentEnabled = appConfig.Flags.NfsMountDagDeployment @@ -212,6 +222,8 @@ $ astro deployment update [deployment ID] --dag-deployment-type=volume --nfs-loc }, } + cmd.Flags().BoolVarP(&skipPrompt, "force", "f", false, SkipUserPromptMsgForUpdateDeployment) + var nfsMountDAGDeploymentEnabled, triggererEnabled, gitSyncDAGDeploymentEnabled, dagOnlyDeployEnabled bool if appConfig != nil { nfsMountDAGDeploymentEnabled = appConfig.Flags.NfsMountDagDeployment @@ -374,6 +386,15 @@ func deploymentCreate(cmd *cobra.Command, out io.Writer) error { createTriggererReplicas = -1 } + // If it's a dag_deploy type, validate from the user first + if !skipPrompt && dagDeploymentType == houston.DagOnlyDeploymentType { + y, _ := input.Confirm(CreateDeploymentWithTypeDagDeployPromptMsg) + if !y { + fmt.Println("canceling deployment create..") + return nil + } + } + // we should validate only in case when this feature has been enabled if nfsMountDAGDeploymentEnabled || gitSyncDAGDeploymentEnabled || dagOnlyDeployEnabled { err = validateDagDeploymentArgs(dagDeploymentType, nfsLocation, gitRepoURL, false) @@ -453,6 +474,32 @@ func deploymentUpdate(cmd *cobra.Command, args []string, dagDeploymentType, nfsL dagOnlyDeployEnabled = appConfig.Flags.DagOnlyDeployment } + // new dag deployment type or current dag deployment type is dag_deploy, confirm from user + if !skipPrompt { + deploymentInfo, err := houston.Call(houstonClient.GetDeployment)(args[0]) + if err != nil { + return fmt.Errorf("failed to get deployment info: %w", err) + } + + // non dag_deploy to dag_deploy + if deploymentInfo.DagDeployment.Type != houston.DagOnlyDeploymentType && dagDeploymentType == houston.DagOnlyDeploymentType { + y, _ := input.Confirm(UpdateDeploymentTypeToDagDeployPromptMsg) + if !y { + fmt.Println("canceling deployment update..") + return nil + } + } + + // dag_deploy to non dag_deploy + if deploymentInfo.DagDeployment.Type == houston.DagOnlyDeploymentType && dagDeploymentType != houston.DagOnlyDeploymentType { + y, _ := input.Confirm(UpdateDeploymentTypeFromDagDeployPromptMsg) + if !y { + fmt.Println("canceling deployment update..") + return nil + } + } + } + // we should validate only in case when this feature has been enabled if nfsMountDAGDeploymentEnabled || gitSyncDAGDeploymentEnabled || dagOnlyDeployEnabled { err := validateDagDeploymentArgs(dagDeploymentType, nfsLocation, gitRepoURL, true) diff --git a/cmd/software/deployment_test.go b/cmd/software/deployment_test.go index 288f84b21..5af035bea 100644 --- a/cmd/software/deployment_test.go +++ b/cmd/software/deployment_test.go @@ -2,6 +2,7 @@ package software import ( "bytes" + "errors" "os" "testing" "time" @@ -256,8 +257,8 @@ func TestDeploymentCreateCommandDagOnlyDeployEnabled(t *testing.T) { expectedOutput string expectedError string }{ - {cmdArgs: []string{"create", "--label=new-deployment-name", "--executor=celery", "--dag-deployment-type=dag_deploy"}, expectedOutput: "Successfully created deployment with Celery executor. Deployment can be accessed at the following URLs", expectedError: ""}, - {cmdArgs: []string{"create", "--label=new-deployment-name", "--executor=celery", "--dag-deployment-type=dummy"}, expectedOutput: "", expectedError: ErrInvalidDAGDeploymentType.Error()}, + {cmdArgs: []string{"create", "--label=new-deployment-name", "--executor=celery", "--dag-deployment-type=dag_deploy", "--force"}, expectedOutput: "Successfully created deployment with Celery executor. Deployment can be accessed at the following URLs", expectedError: ""}, + {cmdArgs: []string{"create", "--label=new-deployment-name", "--executor=celery", "--dag-deployment-type=dummy", "--force"}, expectedOutput: "", expectedError: ErrInvalidDAGDeploymentType.Error()}, } for _, tt := range myTests { houstonClient = api @@ -301,24 +302,415 @@ func TestDeploymentCreateCommandGitSyncDisabled(t *testing.T) { } } -func TestDeploymentUpdateTriggererEnabledCommand(t *testing.T) { +func TestDeploymentCreateWithTypeDagDeploy(t *testing.T) { + t.Run("user should not be prompted if deployment type is not dag_deploy", func(t *testing.T) { + testUtil.InitTestConfig(testUtil.SoftwarePlatform) + appConfig = &houston.AppConfig{ + TriggererEnabled: true, + Flags: houston.FeatureFlags{ + TriggererEnabled: true, + }, + } + api := new(mocks.ClientInterface) + api.On("GetAppConfig", nil).Return(appConfig, nil) + api.On("CreateDeployment", mock.Anything).Return(mockDeployment, nil) + + cmdArgs := []string{"create", "--label=new-deployment-name", "--executor=celery", "--triggerer-replicas=1"} + expectedOutput := "Successfully created deployment with Celery executor. Deployment can be accessed at the following URLs" + houstonClient = api + output, err := execDeploymentCmd(cmdArgs...) + assert.NoError(t, err) + assert.Contains(t, output, expectedOutput) + api.AssertExpectations(t) + }) + + t.Run("user should not be prompted if deployment type is dag_deploy but -f flag is sent", func(t *testing.T) { + testUtil.InitTestConfig(testUtil.SoftwarePlatform) + appConfig = &houston.AppConfig{ + TriggererEnabled: true, + Flags: houston.FeatureFlags{ + TriggererEnabled: true, + DagOnlyDeployment: true, + }, + } + api := new(mocks.ClientInterface) + api.On("GetAppConfig", nil).Return(appConfig, nil) + api.On("CreateDeployment", mock.Anything).Return(mockDeployment, nil) + + cmdArgs := []string{"create", "--label=new-deployment-name", "--executor=celery", "--dag-deployment-type=dag_deploy", "--triggerer-replicas=1", "--force"} + expectedOutput := "Successfully created deployment with Celery executor. Deployment can be accessed at the following URLs" + houstonClient = api + output, err := execDeploymentCmd(cmdArgs...) + assert.NoError(t, err) + assert.Contains(t, output, expectedOutput) + api.AssertExpectations(t) + }) + + t.Run("user should be prompted if deployment type is dag_deploy and -f flag is not sent. No deployment is created without confirmation.", func(t *testing.T) { + testUtil.InitTestConfig(testUtil.SoftwarePlatform) + appConfig = &houston.AppConfig{ + TriggererEnabled: true, + Flags: houston.FeatureFlags{ + TriggererEnabled: true, + DagOnlyDeployment: true, + }, + } + + api := new(mocks.ClientInterface) + api.On("GetAppConfig", nil).Return(appConfig, nil) + api.On("CreateDeployment", mock.Anything).Return(mockDeployment, nil) + cmdArgs := []string{"create", "--label=new-deployment-name", "--executor=celery", "--dag-deployment-type=dag_deploy", "--triggerer-replicas=1"} + houstonClient = api + + // mock os.Stdin + input := []byte("1") + r, w, err := os.Pipe() + if err != nil { + t.Fatal(err) + } + _, err = w.Write(input) + if err != nil { + t.Error(err) + } + w.Close() + stdin := os.Stdin + // Restore stdin right after the test. + defer func() { os.Stdin = stdin }() + os.Stdin = r + defer testUtil.MockUserInput(t, "n")() + + _, err = execDeploymentCmd(cmdArgs...) + assert.NoError(t, err) + // Houston CreateDeployment API should not be called if user does not confirm the prompt + api.AssertNotCalled(t, "CreateDeployment", mock.Anything) + }) + + t.Run("user should be prompted if deployment type is dag_deploy and -f flag is not sent. Deployment is created with confirmation.", func(t *testing.T) { + testUtil.InitTestConfig(testUtil.SoftwarePlatform) + appConfig = &houston.AppConfig{ + TriggererEnabled: true, + Flags: houston.FeatureFlags{ + TriggererEnabled: true, + DagOnlyDeployment: true, + }, + } + + api := new(mocks.ClientInterface) + api.On("GetAppConfig", nil).Return(appConfig, nil) + api.On("CreateDeployment", mock.Anything).Return(mockDeployment, nil) + cmdArgs := []string{"create", "--label=new-deployment-name", "--executor=celery", "--dag-deployment-type=dag_deploy", "--triggerer-replicas=1"} + houstonClient = api + + // mock os.Stdin + input := []byte("1") + r, w, err := os.Pipe() + if err != nil { + t.Fatal(err) + } + _, err = w.Write(input) + if err != nil { + t.Error(err) + } + w.Close() + stdin := os.Stdin + // Restore stdin right after the test. + defer func() { os.Stdin = stdin }() + os.Stdin = r + defer testUtil.MockUserInput(t, "y")() + + _, err = execDeploymentCmd(cmdArgs...) + assert.NoError(t, err) + // Houston CreateDeployment API should be called if user confirms the prompt + api.AssertCalled(t, "CreateDeployment", mock.Anything) + }) +} + +func TestDeploymentUpdateWithTypeDagDeploy(t *testing.T) { + t.Run("user should not be prompted if new deployment type is not dag_deploy", func(t *testing.T) { + testUtil.InitTestConfig(testUtil.SoftwarePlatform) + appConfig = &houston.AppConfig{ + Flags: houston.FeatureFlags{ + DagOnlyDeployment: true, + }, + } + + api := new(mocks.ClientInterface) + api.On("GetAppConfig", nil).Return(appConfig, nil) + api.On("UpdateDeployment", mock.Anything).Return(mockDeployment, nil) + dagDeployment := &houston.DagDeploymentConfig{ + Type: houston.ImageDeploymentType, + } + deployment := &houston.Deployment{ + DagDeployment: *dagDeployment, + } + api.On("GetDeployment", mock.Anything).Return(deployment, nil).Once() + cmdArgs := []string{"update", "cknrml96n02523xr97ygj95n5", "--label=test22222", "--dag-deployment-type=image"} + houstonClient = api + output, err := execDeploymentCmd(cmdArgs...) + assert.NoError(t, err) + assert.Contains(t, output, "Successfully updated deployment") + }) + + t.Run("GetDeployment throws an error", func(t *testing.T) { + testUtil.InitTestConfig(testUtil.SoftwarePlatform) + appConfig = &houston.AppConfig{ + Flags: houston.FeatureFlags{ + DagOnlyDeployment: true, + }, + } + + api := new(mocks.ClientInterface) + api.On("GetAppConfig", nil).Return(appConfig, nil) + api.On("UpdateDeployment", mock.Anything).Return(mockDeployment, nil) + getDeploymentError := errors.New("Test error") + api.On("GetDeployment", mock.Anything).Return(nil, getDeploymentError).Once() + cmdArgs := []string{"update", "cknrml96n02523xr97ygj95n5", "--label=test22222", "--dag-deployment-type=dag_deploy"} + houstonClient = api + _, err := execDeploymentCmd(cmdArgs...) + assert.EqualError(t, err, "failed to get deployment info: "+getDeploymentError.Error()) + }) + + t.Run("user should not be prompted if new deployment type is dag_deploy and current deployment type is also dag_deploy", func(t *testing.T) { + testUtil.InitTestConfig(testUtil.SoftwarePlatform) + appConfig = &houston.AppConfig{ + Flags: houston.FeatureFlags{ + DagOnlyDeployment: true, + }, + } + + api := new(mocks.ClientInterface) + api.On("GetAppConfig", nil).Return(appConfig, nil) + api.On("UpdateDeployment", mock.Anything).Return(mockDeployment, nil) + dagDeployment := &houston.DagDeploymentConfig{ + Type: houston.DagOnlyDeploymentType, + } + deployment := &houston.Deployment{ + DagDeployment: *dagDeployment, + } + api.On("GetDeployment", mock.Anything).Return(deployment, nil).Once() + cmdArgs := []string{"update", "cknrml96n02523xr97ygj95n5", "--label=test22222", "--dag-deployment-type=dag_deploy"} + houstonClient = api + output, err := execDeploymentCmd(cmdArgs...) + assert.NoError(t, err) + assert.Contains(t, output, "Successfully updated deployment") + }) + + t.Run("user should be prompted if new deployment type is dag_deploy and current deployment type is not dag_deploy. User rejects.", func(t *testing.T) { + testUtil.InitTestConfig(testUtil.SoftwarePlatform) + appConfig = &houston.AppConfig{ + Flags: houston.FeatureFlags{ + DagOnlyDeployment: true, + }, + } + + api := new(mocks.ClientInterface) + api.On("GetAppConfig", nil).Return(appConfig, nil) + api.On("UpdateDeployment", mock.Anything).Return(mockDeployment, nil) + dagDeployment := &houston.DagDeploymentConfig{ + Type: houston.ImageDeploymentType, + } + deployment := &houston.Deployment{ + DagDeployment: *dagDeployment, + } + api.On("GetDeployment", mock.Anything).Return(deployment, nil).Once() + cmdArgs := []string{"update", "cknrml96n02523xr97ygj95n5", "--label=test22222", "--dag-deployment-type=dag_deploy"} + houstonClient = api + + // mock os.Stdin + input := []byte("1") + r, w, err := os.Pipe() + if err != nil { + t.Fatal(err) + } + _, err = w.Write(input) + if err != nil { + t.Error(err) + } + w.Close() + stdin := os.Stdin + // Restore stdin right after the test. + defer func() { os.Stdin = stdin }() + os.Stdin = r + defer testUtil.MockUserInput(t, "n")() + + _, err = execDeploymentCmd(cmdArgs...) + assert.NoError(t, err) + api.AssertCalled(t, "GetDeployment", mock.Anything) + // Houston UpdateDeployment API should not be called if user does not confirm the prompt + api.AssertNotCalled(t, "UpdateDeployment", mock.Anything) + }) + + t.Run("user should be prompted if new deployment type is dag_deploy and current deployment type is not dag_deploy. User confirms.", func(t *testing.T) { + testUtil.InitTestConfig(testUtil.SoftwarePlatform) + appConfig = &houston.AppConfig{ + Flags: houston.FeatureFlags{ + DagOnlyDeployment: true, + }, + } + + api := new(mocks.ClientInterface) + api.On("GetAppConfig", nil).Return(appConfig, nil) + api.On("UpdateDeployment", mock.Anything).Return(mockDeployment, nil) + dagDeployment := &houston.DagDeploymentConfig{ + Type: houston.ImageDeploymentType, + } + deployment := &houston.Deployment{ + DagDeployment: *dagDeployment, + } + api.On("GetDeployment", mock.Anything).Return(deployment, nil).Once() + cmdArgs := []string{"update", "cknrml96n02523xr97ygj95n5", "--label=test22222", "--dag-deployment-type=dag_deploy"} + houstonClient = api + + // mock os.Stdin + input := []byte("1") + r, w, err := os.Pipe() + if err != nil { + t.Fatal(err) + } + _, err = w.Write(input) + if err != nil { + t.Error(err) + } + w.Close() + stdin := os.Stdin + // Restore stdin right after the test. + defer func() { os.Stdin = stdin }() + os.Stdin = r + defer testUtil.MockUserInput(t, "y")() + + _, err = execDeploymentCmd(cmdArgs...) + assert.NoError(t, err) + api.AssertCalled(t, "GetDeployment", mock.Anything) + // Houston UpdateDeployment API should be called if user confirms the prompt + api.AssertCalled(t, "UpdateDeployment", mock.Anything) + }) +} + +func TestDeploymentUpdateFromTypeDagDeployToNonDagDeploy(t *testing.T) { + t.Run("user should be prompted if new deployment type is not dag_deploy but current type is dag_deploy. User rejects.", func(t *testing.T) { + testUtil.InitTestConfig(testUtil.SoftwarePlatform) + appConfig = &houston.AppConfig{ + Flags: houston.FeatureFlags{ + DagOnlyDeployment: true, + }, + } + api := new(mocks.ClientInterface) + api.On("UpdateDeployment", mock.Anything).Return(mockDeployment, nil) + dagDeployment := &houston.DagDeploymentConfig{ + Type: houston.DagOnlyDeploymentType, + } + deployment := &houston.Deployment{ + DagDeployment: *dagDeployment, + } + api.On("GetDeployment", mock.Anything).Return(deployment, nil).Once() + cmdArgs := []string{"update", "cknrml96n02523xr97ygj95n5", "--label=test22222", "--dag-deployment-type=image"} + houstonClient = api + + // mock os.Stdin + input := []byte("1") + r, w, err := os.Pipe() + if err != nil { + t.Fatal(err) + } + _, err = w.Write(input) + if err != nil { + t.Error(err) + } + w.Close() + stdin := os.Stdin + // Restore stdin right after the test. + defer func() { os.Stdin = stdin }() + os.Stdin = r + defer testUtil.MockUserInput(t, "n")() + + _, err = execDeploymentCmd(cmdArgs...) + assert.NoError(t, err) + api.AssertCalled(t, "GetDeployment", mock.Anything) + // Houston UpdateDeployment API should not be called if user does not confirm the prompt + api.AssertNotCalled(t, "UpdateDeployment", mock.Anything) + }) + + t.Run("user should be prompted if new deployment type is not dag_deploy but current type is dag_deploy. User confirms.", func(t *testing.T) { + testUtil.InitTestConfig(testUtil.SoftwarePlatform) + appConfig = &houston.AppConfig{ + Flags: houston.FeatureFlags{ + DagOnlyDeployment: true, + }, + } + + api := new(mocks.ClientInterface) + api.On("GetAppConfig", nil).Return(appConfig, nil) + api.On("UpdateDeployment", mock.Anything).Return(mockDeployment, nil) + dagDeployment := &houston.DagDeploymentConfig{ + Type: houston.DagOnlyDeploymentType, + } + deployment := &houston.Deployment{ + DagDeployment: *dagDeployment, + } + api.On("GetDeployment", mock.Anything).Return(deployment, nil).Once() + cmdArgs := []string{"update", "cknrml96n02523xr97ygj95n5", "--label=test22222", "--dag-deployment-type=image"} + houstonClient = api + + // mock os.Stdin + input := []byte("1") + r, w, err := os.Pipe() + if err != nil { + t.Fatal(err) + } + _, err = w.Write(input) + if err != nil { + t.Error(err) + } + w.Close() + stdin := os.Stdin + // Restore stdin right after the test. + defer func() { os.Stdin = stdin }() + os.Stdin = r + defer testUtil.MockUserInput(t, "y")() + + _, err = execDeploymentCmd(cmdArgs...) + assert.NoError(t, err) + api.AssertCalled(t, "GetDeployment", mock.Anything) + // Houston UpdateDeployment API should be called if user does not confirm the prompt + api.AssertCalled(t, "UpdateDeployment", mock.Anything) + }) +} + +func TestDeploymentUpdateCommand(t *testing.T) { testUtil.InitTestConfig(testUtil.SoftwarePlatform) appConfig = &houston.AppConfig{ - TriggererEnabled: true, - Flags: houston.FeatureFlags{TriggererEnabled: true}, + NfsMountDagDeployment: true, + Flags: houston.FeatureFlags{ + NfsMountDagDeployment: true, + GitSyncEnabled: true, + }, } api := new(mocks.ClientInterface) api.On("GetAppConfig", nil).Return(appConfig, nil) - api.On("UpdateDeployment", mock.Anything).Return(mockDeployment, nil).Twice() + api.On("UpdateDeployment", mock.Anything).Return(mockDeployment, nil).Times(8) + dagDeployment := &houston.DagDeploymentConfig{ + Type: houston.ImageDeploymentType, + } + deployment := &houston.Deployment{ + DagDeployment: *dagDeployment, + } + api.On("GetDeployment", mock.Anything).Return(deployment, nil).Times(9) myTests := []struct { cmdArgs []string expectedOutput string expectedError string }{ - {cmdArgs: []string{"update", "cknrml96n02523xr97ygj95n5", "--label=test22222", "--triggerer-replicas=1"}, expectedOutput: "Successfully updated deployment", expectedError: ""}, - {cmdArgs: []string{"update", "cknrml96n02523xr97ygj95n5", "--label=test22222"}, expectedOutput: "Successfully updated deployment", expectedError: ""}, + {cmdArgs: []string{"update", "cknrml96n02523xr97ygj95n5", "--label=test22222", "--dag-deployment-type=volume", "--nfs-location=test:/test"}, expectedOutput: "Successfully updated deployment", expectedError: ""}, + {cmdArgs: []string{"update", "cknrml96n02523xr97ygj95n5", "--label=test22222", "--dag-deployment-type=git_sync", "--git-repository-url=https://github.com/bote795/public-ariflow-dags-test.git", "--dag-directory-path=dagscopy/", "--git-branch-name=main", "--sync-interval=200"}, expectedOutput: "Successfully updated deployment", expectedError: ""}, + {cmdArgs: []string{"update", "cknrml96n02523xr97ygj95n5", "--label=test22222", "--dag-deployment-type=git_sync", "-u=https://github.com/bote795/public-ariflow-dags-test.git", "-p=dagscopy/", "-b=main", "-s=200"}, expectedOutput: "Successfully updated deployment", expectedError: ""}, + {cmdArgs: []string{"update", "cknrml96n02523xr97ygj95n5", "--label=test22222", "--dag-deployment-type=git_sync", "--git-repository-url=git@github.com:bote795/private-ariflow-dags-test.git", "--dag-directory-path=dagscopy/", "--git-branch-name=main", "--ssh-key=./testfiles/ssh_key", "--known-hosts=./testfiles/known_hosts"}, expectedOutput: "Successfully updated deployment", expectedError: ""}, + {cmdArgs: []string{"update", "cknrml96n02523xr97ygj95n5", "--label=test22222", "--dag-deployment-type=git_sync", "--git-repository-url=git@github.com:neel-astro/private-airflow-dags-test.git", "--dag-directory-path=dagscopy/", "--git-branch-name=main", "--ssh-key=./testfiles/ssh_key", "--known-hosts=./testfiles/known_hosts"}, expectedOutput: "Successfully updated deployment", expectedError: ""}, + {cmdArgs: []string{"update", "cknrml96n02523xr97ygj95n5", "--label=test22222", "--dag-deployment-type=git_sync", "--git-repository-url=git@github.com:neel-astro/private-airflow-dags-test.git", "--ssh-key=./testfiles/ssh_key", "--known-hosts=./testfiles/known_hosts"}, expectedOutput: "Successfully updated deployment", expectedError: ""}, + {cmdArgs: []string{"update", "cknrml96n02523xr97ygj95n5", "--label=test22222", "--dag-deployment-type=wrong", "--nfs-location=test:/test"}, expectedOutput: "", expectedError: ErrInvalidDAGDeploymentType.Error()}, + {cmdArgs: []string{"update", "cknrml96n02523xr97ygj95n5", "--label=test22222", "--executor=local"}, expectedOutput: "Successfully updated deployment", expectedError: ""}, + {cmdArgs: []string{"update", "cknrml96n02523xr97ygj95n5", "--cloud-role=arn:aws:iam::1234567890:role/test_role4c2301381e"}, expectedOutput: "Successfully updated deployment", expectedError: ""}, } for _, tt := range myTests { houstonClient = api @@ -332,34 +724,30 @@ func TestDeploymentUpdateTriggererEnabledCommand(t *testing.T) { } } -func TestDeploymentUpdateCommand(t *testing.T) { +func TestDeploymentUpdateTriggererEnabledCommand(t *testing.T) { testUtil.InitTestConfig(testUtil.SoftwarePlatform) appConfig = &houston.AppConfig{ - NfsMountDagDeployment: true, - Flags: houston.FeatureFlags{ - NfsMountDagDeployment: true, - GitSyncEnabled: true, - }, + TriggererEnabled: true, + Flags: houston.FeatureFlags{TriggererEnabled: true}, } api := new(mocks.ClientInterface) api.On("GetAppConfig", nil).Return(appConfig, nil) - api.On("UpdateDeployment", mock.Anything).Return(mockDeployment, nil).Times(8) - + api.On("UpdateDeployment", mock.Anything).Return(mockDeployment, nil).Twice() + dagDeployment := &houston.DagDeploymentConfig{ + Type: houston.ImageDeploymentType, + } + deployment := &houston.Deployment{ + DagDeployment: *dagDeployment, + } + api.On("GetDeployment", mock.Anything).Return(deployment, nil).Times(2) myTests := []struct { cmdArgs []string expectedOutput string expectedError string }{ - {cmdArgs: []string{"update", "cknrml96n02523xr97ygj95n5", "--label=test22222", "--dag-deployment-type=volume", "--nfs-location=test:/test"}, expectedOutput: "Successfully updated deployment", expectedError: ""}, - {cmdArgs: []string{"update", "cknrml96n02523xr97ygj95n5", "--label=test22222", "--dag-deployment-type=git_sync", "--git-repository-url=https://github.com/bote795/public-ariflow-dags-test.git", "--dag-directory-path=dagscopy/", "--git-branch-name=main", "--sync-interval=200"}, expectedOutput: "Successfully updated deployment", expectedError: ""}, - {cmdArgs: []string{"update", "cknrml96n02523xr97ygj95n5", "--label=test22222", "--dag-deployment-type=git_sync", "-u=https://github.com/bote795/public-ariflow-dags-test.git", "-p=dagscopy/", "-b=main", "-s=200"}, expectedOutput: "Successfully updated deployment", expectedError: ""}, - {cmdArgs: []string{"update", "cknrml96n02523xr97ygj95n5", "--label=test22222", "--dag-deployment-type=git_sync", "--git-repository-url=git@github.com:bote795/private-ariflow-dags-test.git", "--dag-directory-path=dagscopy/", "--git-branch-name=main", "--ssh-key=./testfiles/ssh_key", "--known-hosts=./testfiles/known_hosts"}, expectedOutput: "Successfully updated deployment", expectedError: ""}, - {cmdArgs: []string{"update", "cknrml96n02523xr97ygj95n5", "--label=test22222", "--dag-deployment-type=git_sync", "--git-repository-url=git@github.com:neel-astro/private-airflow-dags-test.git", "--dag-directory-path=dagscopy/", "--git-branch-name=main", "--ssh-key=./testfiles/ssh_key", "--known-hosts=./testfiles/known_hosts"}, expectedOutput: "Successfully updated deployment", expectedError: ""}, - {cmdArgs: []string{"update", "cknrml96n02523xr97ygj95n5", "--label=test22222", "--dag-deployment-type=git_sync", "--git-repository-url=git@github.com:neel-astro/private-airflow-dags-test.git", "--ssh-key=./testfiles/ssh_key", "--known-hosts=./testfiles/known_hosts"}, expectedOutput: "Successfully updated deployment", expectedError: ""}, - {cmdArgs: []string{"update", "cknrml96n02523xr97ygj95n5", "--label=test22222", "--dag-deployment-type=wrong", "--nfs-location=test:/test"}, expectedOutput: "", expectedError: ErrInvalidDAGDeploymentType.Error()}, - {cmdArgs: []string{"update", "cknrml96n02523xr97ygj95n5", "--label=test22222", "--executor=local"}, expectedOutput: "Successfully updated deployment", expectedError: ""}, - {cmdArgs: []string{"update", "cknrml96n02523xr97ygj95n5", "--cloud-role=arn:aws:iam::1234567890:role/test_role4c2301381e"}, expectedOutput: "Successfully updated deployment", expectedError: ""}, + {cmdArgs: []string{"update", "cknrml96n02523xr97ygj95n5", "--label=test22222", "--triggerer-replicas=1"}, expectedOutput: "Successfully updated deployment", expectedError: ""}, + {cmdArgs: []string{"update", "cknrml96n02523xr97ygj95n5", "--label=test22222"}, expectedOutput: "Successfully updated deployment", expectedError: ""}, } for _, tt := range myTests { houstonClient = api @@ -386,7 +774,13 @@ func TestDeploymentUpdateCommandGitSyncDisabled(t *testing.T) { api := new(mocks.ClientInterface) api.On("GetAppConfig", nil).Return(appConfig, nil) api.On("UpdateDeployment", mock.Anything).Return(mockDeployment, nil) - + dagDeployment := &houston.DagDeploymentConfig{ + Type: houston.ImageDeploymentType, + } + deployment := &houston.Deployment{ + DagDeployment: *dagDeployment, + } + api.On("GetDeployment", mock.Anything).Return(deployment, nil).Times(2) myTests := []struct { cmdArgs []string expectedOutput string @@ -424,8 +818,8 @@ func TestDeploymentUpdateCommandDagOnlyDeployEnabled(t *testing.T) { expectedOutput string expectedError string }{ - {cmdArgs: []string{"update", "cknrml96n02523xr97ygj95n5", "--label=test22222", "--dag-deployment-type=dag_deploy"}, expectedOutput: "Successfully updated deployment", expectedError: ""}, - {cmdArgs: []string{"update", "cknrml96n02523xr97ygj95n5", "--label=test22222", "--dag-deployment-type=invalid"}, expectedOutput: "", expectedError: ErrInvalidDAGDeploymentType.Error()}, + {cmdArgs: []string{"update", "cknrml96n02523xr97ygj95n5", "--label=test22222", "--dag-deployment-type=dag_deploy", "--force"}, expectedOutput: "Successfully updated deployment", expectedError: ""}, + {cmdArgs: []string{"update", "cknrml96n02523xr97ygj95n5", "--label=test22222", "--dag-deployment-type=invalid", "--force"}, expectedOutput: "", expectedError: ErrInvalidDAGDeploymentType.Error()}, } for _, tt := range myTests { houstonClient = api diff --git a/houston/constants.go b/houston/constants.go index 0b424478a..32a6470a1 100644 --- a/houston/constants.go +++ b/houston/constants.go @@ -26,4 +26,7 @@ const ( VolumeDeploymentType = "volume" ImageDeploymentType = "image" DagOnlyDeploymentType = "dag_deploy" + + DagDeployDocsLink = "https://docs.astronomer.io/software/deploy-dags/" + DeployViaCLIDocsLink = "https://docs.astronomer.io/software/deploy-cli/" )