Skip to content

Commit

Permalink
Merge pull request #60 from astronomerio/feature/houston-api-integration
Browse files Browse the repository at this point in the history
Feature/houston api integration
  • Loading branch information
cwurtz committed May 9, 2018
2 parents 6a834b9 + c44c382 commit 1c5d3f7
Show file tree
Hide file tree
Showing 21 changed files with 744 additions and 43 deletions.
6 changes: 5 additions & 1 deletion .gitignore
Expand Up @@ -4,4 +4,8 @@ Dockerfile
meta/
dist/
packages.txt
requirements.txt
requirements.txt

# IDEs
.idea/
.vscode/
8 changes: 7 additions & 1 deletion Gopkg.lock

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

4 changes: 4 additions & 0 deletions Gopkg.toml
Expand Up @@ -68,3 +68,7 @@
[[override]]
name = "github.com/xeipuuv/gojsonschema"
revision = "0c8571ac0ce161a5feb57375a9cdf148c98c0f70"

[[constraint]]
branch = "master"
name = "github.com/shurcooL/go"
29 changes: 29 additions & 0 deletions Makefile
Expand Up @@ -15,6 +15,35 @@ dep:
build:
go build -o ${OUTPUT} -ldflags "${LDFLAGS_VERSION} ${LDFLAGS_GIT_COMMIT}" main.go

format:
@echo "--> Running go fmt"
@go fmt $(GOFILES)

vet:
@echo "--> Running go vet"
@go vet $(GOFILES); if [ $$? -eq 1 ]; then \
echo ""; \
echo "Vet found suspicious constructs. Please check the reported constructs"; \
echo "and fix them if necessary before submitting the code for review."; \
exit 1; \
fi

style:
@echo ">> checking code style"
@! gofmt -d $(shell find . -path ./vendor -prune -o -name '*.go' -print) | grep '^'

staticcheck:
@echo ">> running staticcheck"
@staticcheck $(GOFILES)

gosimple:
@echo ">> running gosimple"
@gosimple $(GOFILES)

tools:
@echo ">> installing some extra tools"
@go get -u -v honnef.co/go/tools/...

install: build
$(eval DESTDIR ?= $(GOBIN))
mkdir -p $(DESTDIR)
Expand Down
48 changes: 40 additions & 8 deletions airflow/airflow.go
@@ -1,17 +1,25 @@
package airflow

import (
"errors"
"fmt"
"os"
"path/filepath"
"regexp"
"strings"

"github.com/iancoleman/strcase"

"github.com/astronomerio/astro-cli/airflow/include"
"github.com/astronomerio/astro-cli/houston"
"github.com/astronomerio/astro-cli/pkg/fileutil"
"github.com/astronomerio/astro-cli/pkg/httputil"
"github.com/astronomerio/astro-cli/config"
"github.com/astronomerio/astro-cli/utils"
"github.com/iancoleman/strcase"
"github.com/pkg/errors"
)

var (
http = httputil.NewHTTPClient()
api = houston.NewHoustonClient(http)
)

