Skip to content

Commit

Permalink
Add Weave Cloud client
Browse files Browse the repository at this point in the history
  • Loading branch information
tomwilkie committed Jul 7, 2016
1 parent f2e40b4 commit 1b64e46
Show file tree
Hide file tree
Showing 3 changed files with 333 additions and 0 deletions.
178 changes: 178 additions & 0 deletions cmd/wcloud/cli.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
package main

import (
"bytes"
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"time"

"github.com/olekukonko/tablewriter"
"gopkg.in/yaml.v2"
)

func env(key, def string) string {
if val, ok := os.LookupEnv(key); ok {
return val
}
return def
}

var (
token = env("SERVICE_TOKEN", "")
baseURL = env("BASE_URL", "https://cloud.weave.works")
)

func usage() {
fmt.Println(`Usage:
deploy <image>:<version> Deploy image to your configured env
list List recent deployments
config (<filename>) Get (or set) the configured env
logs <deploy> Show lots for the given deployment`)
}

func main() {
if len(os.Args) <= 1 {
usage()
os.Exit(1)
}

c := NewClient(token, baseURL)

switch os.Args[1] {
case "deploy":
deploy(c, os.Args[2:])
case "list":
list(c, os.Args[2:])
case "config":
config(c, os.Args[2:])
case "logs":
logs(c, os.Args[2:])
case "help":
usage()
default:
usage()
}
}

func deploy(c Client, args []string) {
if len(args) != 1 {
usage()
return
}
parts := strings.SplitN(args[0], ":", 2)
if len(parts) < 2 {
usage()
return
}
deployment := Deployment{
ImageName: parts[0],
Version: parts[1],
}
if err := c.Deploy(deployment); err != nil {
fmt.Println(err.Error())
os.Exit(1)
}
}

func list(c Client, args []string) {
flags := flag.NewFlagSet("list", flag.ContinueOnError)
page := flags.Int("page", 0, "Zero based index of page to list.")
pagesize := flags.Int("page-size", 10, "Number of results per page")
if err := flags.Parse(args); err != nil {
usage()
return
}
deployments, err := c.GetDeployments(*page, *pagesize)
if err != nil {
fmt.Println(err.Error())
os.Exit(1)
}

table := tablewriter.NewWriter(os.Stdout)
table.SetHeader([]string{"Created", "ID", "Image", "Version", "State"})
table.SetBorder(false)
table.SetColumnSeparator(" ")
for _, deployment := range deployments {
table.Append([]string{
deployment.CreatedAt.Format(time.RFC822),
deployment.ID,
deployment.ImageName,
deployment.Version,
deployment.State,
})
}
table.Render()
}

func loadConfig(filename string) (*Config, error) {
extension := filepath.Ext(filename)
var config Config
buf, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
if extension == ".yaml" || extension == ".yml" {
if err := yaml.Unmarshal(buf, &config); err != nil {
return nil, err
}
} else {
if err := json.NewDecoder(bytes.NewReader(buf)).Decode(&config); err != nil {
return nil, err
}
}
return &config, nil
}

func config(c Client, args []string) {
if len(args) > 1 {
usage()
return
}

if len(args) == 1 {
config, err := loadConfig(args[0])
if err != nil {
fmt.Println("Error reading config:", err)
os.Exit(1)
}

if err := c.SetConfig(config); err != nil {
fmt.Println(err.Error())
os.Exit(1)
}
} else {
config, err := c.GetConfig()
if err != nil {
fmt.Println(err.Error())
os.Exit(1)
}

buf, err := yaml.Marshal(config)
if err != nil {
fmt.Println(err.Error())
os.Exit(1)
}

fmt.Println(string(buf))
}
}

func logs(c Client, args []string) {
if len(args) != 1 {
usage()
return
}

output, err := c.GetLogs(args[0])
if err != nil {
fmt.Println(err.Error())
os.Exit(1)
}

fmt.Println(string(output))
}
131 changes: 131 additions & 0 deletions cmd/wcloud/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
package main

import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
)

// Client for the deployment service
type Client struct {
token string
baseURL string
}

// NewClient makes a new Client
func NewClient(token, baseURL string) Client {
return Client{
token: token,
baseURL: baseURL,
}
}

func (c Client) newRequest(method, path string, body io.Reader) (*http.Request, error) {
req, err := http.NewRequest(method, c.baseURL+path, body)
if err != nil {
return nil, err
}
req.Header.Add("Authorization", fmt.Sprintf("Scope-Probe token=%s", c.token))
return req, nil
}

// Deploy notifies the deployment service about a new deployment
func (c Client) Deploy(deployment Deployment) error {
var buf bytes.Buffer
if err := json.NewEncoder(&buf).Encode(deployment); err != nil {
return err
}
req, err := c.newRequest("POST", "/api/deploy", &buf)
if err != nil {
return err
}
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
if res.StatusCode != 204 {
return fmt.Errorf("Error making request: %s", res.Status)
}
return nil
}

// GetDeployments returns a list of deployments
func (c Client) GetDeployments(page, pagesize int) ([]Deployment, error) {
req, err := c.newRequest("GET", fmt.Sprintf("/api/deploy?page=%d&pagesize=%d", page, pagesize), nil)
if err != nil {
return nil, err
}
res, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
if res.StatusCode != 200 {
return nil, fmt.Errorf("Error making request: %s", res.Status)
}
var response struct {
Deployments []Deployment `json:"deployments"`
}
if err := json.NewDecoder(res.Body).Decode(&response); err != nil {
return nil, err
}
return response.Deployments, nil
}

// GetConfig returns the current Config
func (c Client) GetConfig() (*Config, error) {
req, err := c.newRequest("GET", "/api/config/deploy", nil)
if err != nil {
return nil, err
}
res, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
if res.StatusCode != 200 {
return nil, fmt.Errorf("Error making request: %s", res.Status)
}
var config Config
if err := json.NewDecoder(res.Body).Decode(&config); err != nil {
return nil, err
}
return &config, nil
}

// SetConfig sets the current Config
func (c Client) SetConfig(config *Config) error {
var buf bytes.Buffer
if err := json.NewEncoder(&buf).Encode(config); err != nil {
return err
}
req, err := c.newRequest("POST", "/api/config/deploy", &buf)
if err != nil {
return err
}
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
if res.StatusCode != 204 {
return fmt.Errorf("Error making request: %s", res.Status)
}
return nil
}

// GetLogs returns the logs for a given deployment.
func (c Client) GetLogs(deployID string) ([]byte, error) {
req, err := c.newRequest("GET", fmt.Sprintf("/api/deploy/%s/log", deployID), nil)
if err != nil {
return nil, err
}
res, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
if res.StatusCode != 200 {
return nil, fmt.Errorf("Error making request: %s", res.Status)
}
return ioutil.ReadAll(res.Body)
}
24 changes: 24 additions & 0 deletions cmd/wcloud/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package main

import (
"time"
)

// Deployment describes a deployment
type Deployment struct {
ID string `json:"id"`
CreatedAt time.Time `json:"created_at"`
ImageName string `json:"image_name"`
Version string `json:"version"`
Priority int `json:"priority"`
State string `json:"status"`
LogKey string `json:"-"`
}

// Config for the deployment system for a user.
type Config struct {
RepoURL string `json:"repo_url" yaml:"repo_url"`
RepoPath string `json:"repo_path" yaml:"repo_path"`
RepoKey string `json:"repo_key" yaml:"repo_key"`
KubeconfigPath string `json:"kubeconfig_path" yaml:"kubeconfig_path"`
}

0 comments on commit 1b64e46

Please sign in to comment.