Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Thomas Orrick committed Aug 11, 2015
0 parents commit ac097c2
Show file tree
Hide file tree
Showing 8 changed files with 394 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.DS_Store
spyglass
spyglass-*
16 changes: 16 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
ARCH = amd64
.PHONY: all build_linux build_darwin build_windows

all: build_linux build_darwin build_windows

build_linux:
./docker.sh linux $(arch)

build_darwin:
./docker.sh darwin $(arch)

build_windows:
./docker.sh windows $(arch)

clean:
rm -f spyglass-*
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Spyglass
========

Build Server deployment CLI

# Usage
* Set `APERTURE_SERVER_URL` environment variable to your OpenAperture dns name.
* Run `spyglass configure` to set your credentials or use `APERTURE_USERNAME` and `APERTURE_PASSWORD` environment variables.

More usage and help information can be found by running `spyglass --help`
4 changes: 4 additions & 0 deletions build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#! /bin/bash

go get
go build -v -o spyglass-$GOOS-$GOARCH
133 changes: 133 additions & 0 deletions cli.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package main

import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path"
"time"

"github.com/codegangsta/cli"
"github.com/segmentio/go-prompt"
"github.com/torrick/spyglass/openaperture"
)

func main() {
app := cli.NewApp()
environmentFlag := cli.StringFlag{Name: "environment, e", Usage: "environment to build or deploy"}
commitHashFlag := cli.StringFlag{Name: "commit, c", Usage: "commit hash or branch to build or deploy"}
app.Name = "spyglass"
app.Version = "0.2.5"
app.Author = "Thomas Orrick"
app.Email = "[email protected]"
app.Flags = []cli.Flag{
cli.BoolFlag{Name: "follow, f", Usage: "continually check status of a build or deploy"},
cli.StringFlag{Name: "server, s", Usage: "build server url", EnvVar: "APERTURE_SERVER_URL"},
}
app.Commands = []cli.Command{
{
Name: "deploy",
Usage: "build and deploy a docker repository",
Action: func(c *cli.Context) {
validate(c)
fmt.Printf("Sending deploy request for:\n Project: %s\n Environment: %s\n", c.Args().First(), c.String("environment"))
project := deploy(openaperture.NewProject(c.Args().First(), c.String("environment"), c.String("commit"), c.GlobalString("server"),
c.String("build-exchange"), c.String("deploy-exchange"), c.Bool("force")))
if c.GlobalBool("follow") {
checkStatus(project)
}
},
Flags: []cli.Flag{
environmentFlag,
commitHashFlag,
cli.StringFlag{Name: "build-exchange", Usage: "Set the build exchange id"},
cli.StringFlag{Name: "deploy-exchange", Usage: "Set the deploy exchange id"},
cli.BoolFlag{Name: "force", Usage: "Force a docker build"},
},
},
{
Name: "configure",
Usage: "set configuration options",
Action: func(c *cli.Context) {
configure(c)
},
},
}
app.Run(os.Args)
}

func configure(c *cli.Context) {
username := prompt.String("Username")
password := prompt.Password("Password")
config := map[string]string{"username": username, "password": password}
configJSON, _ := json.Marshal(config)
ioutil.WriteFile(path.Join(os.Getenv("HOME"), ".aperturecfg"), configJSON, 0600)
}

func checkStatus(project *openaperture.Project) {
auth, err := openaperture.GetAuth()
if err != nil {
panic(err.Error())
}
ticker := time.NewTicker(5 * time.Second)
quit := make(chan struct{})
for {
select {
case <-ticker.C:
workflow, err := project.Status(auth)
if err != nil {
close(quit)
fmt.Println(err.Error())
os.Exit(1)
} else if workflow.WorkflowError {
close(quit)
fmt.Println("Workflow failed")
fmt.Println(workflow.EventLog)
os.Exit(1)
} else if workflow.WorkflowCompleted {
fmt.Printf("Workflow completed in %s\n", workflow.ElapsedWorkflowTime)
close(quit)
} else {
fmt.Printf("Milestone: %s in progress\n", workflow.CurrentStep)
}
case <-quit:
ticker.Stop()
os.Exit(0)
}
}
}

func validate(c *cli.Context) {
if c.String("environment") == "" {
fmt.Printf("Environment was not set. Please specify an environment to %s\n", c.Command.Name)
os.Exit(1)
}
if c.String("commit") == "" {
fmt.Printf("Commit hash or branch was not set. Please specify a commit hash or branch to %s\n", c.Command.Name)
os.Exit(1)
}
if c.Args().First() == "" {
fmt.Printf("Project name was not set. Please specify a project to %s\n", c.Command.Name)
os.Exit(1)
}
}

func deploy(project *openaperture.Project) *openaperture.Project {
operations := []string{"build", "deploy"}
token, err := openaperture.GetAuth()
if err != nil {
panic(err.Error())
}
resp, err := project.CreateWorkflow(token, operations)
if err != nil {
panic(err.Error())
}
fmt.Printf("Workflow created: %s\n", resp.Location)
err = project.ExecuteWorkflow(token, resp.Location)
if err != nil {
panic(err.Error())
}
fmt.Println("Successfully sent deploy request")
return project
}
1 change: 1 addition & 0 deletions docker.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
docker run --rm -it -e GOOS=$1 -e GOARCH=amd64 -v $GOPATH:/go -w /go/src/github.com/torrick/spyglass golang:1.4-cross ./build.sh
79 changes: 79 additions & 0 deletions openaperture/auth.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package openaperture

import (
"bytes"
"encoding/json"
"errors"
"io/ioutil"
"net/http"
"os"
"path"
)

//Auth struct
type Auth struct {
AccessToken string `json:"access_token"`
TokenType string `json:"token_type"`
ExpiresIn string `json:"expires_in"`
Scope string `json:"scope"`
}

//GetAuthorizationHeader build a proper authorization header for all api calls
func (oauth *Auth) GetAuthorizationHeader() string {
return "Bearer access_token=" + oauth.AccessToken
}

// GetAuth returns authentication config from various sources
func GetAuth() (*Auth, error) {
if _, err := os.Stat(path.Join(os.Getenv("HOME"), ".aperturecfg")); os.IsNotExist(err) {
return EnvAuth()
}
return SharedAuth()
}

// SharedAuth generates an authentication config from local json file
func SharedAuth() (*Auth, error) {
var config map[string]string
configPath := path.Join(os.Getenv("HOME"), ".aperturecfg")
configBytes, err := ioutil.ReadFile(configPath)
if err != nil {
return nil, err
}
json.Unmarshal(configBytes, &config)
return NewAuth(config["username"], config["password"])
}

// EnvAuth pulls authentication information from environment variables
func EnvAuth() (*Auth, error) {
username := os.Getenv("APERTURE_USERNAME")
password := os.Getenv("APERTURE_PASSWORD")
if username == "" || password == "" {
return nil, errors.New("username or password is blank")
}
return NewAuth(username, password)
}

// NewAuth requests a new token from idp
func NewAuth(username string, password string) (*Auth, error) {
var auth Auth
url := "https://auth.psft.co/oauth/token"
credentials := map[string]string{
"grant_type": "password",
"username": username,
"password": password,
}
payload, _ := json.Marshal(credentials)
req, err := http.NewRequest("POST", url, bytes.NewBuffer(payload))
req.Header.Set("Content-Type", "application/json")

client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, err
}

defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
json.Unmarshal(body, &auth)
return &auth, nil
}
Loading

0 comments on commit ac097c2

Please sign in to comment.