mirror of https://github.com/docker/compose.git
Add compose up and down
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
This commit is contained in:
parent
f32235b8ba
commit
03e418cbbb
|
@ -96,6 +96,14 @@ func createACIContainers(ctx context.Context, aciContext store.AciContext, group
|
||||||
return containerGroup, err
|
return containerGroup, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func deleteACIContainerGroup(ctx context.Context, aciContext store.AciContext, containerGroupName string) (c containerinstance.ContainerGroup, err error) {
|
||||||
|
containerGroupsClient, err := getContainerGroupsClient(aciContext.SubscriptionID)
|
||||||
|
if err != nil {
|
||||||
|
return c, fmt.Errorf("cannot get container group client: %v", err)
|
||||||
|
}
|
||||||
|
return containerGroupsClient.Delete(ctx, aciContext.ResourceGroup, containerGroupName)
|
||||||
|
}
|
||||||
|
|
||||||
func execACIContainer(ctx context.Context, aciContext store.AciContext, command, containerGroup string, containerName string) (c containerinstance.ContainerExecResponse, err error) {
|
func execACIContainer(ctx context.Context, aciContext store.AciContext, command, containerGroup string, containerName string) (c containerinstance.ContainerExecResponse, err error) {
|
||||||
containerClient, err := getContainerClient(aciContext.SubscriptionID)
|
containerClient, err := getContainerClient(aciContext.SubscriptionID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -21,7 +21,7 @@ import (
|
||||||
"github.com/docker/api/context/store"
|
"github.com/docker/api/context/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
type containerService struct {
|
type aciApiService struct {
|
||||||
containerGroupsClient containerinstance.ContainerGroupsClient
|
containerGroupsClient containerinstance.ContainerGroupsClient
|
||||||
ctx store.AciContext
|
ctx store.AciContext
|
||||||
}
|
}
|
||||||
|
@ -36,8 +36,13 @@ func getter() interface{} {
|
||||||
return &store.AciContext{}
|
return &store.AciContext{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AciService interface {
|
||||||
|
containers.ContainerService
|
||||||
|
compose.Service
|
||||||
|
}
|
||||||
|
|
||||||
// New creates a backend that can manage containers on ACI
|
// New creates a backend that can manage containers on ACI
|
||||||
func New(ctx context.Context) (containers.ContainerService, error) {
|
func New(ctx context.Context) (AciService, error) {
|
||||||
currentContext := apicontext.CurrentContext(ctx)
|
currentContext := apicontext.CurrentContext(ctx)
|
||||||
contextStore, err := store.New()
|
contextStore, err := store.New()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -53,13 +58,13 @@ func New(ctx context.Context) (containers.ContainerService, error) {
|
||||||
containerGroupsClient := containerinstance.NewContainerGroupsClient(aciContext.SubscriptionID)
|
containerGroupsClient := containerinstance.NewContainerGroupsClient(aciContext.SubscriptionID)
|
||||||
containerGroupsClient.Authorizer = auth
|
containerGroupsClient.Authorizer = auth
|
||||||
|
|
||||||
return &containerService{
|
return &aciApiService{
|
||||||
containerGroupsClient: containerGroupsClient,
|
containerGroupsClient: containerGroupsClient,
|
||||||
ctx: aciContext,
|
ctx: aciContext,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cs *containerService) List(ctx context.Context) ([]containers.Container, error) {
|
func (cs *aciApiService) List(ctx context.Context) ([]containers.Container, error) {
|
||||||
var containerGroups []containerinstance.ContainerGroup
|
var containerGroups []containerinstance.ContainerGroup
|
||||||
result, err := cs.containerGroupsClient.ListByResourceGroup(ctx, cs.ctx.ResourceGroup)
|
result, err := cs.containerGroupsClient.ListByResourceGroup(ctx, cs.ctx.ResourceGroup)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -73,7 +78,7 @@ func (cs *containerService) List(ctx context.Context) ([]containers.Container, e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
res := []containers.Container{}
|
var res []containers.Container
|
||||||
for _, containerGroup := range containerGroups {
|
for _, containerGroup := range containerGroups {
|
||||||
group, err := cs.containerGroupsClient.Get(ctx, cs.ctx.ResourceGroup, *containerGroup.Name)
|
group, err := cs.containerGroupsClient.Get(ctx, cs.ctx.ResourceGroup, *containerGroup.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -96,7 +101,7 @@ func (cs *containerService) List(ctx context.Context) ([]containers.Container, e
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cs *containerService) Run(ctx context.Context, r containers.ContainerConfig) error {
|
func (cs *aciApiService) Run(ctx context.Context, r containers.ContainerConfig) error {
|
||||||
var ports []types.ServicePortConfig
|
var ports []types.ServicePortConfig
|
||||||
for _, p := range r.Ports {
|
for _, p := range r.Ports {
|
||||||
ports = append(ports, types.ServicePortConfig{
|
ports = append(ports, types.ServicePortConfig{
|
||||||
|
@ -127,7 +132,7 @@ func (cs *containerService) Run(ctx context.Context, r containers.ContainerConfi
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cs *containerService) Exec(ctx context.Context, name string, command string, reader io.Reader, writer io.Writer) error {
|
func (cs *aciApiService) Exec(ctx context.Context, name string, command string, reader io.Reader, writer io.Writer) error {
|
||||||
containerExecResponse, err := execACIContainer(ctx, cs.ctx, command, name, name)
|
containerExecResponse, err := execACIContainer(ctx, cs.ctx, command, name, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -142,7 +147,7 @@ func (cs *containerService) Exec(ctx context.Context, name string, command strin
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cs *containerService) Logs(ctx context.Context, containerName string, req containers.LogsRequest) error {
|
func (cs *aciApiService) Logs(ctx context.Context, containerName string, req containers.LogsRequest) error {
|
||||||
logs, err := getACIContainerLogs(ctx, cs.ctx, containerName, containerName)
|
logs, err := getACIContainerLogs(ctx, cs.ctx, containerName, containerName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -163,3 +168,27 @@ func (cs *containerService) Logs(ctx context.Context, containerName string, req
|
||||||
_, err = fmt.Fprint(req.Writer, logs)
|
_, err = fmt.Fprint(req.Writer, logs)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cs *aciApiService) Up(ctx context.Context, opts compose.ProjectOptions) error {
|
||||||
|
project, err := compose.ProjectFromOptions(&opts)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logrus.Debugf("Up on project with name %q\n", project.Name)
|
||||||
|
groupDefinition, err := convert.ToContainerGroup(cs.ctx, *project)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = createACIContainers(ctx, cs.ctx, groupDefinition)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cs *aciApiService) Down(ctx context.Context, opts compose.ProjectOptions) error {
|
||||||
|
project, err := compose.ProjectFromOptions(&opts)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logrus.Debugf("Down on project with name %q\n", project.Name)
|
||||||
|
_, err = deleteACIContainerGroup(ctx, cs.ctx, project.Name)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
package compose
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"github.com/docker/api/client"
|
||||||
|
"github.com/docker/api/compose"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Command() *cobra.Command {
|
||||||
|
command := &cobra.Command{
|
||||||
|
Short: "Docker Compose",
|
||||||
|
Use: "compose",
|
||||||
|
}
|
||||||
|
command.AddCommand(
|
||||||
|
upCommand(),
|
||||||
|
downCommand(),
|
||||||
|
)
|
||||||
|
return command
|
||||||
|
}
|
||||||
|
|
||||||
|
func upCommand() *cobra.Command {
|
||||||
|
opts := &compose.ProjectOptions{}
|
||||||
|
upCmd := &cobra.Command{
|
||||||
|
Use: "up",
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
c, err := client.New(cmd.Context())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return c.AciService().Up(cmd.Context(), *opts)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
upCmd.Flags().StringVar(&opts.Name, "name", "", "Project name")
|
||||||
|
upCmd.Flags().StringVar(&opts.WorkDir, "workdir", ".", "Work dir")
|
||||||
|
upCmd.Flags().StringArrayVarP(&opts.ConfigPaths, "file", "f", []string{}, "Compose configuration files")
|
||||||
|
upCmd.Flags().StringArrayVarP(&opts.Environment, "environment", "e", []string{}, "Environment variables")
|
||||||
|
|
||||||
|
return upCmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func downCommand() *cobra.Command {
|
||||||
|
opts := &compose.ProjectOptions{}
|
||||||
|
downCmd := &cobra.Command{
|
||||||
|
Use: "down",
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
c, err := client.New(cmd.Context())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return c.AciService().Down(cmd.Context(), *opts)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
downCmd.Flags().StringVar(&opts.Name, "name", "", "Project name")
|
||||||
|
downCmd.Flags().StringVar(&opts.WorkDir, "workdir", ".", "Work dir")
|
||||||
|
|
||||||
|
return downCmd
|
||||||
|
}
|
|
@ -62,5 +62,5 @@ func runExec(ctx context.Context, opts execOpts, name string, command string) er
|
||||||
stdout = con
|
stdout = con
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.ContainerService().Exec(ctx, name, command, os.Stdin, stdout)
|
return c.AciService().Exec(ctx, name, command, os.Stdin, stdout)
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,5 +46,5 @@ func runLogs(ctx context.Context, containerName string, opts logsOpts) error {
|
||||||
Writer: os.Stdout,
|
Writer: os.Stdout,
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.ContainerService().Logs(ctx, containerName, req)
|
return c.AciService().Logs(ctx, containerName, req)
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ var PsCommand = cobra.Command{
|
||||||
return errors.Wrap(err, "cannot connect to backend")
|
return errors.Wrap(err, "cannot connect to backend")
|
||||||
}
|
}
|
||||||
|
|
||||||
containers, err := c.ContainerService().List(ctx)
|
containers, err := c.AciService().List(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "fetch containers")
|
return errors.Wrap(err, "fetch containers")
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,5 +65,5 @@ func runRun(ctx context.Context, image string, opts runOpts) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.ContainerService().Run(ctx, project)
|
return c.AciService().Run(ctx, project)
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,7 @@ import (
|
||||||
|
|
||||||
// Backend registrations
|
// Backend registrations
|
||||||
_ "github.com/docker/api/azure"
|
_ "github.com/docker/api/azure"
|
||||||
|
"github.com/docker/api/cli/cmd/compose"
|
||||||
_ "github.com/docker/api/example"
|
_ "github.com/docker/api/example"
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
@ -102,6 +103,7 @@ func main() {
|
||||||
run.Command(),
|
run.Command(),
|
||||||
cmd.ExecCommand(),
|
cmd.ExecCommand(),
|
||||||
cmd.LogsCommand(),
|
cmd.LogsCommand(),
|
||||||
|
compose.Command(),
|
||||||
)
|
)
|
||||||
|
|
||||||
helpFunc := root.HelpFunc()
|
helpFunc := root.HelpFunc()
|
||||||
|
|
|
@ -31,11 +31,11 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
|
"github.com/docker/api/azure"
|
||||||
"github.com/docker/api/backend"
|
"github.com/docker/api/backend"
|
||||||
backendv1 "github.com/docker/api/backend/v1"
|
backendv1 "github.com/docker/api/backend/v1"
|
||||||
cliv1 "github.com/docker/api/cli/v1"
|
cliv1 "github.com/docker/api/cli/v1"
|
||||||
composev1 "github.com/docker/api/compose/v1"
|
composev1 "github.com/docker/api/compose/v1"
|
||||||
"github.com/docker/api/containers"
|
|
||||||
containersv1 "github.com/docker/api/containers/v1"
|
containersv1 "github.com/docker/api/containers/v1"
|
||||||
apicontext "github.com/docker/api/context"
|
apicontext "github.com/docker/api/context"
|
||||||
"github.com/docker/api/context/store"
|
"github.com/docker/api/context/store"
|
||||||
|
@ -57,13 +57,13 @@ func New(ctx context.Context) (*Client, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ba, ok := b.(containers.ContainerService)
|
aciService, ok := b.(azure.AciService)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("backend not found")
|
return nil, errors.New("backend not found")
|
||||||
}
|
}
|
||||||
return &Client{
|
return &Client{
|
||||||
backendType: contextType,
|
backendType: contextType,
|
||||||
cc: ba,
|
cc: aciService,
|
||||||
}, nil
|
}, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -76,10 +76,10 @@ type Client struct {
|
||||||
composev1.ComposeClient
|
composev1.ComposeClient
|
||||||
|
|
||||||
backendType string
|
backendType string
|
||||||
cc containers.ContainerService
|
cc azure.AciService
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContainerService returns the backend service for the current context
|
// AciService returns the backend service for the current context
|
||||||
func (c *Client) ContainerService() containers.ContainerService {
|
func (c *Client) AciService() azure.AciService {
|
||||||
return c.cc
|
return c.cc
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
package compose
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Service manages a compose project
|
||||||
|
type Service interface {
|
||||||
|
// Up executes the equivalent to a `compose up`
|
||||||
|
Up(ctx context.Context, opts ProjectOptions) error
|
||||||
|
// Down executes the equivalent to a `compose down`
|
||||||
|
Down(ctx context.Context, opts ProjectOptions) error
|
||||||
|
}
|
|
@ -51,7 +51,11 @@ func ProjectFromOptions(options *ProjectOptions) (*Project, error) {
|
||||||
name := options.Name
|
name := options.Name
|
||||||
if name == "" {
|
if name == "" {
|
||||||
r := regexp.MustCompile(`[^a-z0-9\\-_]+`)
|
r := regexp.MustCompile(`[^a-z0-9\\-_]+`)
|
||||||
name = r.ReplaceAllString(strings.ToLower(filepath.Base(options.WorkDir)), "")
|
absPath, err := filepath.Abs(options.WorkDir)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
name = r.ReplaceAllString(strings.ToLower(filepath.Base(absPath)), "")
|
||||||
}
|
}
|
||||||
|
|
||||||
return newProject(types.ConfigDetails{
|
return newProject(types.ConfigDetails{
|
||||||
|
|
|
@ -31,7 +31,7 @@ type proxyContainerAPI struct{}
|
||||||
func (p *proxyContainerAPI) List(ctx context.Context, _ *v1.ListRequest) (*v1.ListResponse, error) {
|
func (p *proxyContainerAPI) List(ctx context.Context, _ *v1.ListRequest) (*v1.ListResponse, error) {
|
||||||
client := Client(ctx)
|
client := Client(ctx)
|
||||||
|
|
||||||
c, err := client.ContainerService().List(ctx)
|
c, err := client.AciService().List(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &v1.ListResponse{}, nil
|
return &v1.ListResponse{}, nil
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ func (p *proxyContainerAPI) List(ctx context.Context, _ *v1.ListRequest) (*v1.Li
|
||||||
func (p *proxyContainerAPI) Create(ctx context.Context, request *v1.CreateRequest) (*v1.CreateResponse, error) {
|
func (p *proxyContainerAPI) Create(ctx context.Context, request *v1.CreateRequest) (*v1.CreateResponse, error) {
|
||||||
client := Client(ctx)
|
client := Client(ctx)
|
||||||
|
|
||||||
err := client.ContainerService().Run(ctx, containers.ContainerConfig{
|
err := client.AciService().Run(ctx, containers.ContainerConfig{
|
||||||
ID: request.Id,
|
ID: request.Id,
|
||||||
Image: request.Image,
|
Image: request.Image,
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue