Switch to go-swagger for client lib and checks for IRON_TOKEN (#406)

* wip - for review, using go-swagger client and checking for IRON_TOKEN and passing as auth header.

* wip - auth header

* add golang builder

* finish client builder

* change gh username

* fix git command

* update readme and small fixes

* some improvements

* using go-swagger

* fn new client

* revert swagger

* make fn routes and apps work with new client (go-swagger)

* some fixes in fn apps

* update functions_go
This commit is contained in:
Travis Reeder
2017-01-24 08:08:40 -08:00
committed by GitHub
parent e5290a5b9e
commit b827135200
8 changed files with 794 additions and 288 deletions

View File

@@ -24,6 +24,12 @@ ruby build.rb
Boom. That's it.
## Building with the Go Builder
```sh
go run main.go
```
## Troubleshooting
Sometimes this will fail due to github caching or something and versions will be off. Just bump version and retry.

View File

@@ -22,7 +22,7 @@ ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE
def clone(lang)
Dir.chdir 'tmp'
ldir = "functions_#{lang}"
if !Dir.exists? ldir
if !Dir.exist? ldir
cmd = "git clone https://github.com/iron-io/#{ldir}"
stream_exec(cmd)
else
@@ -84,6 +84,12 @@ languages.each do |l|
next
end
p options
if l == 'go'
puts "SKIPPING GO, it's manual for now."
# This is using https://goswagger.io/ instead
# TODO: run this build command instead: this works if run manually
# glide install -v && docker run --rm -it -v $HOME/dev/go:/go -w /go/src/github.com/iron-io/functions_go quay.io/goswagger/swagger generate client -f https://raw.githubusercontent.com/iron-io/functions/master/docs/swagger.yml -A functions
else
gen = JSON.parse(HTTP.post("https://generator.swagger.io/api/gen/clients/#{l}",
json: {
swaggerUrl: swaggerUrl,
@@ -96,6 +102,7 @@ languages.each do |l|
zipfile = "tmp/#{lv}.zip"
stream_exec "curl -o #{zipfile} #{gen['link']} -k"
stream_exec "unzip -o #{zipfile} -d tmp/#{lv}"
end
# delete the skip_files
skip_files.each do |sf|

315
clients/main.go Normal file
View File

@@ -0,0 +1,315 @@
package main
import (
"bytes"
"encoding/json"
"fmt"
"github.com/go-openapi/loads/fmts"
"github.com/go-openapi/spec"
"io/ioutil"
"log"
"net/http"
"os"
"os/exec"
"os/user"
"path/filepath"
"strings"
)
const (
swaggerURL = "../docs/swagger.yml"
rootTmpDir = "tmp"
)
var cwd string
func main() {
os.RemoveAll(rootTmpDir)
cwd, _ = os.Getwd()
defer func() {
os.RemoveAll(rootTmpDir)
}()
// Download swagger yaml and convert to JSON
d, err := fmts.YAMLDoc(swaggerURL)
if err != nil {
log.Fatalf("Failed to convert swagger yaml to json: %v", err)
}
var sw spec.Swagger
if err := json.Unmarshal(d, &sw); err != nil {
log.Fatalf("Failed to convert swagger yaml to json: %v", err)
}
version := sw.Info.Version
fmt.Printf("VERSION: %s\n", version)
swg, err := ioutil.ReadFile(swaggerURL)
if err != nil {
log.Fatalf("Failed to load swagger file: %v", err)
}
gistURL := createGist(swg)
var only string
if len(os.Args) > 1 && os.Args[1] != "" {
only = os.Args[1]
}
var languages []string
if only != "" {
languages = append(languages, only)
} else {
// Download available languages from swagger generator api
languages = getLanguages()
}
for _, language := range languages {
var skipFiles []string
tmpDir := filepath.Join(rootTmpDir, language)
srcDir := filepath.Join(tmpDir, "src")
clientDir := filepath.Join(tmpDir, fmt.Sprintf("%s-client", language))
short := language
options := make(map[string]interface{})
var deploy [][]string
// Specfic language configurations
switch language {
case "go":
options["packageName"] = "functions"
options["packageVersion"] = version
case "ruby":
skipFiles = append(skipFiles, "#{gem_name}.gemspec")
deploy = append(deploy, []string{"gem", "build #{gem_name}.gemspec", "gem push #{gem_name}-#{version}.gem"})
options["gemName"] = "iron_functions"
options["moduleName"] = "IronFunctions"
options["gemVersion"] = version
options["gemHomepage"] = "https://github.com/iron-io/functions_ruby"
options["gemSummary"] = "Ruby gem for IronFunctions"
options["gemDescription"] = "Ruby gem for IronFunctions."
options["gemAuthorEmail"] = "travis@iron.io"
case "javascript":
short = "js"
options["projectName"] = "iron_functions"
deploy = append(deploy, []string{"npm", "publish"})
default:
continue
}
log.Printf("Generating `%s` client...\n", language)
err = os.MkdirAll(clientDir, 0777)
if err != nil {
log.Printf("Failed to create temporary directory for %s client. Skipping...", language)
}
// Generate client
if language == "go" {
err := genSwaggerClient(clientDir)
if err != nil {
log.Printf("Failed to (swagger-go) generated %s client. Skipping...", language)
continue
}
} else {
gen, err := generateClient(gistURL, language, options)
if err != nil {
log.Printf("Failed to generated %s client. Skipping...", language)
continue
}
// Download generated client
log.Printf("Downloading `%s` client...\n", language)
gf, err := getFile(strings.Replace(gen.Link, "https", "http", 1))
if err != nil {
log.Printf("Failed to download generated %s client. Skipping...", language)
}
ioutil.WriteFile(filepath.Join(tmpDir, "gen.zip"), gf, 0777)
// Unzip
log.Printf("Unzipping `%s` client...\n", language)
exec.Command("unzip", "-o", filepath.Join(tmpDir, "gen.zip"), "-d", tmpDir).Run()
os.Remove(filepath.Join(tmpDir, "gen.zip"))
}
branch := fmt.Sprintf("update-version-%s", version)
log.Printf("Cloning previous `%s` source...\n", language)
exec.Command("git", "clone", fmt.Sprintf("git@github.com:iron-io/functions_%s.git", short), srcDir).Run()
// Skip language specific files
for _, skip := range skipFiles {
os.Remove(filepath.Join(tmpDir, clientDir, skip))
}
// Copying new client
log.Printf("Copying new `%s` client to src directory\n", language)
// Only solution I found
filepath.Walk(clientDir, func(path string, info os.FileInfo, err error) error {
if path == clientDir {
return nil
}
exec.Command("cp", "-r", path, srcDir).Run()
if info.IsDir() {
return filepath.SkipDir
}
return nil
})
f, err := os.OpenFile(filepath.Join(srcDir, "VERSION"), os.O_TRUNC|os.O_WRONLY, 0644)
if err != nil {
log.Printf("Failed to save new `%s` VERSION file. Skipping...", language)
continue
}
f.WriteString(version)
f.Close()
os.Chdir(srcDir)
exec.Command("git", "checkout", "-b", branch).Run()
exec.Command("git", "add", ".").Run()
exec.Command("git", "commit", "-am", fmt.Sprintf("Updated to api version %s", version)).Run()
log.Printf("Pushing new `%s` client\n", language)
r := exec.Command("git", "push", "origin", branch).Run()
if r != nil && r.Error() != "" {
log.Printf("Failed to push new version: %s\n", r.Error())
break
}
log.Printf("Releasing new `%s` client\n", language)
for _, d := range deploy {
exec.Command(d[0], d[1])
}
log.Printf("Updated `%s` client to `%s` \n", language, version)
os.Chdir(cwd)
}
}
type generatedClient struct {
Link string `json:"link"`
}
func generateClient(url, lang string, options map[string]interface{}) (gc generatedClient, err error) {
payload := map[string]interface{}{
"swaggerUrl": url,
"options": options,
}
data, err := json.Marshal(payload)
if err != nil {
return
}
resp, err := http.Post(fmt.Sprintf("http://generator.swagger.io/api/gen/clients/%s", lang), "application/json", bytes.NewBuffer(data))
if err != nil {
return
}
result, err := ioutil.ReadAll(resp.Body)
if err != nil {
return
}
err = json.Unmarshal(result, &gc)
if err != nil {
return
}
return
}
func getFile(url string) ([]byte, error) {
resp, err := http.Get(url)
if err != nil {
return nil, err
}
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return data, nil
}
func getLanguages() (langs []string) {
data, err := getFile("http://generator.swagger.io/api/gen/clients")
if err != nil {
log.Fatalf("Failed to load swagger languages: %v", err)
os.Exit(-1)
}
err = json.Unmarshal(data, &langs)
if err != nil {
log.Fatalf("Failed to load swagger languages: %v", err)
os.Exit(-1)
}
return
}
type GistFile struct {
Content string `json:"content"`
}
type Gist struct {
Description string `json:"description"`
Public bool `json:"public"`
Files map[string]GistFile `json:"files"`
}
type GistResponse struct {
Files map[string]struct {
RawURL string `json:"raw_url"`
} `json:"files"`
}
func createGist(b []byte) string {
var responseObj GistResponse
gist := Gist{
"",
false,
map[string]GistFile{
"swaggerSpec": {string(b)},
},
}
b, err := json.Marshal(gist)
if err != nil {
log.Fatal("JSON Error: ", err)
}
br := bytes.NewBuffer(b)
resp, err := http.Post("https://api.github.com/gists", "application/json", br)
if err != nil {
log.Fatal("HTTP Error: ", err)
}
err = json.NewDecoder(resp.Body).Decode(&responseObj)
if err != nil {
log.Fatal("Response JSON Error: ", err)
}
return responseObj.Files["swaggerSpec"].RawURL
}
const (
goSwaggerImage = "quay.io/goswagger/swagger"
)
func genSwaggerClient(target string) error {
u, err := user.Current()
if err != nil {
return err
}
cmd := exec.Command("docker", "run", "--rm", "-u", fmt.Sprintf("%s:%s", u.Uid, u.Gid), "-v", fmt.Sprintf("%s/%s:/go/src/github.com/iron-io/functions_go", cwd, target), "-v", fmt.Sprintf("%s/%s:/go/swagger.spec", cwd, swaggerURL), "-w", "/go/src", "quay.io/goswagger/swagger", "generate", "client", "-f", "/go/swagger.spec", "-t", "github.com/iron-io/functions_go", "-A", "functions")
d, err := cmd.CombinedOutput()
if err != nil {
log.Printf("Error running go-swagger: %s\n", d)
return err
}
return nil
}

37
fn/api.go Normal file
View File

@@ -0,0 +1,37 @@
package main
import (
"os"
httptransport "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
fnclient "github.com/iron-io/functions_go/client"
"log"
"net/url"
)
func host() string {
apiURL := os.Getenv("API_URL")
if apiURL == "" {
apiURL = "http://localhost:8080"
}
u, err := url.Parse(apiURL)
if err != nil {
log.Fatalln("Couldn't parse API URL:", err)
}
return u.Host
}
func apiClient() *fnclient.Functions {
transport := httptransport.New(host(), "/v1", []string{"http"})
if os.Getenv("IRON_TOKEN") != "" {
transport.DefaultAuthentication = httptransport.BearerToken(os.Getenv("IRON_TOKEN"))
}
// create the API client, with the transport
client := fnclient.New(transport, strfmt.Default)
return client
}

View File

@@ -4,20 +4,22 @@ import (
"encoding/json"
"errors"
"fmt"
"net/http"
"os"
"text/tabwriter"
"github.com/iron-io/functions_go"
"context"
fnclient "github.com/iron-io/functions_go/client"
apiapps "github.com/iron-io/functions_go/client/apps"
"github.com/iron-io/functions_go/models"
"github.com/urfave/cli"
)
type appsCmd struct {
*functions.AppsApi
client *fnclient.Functions
}
func apps() cli.Command {
a := appsCmd{AppsApi: functions.NewAppsApi()}
a := appsCmd{client: apiClient()}
return cli.Command{
Name: "apps",
@@ -90,25 +92,26 @@ func apps() cli.Command {
}
func (a *appsCmd) list(c *cli.Context) error {
if err := resetBasePath(a.Configuration); err != nil {
return fmt.Errorf("error setting endpoint: %v", err)
}
resp, err := a.client.Apps.GetApps(&apiapps.GetAppsParams{
Context: context.Background(),
})
wrapper, _, err := a.AppsGet()
if err != nil {
return fmt.Errorf("error getting app: %v", err)
switch err.(type) {
case *apiapps.GetAppsAppNotFound:
return fmt.Errorf("error: %v", err.(*apiapps.GetAppsAppNotFound).Payload.Error.Message)
case *apiapps.GetAppsAppDefault:
return fmt.Errorf("unexpected error: %v", err.(*apiapps.GetAppsAppDefault).Payload.Error.Message)
}
return fmt.Errorf("unexpected error: %v", err)
}
if msg := wrapper.Error_.Message; msg != "" {
return errors.New(msg)
}
if len(wrapper.Apps) == 0 {
if len(resp.Payload.Apps) == 0 {
fmt.Println("no apps found")
return nil
}
for _, app := range wrapper.Apps {
for _, app := range resp.Payload.Apps {
fmt.Println(app.Name)
}
@@ -120,24 +123,29 @@ func (a *appsCmd) create(c *cli.Context) error {
return errors.New("error: app creating takes one argument, an app name")
}
if err := resetBasePath(a.Configuration); err != nil {
return fmt.Errorf("error setting endpoint: %v", err)
}
body := functions.AppWrapper{App: functions.App{
body := &models.AppWrapper{App: &models.App{
Name: c.Args().Get(0),
Config: extractEnvConfig(c.StringSlice("config")),
}}
wrapper, _, err := a.AppsPost(body)
resp, err := a.client.Apps.PostApps(&apiapps.PostAppsParams{
Context: context.Background(),
Body: body,
})
if err != nil {
return fmt.Errorf("error creating app: %v", err)
switch err.(type) {
case *apiapps.PostAppsBadRequest:
return fmt.Errorf("error: %v", err.(*apiapps.PostAppsBadRequest).Payload.Error.Message)
case *apiapps.PostAppsConflict:
return fmt.Errorf("error: %v", err.(*apiapps.PostAppsConflict).Payload.Error.Message)
case *apiapps.PostAppsDefault:
return fmt.Errorf("unexpected error: %v", err.(*apiapps.PostAppsDefault).Payload.Error.Message)
}
return fmt.Errorf("unexpected error: %v", err)
}
if msg := wrapper.Error_.Message; msg != "" {
return errors.New(msg)
}
fmt.Println(wrapper.App.Name, "created")
fmt.Println(resp.Payload.App.Name, "created")
return nil
}
@@ -146,21 +154,24 @@ func (a *appsCmd) configList(c *cli.Context) error {
return errors.New("error: app description takes one argument, an app name")
}
if err := resetBasePath(a.Configuration); err != nil {
return fmt.Errorf("error setting endpoint: %v", err)
}
appName := c.Args().Get(0)
wrapper, _, err := a.AppsAppGet(appName)
resp, err := a.client.Apps.GetAppsApp(&apiapps.GetAppsAppParams{
Context: context.Background(),
App: appName,
})
if err != nil {
return fmt.Errorf("error creating app: %v", err)
switch err.(type) {
case *apiapps.GetAppsAppNotFound:
return fmt.Errorf("error: %v", err.(*apiapps.GetAppsAppNotFound).Payload.Error.Message)
case *apiapps.GetAppsAppDefault:
return fmt.Errorf("unexpected error: %v", err.(*apiapps.GetAppsAppDefault).Payload.Error.Message)
}
return fmt.Errorf("unexpected error: %v", err)
}
if msg := wrapper.Error_.Message; msg != "" {
return errors.New(msg)
}
config := wrapper.App.Config
config := resp.Payload.App.Config
if len(config) == 0 {
return errors.New("this application has no configurations")
}
@@ -171,11 +182,11 @@ func (a *appsCmd) configList(c *cli.Context) error {
os.Exit(1)
}
} else if c.Bool("shell") {
for k, v := range wrapper.App.Config {
for k, v := range resp.Payload.App.Config {
fmt.Print("export ", k, "=", v, "\n")
}
} else {
fmt.Println(wrapper.App.Name, "configuration:")
fmt.Println(resp.Payload.App.Name, "configuration:")
w := tabwriter.NewWriter(os.Stdout, 0, 8, 1, ' ', 0)
for k, v := range config {
fmt.Fprint(w, k, ":\t", v, "\n")
@@ -190,24 +201,26 @@ func (a *appsCmd) configSet(c *cli.Context) error {
return errors.New("error: application configuration setting takes three arguments: an app name, a key and a value")
}
if err := resetBasePath(a.Configuration); err != nil {
return fmt.Errorf("error setting endpoint: %v", err)
}
appName := c.Args().Get(0)
key := c.Args().Get(1)
value := c.Args().Get(2)
wrapper, _, err := a.AppsAppGet(appName)
resp, err := a.client.Apps.GetAppsApp(&apiapps.GetAppsAppParams{
Context: context.Background(),
App: appName,
})
if err != nil {
return fmt.Errorf("error creating app: %v", err)
switch err.(type) {
case *apiapps.GetAppsAppNotFound:
return fmt.Errorf("error: %v", err.(*apiapps.GetAppsAppNotFound).Payload.Error.Message)
case *apiapps.GetAppsAppDefault:
return fmt.Errorf("unexpected error: %v", err.(*apiapps.GetAppsAppDefault).Payload.Error.Message)
}
return fmt.Errorf("unexpected error: %v", err)
}
if msg := wrapper.Error_.Message; msg != "" {
return errors.New(msg)
}
config := wrapper.App.Config
config := resp.Payload.App.Config
if config == nil {
config = make(map[string]string)
@@ -215,11 +228,11 @@ func (a *appsCmd) configSet(c *cli.Context) error {
config[key] = value
if err := a.storeApp(appName, config); err != nil {
if err := a.patchApp(appName, config); err != nil {
return fmt.Errorf("error updating app configuration: %v", err)
}
fmt.Println(wrapper.App.Name, "updated", key, "with", value)
fmt.Println(resp.Payload.App.Name, "updated", key, "with", value)
return nil
}
@@ -228,23 +241,25 @@ func (a *appsCmd) configUnset(c *cli.Context) error {
return errors.New("error: application configuration setting takes three arguments: an app name, a key and a value")
}
if err := resetBasePath(a.Configuration); err != nil {
return fmt.Errorf("error setting endpoint: %v", err)
}
appName := c.Args().Get(0)
key := c.Args().Get(1)
wrapper, _, err := a.AppsAppGet(appName)
resp, err := a.client.Apps.GetAppsApp(&apiapps.GetAppsAppParams{
Context: context.Background(),
App: appName,
})
if err != nil {
return fmt.Errorf("error creating app: %v", err)
switch err.(type) {
case *apiapps.GetAppsAppNotFound:
return fmt.Errorf("error: %v", err.(*apiapps.GetAppsAppNotFound).Payload.Error.Message)
case *apiapps.GetAppsAppDefault:
return fmt.Errorf("unexpected error: %v", err.(*apiapps.GetAppsAppDefault).Payload.Error.Message)
}
return fmt.Errorf("unexpected error: %v", err)
}
if msg := wrapper.Error_.Message; msg != "" {
return errors.New(msg)
}
config := wrapper.App.Config
config := resp.Payload.App.Config
if config == nil {
config = make(map[string]string)
@@ -256,23 +271,37 @@ func (a *appsCmd) configUnset(c *cli.Context) error {
delete(config, key)
if err := a.storeApp(appName, config); err != nil {
if err := a.patchApp(appName, config); err != nil {
return fmt.Errorf("error updating app configuration: %v", err)
}
fmt.Println(wrapper.App.Name, "removed", key)
fmt.Println(resp.Payload.App.Name, "removed", key)
return nil
}
func (a *appsCmd) storeApp(appName string, config map[string]string) error {
body := functions.AppWrapper{App: functions.App{
Name: appName,
func (a *appsCmd) patchApp(appName string, config map[string]string) error {
body := &models.AppWrapper{App: &models.App{
Config: config,
}}
if _, _, err := a.AppsPost(body); err != nil {
return fmt.Errorf("error updating app configuration: %v", err)
_, err := a.client.Apps.PatchAppsApp(&apiapps.PatchAppsAppParams{
Context: context.Background(),
App: appName,
Body: body,
})
if err != nil {
switch err.(type) {
case *apiapps.PatchAppsAppBadRequest:
return errors.New(err.(*apiapps.PatchAppsAppBadRequest).Payload.Error.Message)
case *apiapps.PatchAppsAppNotFound:
return errors.New(err.(*apiapps.PatchAppsAppNotFound).Payload.Error.Message)
case *apiapps.PatchAppsAppDefault:
return errors.New(err.(*apiapps.PatchAppsAppDefault).Payload.Error.Message)
}
return fmt.Errorf("unexpected error: %v", err)
}
return nil
}
@@ -282,17 +311,19 @@ func (a *appsCmd) delete(c *cli.Context) error {
return errors.New("error: deleting an app takes one argument, an app name")
}
if err := resetBasePath(a.Configuration); err != nil {
return fmt.Errorf("error setting endpoint: %v", err)
}
_, err := a.client.Apps.DeleteAppsApp(&apiapps.DeleteAppsAppParams{
Context: context.Background(),
App: appName,
})
resp, err := a.AppsAppDelete(appName)
if err != nil {
return fmt.Errorf("error deleting app: %v", err)
switch err.(type) {
case *apiapps.DeleteAppsAppNotFound:
return errors.New(err.(*apiapps.DeleteAppsAppNotFound).Payload.Error.Message)
case *apiapps.DeleteAppsAppDefault:
return errors.New(err.(*apiapps.DeleteAppsAppDefault).Payload.Error.Message)
}
if resp.StatusCode == http.StatusBadRequest {
return errors.New("could not delete this application - pending routes")
return fmt.Errorf("unexpected error: %v", err)
}
fmt.Println(appName, "deleted")

91
fn/glide.lock generated
View File

@@ -1,8 +1,10 @@
hash: 9356255bb45ddb833b045e985b2dbf0721791b431849a4f36a50b0897e888c3c
updated: 2016-12-29T19:40:42.322381915-02:00
hash: a586a0b85eb753b0b618a3e763123480deb2ba6389496c1f1b897a9305326026
updated: 2016-12-07T11:54:35.937180292-08:00
imports:
- name: github.com/asaskevich/govalidator
version: 7b3beb6df3c42abd3509abfc3bcacc0fbfb7c877
- name: github.com/aws/aws-sdk-go
version: 90dec2183a5f5458ee79cbaf4b8e9ab910bc81a6
version: db9509b01e2e00890091ca164aebf0b1ca62eef8
subpackages:
- aws
- aws/awserr
@@ -12,33 +14,42 @@ imports:
- aws/corehandlers
- aws/credentials
- aws/credentials/ec2rolecreds
- aws/credentials/endpointcreds
- aws/credentials/stscreds
- aws/defaults
- aws/ec2metadata
- aws/endpoints
- aws/request
- aws/session
- aws/signer/v4
- private/endpoints
- private/protocol
- private/protocol/json/jsonutil
- private/protocol/jsonrpc
- private/protocol/query
- private/protocol/query/queryutil
- private/protocol/rest
- private/protocol/restjson
- private/protocol/xml/xmlutil
- service/lambda
- service/sts
- name: github.com/Azure/go-ansiterm
version: fa152c58bc15761d0200cb75fe958b89a9d4888e
subpackages:
- winterm
- name: github.com/coreos/go-semver
version: 8ab6407b697782a06568d4b7f1db25550ec2e4c6
version: 9474efc580562cce8f761659fbce31b6feb8ce88
subpackages:
- semver
- name: github.com/docker/docker
version: fae5a9e053ad06bea0429babae2507762d8cc1de
version: eefbf1ddd3ee4e6b6e6dc7e938e77a96ceb40163
subpackages:
- api/types
- api/types/blkiodev
- api/types/container
- api/types/filters
- api/types/mount
- api/types/network
- api/types/registry
- api/types/strslice
- api/types/swarm
- api/types/versions
@@ -58,26 +69,55 @@ imports:
- pkg/term
- pkg/term/windows
- name: github.com/docker/go-connections
version: f512407a188ecb16f31a33dbc9c4e4814afc1b03
version: 4ccf312bf1d35e5dbda654e57a9be4c3f3cd0366
subpackages:
- nat
- name: github.com/docker/go-units
version: 8a7beacffa3009a9ac66bad506b18ffdd110cf97
version: e30f1e79f3cd72542f2026ceec18d3bd67ab859c
- name: github.com/fsouza/go-dockerclient
version: ece08f96ac5f26f4073ab5c38f198c3e5000c554
version: a633c5ee3344bd557a9a22e9b7259cab6447cd22
- name: github.com/giantswarm/semver-bump
version: 7ec6ac8985c24dd50b4942f9a908d13cdfe70f23
subpackages:
- bump
- storage
- name: github.com/go-ini/ini
version: 6e4869b434bd001f6983749881c7ead3545887d8
version: 2ba15ac2dc9cdf88c110ec2dc0ced7fa45f5678c
- name: github.com/go-openapi/analysis
version: 7222828b8ce19afee3c595aef6643b9e42150120
- name: github.com/go-openapi/errors
version: 49fe8b3a0e0d32a617d8d50c67f856ad6e45b28b
- name: github.com/go-openapi/jsonpointer
version: 8d96a2dc61536b690bd36b2e9df0b3c0b62825b2
- name: github.com/go-openapi/jsonreference
version: 36d33bfe519efae5632669801b180bf1a245da3b
- name: github.com/go-openapi/loads
version: 315567415dfd74b651f7a62cabfc82a57ed7b9ad
- name: github.com/go-openapi/runtime
version: 14b161b40ece9dac8e244ab2fde2d209e108c6f5
subpackages:
- client
- name: github.com/go-openapi/spec
version: f7ae86df5bc115a2744343016c789a89f065a4bd
- name: github.com/go-openapi/strfmt
version: 34fc3ba7c0f5fb615fda47a2b4fbd4c641b215f2
- name: github.com/go-openapi/swag
version: 3b6d86cd965820f968760d5d419cb4add096bdd7
- name: github.com/go-openapi/validate
version: 027696d4b54399770f1cdcc6c6daa56975f9e14e
- name: github.com/go-resty/resty
version: 24dc7ba4bc1ef9215048b28e7248f99c42901db5
- name: github.com/hashicorp/go-cleanhttp
version: ad28ea4487f05916463e2423a55166280e8254b5
- name: github.com/iron-io/functions_go
version: f38f2174656467ec3ed404b7294e9ee172573e43
version: 69e4dec8454c3c710045263c2ede76139c141146
subpackages:
- client
- client/apps
- client/routes
- client/tasks
- client/version
- models
- name: github.com/iron-io/iron_go3
version: b50ecf8ff90187fc5fabccd9d028dd461adce4ee
subpackages:
@@ -85,7 +125,7 @@ imports:
- config
- worker
- name: github.com/iron-io/lambda
version: d883e4b5ef216c3fcda72cf6628d9d72dd53be49
version: 4a046af3249dd5933a8d328f965e9717c97fef24
subpackages:
- lambda
- name: github.com/jmespath/go-jmespath
@@ -96,30 +136,49 @@ imports:
version: 08cceb5d0b5331634b9826762a8fd53b29b86ad8
subpackages:
- errors
- name: github.com/mailru/easyjson
version: 159cdb893c982e3d1bc6450322fedd514f9c9de3
subpackages:
- buffer
- jlexer
- jwriter
- name: github.com/Microsoft/go-winio
version: ce2922f643c8fd76b46cadc7f404a06282678b34
version: 24a3e3d3fc7451805e09d11e11e95d9a0a4f205e
- name: github.com/mitchellh/mapstructure
version: f3009df150dadf309fdee4a54ed65c124afad715
- name: github.com/opencontainers/runc
version: 49ed0a10e4edba88f9221ec730d668099f6d6de8
version: 8893fa693bf9bf29e5a156369bc51b887df43924
subpackages:
- libcontainer/system
- libcontainer/user
- name: github.com/PuerkitoBio/purell
version: 0bcb03f4b4d0a9428594752bd2a3b9aa0a9d4bd4
- name: github.com/PuerkitoBio/urlesc
version: 5bd2802263f21d8788851d5305584c82a5c75d7e
- name: github.com/satori/go.uuid
version: 879c5887cd475cd7864858769793b2ceb0d44feb
- name: github.com/Sirupsen/logrus
version: d26492970760ca5d33129d2d799e34be5c4782eb
- name: github.com/urfave/cli
version: d86a009f5e13f83df65d0d6cee9a2e3f1445f0da
version: 0bdeddeeb0f650497d603c4ad7b20cfe685682f6
- name: golang.org/x/net
version: f315505cf3349909cdf013ea56690da34e96a451
subpackages:
- context
- context/ctxhttp
- idna
- publicsuffix
- name: golang.org/x/sys
version: c200b10b5d5e122be351b67af224adc6128af5bf
version: d5645953809d8b4752afb2c3224b1f1ad73dfa70
subpackages:
- unix
- windows
- name: golang.org/x/text
version: 5c6cf4f9a2357d38515014cea8c488ed22bdab90
subpackages:
- transform
- unicode/norm
- width
- name: gopkg.in/yaml.v2
version: a5b47d31c556af34a302ce5d659e6fea44d90de0
testImports: []

View File

@@ -1,6 +1,7 @@
package main
import (
"context"
"encoding/json"
"errors"
"fmt"
@@ -13,17 +14,20 @@ import (
"text/tabwriter"
"time"
functions "github.com/iron-io/functions_go"
fnclient "github.com/iron-io/functions_go/client"
apiroutes "github.com/iron-io/functions_go/client/routes"
"github.com/iron-io/functions_go/models"
"github.com/jmoiron/jsonq"
"github.com/urfave/cli"
)
type routesCmd struct {
*functions.RoutesApi
client *fnclient.Functions
}
func routes() cli.Command {
r := routesCmd{RoutesApi: functions.NewRoutesApi()}
r := routesCmd{client: apiClient()}
return cli.Command{
Name: "routes",
@@ -167,7 +171,7 @@ func routes() cli.Command {
}
func call() cli.Command {
r := routesCmd{RoutesApi: functions.NewRoutesApi()}
r := routesCmd{client: apiClient()}
return cli.Command{
Name: "call",
@@ -183,35 +187,33 @@ func (a *routesCmd) list(c *cli.Context) error {
return errors.New("error: routes listing takes one argument, an app name")
}
if err := resetBasePath(a.Configuration); err != nil {
return fmt.Errorf("error setting endpoint: %v", err)
}
appName := c.Args().Get(0)
wrapper, _, err := a.AppsAppRoutesGet(appName)
if err != nil {
return fmt.Errorf("error getting routes: %v", err)
}
if msg := wrapper.Error_.Message; msg != "" {
return errors.New(msg)
}
resp, err := a.client.Routes.GetAppsAppRoutes(&apiroutes.GetAppsAppRoutesParams{
Context: context.Background(),
App: appName,
})
baseURL, err := url.Parse(a.Configuration.BasePath)
if err != nil {
return fmt.Errorf("error parsing base path: %v", err)
switch err.(type) {
case *apiroutes.GetAppsAppRoutesNotFound:
return fmt.Errorf("error: %v", err.(*apiroutes.GetAppsAppRoutesNotFound).Payload.Error.Message)
case *apiroutes.GetAppsAppRoutesDefault:
return fmt.Errorf("unexpected error: %v", err.(*apiroutes.GetAppsAppRoutesDefault).Payload.Error.Message)
}
return fmt.Errorf("unexpected error: %v", err)
}
w := tabwriter.NewWriter(os.Stdout, 0, 8, 0, '\t', 0)
fmt.Fprint(w, "path", "\t", "image", "\t", "endpoint", "\n")
for _, route := range wrapper.Routes {
for _, route := range resp.Payload.Routes {
u, err := url.Parse("../")
u.Path = path.Join(u.Path, "r", appName, route.Path)
if err != nil {
return fmt.Errorf("error parsing functions route path: %v", err)
}
fmt.Fprint(w, route.Path, "\t", route.Image, "\t", baseURL.ResolveReference(u).String(), "\n")
fmt.Fprint(w, route.Path, "\t", route.Image, "\n")
}
w.Flush()
@@ -223,23 +225,17 @@ func (a *routesCmd) call(c *cli.Context) error {
return errors.New("error: routes listing takes three arguments: an app name and a route")
}
if err := resetBasePath(a.Configuration); err != nil {
return fmt.Errorf("error setting endpoint: %v", err)
}
appName := c.Args().Get(0)
route := c.Args().Get(1)
baseURL, err := url.Parse(a.Configuration.BasePath)
if err != nil {
return fmt.Errorf("error parsing base path: %v", err)
u := url.URL{
Scheme: "http",
Host: host(),
}
u, err := url.Parse("../")
u.Path = path.Join(u.Path, "r", appName, route)
content := stdin()
return callfn(baseURL.ResolveReference(u).String(), content, os.Stdout, c.StringSlice("e"))
return callfn(u.String(), content, os.Stdout, c.StringSlice("e"))
}
func callfn(u string, content io.Reader, output io.Writer, env []string) error {
@@ -281,10 +277,6 @@ func (a *routesCmd) create(c *cli.Context) error {
return errors.New("error: routes creation takes at least one argument: an app name")
}
if err := resetBasePath(a.Configuration); err != nil {
return fmt.Errorf("error setting endpoint: %v", err)
}
appName := c.Args().Get(0)
route := c.Args().Get(1)
image := c.Args().Get(2)
@@ -298,9 +290,8 @@ func (a *routesCmd) create(c *cli.Context) error {
if err != nil {
if _, ok := err.(*notFoundError); ok {
return errors.New("error: image name is missing or no function file found")
} else {
return err
}
return err
}
image = ff.FullName()
if ff.Format != nil {
@@ -334,29 +325,39 @@ func (a *routesCmd) create(c *cli.Context) error {
timeout = t
}
body := functions.RouteWrapper{
Route: functions.Route{
to := int64(timeout.Seconds())
body := &models.RouteWrapper{
Route: &models.Route{
Path: route,
Image: image,
Memory: c.Int64("memory"),
Type_: c.String("type"),
Type: c.String("type"),
Config: extractEnvConfig(c.StringSlice("config")),
Format: format,
MaxConcurrency: int32(maxC),
Timeout: int32(timeout.Seconds()),
Timeout: &to,
},
}
wrapper, _, err := a.AppsAppRoutesPost(appName, body)
resp, err := a.client.Routes.PostAppsAppRoutes(&apiroutes.PostAppsAppRoutesParams{
Context: context.Background(),
App: appName,
Body: body,
})
if err != nil {
return fmt.Errorf("error creating route: %v", err)
switch err.(type) {
case *apiroutes.PostAppsAppRoutesBadRequest:
return fmt.Errorf("error: %v", err.(*apiroutes.PostAppsAppRoutesBadRequest).Payload.Error.Message)
case *apiroutes.PostAppsAppRoutesConflict:
return fmt.Errorf("error: %v", err.(*apiroutes.PostAppsAppRoutesConflict).Payload.Error.Message)
case *apiroutes.PostAppsAppRoutesDefault:
return fmt.Errorf("unexpected error: %v", err.(*apiroutes.PostAppsAppRoutesDefault).Payload.Error.Message)
}
return fmt.Errorf("unexpected error: %v", err)
}
if msg := wrapper.Error_.Message; msg != "" {
return errors.New(msg)
}
fmt.Println(wrapper.Route.Path, "created with", wrapper.Route.Image)
fmt.Println(resp.Payload.Route.Path, "created with", resp.Payload.Route.Image)
return nil
}
@@ -365,63 +366,118 @@ func (a *routesCmd) delete(c *cli.Context) error {
return errors.New("error: routes listing takes three arguments: an app name and a path")
}
if err := resetBasePath(a.Configuration); err != nil {
return fmt.Errorf("error setting endpoint: %v", err)
}
appName := c.Args().Get(0)
route := c.Args().Get(1)
resp, err := a.AppsAppRoutesRouteDelete(appName, route)
_, err := a.client.Routes.DeleteAppsAppRoutesRoute(&apiroutes.DeleteAppsAppRoutesRouteParams{
Context: context.Background(),
App: appName,
Route: route,
})
if err != nil {
return fmt.Errorf("error deleting route: %v", err)
switch err.(type) {
case *apiroutes.DeleteAppsAppRoutesRouteNotFound:
return fmt.Errorf("error: %v", err.(*apiroutes.DeleteAppsAppRoutesRouteNotFound).Payload.Error.Message)
case *apiroutes.DeleteAppsAppRoutesRouteDefault:
return fmt.Errorf("unexpected error: %v", err.(*apiroutes.DeleteAppsAppRoutesRouteDefault).Payload.Error.Message)
}
if resp.StatusCode >= http.StatusBadRequest {
return fmt.Errorf("route not found: %s", route)
return fmt.Errorf("unexpected error: %v", err)
}
fmt.Println(route, "deleted")
return nil
}
func (a *routesCmd) update(c *cli.Context) error {
if c.Args().Get(0) == "" {
return errors.New("error: routes creation takes at least one argument: an app name")
}
// _, err = a.client.Routes.PatchAppsAppRoutesRoute(&apiroutes.PatchAppsAppRoutesRouteParams{
// Context: context.Background(),
// App: appName,
// Route: route,
// Body: resp.Payload,
// })
if err := resetBasePath(a.Configuration); err != nil {
return fmt.Errorf("error setting endpoint: %v", err)
// if err != nil {
// switch err.(type) {
// case *apiroutes.PatchAppsAppRoutesRouteBadRequest:
// return fmt.Errorf("error: %v", err.(*apiroutes.PatchAppsAppRoutesRouteBadRequest).Payload.Error.Message)
// case *apiroutes.PatchAppsAppRoutesRouteNotFound:
// return fmt.Errorf("error: %v", err.(*apiroutes.PatchAppsAppRoutesRouteNotFound).Payload.Error.Message)
// case *apiroutes.PatchAppsAppRoutesRouteDefault:
// return fmt.Errorf("unexpected error: %v", err.(*apiroutes.PatchAppsAppRoutesRouteDefault).Payload.Error.Message)
// }
// return fmt.Errorf("unexpected error: %v", err)
// }
func (a *routesCmd) update(c *cli.Context) error {
if c.Args().Get(0) == "" || c.Args().Get(1) == "" {
return errors.New("error: route configuration description takes two arguments: an app name and a route")
}
appName := c.Args().Get(0)
route := c.Args().Get(1)
if route == "" {
return errors.New("error: route path is missing")
}
headers := map[string][]string{}
for _, header := range c.StringSlice("headers") {
parts := strings.Split(header, "=")
headers[parts[0]] = strings.Split(parts[1], ";")
}
patchRoute := &functions.Route{
Image: c.String("image"),
Memory: c.Int64("memory"),
Type_: c.String("type"),
Config: extractEnvConfig(c.StringSlice("config")),
Headers: headers,
Format: c.String("format"),
MaxConcurrency: int32(c.Int64("max-concurrency")),
Timeout: int32(c.Int64("timeout")),
}
err := a.patchRoute(appName, route, patchRoute)
resp, err := a.client.Routes.GetAppsAppRoutesRoute(&apiroutes.GetAppsAppRoutesRouteParams{
Context: context.Background(),
App: appName,
Route: route,
})
if err != nil {
return err
switch err.(type) {
case *apiroutes.GetAppsAppRoutesRouteNotFound:
return fmt.Errorf("error: %v", err.(*apiroutes.GetAppsAppRoutesRouteNotFound).Payload.Error.Message)
case *apiroutes.GetAppsAppRoutesRouteDefault:
return fmt.Errorf("unexpected error: %v", err.(*apiroutes.GetAppsAppRoutesRouteDefault).Payload.Error.Message)
}
return fmt.Errorf("unexpected error: %v", err)
}
config := resp.Payload.Route.Config
if len(config) == 0 {
return errors.New("this route has no configurations")
}
if c.Bool("json") {
if err := json.NewEncoder(os.Stdout).Encode(config); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
} else if c.Bool("shell") {
for k, v := range config {
fmt.Print("export ", k, "=", v, "\n")
}
} else {
fmt.Println(appName, resp.Payload.Route.Path, "configuration:")
w := tabwriter.NewWriter(os.Stdout, 0, 8, 1, ' ', 0)
for k, v := range config {
fmt.Fprint(w, k, ":\t", v, "\n")
}
w.Flush()
}
// if route == "" {
// return errors.New("error: route path is missing")
// }
// headers := map[string][]string{}
// for _, header := range c.StringSlice("headers") {
// parts := strings.Split(header, "=")
// headers[parts[0]] = strings.Split(parts[1], ";")
// }
// patchRoute := &functions.Route{
// Image: c.String("image"),
// Memory: c.Int64("memory"),
// Type_: c.String("type"),
// Config: extractEnvConfig(c.StringSlice("config")),
// Headers: headers,
// Format: c.String("format"),
// MaxConcurrency: int32(c.Int64("max-concurrency")),
// Timeout: int32(c.Int64("timeout")),
// }
// err := a.patchRoute(appName, route, patchRoute)
// if err != nil {
// return err
// }
fmt.Println(appName, route, "updated")
return nil
@@ -432,27 +488,69 @@ func (a *routesCmd) configSet(c *cli.Context) error {
return errors.New("error: route configuration setting takes four arguments: an app name, a route, a key and a value")
}
if err := resetBasePath(a.Configuration); err != nil {
return fmt.Errorf("error setting endpoint: %v", err)
}
appName := c.Args().Get(0)
route := c.Args().Get(1)
key := c.Args().Get(2)
value := c.Args().Get(3)
patchRoute := functions.Route{
Config: make(map[string]string),
}
resp, err := a.client.Routes.GetAppsAppRoutesRoute(&apiroutes.GetAppsAppRoutesRouteParams{
Context: context.Background(),
App: appName,
Route: route,
})
patchRoute.Config[key] = value
err := a.patchRoute(appName, route, &patchRoute)
if err != nil {
return err
switch err.(type) {
case *apiroutes.GetAppsAppRoutesRouteNotFound:
return fmt.Errorf("error: %v", err.(*apiroutes.GetAppsAppRoutesRouteNotFound).Payload.Error.Message)
case *apiroutes.GetAppsAppRoutesRouteDefault:
return fmt.Errorf("unexpected error: %v", err.(*apiroutes.GetAppsAppRoutesRouteDefault).Payload.Error.Message)
}
return fmt.Errorf("unexpected error: %v", err)
}
fmt.Println(appName, route, "updated", key, "with", value)
config := resp.Payload.Route.Config
if config == nil {
config = make(map[string]string)
}
config[key] = value
resp.Payload.Route.Config = config
_, err = a.client.Routes.PatchAppsAppRoutesRoute(&apiroutes.PatchAppsAppRoutesRouteParams{
Context: context.Background(),
App: appName,
Route: route,
Body: resp.Payload,
})
if err != nil {
switch err.(type) {
case *apiroutes.PatchAppsAppRoutesRouteBadRequest:
return fmt.Errorf("error: %v", err.(*apiroutes.PatchAppsAppRoutesRouteBadRequest).Payload.Error.Message)
case *apiroutes.PatchAppsAppRoutesRouteNotFound:
return fmt.Errorf("error: %v", err.(*apiroutes.PatchAppsAppRoutesRouteNotFound).Payload.Error.Message)
case *apiroutes.PatchAppsAppRoutesRouteDefault:
return fmt.Errorf("unexpected error: %v", err.(*apiroutes.PatchAppsAppRoutesRouteDefault).Payload.Error.Message)
}
return fmt.Errorf("unexpected error: %v", err)
}
fmt.Println(appName, resp.Payload.Route.Path, "updated", key, "with", value)
// patchRoute := functions.Route{
// Config: make(map[string]string),
// }
// patchRoute.Config[key] = value
// err := a.patchRoute(appName, route, &patchRoute)
// if err != nil {
// return err
// }
// fmt.Println(appName, route, "updated", key, "with", value)
return nil
}
@@ -461,84 +559,40 @@ func (a *routesCmd) configUnset(c *cli.Context) error {
return errors.New("error: route configuration setting takes four arguments: an app name, a route and a key")
}
if err := resetBasePath(a.Configuration); err != nil {
return fmt.Errorf("error setting endpoint: %v", err)
}
appName := c.Args().Get(0)
route := c.Args().Get(1)
key := c.Args().Get(2)
patchRoute := functions.Route{
Config: make(map[string]string),
}
resp, err := a.client.Routes.GetAppsAppRoutesRoute(&apiroutes.GetAppsAppRoutesRouteParams{
Context: context.Background(),
App: appName,
Route: route,
})
patchRoute.Config["-"+key] = ""
err := a.patchRoute(appName, route, &patchRoute)
if err != nil {
return err
switch err.(type) {
case *apiroutes.GetAppsAppRoutesRouteNotFound:
return fmt.Errorf("error: %v", err.(*apiroutes.GetAppsAppRoutesRouteNotFound).Payload.Error.Message)
case *apiroutes.GetAppsAppRoutesRouteDefault:
return fmt.Errorf("unexpected error: %v", err.(*apiroutes.GetAppsAppRoutesRouteDefault).Payload.Error.Message)
}
return fmt.Errorf("unexpected error: %v", err)
}
fmt.Println(appName, route, "removed", key)
return nil
}
config := resp.Payload.Route.Config
func (a *routesCmd) patchRoute(appName, routePath string, r *functions.Route) error {
wrapper, _, err := a.AppsAppRoutesRouteGet(appName, routePath)
if err != nil {
return fmt.Errorf("error loading route: %v", err)
if config == nil {
config = make(map[string]string)
}
if msg := wrapper.Error_.Message; msg != "" {
return errors.New(msg)
if _, ok := config[key]; !ok {
return fmt.Errorf("configuration key %s not found", key)
}
wrapper.Route.Path = ""
if r != nil {
if r.Config != nil {
for k, v := range r.Config {
if string(k[0]) == "-" {
delete(r.Config, string(k[1:]))
continue
}
wrapper.Route.Config[k] = v
}
}
if r.Headers != nil {
for k, v := range r.Headers {
if v[0] == "" {
delete(r.Headers, k)
continue
}
wrapper.Route.Headers[k] = v
}
}
if r.Image != "" {
wrapper.Route.Image = r.Image
}
if r.Format != "" {
wrapper.Route.Format = r.Format
}
if r.MaxConcurrency > 0 {
wrapper.Route.MaxConcurrency = r.MaxConcurrency
}
if r.Memory > 0 {
wrapper.Route.Memory = r.Memory
}
if r.Timeout > 0 {
wrapper.Route.Timeout = r.Timeout
}
}
if wrapper, _, err = a.AppsAppRoutesRoutePatch(appName, routePath, *wrapper); err != nil {
return fmt.Errorf("error updating route: %v", err)
}
if msg := wrapper.Error_.Message; msg != "" {
return errors.New(msg)
}
delete(config, key)
resp.Payload.Route.Config = config
fmt.Println(appName, resp.Payload.Route.Path, "removed", key)
return nil
}
@@ -547,38 +601,35 @@ func (a *routesCmd) inspect(c *cli.Context) error {
return errors.New("error: routes listing takes three arguments: an app name and a path")
}
if err := resetBasePath(a.Configuration); err != nil {
return fmt.Errorf("error setting endpoint: %v", err)
}
appName := c.Args().Get(0)
route := c.Args().Get(1)
prop := c.Args().Get(2)
wrapper, resp, err := a.AppsAppRoutesRouteGet(appName, route)
if err != nil {
return fmt.Errorf("error retrieving route: %v", err)
}
resp, err := a.client.Routes.GetAppsAppRoutesRoute(&apiroutes.GetAppsAppRoutesRouteParams{
Context: context.Background(),
App: appName,
Route: route,
})
if msg := wrapper.Error_.Message; msg != "" {
return errors.New(msg)
if err != nil {
switch err.(type) {
case *apiroutes.GetAppsAppRoutesRouteNotFound:
return fmt.Errorf("error: %v", err.(*apiroutes.GetAppsAppRoutesRouteNotFound).Payload.Error.Message)
case *apiroutes.GetAppsAppRoutesRouteDefault:
return fmt.Errorf("unexpected error: %v", err.(*apiroutes.GetAppsAppRoutesRouteDefault).Payload.Error.Message)
}
return fmt.Errorf("unexpected error: %v", err)
}
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", "\t")
if prop == "" {
enc.Encode(wrapper.Route)
enc.Encode(resp.Payload.Route)
return nil
}
var inspect struct{ Route map[string]interface{} }
err = json.Unmarshal(resp.Payload, &inspect)
if err != nil {
return fmt.Errorf("error inspect route: %v", err)
}
jq := jsonq.NewQuery(inspect.Route)
jq := jsonq.NewQuery(resp.Payload.Route)
field, err := jq.Interface(strings.Split(prop, ".")...)
if err != nil {
return errors.New("failed to inspect the property")