Ver código fonte

Implement --domainname flag on compose up, also defining compose extension "x-aci-domain-name" to store ACI DNSLabelName.

Signed-off-by: Guillaume Tardif <[email protected]>
Guillaume Tardif 5 anos atrás
pai
commit
334ebf5f75

+ 39 - 18
aci/convert/convert.go

@@ -43,8 +43,10 @@ const (
 	StatusRunning = "Running"
 	// ComposeDNSSidecarName name of the dns sidecar container
 	ComposeDNSSidecarName = "aci--dns--sidecar"
-	dnsSidecarImage       = "busybox:1.31.1"
+	// ExtensionDomainName compose extension to set ACI DNS label name
+	ExtensionDomainName = "x-aci-domain-name"
 
+	dnsSidecarImage                = "busybox:1.31.1"
 	azureFileDriverName            = "azure_file"
 	volumeDriveroptsShareNameKey   = "share_name"
 	volumeDriveroptsAccountNameKey = "storage_account_name"
@@ -103,26 +105,16 @@ func ToContainerGroup(ctx context.Context, aciContext store.AciContext, p types.
 			return containerinstance.ContainerGroup{}, errors.New("ACI integration does not support labels in compose applications")
 		}
 		if service.Ports != nil {
-			var containerPorts []containerinstance.ContainerPort
-			for _, portConfig := range service.Ports {
-				if portConfig.Published != 0 && portConfig.Published != portConfig.Target {
-					msg := fmt.Sprintf("Port mapping is not supported with ACI, cannot map port %d to %d for container %s",
-						portConfig.Published, portConfig.Target, service.Name)
-					return groupDefinition, errors.New(msg)
-				}
-				portNumber := int32(portConfig.Target)
-				containerPorts = append(containerPorts, containerinstance.ContainerPort{
-					Port: to.Int32Ptr(portNumber),
-				})
-				groupPorts = append(groupPorts, containerinstance.Port{
-					Port:     to.Int32Ptr(portNumber),
-					Protocol: containerinstance.TCP,
-				})
+			containerPorts, serviceGroupPorts, dnsLabelName, err := convertPortsToAci(service, p)
+			if err != nil {
+				return groupDefinition, err
 			}
 			containerDefinition.ContainerProperties.Ports = &containerPorts
+			groupPorts = append(groupPorts, serviceGroupPorts...)
 			groupDefinition.ContainerGroupProperties.IPAddress = &containerinstance.IPAddress{
-				Type:  containerinstance.Public,
-				Ports: &groupPorts,
+				Type:         containerinstance.Public,
+				Ports:        &groupPorts,
+				DNSNameLabel: dnsLabelName,
 			}
 		}
 
@@ -137,6 +129,35 @@ func ToContainerGroup(ctx context.Context, aciContext store.AciContext, p types.
 	return groupDefinition, nil
 }
 
+func convertPortsToAci(service serviceConfigAciHelper, p types.Project) ([]containerinstance.ContainerPort, []containerinstance.Port, *string, error) {
+	var groupPorts []containerinstance.Port
+	var containerPorts []containerinstance.ContainerPort
+	for _, portConfig := range service.Ports {
+		if portConfig.Published != 0 && portConfig.Published != portConfig.Target {
+			msg := fmt.Sprintf("Port mapping is not supported with ACI, cannot map port %d to %d for container %s",
+				portConfig.Published, portConfig.Target, service.Name)
+			return nil, nil, nil, errors.New(msg)
+		}
+		portNumber := int32(portConfig.Target)
+		containerPorts = append(containerPorts, containerinstance.ContainerPort{
+			Port: to.Int32Ptr(portNumber),
+		})
+		groupPorts = append(groupPorts, containerinstance.Port{
+			Port:     to.Int32Ptr(portNumber),
+			Protocol: containerinstance.TCP,
+		})
+	}
+	var dnsLabelName *string = nil
+	if extension, ok := p.Extensions[ExtensionDomainName]; ok {
+		domain, ok := extension.(string)
+		if !ok {
+			return nil, nil, nil, fmt.Errorf("could not read %s compose extension as string", ExtensionDomainName)
+		}
+		dnsLabelName = &domain
+	}
+	return containerPorts, groupPorts, dnsLabelName, nil
+}
+
 func getDNSSidecar(containers []containerinstance.Container) containerinstance.Container {
 	var commands []string
 	for _, container := range containers {

+ 3 - 2
cli/cmd/compose/compose.go

@@ -29,6 +29,7 @@ import (
 
 type composeOptions struct {
 	Name        string
+	DomainName  string
 	WorkingDir  string
 	ConfigPaths []string
 	Environment []string
@@ -60,7 +61,7 @@ func (o *composeOptions) toProjectOptions() (*cli.ProjectOptions, error) {
 }
 
 // Command returns the compose command with its child commands
-func Command() *cobra.Command {
+func Command(contextType string) *cobra.Command {
 	command := &cobra.Command{
 		Short: "Docker Compose",
 		Use:   "compose",
@@ -70,7 +71,7 @@ func Command() *cobra.Command {
 	}
 
 	command.AddCommand(
-		upCommand(),
+		upCommand(contextType),
 		downCommand(),
 		psCommand(),
 		listCommand(),

+ 11 - 2
cli/cmd/compose/up.go

@@ -20,14 +20,15 @@ import (
 	"context"
 
 	"github.com/compose-spec/compose-go/cli"
-
 	"github.com/spf13/cobra"
 
+	aciconvert "github.com/docker/compose-cli/aci/convert"
 	"github.com/docker/compose-cli/api/client"
+	"github.com/docker/compose-cli/context/store"
 	"github.com/docker/compose-cli/progress"
 )
 
-func upCommand() *cobra.Command {
+func upCommand(contextType string) *cobra.Command {
 	opts := composeOptions{}
 	upCmd := &cobra.Command{
 		Use: "up",
@@ -40,6 +41,11 @@ func upCommand() *cobra.Command {
 	upCmd.Flags().StringArrayVarP(&opts.ConfigPaths, "file", "f", []string{}, "Compose configuration files")
 	upCmd.Flags().StringArrayVarP(&opts.Environment, "environment", "e", []string{}, "Environment variables")
 	upCmd.Flags().BoolP("detach", "d", true, " Detached mode: Run containers in the background")
+
+	if contextType == store.AciContextType {
+		upCmd.Flags().StringVar(&opts.DomainName, "domainname", "", "Container NIS domain name")
+	}
+
 	return upCmd
 }
 
@@ -55,6 +61,9 @@ func runUp(ctx context.Context, opts composeOptions) error {
 			return "", err
 		}
 		project, err := cli.ProjectFromOptions(options)
+		if opts.DomainName != "" {
+			project.Extensions = map[string]interface{}{aciconvert.ExtensionDomainName: opts.DomainName}
+		}
 		if err != nil {
 			return "", err
 		}

+ 4 - 2
cli/main.go

@@ -126,7 +126,6 @@ func main() {
 		cmd.StopCommand(),
 		cmd.KillCommand(),
 		cmd.SecretCommand(),
-		compose.Command(),
 
 		// Place holders
 		cmd.EcsCommand(),
@@ -179,7 +178,10 @@ func main() {
 		ctype = cc.Type()
 	}
 
-	root.AddCommand(run.Command(ctype))
+	root.AddCommand(
+		run.Command(ctype),
+		compose.Command(ctype),
+	)
 
 	if ctype == store.AciContextType {
 		// we can also pass ctype as a parameter to the volume command and customize subcommands, flags, etc. when we have other backend implementations

+ 10 - 2
tests/aci-e2e/e2e-aci_test.go

@@ -453,7 +453,7 @@ func TestContainerRunAttached(t *testing.T) {
 
 func TestComposeUpUpdate(t *testing.T) {
 	c := NewParallelE2eCLI(t, binDir)
-	_, _ = setupTestResourceGroup(t, c)
+	_, groupID := setupTestResourceGroup(t, c)
 
 	const (
 		composeFile              = "../composefiles/aci-demo/aci_demo_port.yaml"
@@ -465,8 +465,11 @@ func TestComposeUpUpdate(t *testing.T) {
 	)
 
 	t.Run("compose up", func(t *testing.T) {
+		dnsLabelName := "nginx-" + groupID
+		fqdn := dnsLabelName + "." + location + ".azurecontainer.io"
 		// Name of Compose project is taken from current folder "acie2e"
-		c.RunDockerCmd("compose", "up", "-f", composeFile)
+		c.RunDockerCmd("compose", "up", "-f", composeFile, "--domainname", dnsLabelName)
+
 		res := c.RunDockerCmd("ps")
 		out := lines(res.Stdout())
 		// Check three containers are running
@@ -493,6 +496,11 @@ func TestComposeUpUpdate(t *testing.T) {
 		b, err := ioutil.ReadAll(r.Body)
 		assert.NilError(t, err)
 		assert.Assert(t, strings.Contains(string(b), `"word":`))
+
+		endpoint = fmt.Sprintf("http://%s:%d", fqdn, containerInspect.Ports[0].HostPort)
+		r, err = HTTPGetWithRetry(endpoint+"/words/noun", 3)
+		assert.NilError(t, err)
+		assert.Equal(t, r.StatusCode, http.StatusOK)
 	})
 
 	t.Run("compose ps", func(t *testing.T) {