Skip to content

Commit

Permalink
Adding support for environment variables for stack deployment
Browse files Browse the repository at this point in the history
  • Loading branch information
qube committed Oct 26, 2017
1 parent e135bfb commit 0dcc71a
Show file tree
Hide file tree
Showing 11 changed files with 159 additions and 112 deletions.
17 changes: 3 additions & 14 deletions api/rpc/stack/stack.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
package stack

import (
"os"
"strings"

log "github.com/sirupsen/logrus"

"github.com/appcelerator/amp/data/accounts"
"github.com/appcelerator/amp/data/stacks"
"github.com/appcelerator/amp/pkg/docker"
log "github.com/sirupsen/logrus"
"golang.org/x/net/context"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
Expand Down Expand Up @@ -38,7 +36,7 @@ func convertError(err error) error {
// Deploy implements stack.Server
func (s *Server) Deploy(ctx context.Context, in *DeployRequest) (*DeployReply, error) {
// Check if stack is using restricted resources
compose, err := s.Docker.ComposeParse(ctx, in.Compose)
compose, err := s.Docker.ComposeParse(ctx, in.Compose, in.Environment)
if err != nil {
return nil, convertError(err)
}
Expand All @@ -63,17 +61,8 @@ func (s *Server) Deploy(ctx context.Context, in *DeployRequest) (*DeployReply, e
}
}

for envName, envValue := range in.EnvVar {
os.Setenv(envName, envValue)
}

// Deploy stack
output, err := s.Docker.StackDeploy(ctx, stack.Name, in.Compose, in.Config)

for envName := range in.EnvVar {
os.Setenv(envName, "")
}

output, err := s.Docker.StackDeploy(ctx, stack.Name, in.Compose, in.Config, in.Environment)
if err != nil {
s.Stacks.Delete(ctx, stack.Id)
return nil, convertError(err)
Expand Down
94 changes: 46 additions & 48 deletions api/rpc/stack/stack.pb.go

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

2 changes: 1 addition & 1 deletion api/rpc/stack/stack.proto
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ service Stack {
message DeployRequest {
string name = 1;
bytes compose = 2;
map<string, string> env_var = 3;
repeated string environment = 3;
bytes config = 4;
}

Expand Down
6 changes: 3 additions & 3 deletions api/rpc/stack/stack.swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -140,9 +140,9 @@
"type": "string",
"format": "byte"
},
"env_var": {
"type": "object",
"additionalProperties": {
"environment": {
"type": "array",
"items": {
"type": "string"
}
},
Expand Down
61 changes: 39 additions & 22 deletions cli/command/stack/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,31 @@ package stack
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"path/filepath"
"strings"

"github.com/appcelerator/amp/api/rpc/stack"
"github.com/appcelerator/amp/cli"
"github.com/appcelerator/amp/docker/cli/cli/config"
"github.com/appcelerator/amp/docker/cli/opts"
"github.com/spf13/cobra"
"golang.org/x/net/context"
"google.golang.org/grpc/status"
)

type deployStackOptions struct {
file string
envVar string
env opts.ListOpts
envFile opts.ListOpts
registryAuth bool
}

var (
opts = deployStackOptions{}
options = deployStackOptions{
env: opts.NewListOpts(opts.ValidateEnv),
envFile: opts.NewListOpts(nil),
}
)

// NewDeployCommand returns a new instance of the stack command.
Expand All @@ -37,50 +41,63 @@ func NewDeployCommand(c cli.Interface) *cobra.Command {
return deploy(c, cmd, args)
},
}
cmd.Flags().StringVarP(&opts.file, "compose-file", "c", "", "Path to a Compose v3 file")
cmd.Flags().StringVarP(&opts.envVar, "env", "e", "", "Environment variable to set during deployment format: var=value")
cmd.Flags().BoolVar(&opts.registryAuth, "with-registry-auth", false, "Send registry authentication details to swarm agents")
cmd.Flags().StringVarP(&options.file, "compose-file", "c", "", "Path to a Compose v3 file")
cmd.Flags().VarP(&options.env, "env", "e", "Set environment variables")
cmd.Flags().Var(&options.envFile, "env-file", "Read in a file of environment variables")
cmd.Flags().BoolVar(&options.registryAuth, "with-registry-auth", false, "Send registry authentication details to swarm agents")
return cmd
}

func deploy(c cli.Interface, cmd *cobra.Command, args []string) error {
envArgs := make(map[string]string)
if opts.envVar != "" {
envs := strings.Split(opts.envVar, "=")
if len(envs) != 2 {
return fmt.Errorf("--env parameter format error, should be: var=value found:: %s", opts.envVar)
// Environment
environment, err := opts.ReadKVStrings(options.envFile.GetAll(), options.env.GetAll())
if err != nil {
return err
}
currentEnv := make([]string, 0, len(environment))
for _, env := range environment { // need to process each var, in order
k := strings.SplitN(env, "=", 2)[0]
for i, current := range currentEnv { // remove duplicates
if current == env {
continue // no update required, may hide this behind flag to preserve order of environment
}
if strings.HasPrefix(current, k+"=") {
currentEnv = append(currentEnv[:i], currentEnv[i+1:]...)
}
}
envArgs[envs[0]] = envs[1]
currentEnv = append(currentEnv, env)
}

// Compose file
var name string
if len(args) == 0 {
basename := filepath.Base(opts.file)
name = strings.Split(strings.TrimSuffix(basename, filepath.Ext(opts.file)), ".")[0]
basename := filepath.Base(options.file)
name = strings.Split(strings.TrimSuffix(basename, filepath.Ext(options.file)), ".")[0]
} else {
name = args[0]
}
c.Console().Printf("Deploying stack %s using %s\n", name, opts.file)
c.Console().Printf("Deploying stack %s using %s\n", name, options.file)

contents, err := ioutil.ReadFile(opts.file)
contents, err := ioutil.ReadFile(options.file)
if err != nil {
return err
}

req := &stack.DeployRequest{
Name: name,
Compose: contents,
EnvVar: envArgs,
Name: name,
Compose: contents,
Environment: environment,
}

// If registryAuth was set, send the docker CLI configuration file to amplifier
if opts.registryAuth {
if options.registryAuth {
cf, err := config.Load(config.Dir())
if err != nil {
return errors.New("Unable to read docker CLI configuration file.")
return errors.New("unable to read docker CLI configuration file")
}
req.Config, err = json.Marshal(cf)
if err != nil {
return errors.New("Unable to marshal docker CLI configuration file.")
return errors.New("unable to marshal docker CLI configuration file")
}
}

Expand Down
6 changes: 6 additions & 0 deletions docker/cli/cli/command/stack/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package stack
import (
"fmt"

"os"

"docker.io/go-docker/api/types/swarm"
"docker.io/go-docker/api/types/versions"
"github.com/appcelerator/amp/docker/cli/cli/command"
Expand All @@ -25,10 +27,14 @@ type DeployOptions struct {
ResolveImage string
SendRegistryAuth bool
Prune bool
Environment []string
}

func RunDeploy(dockerCli command.Cli, opts DeployOptions) error {
ctx := context.Background()
if len(opts.Environment) == 0 {
opts.Environment = os.Environ()
}

if err := validateResolveImageFlag(dockerCli, &opts); err != nil {
return err
Expand Down
8 changes: 4 additions & 4 deletions docker/cli/cli/command/stack/deploy_composefile.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (
)

func deployCompose(ctx context.Context, dockerCli command.Cli, opts DeployOptions) error {
configDetails, err := getConfigDetails(opts.Composefile, dockerCli.In())
configDetails, err := getConfigDetails(opts.Composefile, dockerCli.In(), opts)
if err != nil {
return err
}
Expand Down Expand Up @@ -118,7 +118,7 @@ func propertyWarnings(properties map[string]string) string {
return strings.Join(msgs, "\n\n")
}

func getConfigDetails(composefile string, stdin io.Reader) (composetypes.ConfigDetails, error) {
func getConfigDetails(composefile string, stdin io.Reader, opts DeployOptions) (composetypes.ConfigDetails, error) {
var details composetypes.ConfigDetails

if composefile == "-" {
Expand All @@ -141,11 +141,11 @@ func getConfigDetails(composefile string, stdin io.Reader) (composetypes.ConfigD
}
// TODO: support multiple files
details.ConfigFiles = []composetypes.ConfigFile{*configFile}
details.Environment, err = buildEnvironment(os.Environ())
details.Environment, err = BuildEnvironment(opts.Environment)
return details, err
}

func buildEnvironment(env []string) (map[string]string, error) {
func BuildEnvironment(env []string) (map[string]string, error) {
result := make(map[string]string, len(env))
for _, s := range env {
// if value is empty, s is like "K=", not "K".
Expand Down
Loading

0 comments on commit 0dcc71a

Please sign in to comment.