mirror of https://github.com/docker/compose.git
Do not bind mount configs and secrets when source is a file but copy it into the container
Signed-off-by: schaubl <schaubl@users.noreply.github.com>
This commit is contained in:
parent
d3d378b92a
commit
f54922f13f
|
@ -288,6 +288,12 @@ func (s *composeService) getCreateConfigs(ctx context.Context,
|
||||||
return createConfigs{}, err
|
return createConfigs{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CONFIGS and SECRETS
|
||||||
|
err = checkContainerConfigsSecrets(*p, service)
|
||||||
|
if err != nil {
|
||||||
|
return createConfigs{}, err
|
||||||
|
}
|
||||||
|
|
||||||
// NETWORKING
|
// NETWORKING
|
||||||
links, err := s.getLinks(ctx, p.Name, service, number)
|
links, err := s.getLinks(ctx, p.Name, service, number)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -915,128 +921,79 @@ func fillBindMounts(p types.Project, s types.ServiceConfig, m map[string]mount.M
|
||||||
m[bindMount.Target] = bindMount
|
m[bindMount.Target] = bindMount
|
||||||
}
|
}
|
||||||
|
|
||||||
secrets, err := buildContainerSecretMounts(p, s)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
for _, s := range secrets {
|
|
||||||
if _, found := m[s.Target]; found {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
m[s.Target] = s
|
|
||||||
}
|
|
||||||
|
|
||||||
configs, err := buildContainerConfigMounts(p, s)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
for _, c := range configs {
|
|
||||||
if _, found := m[c.Target]; found {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
m[c.Target] = c
|
|
||||||
}
|
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildContainerConfigMounts(p types.Project, s types.ServiceConfig) ([]mount.Mount, error) {
|
func checkContainerConfigsSecrets(p types.Project, s types.ServiceConfig) error {
|
||||||
var mounts = map[string]mount.Mount{}
|
err := checkContainerConfigs(p, s)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
configsBaseDir := "/"
|
err = checkContainerSecrets(p, s)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkContainerConfigs(p types.Project, s types.ServiceConfig) error {
|
||||||
for _, config := range s.Configs {
|
for _, config := range s.Configs {
|
||||||
target := config.Target
|
|
||||||
if config.Target == "" {
|
|
||||||
target = configsBaseDir + config.Source
|
|
||||||
} else if !isAbsTarget(config.Target) {
|
|
||||||
target = configsBaseDir + config.Target
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.UID != "" || config.GID != "" || config.Mode != nil {
|
if config.UID != "" || config.GID != "" || config.Mode != nil {
|
||||||
logrus.Warn("config `uid`, `gid` and `mode` are not supported, they will be ignored")
|
logrus.Warn("config `uid`, `gid` and `mode` are not supported, they will be ignored")
|
||||||
}
|
}
|
||||||
|
|
||||||
definedConfig := p.Configs[config.Source]
|
definedConfig := p.Configs[config.Source]
|
||||||
if definedConfig.External {
|
if definedConfig.External {
|
||||||
return nil, fmt.Errorf("unsupported external config %s", definedConfig.Name)
|
return fmt.Errorf("unsupported external config %s", definedConfig.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
if definedConfig.Driver != "" {
|
if definedConfig.Driver != "" {
|
||||||
return nil, errors.New("Docker Compose does not support configs.*.driver")
|
return errors.New("Docker Compose does not support configs.*.driver")
|
||||||
}
|
}
|
||||||
if definedConfig.TemplateDriver != "" {
|
if definedConfig.TemplateDriver != "" {
|
||||||
return nil, errors.New("Docker Compose does not support configs.*.template_driver")
|
return errors.New("Docker Compose does not support configs.*.template_driver")
|
||||||
}
|
}
|
||||||
|
|
||||||
if definedConfig.Environment != "" || definedConfig.Content != "" {
|
if definedConfig.File != "" {
|
||||||
|
_, err := os.Stat(definedConfig.File)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error with source file of config %s: %s", definedConfig.Name, err.Error())
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
bindMount, err := buildMount(p, types.ServiceVolumeConfig{
|
|
||||||
Type: types.VolumeTypeBind,
|
|
||||||
Source: definedConfig.File,
|
|
||||||
Target: target,
|
|
||||||
ReadOnly: true,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
mounts[target] = bindMount
|
|
||||||
}
|
}
|
||||||
values := make([]mount.Mount, 0, len(mounts))
|
return nil
|
||||||
for _, v := range mounts {
|
|
||||||
values = append(values, v)
|
|
||||||
}
|
|
||||||
return values, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildContainerSecretMounts(p types.Project, s types.ServiceConfig) ([]mount.Mount, error) {
|
func checkContainerSecrets(p types.Project, s types.ServiceConfig) error {
|
||||||
var mounts = map[string]mount.Mount{}
|
|
||||||
|
|
||||||
secretsDir := "/run/secrets/"
|
|
||||||
for _, secret := range s.Secrets {
|
for _, secret := range s.Secrets {
|
||||||
target := secret.Target
|
|
||||||
if secret.Target == "" {
|
|
||||||
target = secretsDir + secret.Source
|
|
||||||
} else if !isAbsTarget(secret.Target) {
|
|
||||||
target = secretsDir + secret.Target
|
|
||||||
}
|
|
||||||
|
|
||||||
if secret.UID != "" || secret.GID != "" || secret.Mode != nil {
|
if secret.UID != "" || secret.GID != "" || secret.Mode != nil {
|
||||||
logrus.Warn("secrets `uid`, `gid` and `mode` are not supported, they will be ignored")
|
logrus.Warn("secrets `uid`, `gid` and `mode` are not supported, they will be ignored")
|
||||||
}
|
}
|
||||||
|
|
||||||
definedSecret := p.Secrets[secret.Source]
|
definedSecret := p.Secrets[secret.Source]
|
||||||
if definedSecret.External {
|
if definedSecret.External {
|
||||||
return nil, fmt.Errorf("unsupported external secret %s", definedSecret.Name)
|
return fmt.Errorf("unsupported external secret %s", definedSecret.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
if definedSecret.Driver != "" {
|
if definedSecret.Driver != "" {
|
||||||
return nil, errors.New("Docker Compose does not support secrets.*.driver")
|
return errors.New("Docker Compose does not support secrets.*.driver")
|
||||||
}
|
}
|
||||||
if definedSecret.TemplateDriver != "" {
|
if definedSecret.TemplateDriver != "" {
|
||||||
return nil, errors.New("Docker Compose does not support secrets.*.template_driver")
|
return errors.New("Docker Compose does not support secrets.*.template_driver")
|
||||||
}
|
}
|
||||||
|
|
||||||
if definedSecret.Environment != "" {
|
if definedSecret.File != "" {
|
||||||
|
_, err := os.Stat(definedSecret.File)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error with source file of secret %s: %s", definedSecret.Name, err.Error())
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
mnt, err := buildMount(p, types.ServiceVolumeConfig{
|
|
||||||
Type: types.VolumeTypeBind,
|
|
||||||
Source: definedSecret.File,
|
|
||||||
Target: target,
|
|
||||||
ReadOnly: true,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
mounts[target] = mnt
|
|
||||||
}
|
}
|
||||||
values := make([]mount.Mount, 0, len(mounts))
|
return nil
|
||||||
for _, v := range mounts {
|
|
||||||
values = append(values, v)
|
|
||||||
}
|
|
||||||
return values, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func isAbsTarget(p string) bool {
|
func isAbsTarget(p string) bool {
|
||||||
|
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -31,7 +32,23 @@ import (
|
||||||
func (s *composeService) injectSecrets(ctx context.Context, project *types.Project, service types.ServiceConfig, id string) error {
|
func (s *composeService) injectSecrets(ctx context.Context, project *types.Project, service types.ServiceConfig, id string) error {
|
||||||
for _, config := range service.Secrets {
|
for _, config := range service.Secrets {
|
||||||
file := project.Secrets[config.Source]
|
file := project.Secrets[config.Source]
|
||||||
if file.Environment == "" {
|
content := file.Content
|
||||||
|
|
||||||
|
if file.Environment != "" {
|
||||||
|
env, ok := project.Environment[file.Environment]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("environment variable %q required by file %q is not set", file.Environment, file.Name)
|
||||||
|
}
|
||||||
|
content = env
|
||||||
|
} else if file.File != "" {
|
||||||
|
data, err := os.ReadFile(file.File)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
content = string(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
if content == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,11 +58,7 @@ func (s *composeService) injectSecrets(ctx context.Context, project *types.Proje
|
||||||
config.Target = "/run/secrets/" + config.Target
|
config.Target = "/run/secrets/" + config.Target
|
||||||
}
|
}
|
||||||
|
|
||||||
env, ok := project.Environment[file.Environment]
|
b, err := createTar(content, types.FileReferenceConfig(config))
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("environment variable %q required by file %q is not set", file.Environment, file.Name)
|
|
||||||
}
|
|
||||||
b, err := createTar(env, types.FileReferenceConfig(config))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -64,13 +77,21 @@ func (s *composeService) injectConfigs(ctx context.Context, project *types.Proje
|
||||||
for _, config := range service.Configs {
|
for _, config := range service.Configs {
|
||||||
file := project.Configs[config.Source]
|
file := project.Configs[config.Source]
|
||||||
content := file.Content
|
content := file.Content
|
||||||
|
|
||||||
if file.Environment != "" {
|
if file.Environment != "" {
|
||||||
env, ok := project.Environment[file.Environment]
|
env, ok := project.Environment[file.Environment]
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("environment variable %q required by file %q is not set", file.Environment, file.Name)
|
return fmt.Errorf("environment variable %q required by file %q is not set", file.Environment, file.Name)
|
||||||
}
|
}
|
||||||
content = env
|
content = env
|
||||||
|
} else if file.File != "" {
|
||||||
|
data, err := os.ReadFile(file.File)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
content = string(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
if content == "" {
|
if content == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@ func TestLocalComposeVolume(t *testing.T) {
|
||||||
res := c.RunDockerCmd(t, "inspect", "compose-e2e-volume-nginx2-1", "--format", "{{ json .Mounts }}")
|
res := c.RunDockerCmd(t, "inspect", "compose-e2e-volume-nginx2-1", "--format", "{{ json .Mounts }}")
|
||||||
output := res.Stdout()
|
output := res.Stdout()
|
||||||
assert.Assert(t, strings.Contains(output, `"Destination":"/usr/src/app/node_modules","Driver":"local","Mode":"z","RW":true,"Propagation":""`), output)
|
assert.Assert(t, strings.Contains(output, `"Destination":"/usr/src/app/node_modules","Driver":"local","Mode":"z","RW":true,"Propagation":""`), output)
|
||||||
assert.Assert(t, strings.Contains(output, `"Destination":"/myconfig","Mode":"","RW":false,"Propagation":"rprivate"`), output)
|
assert.Assert(t, !strings.Contains(output, `"Destination":"/myconfig","Mode":"","RW":false,"Propagation":"rprivate"`), output)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("check config content", func(t *testing.T) {
|
t.Run("check config content", func(t *testing.T) {
|
||||||
|
|
Loading…
Reference in New Issue