Skip to content

Commit

Permalink
Software backward compatible with CLI (#703)
Browse files Browse the repository at this point in the history
* base code for supporting multiple platform version

* added logic at command, flag and query level

* merge branch main into software-backward-compatible

* add unit tests

* fixed linting and moved away from decorator in houston

* merge branch main into software-backward-compatible-2

* added more tests to houston package

* updated help response and cases for astro dev init cmd

* updated help templates

* updated help templates

* moved to houston decorator

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* added tests to get up the coverage

* Fix workspace user id field name typo

* Fix teams command availability

* Fix deployment update api for 0.25.x platform version

* fix getAppConfig api logic for 0.25 houston

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
neel-astro and pre-commit-ci[bot] committed Nov 14, 2022
1 parent 066e35d commit f9557e4
Show file tree
Hide file tree
Showing 81 changed files with 3,023 additions and 1,809 deletions.
12 changes: 6 additions & 6 deletions airflow/mocks/ContainerHandler.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 14 additions & 4 deletions cmd/airflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/astronomer/astro-cli/cmd/utils"
"github.com/astronomer/astro-cli/config"
"github.com/astronomer/astro-cli/context"
"github.com/astronomer/astro-cli/houston"
"github.com/astronomer/astro-cli/pkg/fileutil"
"github.com/astronomer/astro-cli/pkg/httputil"
"github.com/astronomer/astro-cli/pkg/input"
Expand Down Expand Up @@ -130,16 +131,25 @@ func newAirflowInitCmd() *cobra.Command {
RunE: airflowInit,
}
cmd.Flags().StringVarP(&projectName, "name", "n", "", "Name of Astro project")
cmd.Flags().StringVarP(&runtimeVersion, "runtime-version", "v", "", "Specify a version of Astro Runtime that you want to create an Astro project with. If not specified, the latest is assumed. You can change this version in your Dockerfile at any time.")
cmd.Flags().StringVarP(&airflowVersion, "airflow-version", "a", "", "Version of Airflow you want to create an Astro project with. If not specified, latest is assumed. You can change this version in your Dockerfile at any time.")
var err error
var avoidACFlag bool

// In case user is connected to Astronomer Platform and is connected to older version of platform
if context.IsCloudContext() || houstonVersion == "" || (!context.IsCloudContext() && houston.VerifyVersionMatch(houstonVersion, houston.VersionRestrictions{GTE: "0.29.0"})) {
cmd.Flags().StringVarP(&runtimeVersion, "runtime-version", "v", "", "Specify a version of Astro Runtime that you want to create an Astro project with. If not specified, the latest is assumed. You can change this version in your Dockerfile at any time.")
} else { // default to using AC flag, since runtime is not available for these cases
useAstronomerCertified = true
avoidACFlag = true
}

if !context.IsCloudContext() {
if !context.IsCloudContext() && !avoidACFlag {
cmd.Example = initSoftwareExample
cmd.Flags().BoolVarP(&useAstronomerCertified, "use-astronomer-certified", "", false, "If specified, initializes a project using Astronomer Certified Airflow image instead of Astro Runtime.")
}

_, err := context.GetCurrentContext()
if err != nil { // Case when user is not logged in to any platform
_, err = context.GetCurrentContext()
if err != nil && !avoidACFlag { // Case when user is not logged in to any platform
cmd.Flags().BoolVarP(&useAstronomerCertified, "use-astronomer-certified", "", false, "If specified, initializes a project using Astronomer Certified Airflow image instead of Astro Runtime.")
_ = cmd.Flags().MarkHidden("use-astronomer-certified")
}
Expand Down
56 changes: 52 additions & 4 deletions cmd/airflow_test.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package cmd

import (
"bytes"
"errors"
"io"
"os"
"strings"
"testing"
"time"

"github.com/astronomer/astro-cli/airflow"
"github.com/astronomer/astro-cli/airflow/mocks"
Expand Down Expand Up @@ -38,6 +40,52 @@ func TestDevInitCommand(t *testing.T) {
assert.Contains(t, output, "--use-astronomer-certified")
}

func TestDevInitCommandSoftware(t *testing.T) {
testUtil.InitTestConfig(testUtil.SoftwarePlatform)

t.Run("unknown software version", func(t *testing.T) {
houstonVersion = ""
cmd := newAirflowInitCmd()
buf := new(bytes.Buffer)
cmd.SetOut(buf)
cmd.SetArgs([]string{"dev", "init", "--help"})
_, err := cmd.ExecuteC()
output := buf.String()
assert.NoError(t, err)
assert.Contains(t, output, "astro dev", output)
assert.Contains(t, output, "--use-astronomer-certified")
assert.Contains(t, output, "--runtime-version string")
})

t.Run("0.28.0 software version", func(t *testing.T) {
houstonVersion = "0.28.0"
cmd := newAirflowInitCmd()
buf := new(bytes.Buffer)
cmd.SetOut(buf)
cmd.SetArgs([]string{"--help"})
_, err := cmd.ExecuteC()
output := buf.String()
assert.NoError(t, err)
assert.Contains(t, output, "astro dev", output)
assert.NotContains(t, output, "--use-astronomer-certified")
assert.NotContains(t, output, "--runtime-version string")
})

t.Run("0.29.0 software version", func(t *testing.T) {
houstonVersion = "0.29.0"
cmd := newAirflowInitCmd()
buf := new(bytes.Buffer)
cmd.SetOut(buf)
cmd.SetArgs([]string{"dev", "init", "--help"})
_, err := cmd.ExecuteC()
output := buf.String()
assert.NoError(t, err)
assert.Contains(t, output, "astro dev", output)
assert.Contains(t, output, "--use-astronomer-certified")
assert.Contains(t, output, "--runtime-version string")
})
}

func TestNewAirflowInitCmd(t *testing.T) {
cmd := newAirflowInitCmd()
assert.Nil(t, cmd.PersistentPreRunE(new(cobra.Command), []string{}))
Expand Down Expand Up @@ -354,7 +402,7 @@ func TestAirflowStart(t *testing.T) {

mockContainerHandler := new(mocks.ContainerHandler)
containerHandlerInit = func(airflowHome, envFile, dockerfile, imageName string) (airflow.ContainerHandler, error) {
mockContainerHandler.On("Start", "", "airflow_settings.yaml", false, false).Return(nil).Once()
mockContainerHandler.On("Start", "", "airflow_settings.yaml", false, false, 1*time.Minute).Return(nil).Once()
return mockContainerHandler, nil
}

Expand All @@ -369,7 +417,7 @@ func TestAirflowStart(t *testing.T) {

mockContainerHandler := new(mocks.ContainerHandler)
containerHandlerInit = func(airflowHome, envFile, dockerfile, imageName string) (airflow.ContainerHandler, error) {
mockContainerHandler.On("Start", "", "airflow_settings.yaml", false, false).Return(errMock).Once()
mockContainerHandler.On("Start", "", "airflow_settings.yaml", false, false, 1*time.Minute).Return(errMock).Once()
return mockContainerHandler, nil
}

Expand Down Expand Up @@ -642,7 +690,7 @@ func TestAirflowRestart(t *testing.T) {
mockContainerHandler := new(mocks.ContainerHandler)
containerHandlerInit = func(airflowHome, envFile, dockerfile, imageName string) (airflow.ContainerHandler, error) {
mockContainerHandler.On("Stop").Return(nil).Once()
mockContainerHandler.On("Start", "", "airflow_settings.yaml", true, true).Return(nil).Once()
mockContainerHandler.On("Start", "", "airflow_settings.yaml", true, true, 1*time.Minute).Return(nil).Once()
return mockContainerHandler, nil
}

Expand Down Expand Up @@ -675,7 +723,7 @@ func TestAirflowRestart(t *testing.T) {
mockContainerHandler := new(mocks.ContainerHandler)
containerHandlerInit = func(airflowHome, envFile, dockerfile, imageName string) (airflow.ContainerHandler, error) {
mockContainerHandler.On("Stop").Return(nil).Once()
mockContainerHandler.On("Start", "", "airflow_settings.yaml", true, true).Return(errMock).Once()
mockContainerHandler.On("Start", "", "airflow_settings.yaml", true, true, 1*time.Minute).Return(errMock).Once()
return mockContainerHandler, nil
}

Expand Down
4 changes: 2 additions & 2 deletions cmd/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func login(cmd *cobra.Command, args []string, astroClient astro.Client, out io.W

if len(args) == 1 {
if !context.IsCloudDomain(args[0]) {
return softwareLogin(args[0], oAuth, "", "", houstonClient, out)
return softwareLogin(args[0], oAuth, "", "", houstonVersion, houstonClient, out)
}
return cloudLogin(args[0], "", token, astroClient, out, shouldDisplayLoginLink)
}
Expand All @@ -70,7 +70,7 @@ func login(cmd *cobra.Command, args []string, astroClient astro.Client, out io.W
} else if context.IsCloudDomain(ctx.Domain) {
return cloudLogin(ctx.Domain, "", token, astroClient, out, shouldDisplayLoginLink)
}
return softwareLogin(ctx.Domain, oAuth, "", "", houstonClient, out)
return softwareLogin(ctx.Domain, oAuth, "", "", houstonVersion, houstonClient, out)
}

func logout(cmd *cobra.Command, args []string, out io.Writer) error {
Expand Down
2 changes: 1 addition & 1 deletion cmd/auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func TestLogin(t *testing.T) {
return nil
}

softwareLogin = func(domain string, oAuthOnly bool, username, password string, client houston.ClientInterface, out io.Writer) error {
softwareLogin = func(domain string, oAuthOnly bool, username, password, houstonVersion string, client houston.ClientInterface, out io.Writer) error {
assert.Equal(t, softwareDomain, domain)
return nil
}
Expand Down
46 changes: 20 additions & 26 deletions cmd/root.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
package cmd

import (
"crypto/tls"
"fmt"
"net"
"net/http"
"os"
"time"

astro "github.com/astronomer/astro-cli/astro-client"
cloudCmd "github.com/astronomer/astro-cli/cmd/cloud"
Expand All @@ -23,8 +19,9 @@ import (
)

var (
houstonClient houston.ClientInterface
verboseLevel string
verboseLevel string
houstonClient houston.ClientInterface
houstonVersion string
)

const (
Expand All @@ -34,24 +31,19 @@ const (

// NewRootCmd adds all of the primary commands for the cli
func NewRootCmd() *cobra.Command {
httpClient := httputil.NewHTTPClient()
// configure http transport
dialTimeout := config.CFG.HoustonDialTimeout.GetInt()
// #nosec
httpClient.HTTPClient.Transport = &http.Transport{
Dial: (&net.Dialer{
Timeout: time.Duration(dialTimeout) * time.Second,
}).Dial,
TLSHandshakeTimeout: time.Duration(dialTimeout) * time.Second,
TLSClientConfig: &tls.Config{InsecureSkipVerify: config.CFG.HoustonSkipVerifyTLS.GetBool()},
}
var err error
httpClient := houston.NewHTTPClient()
houstonClient = houston.NewClient(httpClient)
houstonVersion, err = houstonClient.GetPlatformVersion(nil)
if err != nil {
softwareCmd.InitDebugLogs = append(softwareCmd.InitDebugLogs, fmt.Sprintf("Unable to get Houston version: %s", err.Error()))
}

astroClient := astro.NewAstroClient(httputil.NewHTTPClient())

ctx := cloudPlatform
currCtx := context.IsCloudContext()
if !currCtx {
isCloudCtx := context.IsCloudContext()
if !isCloudCtx {
ctx = softwarePlatform
}

Expand All @@ -69,10 +61,10 @@ func NewRootCmd() *cobra.Command {
Welcome to the Astro CLI, the modern command line interface for data orchestration. You can use it for Astro, Astronomer Software, or Local Development.`,
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
if currCtx {
if isCloudCtx {
return cloudCmd.Setup(cmd, args, astroClient)
}
// Software PersistentPreRunE component
// common PersistentPreRunE component between software & cloud
// setting up log verbosity and dumping debug logs collected during CLI-initialization
if err := softwareCmd.SetUpLogs(os.Stdout, verboseLevel); err != nil {
return err
Expand All @@ -82,8 +74,6 @@ Welcome to the Astro CLI, the modern command line interface for data orchestrati
},
}

rootCmd.SetHelpTemplate(getResourcesHelpTemplate(ctx))

rootCmd.AddCommand(
newLoginCommand(astroClient, os.Stdout),
newLogoutCommand(os.Stdout),
Expand All @@ -108,17 +98,21 @@ Welcome to the Astro CLI, the modern command line interface for data orchestrati
rootCmd.AddCommand(
softwareCmd.AddCmds(houstonClient, os.Stdout)...,
)
softwareCmd.VersionMatchCmds(rootCmd, []string{"astro"})
}

rootCmd.SetHelpTemplate(getResourcesHelpTemplate(houstonVersion, ctx))
rootCmd.PersistentFlags().StringVarP(&verboseLevel, "verbosity", "", logrus.WarnLevel.String(), "Log level (debug, info, warn, error, fatal, panic")

return rootCmd
}

func getResourcesHelpTemplate(ctx string) string {
func getResourcesHelpTemplate(version, ctx string) string {
return fmt.Sprintf(`{{with (or .Long .Short)}}{{. | trimTrailingWhitespaces}}
Current Context: %s
Current Context: %s{{if and (eq "%s" "Astronomer Software") (ne "%s" "")}}
Platform Version: %s{{end}}
{{end}}{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}
`, ansi.Bold(ctx))
`, ansi.Bold(ctx), ctx, version, ansi.Bold(version))
}
1 change: 0 additions & 1 deletion cmd/software/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,6 @@ func deploymentCreate(cmd *cobra.Command, out io.Writer) error {
return err
}
}

req := &deployment.CreateDeploymentRequest{
Label: deploymentCreateLabel,
WS: ws,
Expand Down
8 changes: 4 additions & 4 deletions cmd/software/deployment_service_account_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func TestDeploymentSAListCommand(t *testing.T) {
}

api := new(mocks.ClientInterface)
api.On("GetAppConfig").Return(mockAppConfig, nil)
api.On("GetAppConfig", nil).Return(mockAppConfig, nil)
api.On("ListDeploymentServiceAccounts", mockDeployment.ID).Return([]houston.ServiceAccount{mockSA}, nil)

houstonClient = api
Expand Down Expand Up @@ -59,8 +59,8 @@ func TestDeploymentSaDeleteRootCommand(t *testing.T) {
testUtil.InitTestConfig(testUtil.SoftwarePlatform)

api := new(mocks.ClientInterface)
api.On("GetAppConfig").Return(mockAppConfig, nil)
api.On("DeleteDeploymentServiceAccount", "1234", mockDeploymentSA.ID).Return(mockDeploymentSA, nil)
api.On("GetAppConfig", nil).Return(mockAppConfig, nil)
api.On("DeleteDeploymentServiceAccount", houston.DeleteServiceAccountRequest{DeploymentID: "1234", ServiceAccountID: mockDeploymentSA.ID}).Return(mockDeploymentSA, nil)
houstonClient = api
output, err := execDeploymentCmd("service-account", "delete", mockDeploymentSA.ID, "--deployment-id=1234")
assert.NoError(t, err)
Expand Down Expand Up @@ -95,7 +95,7 @@ func TestDeploymentSaCreateCommand(t *testing.T) {
}

api := new(mocks.ClientInterface)
api.On("GetAppConfig").Return(mockAppConfig, nil)
api.On("GetAppConfig", nil).Return(mockAppConfig, nil)
api.On("CreateDeploymentServiceAccount", expectedSARequest).Return(mockSA, nil)

houstonClient = api
Expand Down

0 comments on commit f9557e4

Please sign in to comment.