cmd

package
v0.9.7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 10, 2020 License: MIT Imports: 18 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var APICommand = cli.Command{
	Name:      "api",
	Usage:     "Call Barcelona API",
	ArgsUsage: "METHOD PATH [BODY]",
	Action: func(c *cli.Context) error {
		method := strings.ToUpper(c.Args().Get(0))
		path := c.Args().Get(1)
		body := bytes.NewBufferString(c.Args().Get(2))

		oper := operations.NewApiOperation(method, path, body, api.DefaultClient)
		return operations.Execute(oper)
	},
}
View Source
var AppCommand = cli.Command{
	Name:  "app",
	Usage: "Manage heritages",
	Subcommands: []cli.Command{
		{
			Name:      "delete",
			Usage:     "Delete a heritage",
			ArgsUsage: "HERITAGE_NAME",
			Flags: []cli.Flag{
				cli.BoolFlag{
					Name: "no-confirmation",
				},
			},
			Action: func(c *cli.Context) error {
				name := c.Args().Get(0)

				oper := operations.NewAppOperation(name, operations.Delete, c.Bool("no-confirmation"), api.DefaultClient, utils.NewStdinInputReader())
				return operations.Execute(oper)
			},
		},
		{
			Name:      "show",
			Usage:     "Show a heritage",
			ArgsUsage: "HERITAGE_NAME",
			Action: func(c *cli.Context) error {
				name := c.Args().Get(0)

				oper := operations.NewAppOperation(name, operations.Show, false, api.DefaultClient, utils.NewStdinInputReader())
				return operations.Execute(oper)
			},
		},
	},
}
View Source
var CreateCommand = cli.Command{
	Name:  "create",
	Usage: "Create a new Barcelona heritage",
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:  "environment, e",
			Usage: "Environment of heritage",
		},
		cli.StringFlag{
			Name:  "district, d",
			Value: "default",
			Usage: "District name",
		},
		cli.StringFlag{
			Name:  "tag, t",
			Value: "latest",
			Usage: "District name",
		},
	},
	Action: func(c *cli.Context) error {
		h, err := LoadEnvironment(c.String("environment"))
		if err != nil {
			return cli.NewExitError(err.Error(), 1)
		}
		h.FillinDefaults()
		h.ImageTag = c.String("tag")

		resp, err := api.DefaultClient.CreateHeritage(c.String("district"), h)
		if err != nil {
			return cli.NewExitError(err.Error(), 1)
		}
		resp.Print()

		return nil
	},
}
View Source
var DeployCommand = cli.Command{
	Name:  "deploy",
	Usage: "Deploy a Barcelona heritage",
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:  "environment, e",
			Usage: "Environment of heritage",
		},
		cli.StringFlag{
			Name:  "tag, t",
			Usage: "Tag of docker image",
		},
		cli.StringFlag{
			Name:  "heritage-token",
			Usage: "Heritage token",
		},
		cli.BoolFlag{
			Name:  "quiet, q",
			Usage: "Do not print output if successful",
		},
	},
	Action: func(c *cli.Context) error {
		env := c.String("environment")
		tag := c.String("tag")
		token := c.String("heritage-token")
		quiet := c.Bool("quiet")

		var heritage *api.Heritage
		var err error
		if len(token) > 0 {
			heritage, err = doDeployWithHeritageToken(env, tag, token)
		} else {
			heritage, err = doDeploy(env, tag)
		}
		if err != nil {
			return cli.NewExitError(err.Error(), 1)
		}

		if !quiet {
			heritage.Print()
		}

		return nil
	},
}
View Source
var DistrictCommand = cli.Command{
	Name:  "district",
	Usage: "District operations",
	Subcommands: []cli.Command{
		{
			Name:      "create",
			Usage:     "Create a new district",
			ArgsUsage: "DISTRICT_NAME",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "region",
					Value: "us-east-1",
					Usage: "AWS region",
				},
				cli.StringFlag{
					Name:  "nat-type",
					Value: "instance",
					Usage: "NAT type",
				},
				cli.StringFlag{
					Name:  "cluster-instance-type",
					Value: "t2.small",
					Usage: "Cluster Instance Type",
				},
			},
			Action: func(c *cli.Context) error {
				districtName := c.Args().Get(0)
				if len(districtName) == 0 {
					return cli.NewExitError("district name is required", 1)
				}

				size := 1
				request := api.DistrictRequest{
					Name:                districtName,
					Region:              c.String("region"),
					NatType:             c.String("nat-type"),
					ClusterSize:         &size,
					ClusterInstanceType: c.String("cluster-instance-type"),
					ClusterBackend:      "autoscaling",
				}
				request.AwsAccessKeyId = utils.Ask("AWS Access Key ID", true, false, utils.NewStdinInputReader())
				request.AwsSecretAccessKey = utils.Ask("AWS Secret Access Key", true, true, utils.NewStdinInputReader())

				district, err := api.DefaultClient.CreateDistrict(&request)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}

				printDistrict(district)

				return nil
			},
		},
		{
			Name:  "list",
			Usage: "List Districts",
			Action: func(c *cli.Context) error {
				districts, err := api.DefaultClient.ListDistricts()
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}
				printDistricts(districts)

				return nil
			},
		},
		{
			Name:      "show",
			Usage:     "Show District Information",
			ArgsUsage: "DISTRICT_NAME",
			Action: func(c *cli.Context) error {
				districtName := c.Args().Get(0)
				if len(districtName) == 0 {
					return cli.NewExitError("district name is required", 1)
				}

				district, err := api.DefaultClient.ShowDistrict(districtName)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}
				printDistrict(district)

				return nil
			},
		},
		{
			Name:      "update",
			Usage:     "Update District Information",
			ArgsUsage: "DISTRICT_NAME",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "nat-type",
					Usage: "NAT type",
				},
				cli.StringFlag{
					Name:  "cluster-instance-type",
					Usage: "Cluster Instance Type",
				},
				cli.IntFlag{
					Name:  "cluster-size",
					Value: -1,
					Usage: "Cluster Instance Type",
				},
				cli.BoolFlag{
					Name:  "apply",
					Usage: "Apply immediately",
				},
			},
			Action: func(c *cli.Context) error {
				districtName := c.Args().Get(0)
				if len(districtName) == 0 {
					return cli.NewExitError("district name is required", 1)
				}

				request := api.DistrictRequest{
					Name:                districtName,
					NatType:             c.String("nat-type"),
					ClusterInstanceType: c.String("cluster-instance-type"),
				}
				if size := c.Int("cluster-size"); size >= 0 {
					request.ClusterSize = &size
				}

				district, err := api.DefaultClient.UpdateDistrict(&request)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}
				printDistrict(district)

				err = applyOrNotice(districtName, c.Bool("apply"))
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}

				return nil
			},
		},
		{
			Name:      "apply",
			Usage:     "apply district stack",
			ArgsUsage: "DISTRICT_NAME",
			Action: func(c *cli.Context) error {
				districtName := c.Args().Get(0)
				if len(districtName) == 0 {
					return cli.NewExitError("district name is required", 1)
				}

				err := applyOrNotice(districtName, true)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}

				return nil
			},
		},
		{
			Name:      "delete",
			Usage:     "Delete a district",
			ArgsUsage: "DISTRICT_NAME",
			Flags: []cli.Flag{
				cli.BoolFlag{
					Name: "no-confirmation",
				},
			},
			Action: func(c *cli.Context) error {
				districtName := c.Args().Get(0)
				if len(districtName) == 0 {
					return cli.NewExitError("district name is required", 1)
				}

				fmt.Printf("You are attempting to delete %s\n", districtName)
				if !c.Bool("no-confirmation") && !utils.AreYouSure("This operation cannot be undone. Are you sure?", utils.NewStdinInputReader()) {
					return nil
				}

				err := api.DefaultClient.DeleteDistrict(districtName)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}
				return nil
			},
		},
		{
			Name:      "put-plugin",
			Usage:     "Add or Update plugin configuration",
			ArgsUsage: "DISTRICT_NAME PLUGIN_NAME",
			Flags: []cli.Flag{
				cli.StringSliceFlag{
					Name:  "attribute, a",
					Usage: "ATTR_NAME=VALUE",
				},
				cli.BoolFlag{
					Name:  "apply",
					Usage: "Apply immediately",
				},
			},
			Action: func(c *cli.Context) error {
				districtName := c.Args().Get(0)
				if len(districtName) == 0 {
					return cli.NewExitError("district name is required", 1)
				}

				pluginName := c.Args().Get(1)
				if len(districtName) == 0 {
					return cli.NewExitError("plugin name is required", 1)
				}

				req := api.Plugin{
					Name: pluginName,
				}
				req.Attributes = make(map[string]string)
				attrs := c.StringSlice("attribute")
				for _, s := range attrs {
					ss := strings.SplitN(s, "=", 2)
					req.Attributes[ss[0]] = ss[1]
				}

				plugin, err := api.DefaultClient.PutPlugin(districtName, &req)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}
				printPlugin(plugin)

				err = applyOrNotice(districtName, c.Bool("apply"))
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}

				return nil
			},
		},
		{
			Name:      "delete-plugin",
			Usage:     "Delete a plugin",
			ArgsUsage: "DISTRICT_NAME PLUGIN_NAME",
			Action: func(c *cli.Context) error {
				districtName := c.Args().Get(0)
				if len(districtName) == 0 {
					return cli.NewExitError("district name is required", 1)
				}

				pluginName := c.Args().Get(1)
				if len(districtName) == 0 {
					return cli.NewExitError("plugin name is required", 1)
				}

				err := api.DefaultClient.DeletePlugin(districtName, pluginName)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}
				return nil
			},
		},
		{
			Name:      "put-dockercfg",
			Usage:     "Add or Replace dockercfg",
			ArgsUsage: "DISTRICT_NAME",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "filename, f",
					Usage: "FILENAME",
				},
				cli.StringFlag{
					Name:  "config, c",
					Usage: "JSON",
				},
				cli.BoolFlag{
					Name:  "apply",
					Usage: "Apply immediately",
				},
			},
			Action: func(c *cli.Context) error {
				districtName := c.Args().Get(0)
				if len(districtName) == 0 {
					return cli.NewExitError("district name is required", 1)
				}

				filename := c.String("filename")
				config := c.String("config")

				if len(filename) > 0 && len(config) > 0 {
					return cli.NewExitError("filename and config are exclusive", 1)
				}

				var jsonBytes []byte
				var err error
				if len(filename) > 0 {
					jsonBytes, err = ioutil.ReadFile(filename)
					if err != nil {
						return cli.NewExitError(err.Error(), 1)
					}
				} else if len(config) > 0 {
					jsonBytes = []byte(config)
				} else {
					return cli.NewExitError("Specify dockercfg", 1)
				}

				var dockercfg interface{}
				err = json.Unmarshal(jsonBytes, &dockercfg)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}
				params := make(map[string]interface{})
				params["dockercfg"] = dockercfg
				paramsB, err := json.Marshal(params)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}

				_, err = api.DefaultClient.Patch("/districts/"+districtName, bytes.NewBuffer(paramsB))
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}

				err = applyOrNotice(districtName, c.Bool("apply"))
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}

				return nil
			},
		},
	},
}
View Source
var EndpointCommand = cli.Command{
	Name:  "endpoint",
	Usage: "Endpoint operations",
	Subcommands: []cli.Command{
		{
			Name:      "create",
			Usage:     "Create a new endpoint",
			ArgsUsage: "ENDPOINT_NAME",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "district, d",
					Value: "default",
					Usage: "AWS region",
				},
				cli.BoolFlag{
					Name:  "public",
					Usage: "Public facing endpoint",
				},
				cli.StringFlag{
					Name:  "certificate-arn",
					Usage: "ACM Certificate ARN",
				},
				cli.StringFlag{
					Name:  "ssl-policy",
					Usage: "HTTPS SSL Policy",
				},
			},
			Action: func(c *cli.Context) error {
				endpointName := c.Args().Get(0)
				if len(endpointName) == 0 {
					return cli.NewExitError("endpoint name is required", 1)
				}

				public := c.Bool("public")
				request := api.Endpoint{
					Name:          endpointName,
					Public:        &public,
					CertificateID: c.String("certificate-arn"),
					SslPolicy:     c.String("ssl-policy"),
				}

				b, err := json.Marshal(&request)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}

				resp, err := api.DefaultClient.Request("POST", fmt.Sprintf("/districts/%s/endpoints", c.String("district")), bytes.NewBuffer(b))
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}
				var eResp api.EndpointResponse
				err = json.Unmarshal(resp, &eResp)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}
				printEndpoint(eResp.Endpoint)

				return nil
			},
		},
		{
			Name:      "show",
			Usage:     "Show endpoint information",
			ArgsUsage: "ENDPOINT_NAME",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "district, d",
					Value: "default",
					Usage: "District name",
				},
			},
			Action: func(c *cli.Context) error {
				endpointName := c.Args().Get(0)
				if len(endpointName) == 0 {
					return cli.NewExitError("endpoint name is required", 1)
				}

				resp, err := api.DefaultClient.Request("GET", fmt.Sprintf("/districts/%s/endpoints/%s", c.String("district"), endpointName), nil)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}
				var eResp api.EndpointResponse
				err = json.Unmarshal(resp, &eResp)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}
				printEndpoint(eResp.Endpoint)

				return nil
			},
		},
		{
			Name:  "list",
			Usage: "List endpoints",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "district, d",
					Value: "default",
					Usage: "District name",
				},
			},
			Action: func(c *cli.Context) error {
				resp, err := api.DefaultClient.Request("GET", fmt.Sprintf("/districts/%s/endpoints", c.String("district")), nil)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}
				var eResp api.EndpointResponse
				err = json.Unmarshal(resp, &eResp)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}
				printEndpoints(eResp.Endpoints)

				return nil
			},
		},
		{
			Name:      "update",
			Usage:     "Update an endpoint",
			ArgsUsage: "ENDPOINT_NAME",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "district, d",
					Value: "default",
					Usage: "District name",
				},
				cli.StringFlag{
					Name:  "certificate-arn",
					Usage: "ACM Certificate ARN",
				},
				cli.StringFlag{

					Usage: "HTTPS SSL Policy",
				},
			},
			Action: func(c *cli.Context) error {
				endpointName := c.Args().Get(0)
				if len(endpointName) == 0 {
					return cli.NewExitError("endpoint name is required", 1)
				}

				request := api.Endpoint{
					CertificateID: c.String("certificate-arn"),
					SslPolicy:     c.String("ssl-policy"),
				}

				b, err := json.Marshal(&request)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}

				resp, err := api.DefaultClient.Request("PATCH", fmt.Sprintf("/districts/%s/endpoints/%s", c.String("district"), endpointName), bytes.NewBuffer(b))
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}
				var eResp api.EndpointResponse
				err = json.Unmarshal(resp, &eResp)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}
				printEndpoint(eResp.Endpoint)

				return nil
			},
		},
		{
			Name:      "delete",
			Usage:     "Delete an endpoint",
			ArgsUsage: "ENDPOINT_NAME",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "district, d",
					Value: "default",
					Usage: "District name",
				},
				cli.BoolFlag{
					Name: "no-confirmation",
				},
			},
			Action: func(c *cli.Context) error {
				endpointName := c.Args().Get(0)
				if len(endpointName) == 0 {
					return cli.NewExitError("endpoint name is required", 1)
				}

				fmt.Printf("You are attempting to delete /%s/endpoints/%s\n", c.String("district"), endpointName)
				if !c.Bool("no-confirmation") && !utils.AreYouSure("This operation cannot be undone. Are you sure?", utils.NewStdinInputReader()) {
					return nil
				}

				_, err := api.DefaultClient.Request("DELETE", fmt.Sprintf("/districts/%s/endpoints/%s", c.String("district"), endpointName), nil)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}
				return nil
			},
		},
	},
}
View Source
var EnvCommand = cli.Command{
	Name:  "env",
	Usage: "Environment variable operations",
	Subcommands: []cli.Command{
		{
			Name:  "get",
			Usage: "Get environment variables",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "environment, e",
					Usage: "Environment of heritage",
				},
				cli.StringFlag{
					Name:  "heritage-name, H",
					Usage: "Heritage name",
				},
			},
			Action: func(c *cli.Context) error {
				envName := c.String("environment")
				heritageName := c.String("heritage-name")
				if len(envName) > 0 && len(heritageName) > 0 {
					return cli.NewExitError("environment and heritage-name are exclusive", 1)
				}
				if len(envName) > 0 {
					env, err := LoadEnvironment(c.String("environment"))
					if err != nil {
						return cli.NewExitError(err.Error(), 1)
					}
					heritageName = env.Name
				}

				resp, err := api.DefaultClient.Get("/heritages/"+heritageName, nil)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}
				var respHeritage api.HeritageResponse
				err = json.Unmarshal(resp, &respHeritage)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}
				printEnv(respHeritage.Heritage.EnvVars)

				return nil
			},
		},
		{
			Name:  "set",
			Usage: "Set environment variables",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "environment, e",
					Usage: "Environment of heritage",
				},
				cli.StringFlag{
					Name:  "heritage-name, H",
					Usage: "Heritage name",
				},
				cli.BoolFlag{
					Name:  "secret, s",
					Usage: "Save values as secret",
				},
			},
			ArgsUsage: "KEY1=VALUE1 [KEY2=VALUE2 ...]",
			Action: func(c *cli.Context) error {
				envName := c.String("environment")
				heritageName := c.String("heritage-name")
				if len(envName) > 0 && len(heritageName) > 0 {
					return cli.NewExitError("environment and heritage-name are exclusive", 1)
				}
				if len(envName) > 0 {
					env, err := LoadEnvironment(c.String("environment"))
					if err != nil {
						return cli.NewExitError(err.Error(), 1)
					}
					heritageName = env.Name
				}
				n := c.NArg()
				if n == 0 {
					return cli.NewExitError("Specify NAME=VALUE pairs", 1)
				}

				pairs := make(map[string]string)
				for i := 0; i < n; i++ {
					line := c.Args().Get(i)
					pair := strings.SplitN(line, "=", 2)
					pairs[pair[0]] = pair[1]
				}
				params := map[string]interface{}{
					"env_vars": pairs,
					"secret":   c.Bool("secret"),
				}
				j, err := json.Marshal(params)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}

				resp, err := api.DefaultClient.Post("/heritages/"+heritageName+"/env_vars", bytes.NewBuffer(j))
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}
				var respHeritage api.HeritageResponse
				err = json.Unmarshal(resp, &respHeritage)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}
				printEnv(respHeritage.Heritage.EnvVars)

				return nil
			},
		},
		{
			Name:      "unset",
			Usage:     "Unset environment variables",
			ArgsUsage: "KEY1 [KEY2 ...]",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "environment, e",
					Usage: "Environment of heritage",
				},
				cli.StringFlag{
					Name:  "heritage-name, H",
					Usage: "Heritage name",
				},
			},
			Action: func(c *cli.Context) error {
				envName := c.String("environment")
				heritageName := c.String("heritage-name")
				if len(envName) > 0 && len(heritageName) > 0 {
					return cli.NewExitError("environment and heritage-name are exclusive", 1)
				}
				if len(envName) > 0 {
					env, err := LoadEnvironment(c.String("environment"))
					if err != nil {
						return cli.NewExitError(err.Error(), 1)
					}
					heritageName = env.Name
				}

				params := map[string]interface{}{
					"env_keys": c.Args(),
				}
				j, err := json.Marshal(params)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}

				resp, err := api.DefaultClient.Delete("/heritages/"+heritageName+"/env_vars", bytes.NewBuffer(j))
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}
				var respHeritage api.HeritageResponse
				err = json.Unmarshal(resp, &respHeritage)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}
				printEnv(respHeritage.Heritage.EnvVars)

				return nil
			},
		},
	},
}
View Source
var LoginCommand = cli.Command{
	Name:      "login",
	Usage:     "Login Barcelona",
	ArgsUsage: "https://endpoint GITHUB_TOKEN",
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:  "auth, a",
			Usage: "Auth backend",
			Value: "github",
		},
		cli.StringFlag{
			Name:  "github-token",
			Usage: "GitHub Token",
		},
		cli.StringFlag{
			Name:  "vault-token",
			Usage: "Vault Token",
		},
		cli.StringFlag{
			Name:  "vault-url",
			Usage: "Vault URL",
		},
	},
	Action: func(c *cli.Context) error {
		endpoint := c.Args().Get(0)
		backend := c.String("auth")
		gh_token := c.String("github-token")
		vault_token := c.String("vault-token")
		vault_url := c.String("vault-url")

		ext := struct {
			utils.UserInputReader
			*operations.ProxyLoginOperationClient
			*config.LocalConfig
			*utils.CommandRunner
			*utils.FileOps
		}{
			utils.NewStdinInputReader(),
			&operations.ProxyLoginOperationClient{Client: api.DefaultClient},
			config.Get(),
			&utils.CommandRunner{},
			&utils.FileOps{},
		}

		operation := operations.NewLoginOperation(endpoint, backend, gh_token, vault_token, vault_url, ext)
		return operations.Execute(operation)
	},
	Subcommands: []cli.Command{
		{
			Name:  "info",
			Usage: "Show login information",
			Action: func(c *cli.Context) error {
				operation := operations.NewLoginInfoOperation(config.Get().LoadLogin())
				return operations.Execute(operation)
			},
		},
	},
}
View Source
var NotificationCommand = cli.Command{
	Name:  "notification",
	Usage: "Operate notification",
	Subcommands: []cli.Command{
		{
			Name:  "create",
			Usage: "Create a new notification",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "district, d",
					Value: "default",
					Usage: "District name",
				},
				cli.StringFlag{
					Name:  "target",
					Usage: "Notification Target",
				},
				cli.StringFlag{
					Name:  "endpoint",
					Usage: "Notification Endpoint",
				},
			},
			Action: func(c *cli.Context) error {
				target := c.String("target")
				if len(target) == 0 {
					return cli.NewExitError("target is required", 1)
				}
				endpoint := c.String("endpoint")
				if len(endpoint) == 0 {
					return cli.NewExitError("endpoint is required", 1)
				}

				request := api.Notification{
					Target:   target,
					Endpoint: endpoint,
				}

				b, err := json.Marshal(&request)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}

				resp, err := api.DefaultClient.Request("POST", fmt.Sprintf("/districts/%s/notifications", c.String("district")), bytes.NewBuffer(b))
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}
				var eResp api.NotificationResponse
				err = json.Unmarshal(resp, &eResp)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}
				printNotification(eResp.Notification)

				return nil
			},
		},
		{
			Name:      "show",
			Usage:     "Show notification",
			ArgsUsage: "ID",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "district, d",
					Value: "default",
					Usage: "District name",
				},
			},
			Action: func(c *cli.Context) error {
				id, err := parseIDArg(c)
				if err != nil {
					return err
				}

				resp, err := api.DefaultClient.Request("GET", fmt.Sprintf("/districts/%s/notifications/%d", c.String("district"), id), nil)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}
				var eResp api.NotificationResponse
				err = json.Unmarshal(resp, &eResp)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}
				printNotification(eResp.Notification)

				return nil
			},
		},
		{
			Name:      "update",
			Usage:     "Update notification",
			ArgsUsage: "ID",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "district, d",
					Value: "default",
					Usage: "District name",
				},
				cli.StringFlag{
					Name:  "target",
					Usage: "Notification Target",
				},
				cli.StringFlag{
					Name:  "endpoint",
					Usage: "Notification Endpoint",
				},
			},
			Action: func(c *cli.Context) error {
				id, err := parseIDArg(c)
				if err != nil {
					return err
				}

				request := api.Notification{
					ID:       id,
					Target:   c.String("target"),
					Endpoint: c.String("endpoint"),
				}

				b, err := json.Marshal(&request)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}
				fmt.Println(string(b))

				resp, err := api.DefaultClient.Request("PATCH", fmt.Sprintf("/districts/%s/notifications/%d", c.String("district"), id), bytes.NewBuffer(b))
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}
				var eResp api.NotificationResponse
				err = json.Unmarshal(resp, &eResp)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}
				printNotification(eResp.Notification)

				return nil
			},
		},
		{
			Name:      "delete",
			Usage:     "Delete notification",
			ArgsUsage: "ID",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "district, d",
					Value: "default",
					Usage: "District name",
				},
			},
			Action: func(c *cli.Context) error {
				id, err := parseIDArg(c)
				if err != nil {
					return err
				}

				_, err = api.DefaultClient.Request("DELETE", fmt.Sprintf("/districts/%s/notifications/%d", c.String("district"), id), nil)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}
				return nil
			},
		},
	},
}
View Source
var ReleaseCommand = cli.Command{
	Name:  "release",
	Usage: "Manipulate releases",
	Subcommands: []cli.Command{
		{
			Name:  "list",
			Usage: "List releases",
			Action: func(c *cli.Context) error {
				return nil
			},
		},
		{
			Name:  "rollback",
			Usage: "Roll back to the previous release",
			Action: func(c *cli.Context) error {
				return nil
			},
		},
	},
}
View Source
var ReviewCommand = cli.Command{
	Name:  "review",
	Usage: "Review Apps",
	Subcommands: []cli.Command{
		{
			Name:      "deploy",
			ArgsUsage: "SUBJECT",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "tag, t",
					Usage: "Tag of docker image",
				},
				cli.StringFlag{
					Name:  "token",
					Usage: "review group token",
				},
				cli.StringFlag{
					Name: "retention, r",
				},
			},
			Action: func(c *cli.Context) error {
				subject := c.Args().Get(0)
				tag := c.String("tag")
				token := c.String("token")
				retention := c.String("retention")
				var retentionSec int

				if len(retention) == 0 {
					retentionSec = 24 * 3600
				} else {
					d, err := time.ParseDuration(retention)
					if err != nil {
						return cli.NewExitError(err.Error(), 1)
					}
					retentionSec = int(d.Seconds())
				}

				reviewDef, err := LoadReviewDefinition()
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}

				com := DeployReviewApp{
					Request: &api.ReviewAppRequest{
						ReviewAppDefinition: reviewDef,
						Subject:             subject,
						Retention:           retentionSec,
						ImageTag:            tag,
					},
					Token: token,
				}

				return com.Execute()
			},
		},
		{
			Name:      "delete",
			ArgsUsage: "REVIEWAPP_NAME",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "group",
					Usage: "Review group name",
				},
				cli.StringFlag{
					Name:  "token",
					Usage: "review group token",
				},
			},
			Action: func(c *cli.Context) error {
				name := c.Args().Get(0)
				token := c.String("token")
				groupName := c.String("group")

				var err error
				if len(token) == 0 {
					_, err = api.DefaultClient.Delete("/review_groups/"+groupName+"/apps/"+name, nil)
				} else {
					_, err = api.DefaultClient.Delete("/review_groups/"+groupName+"/ci/apps/"+token+"/"+name, nil)

				}
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}

				return nil
			},
		},
		{
			Name: "list",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "group",
					Usage: "Review group name",
				},
			},
			Action: func(c *cli.Context) error {
				groupName := c.String("group")

				if len(groupName) == 0 {
					reviewDef, err := LoadReviewDefinition()
					if err != nil {
						return cli.NewExitError(err.Error(), 1)
					}
					groupName = reviewDef.GroupName
				}

				resp, err := api.DefaultClient.Get("/review_groups/"+groupName+"/apps", nil)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}
				var appResp api.ReviewAppResponse
				err = json.Unmarshal(resp, &appResp)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}
				renderApps(appResp.ReviewApps)

				return nil
			},
		},
		ReviewGroupCommand,
	},
}
View Source
var ReviewGroupCommand = cli.Command{
	Name: "group",
	Subcommands: []cli.Command{
		{
			Name:      "create",
			ArgsUsage: "GROUP_NAME",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "base-domain",
					Usage: "Base Domain Name",
				},
				cli.StringFlag{
					Name:  "endpoint",
					Usage: "Endpoint name",
				},
			},
			Action: func(c *cli.Context) error {
				name := c.Args().Get(0)
				if len(name) == 0 {
					return cli.NewExitError("Group name is required", 1)
				}

				req := api.ReviewGroupRequest{
					Name:         name,
					BaseDomain:   c.String("base-domain"),
					EndpointName: c.String("endpoint"),
				}

				j, err := json.Marshal(req)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}

				resp, err := api.DefaultClient.Post("/review_groups", bytes.NewBuffer(j))
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}

				var rResp api.ReviewGroupResponse
				err = json.Unmarshal(resp, &rResp)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}

				return nil
			},
		},
		{
			Name:      "show",
			ArgsUsage: "GROUP_NAME",
			Action: func(c *cli.Context) error {
				groupName := c.Args().Get(0)
				resp, err := api.DefaultClient.Get("/review_groups/"+groupName, nil)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}

				var rResp api.ReviewGroupResponse
				err = json.Unmarshal(resp, &rResp)
				group := rResp.ReviewGroup

				fmt.Println("Name: ", group.Name)
				fmt.Println("Base Domain: ", group.BaseDomain)
				fmt.Println("Endpoint: ", group.Endpoint.Name)
				fmt.Println("Token: ", *group.Token)
				fmt.Println("Apps")

				return nil
			},
		},
		{
			Name: "list",
			Action: func(c *cli.Context) error {
				resp, err := api.DefaultClient.Get("/review_groups", nil)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}

				var rResp api.ReviewGroupResponse
				err = json.Unmarshal(resp, &rResp)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}
				groups := rResp.ReviewGroups

				table := tablewriter.NewWriter(os.Stdout)
				table.SetHeader([]string{"Name", "Base Domain", "Endpoint"})
				table.SetBorder(false)
				for _, g := range groups {
					table.Append([]string{g.Name, g.BaseDomain, g.Endpoint.Name})
				}
				table.Render()

				return nil
			},
		},
		{
			Name:      "delete",
			ArgsUsage: "GROUP_NAME",
			Action: func(c *cli.Context) error {
				groupName := c.Args().Get(0)
				_, err := api.DefaultClient.Delete("/review_groups/"+groupName, nil)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}

				return nil
			},
		},
	},
}
View Source
var RunCommand = cli.Command{
	Name:      "run",
	Usage:     "Run command inside Barcelona environment",
	ArgsUsage: "COMMAND...",
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:  "environment, e",
			Usage: "Environment of heritage",
		},
		cli.StringFlag{
			Name:  "heritage-name, H",
			Usage: "Heritage name",
		},
		cli.IntFlag{
			Name:  "memory, m",
			Usage: "Memory size in MB",
		},
		cli.StringFlag{
			Name:  "user, u",
			Usage: "User name",
		},
		cli.BoolFlag{
			Name:  "detach, D",
			Usage: "Detach mode",
		},
		cli.StringSliceFlag{
			Name:  "envvar, E",
			Usage: "Environment variable to pass to task",
		},
	},
	Action: func(c *cli.Context) error {
		envName := c.String("environment")
		heritageName := c.String("heritage-name")
		detach := c.Bool("detach")
		envVars := c.StringSlice("envvar")
		envVarMap, loadEnvVarMapErr := loadEnvVars(envName)

		if loadEnvVarMapErr != nil {
			return cli.NewExitError(loadEnvVarMapErr.Error(), 1)
		}

		if len(envName) > 0 && len(heritageName) > 0 {
			return cli.NewExitError("environment and heritage-name are exclusive", 1)
		}

		if len(heritageName) == 0 {
			env, err := LoadEnvironment(envName)
			if err != nil {
				return cli.NewExitError(err.Error(), 1)
			}
			heritageName = env.Name
		}

		if len(envVars) > 0 {
			varmap, err := checkEnvVars(envVars)
			if err != nil {
				return cli.NewExitError(err.Error(), 1)
			}
			for k, v := range varmap {
				envVarMap[k] = v
			}
		}

		if len(c.Args()) == 0 {
			return cli.NewExitError("Command is required", 1)
		}
		command := strings.Join(c.Args(), " ")
		params := map[string]interface{}{
			"interactive": !detach,
			"command":     command,
			"env_vars":    envVarMap,
		}
		memory := c.Int("memory")
		if memory > 0 {
			params["memory"] = memory
		}

		user := c.String("user")
		if user != "" {
			params["user"] = user
		}
		j, err := json.Marshal(params)
		if err != nil {
			return cli.NewExitError(err.Error(), 1)
		}

		resp, err := api.DefaultClient.Post("/heritages/"+heritageName+"/oneoffs", bytes.NewBuffer(j))
		if err != nil {
			return cli.NewExitError(err.Error(), 1)
		}
		var respOneoff api.OneoffResponse
		err = json.Unmarshal(resp, &respOneoff)
		if err != nil {
			return cli.NewExitError(err.Error(), 1)
		}
		oneoff := respOneoff.Oneoff
		certificate := respOneoff.Certificate

		if detach {
			PrintOneoff(oneoff)
			return nil
		}

		fmt.Println("Waiting for the process to start")

	LOOP:
		for {
			path := fmt.Sprintf("/oneoffs/%d", oneoff.ID)
			resp, err := api.DefaultClient.Get(path, nil)
			if err != nil {
				return cli.NewExitError(err.Error(), 1)
			}
			var respOneoff api.OneoffResponse
			err = json.Unmarshal(resp, &respOneoff)
			if err != nil {
				return cli.NewExitError(err.Error(), 1)
			}
			switch respOneoff.Oneoff.Status {
			case "RUNNING":
				break LOOP
			case "PENDING":
				time.Sleep(3 * time.Second)
			default:

				return cli.NewExitError("Unexpected task status "+respOneoff.Oneoff.Status, 1)
			}
		}

		fmt.Println("Connecting to the process")

		var matchedCI *api.ContainerInstance
		for _, ci := range oneoff.District.ContainerInstances {
			if ci.ContainerInstanceArn == oneoff.ContainerInstanceARN {
				matchedCI = ci
				break
			}
		}

		ssh := SSH{
			IP:          matchedCI.PrivateIPAddress,
			BastionIP:   oneoff.District.BastionIP,
			Certificate: certificate,
		}
		if ssh.Run(oneoff.InteractiveRunCommand) != nil {
			return cli.NewExitError(err.Error(), 1)
		}

		return nil
	},
}
View Source
var SSHCommand = cli.Command{
	Name:      "ssh",
	Usage:     "SSH into Barcelona container instance",
	ArgsUsage: "DISTRICT_NAME CONTAINER_INSTANCE_PRIVATE_IP",
	Action: func(c *cli.Context) error {
		districtName := c.Args().Get(0)
		if len(districtName) == 0 {
			return cli.NewExitError("district name is required", 1)
		}
		ip := c.Args().Get(1)
		if len(ip) == 0 {
			return cli.NewExitError("ip is required", 1)
		}

		resp, err := api.DefaultClient.Post("/districts/"+districtName+"/sign_public_key", nil)
		if err != nil {
			return cli.NewExitError(err.Error(), 1)
		}

		var districtResp api.DistrictResponse
		err = json.Unmarshal(resp, &districtResp)
		if err != nil {
			return cli.NewExitError(err.Error(), 1)
		}

		ssh := SSH{
			IP:          ip,
			BastionIP:   districtResp.District.BastionIP,
			Certificate: districtResp.Certificate,
		}
		if ssh.Run("") != nil {
			return cli.NewExitError(err.Error(), 1)
		}
		return nil
	},
}

Functions

func LoadEnvironment

func LoadEnvironment(env string) (*api.Heritage, error)

func LoadReviewDefinition added in v0.9.1

func LoadReviewDefinition() (*api.ReviewAppDefinition, error)

func PrintOneoff added in v0.9.1

func PrintOneoff(o *api.Oneoff)

Types

type DeployReviewApp added in v0.9.1

type DeployReviewApp struct {
	Request  *api.ReviewAppRequest
	Response *api.ReviewAppResponse
	Token    string
}

func (*DeployReviewApp) Execute added in v0.9.1

func (com *DeployReviewApp) Execute() error

type HeritageConfig

type HeritageConfig struct {
	Environments map[string]*api.Heritage `yaml:"environments" json:"environments"`
	Review       *api.ReviewAppDefinition `yaml:"review" json:"review"`
}

type SSH

type SSH struct {
	IP          string
	BastionIP   string
	Certificate string
}

func (*SSH) Run

func (ssh *SSH) Run(command string) error

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL