Merge pull request #358 from docker/aci_env_variable

Aci env variable
This commit is contained in:
Guillaume Tardif 2020-07-07 12:40:27 +02:00 коммит произвёл GitHub
Родитель 2e867f40d7 f7daa70c87
Коммит de4ba33c60
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
10 изменённых файлов: 206 добавлений и 46 удалений

Просмотреть файл

@ -162,41 +162,11 @@ func (cs *aciContainerService) Run(ctx context.Context, r containers.ContainerCo
return errors.New(fmt.Sprintf("invalid container name. ACI container name cannot include %q", composeContainerSeparator))
}
var ports []types.ServicePortConfig
for _, p := range r.Ports {
ports = append(ports, types.ServicePortConfig{
Target: p.ContainerPort,
Published: p.HostPort,
})
}
projectVolumes, serviceConfigVolumes, err := convert.GetRunVolumes(r.Volumes)
project, err := convert.ContainerToComposeProject(r, singleContainerName)
if err != nil {
return err
}
project := types.Project{
Name: r.ID,
Services: []types.ServiceConfig{
{
Name: singleContainerName,
Image: r.Image,
Ports: ports,
Labels: r.Labels,
Volumes: serviceConfigVolumes,
Deploy: &types.DeployConfig{
Resources: types.Resources{
Limits: &types.Resource{
NanoCPUs: fmt.Sprintf("%f", r.CPULimit),
MemoryBytes: types.UnitBytes(r.MemLimit.Value()),
},
},
},
},
},
Volumes: projectVolumes,
}
logrus.Debugf("Running container %q with name %q\n", r.Image, r.ID)
groupDefinition, err := convert.ToContainerGroup(cs.ctx, project)
if err != nil {

Просмотреть файл

@ -0,0 +1,63 @@
package convert
import (
"fmt"
"strings"
"github.com/compose-spec/compose-go/types"
"github.com/docker/api/containers"
)
// ContainerToComposeProject convert container config to compose project
func ContainerToComposeProject(r containers.ContainerConfig, containerID string) (types.Project, error) {
var ports []types.ServicePortConfig
for _, p := range r.Ports {
ports = append(ports, types.ServicePortConfig{
Target: p.ContainerPort,
Published: p.HostPort,
})
}
projectVolumes, serviceConfigVolumes, err := GetRunVolumes(r.Volumes)
if err != nil {
return types.Project{}, err
}
project := types.Project{
Name: r.ID,
Services: []types.ServiceConfig{
{
Name: containerID,
Image: r.Image,
Ports: ports,
Labels: r.Labels,
Volumes: serviceConfigVolumes,
Environment: toComposeEnvs(r.Environment),
Deploy: &types.DeployConfig{
Resources: types.Resources{
Limits: &types.Resource{
NanoCPUs: fmt.Sprintf("%f", r.CPULimit),
MemoryBytes: types.UnitBytes(r.MemLimit.Value()),
},
},
},
},
},
Volumes: projectVolumes,
}
return project, nil
}
func toComposeEnvs(opts []string) types.MappingWithEquals {
result := map[string]*string{}
for _, env := range opts {
tokens := strings.Split(env, "=")
if len(tokens) > 1 {
result[tokens[0]] = &tokens[1]
} else {
result[env] = nil
}
}
return result
}

Просмотреть файл

@ -0,0 +1,54 @@
/*
Copyright 2020 Docker, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package convert
import (
"testing"
"github.com/Azure/go-autorest/autorest/to"
"github.com/compose-spec/compose-go/types"
"github.com/docker/api/containers"
. "github.com/onsi/gomega"
"github.com/stretchr/testify/suite"
)
type ContainerConvertTestSuite struct {
suite.Suite
}
func (suite *ContainerConvertTestSuite) TestConvertContainerEnvironment() {
container := containers.ContainerConfig{
ID: "container1",
Environment: []string{"key1=value1", "key2", "key3=value3"},
}
project, err := ContainerToComposeProject(container, "ID")
Expect(err).To(BeNil())
service1 := project.Services[0]
Expect(service1.Name).To(Equal("ID"))
Expect(service1.Environment).To(Equal(types.MappingWithEquals{
"key1": to.StringPtr("value1"),
"key2": nil,
"key3": to.StringPtr("value3"),
}))
}
func TestContainerConvertTestSuite(t *testing.T) {
RegisterTestingT(t)
suite.Run(t, new(ContainerConvertTestSuite))
}

Просмотреть файл

@ -22,6 +22,7 @@ import (
"fmt"
"io/ioutil"
"math"
"os"
"strconv"
"strings"
@ -280,7 +281,8 @@ func (s serviceConfigAciHelper) getAciContainer(volumesCache map[string]bool) (c
return containerinstance.Container{
Name: to.StringPtr(s.Name),
ContainerProperties: &containerinstance.ContainerProperties{
Image: to.StringPtr(s.Image),
Image: to.StringPtr(s.Image),
EnvironmentVariables: getEnvVariables(s.Environment),
Resources: &containerinstance.ResourceRequirements{
Limits: &containerinstance.ResourceLimits{
MemoryInGB: to.Float64Ptr(memLimit),
@ -294,7 +296,23 @@ func (s serviceConfigAciHelper) getAciContainer(volumesCache map[string]bool) (c
VolumeMounts: volumes,
},
}, nil
}
func getEnvVariables(composeEnv types.MappingWithEquals) *[]containerinstance.EnvironmentVariable {
result := []containerinstance.EnvironmentVariable{}
for key, value := range composeEnv {
var strValue string
if value == nil {
strValue = os.Getenv(key)
} else {
strValue = *value
}
result = append(result, containerinstance.EnvironmentVariable{
Name: to.StringPtr(key),
Value: to.StringPtr(strValue),
})
}
return &result
}
func bytesToGb(b types.UnitBytes) float64 {

Просмотреть файл

@ -17,6 +17,7 @@
package convert
import (
"os"
"testing"
"github.com/Azure/azure-sdk-for-go/profiles/latest/containerinstance/mgmt/containerinstance"
@ -260,6 +261,32 @@ func (suite *ConvertTestSuite) TestComposeContainerGroupToContainerResourceLimit
Expect(*limits.MemoryInGB).To(Equal(float64(1)))
}
func (suite *ConvertTestSuite) TestComposeContainerGroupToContainerenvVar() {
err := os.Setenv("key2", "value2")
Expect(err).To(BeNil())
project := types.Project{
Services: []types.ServiceConfig{
{
Name: "service1",
Image: "image1",
Environment: types.MappingWithEquals{
"key1": to.StringPtr("value1"),
"key2": nil,
},
},
},
}
group, err := ToContainerGroup(suite.ctx, project)
Expect(err).To(BeNil())
container1 := (*group.Containers)[0]
envVars := *container1.EnvironmentVariables
Expect(len(envVars)).To(Equal(2))
Expect(envVars).To(ContainElement(containerinstance.EnvironmentVariable{Name: to.StringPtr("key1"), Value: to.StringPtr("value1")}))
Expect(envVars).To(ContainElement(containerinstance.EnvironmentVariable{Name: to.StringPtr("key2"), Value: to.StringPtr("value2")}))
}
func TestConvertTestSuite(t *testing.T) {
RegisterTestingT(t)
suite.Run(t, new(ConvertTestSuite))

Просмотреть файл

@ -51,6 +51,7 @@ func Command() *cobra.Command {
cmd.Flags().BoolVarP(&opts.Detach, "detach", "d", false, "Run container in background and print container ID")
cmd.Flags().Float64Var(&opts.Cpus, "cpus", 1., "Number of CPUs")
cmd.Flags().VarP(&opts.Memory, "memory", "m", "Memory limit")
cmd.Flags().StringArrayVarP(&opts.Environment, "env", "e", []string{}, "Set environment variables")
return cmd
}

1
cli/cmd/run/testdata/run-help.golden поставляемый
Просмотреть файл

@ -6,6 +6,7 @@ Usage:
Flags:
--cpus float Number of CPUs (default 1)
-d, --detach Run container in background and print container ID
-e, --env stringArray Set environment variables
-l, --label stringArray Set meta data on a container
-m, --memory bytes Memory limit
--name string Assign a name to the container

Просмотреть файл

@ -30,13 +30,14 @@ import (
// Opts contain run command options
type Opts struct {
Name string
Publish []string
Labels []string
Volumes []string
Cpus float64
Memory formatter.MemBytes
Detach bool
Name string
Publish []string
Labels []string
Volumes []string
Cpus float64
Memory formatter.MemBytes
Detach bool
Environment []string
}
// ToContainerConfig convert run options to a container configuration
@ -56,13 +57,14 @@ func (r *Opts) ToContainerConfig(image string) (containers.ContainerConfig, erro
}
return containers.ContainerConfig{
ID: r.Name,
Image: image,
Ports: publish,
Labels: labels,
Volumes: r.Volumes,
MemLimit: r.Memory,
CPULimit: r.Cpus,
ID: r.Name,
Image: image,
Ports: publish,
Labels: labels,
Volumes: r.Volumes,
MemLimit: r.Memory,
CPULimit: r.Cpus,
Environment: r.Environment,
}, nil
}

Просмотреть файл

@ -68,6 +68,8 @@ type ContainerConfig struct {
MemLimit formatter.MemBytes
// CPUlimit
CPULimit float64
// Environment variables
Environment []string
}
// LogsRequest contains configuration about a log request

Просмотреть файл

@ -302,6 +302,28 @@ func (s *E2eACISuite) TestACIBackend() {
s.NewDockerCommand("compose", "down", "--project-name", composeProjectName).ExecOrDie()
})
s.T().Run("runs mysql with env variables", func(t *testing.T) {
err := os.Setenv("MYSQL_USER", "user1")
Expect(err).To(BeNil())
s.NewDockerCommand("run", "-d", "mysql:5.7", "-e", "MYSQL_ROOT_PASSWORD=rootpwd", "-e", "MYSQL_DATABASE=mytestdb", "-e", "MYSQL_USER", "-e", "MYSQL_PASSWORD=userpwd").ExecOrDie()
output := s.NewDockerCommand("ps").ExecOrDie()
lines := Lines(output)
Expect(len(lines)).To(Equal(2))
containerFields := Columns(lines[1])
containerID := containerFields[0]
Expect(containerFields[1]).To(Equal("mysql:5.7"))
Expect(containerFields[2]).To(Equal("Running"))
errs := make(chan error)
err = WaitFor(time.Second, 100*time.Second, errs, func() bool {
output = s.NewDockerCommand("logs", containerID).ExecOrDie()
return strings.Contains(output, "Giving user user1 access to schema mytestdb")
})
Expect(err).To(BeNil())
})
s.T().Run("switches back to default context", func(t *testing.T) {
output := s.NewCommand("docker", "context", "use", "default").ExecOrDie()
Expect(output).To(ContainSubstring("default"))