Add setup command to define a docker context for ecs-plugin

Signed-off-by: Guillaume Lours <guillaume.lours@docker.com>
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
Guillaume Lours 2020-05-04 18:35:23 +02:00 committed by Nicolas De Loof
parent 09871400ef
commit aa8587095f
No known key found for this signature in database
GPG Key ID: 9858809D6F8F6E7E
6 changed files with 121 additions and 22 deletions

View File

@ -6,16 +6,11 @@ import (
"github.com/docker/ecs-plugin/pkg/amazon" "github.com/docker/ecs-plugin/pkg/amazon"
"github.com/docker/ecs-plugin/pkg/compose" "github.com/docker/ecs-plugin/pkg/compose"
"github.com/docker/ecs-plugin/pkg/docker"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
type ClusterOptions struct { func ComposeCommand(clusteropts *docker.AwsContext) *cobra.Command {
Profile string
Region string
Cluster string
}
func ComposeCommand(clusteropts *ClusterOptions) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "compose", Use: "compose",
} }
@ -41,7 +36,7 @@ func (o upOptions) LoadBalancerArn() *string {
return &o.loadBalancerArn return &o.loadBalancerArn
} }
func ConvertCommand(clusteropts *ClusterOptions, projectOpts *compose.ProjectOptions) *cobra.Command { func ConvertCommand(clusteropts *docker.AwsContext, projectOpts *compose.ProjectOptions) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "convert", Use: "convert",
RunE: compose.WithProject(projectOpts, func(project *compose.Project, args []string) error { RunE: compose.WithProject(projectOpts, func(project *compose.Project, args []string) error {
@ -66,7 +61,7 @@ func ConvertCommand(clusteropts *ClusterOptions, projectOpts *compose.ProjectOpt
return cmd return cmd
} }
func UpCommand(clusteropts *ClusterOptions, projectOpts *compose.ProjectOptions) *cobra.Command { func UpCommand(clusteropts *docker.AwsContext, projectOpts *compose.ProjectOptions) *cobra.Command {
opts := upOptions{} opts := upOptions{}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "up", Use: "up",
@ -86,7 +81,7 @@ type downOptions struct {
DeleteCluster bool DeleteCluster bool
} }
func DownCommand(clusteropts *ClusterOptions, projectOpts *compose.ProjectOptions) *cobra.Command { func DownCommand(clusteropts *docker.AwsContext, projectOpts *compose.ProjectOptions) *cobra.Command {
opts := downOptions{} opts := downOptions{}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "down", Use: "down",

View File

@ -22,7 +22,7 @@ type deleteSecretOptions struct {
recover bool recover bool
} }
func SecretCommand(clusteropts *ClusterOptions) *cobra.Command { func SecretCommand(clusteropts *docker.AwsContext) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "secret", Use: "secret",
Short: "Manages secrets", Short: "Manages secrets",
@ -37,7 +37,7 @@ func SecretCommand(clusteropts *ClusterOptions) *cobra.Command {
return cmd return cmd
} }
func CreateSecret(clusteropts *ClusterOptions) *cobra.Command { func CreateSecret(clusteropts *docker.AwsContext) *cobra.Command {
//opts := createSecretOptions{} //opts := createSecretOptions{}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "create NAME SECRET", Use: "create NAME SECRET",
@ -60,7 +60,7 @@ func CreateSecret(clusteropts *ClusterOptions) *cobra.Command {
return cmd return cmd
} }
func InspectSecret(clusteropts *ClusterOptions) *cobra.Command { func InspectSecret(clusteropts *docker.AwsContext) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "inspect ID", Use: "inspect ID",
Short: "Displays secret details", Short: "Displays secret details",
@ -88,7 +88,7 @@ func InspectSecret(clusteropts *ClusterOptions) *cobra.Command {
return cmd return cmd
} }
func ListSecrets(clusteropts *ClusterOptions) *cobra.Command { func ListSecrets(clusteropts *docker.AwsContext) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "list", Use: "list",
Aliases: []string{"ls"}, Aliases: []string{"ls"},
@ -110,7 +110,7 @@ func ListSecrets(clusteropts *ClusterOptions) *cobra.Command {
return cmd return cmd
} }
func DeleteSecret(clusteropts *ClusterOptions) *cobra.Command { func DeleteSecret(clusteropts *docker.AwsContext) *cobra.Command {
opts := deleteSecretOptions{} opts := deleteSecretOptions{}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "delete NAME", Use: "delete NAME",

33
ecs/cmd/commands/setup.go Normal file
View File

@ -0,0 +1,33 @@
package commands
import (
"github.com/docker/cli/cli-plugins/plugin"
contextStore "github.com/docker/ecs-plugin/pkg/docker"
"github.com/spf13/cobra"
)
func SetupCommand() *cobra.Command {
var opts contextStore.AwsContext
var name string
cmd := &cobra.Command{
Use: "setup",
Short: "",
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
//Override the root command PersistentPreRun
//We just need to initialize the top parent command
return plugin.PersistentPreRunE(cmd, args)
},
RunE: func(cmd *cobra.Command, args []string) error {
return contextStore.NewContext(name, &opts)
},
}
cmd.Flags().StringVarP(&name, "name", "n", "aws", "Context Name")
cmd.Flags().StringVarP(&opts.Profile, "profile", "p", "", "AWS Profile")
cmd.Flags().StringVarP(&opts.Cluster, "cluster", "c", "", "ECS cluster")
cmd.Flags().StringVarP(&opts.Region, "region", "r", "", "AWS region")
cmd.MarkFlagRequired("profile")
cmd.MarkFlagRequired("cluster")
cmd.MarkFlagRequired("region")
return cmd
}

View File

@ -7,6 +7,7 @@ import (
"github.com/docker/cli/cli-plugins/plugin" "github.com/docker/cli/cli-plugins/plugin"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
commands "github.com/docker/ecs-plugin/cmd/commands" commands "github.com/docker/ecs-plugin/cmd/commands"
"github.com/docker/ecs-plugin/pkg/docker"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -26,23 +27,29 @@ func main() {
// NewRootCmd returns the base root command. // NewRootCmd returns the base root command.
func NewRootCmd(name string, dockerCli command.Cli) *cobra.Command { func NewRootCmd(name string, dockerCli command.Cli) *cobra.Command {
var opts commands.ClusterOptions var opts *docker.AwsContext
cmd := &cobra.Command{ cmd := &cobra.Command{
Short: "Docker ECS", Short: "Docker ECS",
Long: `run multi-container applications on Amazon ECS.`, Long: `run multi-container applications on Amazon ECS.`,
Use: name, Use: name,
Annotations: map[string]string{"experimentalCLI": "true"}, Annotations: map[string]string{"experimentalCLI": "true"},
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
err := plugin.PersistentPreRunE(cmd, args)
if err != nil {
return err
}
contextName := dockerCli.CurrentContext()
opts, err = docker.CheckAwsContextExists(contextName)
return err
},
} }
cmd.AddCommand( cmd.AddCommand(
VersionCommand(), VersionCommand(),
commands.ComposeCommand(&opts), commands.ComposeCommand(opts),
commands.SecretCommand(&opts), commands.SecretCommand(opts),
commands.SetupCommand(),
) )
cmd.Flags().StringVarP(&opts.Profile, "profile", "p", "default", "AWS Profile")
cmd.Flags().StringVarP(&opts.Cluster, "cluster", "c", "default", "ECS cluster")
cmd.Flags().StringVarP(&opts.Region, "region", "r", "", "AWS region")
return cmd return cmd
} }

View File

@ -35,6 +35,7 @@ require (
github.com/lib/pq v1.3.0 // indirect github.com/lib/pq v1.3.0 // indirect
github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect
github.com/miekg/pkcs11 v1.0.3 // indirect github.com/miekg/pkcs11 v1.0.3 // indirect
github.com/mitchellh/mapstructure v1.2.2
github.com/morikuni/aec v1.0.0 // indirect github.com/morikuni/aec v1.0.0 // indirect
github.com/onsi/ginkgo v1.11.0 // indirect github.com/onsi/ginkgo v1.11.0 // indirect
github.com/opencontainers/image-spec v1.0.1 // indirect github.com/opencontainers/image-spec v1.0.1 // indirect

View File

@ -0,0 +1,63 @@
package docker
import (
"fmt"
cliconfig "github.com/docker/cli/cli/config"
"github.com/docker/cli/cli/context/store"
"github.com/mitchellh/mapstructure"
)
const contextType = "aws"
type TypeContext struct {
Type string
}
func getter() interface{} {
return &TypeContext{}
}
type AwsContext struct {
Profile string
Cluster string
Region string
}
func NewContext(name string, awsContext *AwsContext) error {
contextStore := initContextStore()
endpoints := map[string]interface{}{
"aws": awsContext,
"docker": awsContext,
}
metadata := store.Metadata{
Name: name,
Endpoints: endpoints,
Metadata: TypeContext{Type: contextType},
}
return contextStore.CreateOrUpdate(metadata)
}
func initContextStore() store.Store {
config := store.NewConfig(getter)
return store.New(cliconfig.ContextStoreDir(), config)
}
func CheckAwsContextExists(contextName string) (*AwsContext, error) {
contextStore := initContextStore()
metadata, err := contextStore.GetMetadata(contextName)
if err != nil {
return nil, err
}
endpoint := metadata.Endpoints["aws"]
awsContext := AwsContext{}
err = mapstructure.Decode(endpoint, &awsContext)
if err != nil {
return nil, err
}
if awsContext == (AwsContext{}) {
return nil, fmt.Errorf("can't use \"%s\" with ECS command because it is not an AWS context", contextName)
}
return &awsContext, nil
}