func initProject(path string) {
Expand Down Expand Up @@ -44,7 +52,7 @@ func initDirs(root string, dirs []string) bool {
fullpath := filepath.Join(root, dir)

// Move on if already exists
if utils.Exists(fullpath) {
if fileutil.Exists(fullpath) {
exists = true
continue
}
Expand All @@ -68,13 +76,13 @@ func initFiles(root string, files map[string]string) bool {
fullpath := filepath.Join(root, file)

// Move on if already exiss
if utils.Exists(fullpath) {
if fileutil.Exists(fullpath) {
exists = true
continue
}

// Write files out
if err := utils.WriteStringToFile(fullpath, content); err != nil {
if err := fileutil.WriteStringToFile(fullpath, content); err != nil {
fmt.Println(err)
}
}
Expand All @@ -85,7 +93,7 @@ func initFiles(root string, files map[string]string) bool {
// Init will scaffold out a new airflow project
func Init(projectName string) error {
// Grab working directory
path := utils.GetWorkingDir()
path := fileutil.GetWorkingDir()

projectName, err := validateOrCreateProjectName(path, projectName)
if err != nil {
Expand All @@ -110,7 +118,31 @@ func Init(projectName string) error {
}

// Create new airflow deployment
func Create() error {
func Create(title string) error {
response, err := api.CreateDeployment(title)
if err != nil {
return err
}
deployment, err := api.FetchDeployment(response.Id)

fmt.Println(response.Message)
fmt.Printf("\nAirflow Dashboard: https://%s-airflow.%s\n", deployment.ReleaseName, config.CFG.CloudDomain.GetString())
fmt.Printf("Flower Dashboard: https://%s-flower.%s\n", deployment.ReleaseName, config.CFG.CloudDomain.GetString())
fmt.Printf("Grafana Dashboard: https://%s-grafana.%s\n", deployment.ReleaseName, config.CFG.CloudDomain.GetString())
return nil
}

// List all airflow deployments
func List() error {
deployments, err := api.FetchDeployments()
if err != nil {
return err
}

for _, d := range deployments {
rowTmp := "Title: %s\nId: %s\nRelease: %s\nVersion: %s\n\n"
fmt.Printf(rowTmp, d.Title, d.Id, d.ReleaseName, d.Version)
}
return nil
}

Expand Down
37 changes: 34 additions & 3 deletions airflow/docker.go
Expand Up @@ -11,14 +11,17 @@ import (
"strings"
"text/tabwriter"

"github.com/astronomerio/astro-cli/airflow/include"
"github.com/astronomerio/astro-cli/config"
docker "github.com/astronomerio/astro-cli/docker"
dockercompose "github.com/docker/libcompose/docker"
"github.com/docker/libcompose/docker/ctx"
"github.com/docker/libcompose/project"
"github.com/docker/libcompose/project/options"
"github.com/pkg/errors"

"github.com/astronomerio/astro-cli/airflow/include"
"github.com/astronomerio/astro-cli/config"
"github.com/astronomerio/astro-cli/docker"
"github.com/astronomerio/astro-cli/houston"
"github.com/astronomerio/astro-cli/pkg/input"
)

const (
Expand Down Expand Up @@ -238,6 +241,34 @@ func PS(airflowHome string) error {

// Deploy pushes a new docker image
func Deploy(path, name string) error {
if name == "" {
deployments, err := api.FetchDeployments()
if err != nil {
return err
}

if len(deployments) == 0 {
return errors.New("No airflow deployments found")
}

deployMap := map[string]houston.Deployment{}
fmt.Println("Select which airflow deployment you want to deploy to:")
for i, deployment := range deployments {
index := i + 1
deployMap[strconv.Itoa(index)] = deployment
fmt.Printf("%d) %s (%s)\n", index, deployment.Title, deployment.ReleaseName)
}

choice := input.InputText("")
selected, ok := deployMap[choice]
if !ok {
return errors.New("Invalid deployment selection")
}
name = selected.ReleaseName
}
fmt.Printf("Deploying: %s\n", name)
fmt.Println(repositoryName(name))

// Get a list of tags in the repository for this image
tags, err := docker.ListRepositoryTags(repositoryName(name))
if err != nil {
Expand Down
32 changes: 26 additions & 6 deletions auth/auth.go
Expand Up @@ -5,19 +5,39 @@ import (

"github.com/astronomerio/astro-cli/config"
"github.com/astronomerio/astro-cli/docker"
"github.com/astronomerio/astro-cli/utils"
"github.com/astronomerio/astro-cli/houston"
"github.com/astronomerio/astro-cli/pkg/httputil"
"github.com/astronomerio/astro-cli/pkg/input"
)

var (
HTTP = httputil.NewHTTPClient()
)

// Login logs a user into the docker registry. Will need to login to Houston next.
func Login() {
registry := config.CFG.RegistryAuthority.GetString()
username := utils.InputText("Username: ")
password, _ := utils.InputPassword("Password: ")
username := input.InputText("Username: ")
password, _ := input.InputPassword("Password: ")

API := houston.NewHoustonClient(HTTP)

// authenticate with houston
token, houstonErr := API.CreateToken(username, password)
if houstonErr != nil {
panic(houstonErr)
} else if token.Success != true {
fmt.Println(token.Message)
return
}

config.CFG.UserAPIAuthToken.SetProjectString(token.Token)

err := docker.ExecLogin(registry, username, password)
if err != nil {
//authenticate with registry
dockerErr := docker.ExecLogin(registry, username, password)
if dockerErr != nil {
// Println instead of panic to prevent excessive error logging to stdout on a failed login
fmt.Println(err)
fmt.Println(dockerErr)
return
}

Expand Down
71 changes: 63 additions & 8 deletions cmd/airflow.go
@@ -1,13 +1,20 @@
package cmd

import (
"errors"
"fmt"
"os"
"path/filepath"
"regexp"
"strings"

"github.com/spf13/cobra"
"github.com/iancoleman/strcase"

"github.com/astronomerio/astro-cli/airflow"
"github.com/astronomerio/astro-cli/config"
"github.com/astronomerio/astro-cli/utils"
"github.com/spf13/cobra"
"github.com/astronomerio/astro-cli/pkg/git"
"github.com/astronomerio/astro-cli/pkg/fileutil"
)

var (
Expand All @@ -32,14 +39,22 @@ var (
Use: "create",
Short: "Create a new airflow deployment",
Long: "Create a new airflow deployment",
Args: cobra.ExactArgs(1),
RunE: airflowCreate,
}

airflowListCmd = &cobra.Command{
Use: "list",
Short: "List airflow clusters",
Long: "List all created airflow clusters",
RunE: airflowList,
}

airflowDeployCmd = &cobra.Command{
Use: "deploy",
Short: "Deploy an airflow project",
Long: "Deploy an airflow project to a given deployment",
Args: cobra.ExactArgs(1),
Args: cobra.MaximumNArgs(1),
PreRun: ensureProjectDir,
RunE: airflowDeploy,
}
Expand Down Expand Up @@ -91,6 +106,9 @@ func init() {
// Airflow create
airflowRootCmd.AddCommand(airflowCreateCmd)

// Airflow list
airflowRootCmd.AddCommand(airflowListCmd)

// Airflow deploy
airflowRootCmd.AddCommand(airflowDeployCmd)
airflowDeployCmd.Flags().BoolVarP(&forceDeploy, "force", "f", false, "Force deploy if uncommited changes")
Expand All @@ -117,20 +135,57 @@ func ensureProjectDir(cmd *cobra.Command, args []string) {

// Use project name for image name
func airflowInit(cmd *cobra.Command, args []string) error {
return airflow.Init(projectName)
// Grab working directory
path := fileutil.GetWorkingDir()

// Validate project name
if len(projectName) != 0 {
projectNameValid := regexp.
MustCompile(`^[A-Za-z0-9]([A-Za-z0-9_-]*[A-Za-z0-9])?$`).
MatchString

if !projectNameValid(projectName) {
return errors.New("Project name is invalid")
}
} else {
projectDirectory := filepath.Base(path)
projectName = strings.Replace(strcase.ToSnake(projectDirectory), "_", "-", -1)
}

exists := config.ProjectConfigExists()
if !exists {
config.CreateProjectConfig(path)
}
config.CFG.ProjectName.SetProjectString(projectName)
airflow.Init(path)

if exists {
fmt.Printf("Reinitialized existing astronomer project in %s\n", path)
} else {
fmt.Printf("Initialized empty astronomer project in %s\n", path)
}

return nil
}

func airflowCreate(cmd *cobra.Command, args []string) error {
return airflow.Create()
return airflow.Create(args[0])
}

func airflowList(cmd *cobra.Command, args []string) error {
return airflow.List()
}

func airflowDeploy(cmd *cobra.Command, args []string) error {
if utils.HasUncommitedChanges() && !forceDeploy {
releaseName := ""
if len(args) > 0 {
releaseName = args[0]
}
if git.HasUncommitedChanges() && !forceDeploy {
fmt.Println("Project directory has uncommmited changes, use `astro airflow deploy [releaseName] -f` to force deploy.")
return nil
}

return airflow.Deploy(projectRoot, args[0])
return airflow.Deploy(projectRoot, releaseName)
}

// Start an airflow cluster
Expand Down

0 comments on commit 1c5d3f7

Please sign in to comment.