mirror of https://github.com/portainer/portainer
fix(stack): env placeholder as host path [BE-11187] (#12186)
parent
517abc662a
commit
753150e03c
|
@ -110,6 +110,11 @@ func (wrapper *PluginWrapper) Validate(ctx context.Context, filePaths []string,
|
|||
return err
|
||||
}
|
||||
|
||||
func (wrapper *PluginWrapper) Config(ctx context.Context, filePaths []string, options libstack.Options) ([]byte, error) {
|
||||
configArgs := append([]string{"config"}, options.ConfigOptions...)
|
||||
return wrapper.command(newCommand(configArgs, filePaths), options)
|
||||
}
|
||||
|
||||
// Command execute a docker-compose command
|
||||
func (wrapper *PluginWrapper) command(command composeCommand, options libstack.Options) ([]byte, error) {
|
||||
program := utils.ProgramPath(wrapper.binaryPath, "docker-compose")
|
||||
|
|
|
@ -143,3 +143,230 @@ func containerExists(containerName string) bool {
|
|||
|
||||
return strings.Contains(string(out), containerName)
|
||||
}
|
||||
|
||||
func Test_Config(t *testing.T) {
|
||||
checkPrerequisites(t)
|
||||
|
||||
ctx := context.Background()
|
||||
dir := t.TempDir()
|
||||
projectName := "configtest"
|
||||
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
composeFileContent string
|
||||
expectFileContent string
|
||||
envFileContent string
|
||||
}{
|
||||
{
|
||||
name: "compose file with relative path",
|
||||
composeFileContent: `services:
|
||||
app:
|
||||
image: 'nginx:latest'
|
||||
ports:
|
||||
- '80:80'
|
||||
volumes:
|
||||
- ./nginx-data:/data`,
|
||||
expectFileContent: `name: configtest
|
||||
services:
|
||||
app:
|
||||
image: nginx:latest
|
||||
networks:
|
||||
default: null
|
||||
ports:
|
||||
- mode: ingress
|
||||
target: 80
|
||||
published: "80"
|
||||
protocol: tcp
|
||||
volumes:
|
||||
- type: bind
|
||||
source: ./nginx-data
|
||||
target: /data
|
||||
bind:
|
||||
create_host_path: true
|
||||
networks:
|
||||
default:
|
||||
name: configtest_default
|
||||
`,
|
||||
envFileContent: "",
|
||||
},
|
||||
{
|
||||
name: "compose file with absolute path",
|
||||
composeFileContent: `services:
|
||||
app:
|
||||
image: 'nginx:latest'
|
||||
ports:
|
||||
- '80:80'
|
||||
volumes:
|
||||
- /nginx-data:/data`,
|
||||
expectFileContent: `name: configtest
|
||||
services:
|
||||
app:
|
||||
image: nginx:latest
|
||||
networks:
|
||||
default: null
|
||||
ports:
|
||||
- mode: ingress
|
||||
target: 80
|
||||
published: "80"
|
||||
protocol: tcp
|
||||
volumes:
|
||||
- type: bind
|
||||
source: /nginx-data
|
||||
target: /data
|
||||
bind:
|
||||
create_host_path: true
|
||||
networks:
|
||||
default:
|
||||
name: configtest_default
|
||||
`,
|
||||
envFileContent: "",
|
||||
},
|
||||
{
|
||||
name: "compose file with declared volume",
|
||||
composeFileContent: `services:
|
||||
app:
|
||||
image: 'nginx:latest'
|
||||
ports:
|
||||
- '80:80'
|
||||
volumes:
|
||||
- nginx-data:/data
|
||||
volumes:
|
||||
nginx-data:
|
||||
driver: local`,
|
||||
expectFileContent: `name: configtest
|
||||
services:
|
||||
app:
|
||||
image: nginx:latest
|
||||
networks:
|
||||
default: null
|
||||
ports:
|
||||
- mode: ingress
|
||||
target: 80
|
||||
published: "80"
|
||||
protocol: tcp
|
||||
volumes:
|
||||
- type: volume
|
||||
source: nginx-data
|
||||
target: /data
|
||||
volume: {}
|
||||
networks:
|
||||
default:
|
||||
name: configtest_default
|
||||
volumes:
|
||||
nginx-data:
|
||||
name: configtest_nginx-data
|
||||
driver: local
|
||||
`,
|
||||
envFileContent: "",
|
||||
},
|
||||
{
|
||||
name: "compose file with relative path environment variable placeholder",
|
||||
composeFileContent: `services:
|
||||
nginx:
|
||||
image: nginx:latest
|
||||
ports:
|
||||
- 8019:80
|
||||
volumes:
|
||||
- ${WEB_HOME}:/usr/share/nginx/html/
|
||||
env_file:
|
||||
- stack.env
|
||||
`,
|
||||
expectFileContent: `name: configtest
|
||||
services:
|
||||
nginx:
|
||||
environment:
|
||||
WEB_HOME: ./html
|
||||
image: nginx:latest
|
||||
networks:
|
||||
default: null
|
||||
ports:
|
||||
- mode: ingress
|
||||
target: 80
|
||||
published: "8019"
|
||||
protocol: tcp
|
||||
volumes:
|
||||
- type: bind
|
||||
source: ./html
|
||||
target: /usr/share/nginx/html
|
||||
bind:
|
||||
create_host_path: true
|
||||
networks:
|
||||
default:
|
||||
name: configtest_default
|
||||
`,
|
||||
envFileContent: `WEB_HOME=./html`,
|
||||
},
|
||||
{
|
||||
name: "compose file with absolute path environment variable placeholder",
|
||||
composeFileContent: `services:
|
||||
nginx:
|
||||
image: nginx:latest
|
||||
ports:
|
||||
- 8019:80
|
||||
volumes:
|
||||
- ${WEB_HOME}:/usr/share/nginx/html/
|
||||
env_file:
|
||||
- stack.env
|
||||
`,
|
||||
|
||||
expectFileContent: `name: configtest
|
||||
services:
|
||||
nginx:
|
||||
environment:
|
||||
WEB_HOME: /usr/share/nginx/html
|
||||
image: nginx:latest
|
||||
networks:
|
||||
default: null
|
||||
ports:
|
||||
- mode: ingress
|
||||
target: 80
|
||||
published: "8019"
|
||||
protocol: tcp
|
||||
volumes:
|
||||
- type: bind
|
||||
source: /usr/share/nginx/html
|
||||
target: /usr/share/nginx/html
|
||||
bind:
|
||||
create_host_path: true
|
||||
networks:
|
||||
default:
|
||||
name: configtest_default
|
||||
`,
|
||||
envFileContent: `WEB_HOME=/usr/share/nginx/html`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
composeFilePath, err := createFile(dir, "docker-compose.yml", tc.composeFileContent)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
envFilePath := ""
|
||||
if tc.envFileContent != "" {
|
||||
envFilePath, err = createFile(dir, "stack.env", tc.envFileContent)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
w := setup(t)
|
||||
actual, err := w.Config(ctx, []string{composeFilePath}, libstack.Options{
|
||||
WorkingDir: dir,
|
||||
ProjectName: projectName,
|
||||
EnvFilePath: envFilePath,
|
||||
ConfigOptions: []string{"--no-path-resolution"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get config: %s. Error: %s", string(actual), err)
|
||||
}
|
||||
|
||||
if string(actual) != tc.expectFileContent {
|
||||
t.Fatalf("unexpected config output: %s(len=%d), expect: %s(len=%d)", actual, len(actual), tc.expectFileContent, len(tc.expectFileContent))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ type Deployer interface {
|
|||
Pull(ctx context.Context, filePaths []string, options Options) error
|
||||
Validate(ctx context.Context, filePaths []string, options Options) error
|
||||
WaitForStatus(ctx context.Context, name string, status Status) <-chan WaitResult
|
||||
Config(ctx context.Context, filePaths []string, options Options) ([]byte, error)
|
||||
}
|
||||
|
||||
type Status string
|
||||
|
@ -47,6 +48,8 @@ type Options struct {
|
|||
// By default, it is an empty string, which means it corresponds to the path of the compose file itself.
|
||||
// This is particularly helpful when mounting a relative path.
|
||||
ProjectDir string
|
||||
// ConfigOptions is a list of options to pass to the docker-compose config command
|
||||
ConfigOptions []string
|
||||
}
|
||||
|
||||
type DeployOptions struct {
|
||||
|
|
Loading…
Reference in New Issue