mirror of https://github.com/portainer/portainer
feat(templates): support env variables in Compose stacks
parent
c8c54cf991
commit
e15da005a5
|
@ -17,6 +17,7 @@ import (
|
|||
type composeStackFromFileContentPayload struct {
|
||||
Name string
|
||||
StackFileContent string
|
||||
Env []portainer.Pair
|
||||
}
|
||||
|
||||
func (payload *composeStackFromFileContentPayload) Validate(r *http.Request) error {
|
||||
|
@ -54,6 +55,7 @@ func (handler *Handler) createComposeStackFromFileContent(w http.ResponseWriter,
|
|||
Type: portainer.DockerComposeStack,
|
||||
EndpointID: endpoint.ID,
|
||||
EntryPoint: filesystem.ComposeFileDefaultName,
|
||||
Env: payload.Env,
|
||||
}
|
||||
|
||||
stackFolder := strconv.Itoa(int(stack.ID))
|
||||
|
@ -92,6 +94,7 @@ type composeStackFromGitRepositoryPayload struct {
|
|||
RepositoryUsername string
|
||||
RepositoryPassword string
|
||||
ComposeFilePathInRepository string
|
||||
Env []portainer.Pair
|
||||
}
|
||||
|
||||
func (payload *composeStackFromGitRepositoryPayload) Validate(r *http.Request) error {
|
||||
|
@ -135,6 +138,7 @@ func (handler *Handler) createComposeStackFromGitRepository(w http.ResponseWrite
|
|||
Type: portainer.DockerComposeStack,
|
||||
EndpointID: endpoint.ID,
|
||||
EntryPoint: payload.ComposeFilePathInRepository,
|
||||
Env: payload.Env,
|
||||
}
|
||||
|
||||
projectPath := handler.FileService.GetStackProjectPath(strconv.Itoa(int(stack.ID)))
|
||||
|
@ -177,6 +181,7 @@ func (handler *Handler) createComposeStackFromGitRepository(w http.ResponseWrite
|
|||
type composeStackFromFileUploadPayload struct {
|
||||
Name string
|
||||
StackFileContent []byte
|
||||
Env []portainer.Pair
|
||||
}
|
||||
|
||||
func (payload *composeStackFromFileUploadPayload) Validate(r *http.Request) error {
|
||||
|
@ -192,6 +197,12 @@ func (payload *composeStackFromFileUploadPayload) Validate(r *http.Request) erro
|
|||
}
|
||||
payload.StackFileContent = composeFileContent
|
||||
|
||||
var env []portainer.Pair
|
||||
err = request.RetrieveMultiPartFormJSONValue(r, "Env", &env, true)
|
||||
if err != nil {
|
||||
return portainer.Error("Invalid Env parameter")
|
||||
}
|
||||
payload.Env = env
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -220,6 +231,7 @@ func (handler *Handler) createComposeStackFromFileUpload(w http.ResponseWriter,
|
|||
Type: portainer.DockerComposeStack,
|
||||
EndpointID: endpoint.ID,
|
||||
EntryPoint: filesystem.ComposeFileDefaultName,
|
||||
Env: payload.Env,
|
||||
}
|
||||
|
||||
stackFolder := strconv.Itoa(int(stack.ID))
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
|
||||
type updateComposeStackPayload struct {
|
||||
StackFileContent string
|
||||
Env []portainer.Pair
|
||||
}
|
||||
|
||||
func (payload *updateComposeStackPayload) Validate(r *http.Request) error {
|
||||
|
@ -112,6 +113,8 @@ func (handler *Handler) updateComposeStack(r *http.Request, stack *portainer.Sta
|
|||
return &httperror.HandlerError{http.StatusBadRequest, "Invalid request payload", err}
|
||||
}
|
||||
|
||||
stack.Env = payload.Env
|
||||
|
||||
stackFolder := strconv.Itoa(int(stack.ID))
|
||||
_, err = handler.FileService.StoreStackFileFromBytes(stackFolder, stack.EntryPoint, []byte(payload.StackFileContent))
|
||||
if err != nil {
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"path"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/portainer/libcompose/config"
|
||||
"github.com/portainer/libcompose/docker"
|
||||
"github.com/portainer/libcompose/docker/client"
|
||||
"github.com/portainer/libcompose/docker/ctx"
|
||||
|
@ -35,19 +36,31 @@ func (manager *ComposeStackManager) Up(stack *portainer.Stack, endpoint *portain
|
|||
TLSCAFile: endpoint.TLSCACertPath,
|
||||
TLSCertFile: endpoint.TLSCertPath,
|
||||
TLSKeyFile: endpoint.TLSKeyPath,
|
||||
APIVersion: "1.24",
|
||||
APIVersion: portainer.SupportedDockerAPIVersion,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
env := make(map[string]string)
|
||||
for _, envvar := range stack.Env {
|
||||
env[envvar.Name] = envvar.Value
|
||||
}
|
||||
|
||||
composeFilePath := path.Join(stack.ProjectPath, stack.EntryPoint)
|
||||
proj, err := docker.NewProject(&ctx.Context{
|
||||
ConfigDir: manager.dataPath,
|
||||
Context: project.Context{
|
||||
ComposeFiles: []string{composeFilePath},
|
||||
EnvironmentLookup: &lookup.EnvfileLookup{
|
||||
Path: filepath.Join(stack.ProjectPath, ".env"),
|
||||
EnvironmentLookup: &lookup.ComposableEnvLookup{
|
||||
Lookups: []config.EnvironmentLookup{
|
||||
&lookup.EnvfileLookup{
|
||||
Path: filepath.Join(stack.ProjectPath, ".env"),
|
||||
},
|
||||
&lookup.MapLookup{
|
||||
Vars: env,
|
||||
},
|
||||
},
|
||||
},
|
||||
ProjectName: stack.Name,
|
||||
},
|
||||
|
@ -69,7 +82,7 @@ func (manager *ComposeStackManager) Down(stack *portainer.Stack, endpoint *porta
|
|||
TLSCAFile: endpoint.TLSCACertPath,
|
||||
TLSCertFile: endpoint.TLSCertPath,
|
||||
TLSKeyFile: endpoint.TLSKeyPath,
|
||||
APIVersion: "1.24",
|
||||
APIVersion: portainer.SupportedDockerAPIVersion,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -223,8 +223,8 @@ function StackServiceFactory($q, Stack, ResourceControlService, FileUploadServic
|
|||
return Stack.update({ endpointId: stack.EndpointId }, { id: stack.Id, StackFileContent: stackFile, Env: env, Prune: prune }).$promise;
|
||||
};
|
||||
|
||||
service.createComposeStackFromFileUpload = function(name, stackFile, endpointId) {
|
||||
return FileUploadService.createComposeStack(name, stackFile, endpointId);
|
||||
service.createComposeStackFromFileUpload = function(name, stackFile, env, endpointId) {
|
||||
return FileUploadService.createComposeStack(name, stackFile, env, endpointId);
|
||||
};
|
||||
|
||||
service.createSwarmStackFromFileUpload = function(name, stackFile, env, endpointId) {
|
||||
|
@ -245,10 +245,11 @@ function StackServiceFactory($q, Stack, ResourceControlService, FileUploadServic
|
|||
return deferred.promise;
|
||||
};
|
||||
|
||||
service.createComposeStackFromFileContent = function(name, stackFileContent, endpointId) {
|
||||
service.createComposeStackFromFileContent = function(name, stackFileContent, env, endpointId) {
|
||||
var payload = {
|
||||
Name: name,
|
||||
StackFileContent: stackFileContent
|
||||
StackFileContent: stackFileContent,
|
||||
Env: env
|
||||
};
|
||||
return Stack.create({ method: 'string', type: 2, endpointId: endpointId }, payload).$promise;
|
||||
};
|
||||
|
@ -277,14 +278,15 @@ function StackServiceFactory($q, Stack, ResourceControlService, FileUploadServic
|
|||
return deferred.promise;
|
||||
};
|
||||
|
||||
service.createComposeStackFromGitRepository = function(name, repositoryOptions, endpointId) {
|
||||
service.createComposeStackFromGitRepository = function(name, repositoryOptions, env, endpointId) {
|
||||
var payload = {
|
||||
Name: name,
|
||||
RepositoryURL: repositoryOptions.RepositoryURL,
|
||||
ComposeFilePathInRepository: repositoryOptions.ComposeFilePathInRepository,
|
||||
RepositoryAuthentication: repositoryOptions.RepositoryAuthentication,
|
||||
RepositoryUsername: repositoryOptions.RepositoryUsername,
|
||||
RepositoryPassword: repositoryOptions.RepositoryPassword
|
||||
RepositoryPassword: repositoryOptions.RepositoryPassword,
|
||||
Env: env
|
||||
};
|
||||
return Stack.create({ method: 'repository', type: 2, endpointId: endpointId }, payload).$promise;
|
||||
};
|
||||
|
|
|
@ -41,12 +41,13 @@ angular.module('portainer.app')
|
|||
});
|
||||
};
|
||||
|
||||
service.createComposeStack = function(stackName, file, endpointId) {
|
||||
service.createComposeStack = function(stackName, file, env, endpointId) {
|
||||
return Upload.upload({
|
||||
url: 'api/stacks?method=file&type=2&endpointId=' + endpointId,
|
||||
data: {
|
||||
file: file,
|
||||
Name: stackName
|
||||
Name: stackName,
|
||||
Env: Upload.json(env)
|
||||
},
|
||||
ignoreLoadingBar: true
|
||||
});
|
||||
|
|
|
@ -65,14 +65,15 @@ function ($scope, $state, StackService, Authentication, Notifications, FormValid
|
|||
}
|
||||
|
||||
function createComposeStack(name, method) {
|
||||
var env = FormHelper.removeInvalidEnvVars($scope.formValues.Env);
|
||||
var endpointId = EndpointProvider.endpointID();
|
||||
|
||||
if (method === 'editor') {
|
||||
var stackFileContent = $scope.formValues.StackFileContent;
|
||||
return StackService.createComposeStackFromFileContent(name, stackFileContent, endpointId);
|
||||
return StackService.createComposeStackFromFileContent(name, stackFileContent, env, endpointId);
|
||||
} else if (method === 'upload') {
|
||||
var stackFile = $scope.formValues.StackFile;
|
||||
return StackService.createComposeStackFromFileUpload(name, stackFile, endpointId);
|
||||
return StackService.createComposeStackFromFileUpload(name, stackFile, env, endpointId);
|
||||
} else if (method === 'repository') {
|
||||
var repositoryOptions = {
|
||||
RepositoryURL: $scope.formValues.RepositoryURL,
|
||||
|
@ -81,7 +82,7 @@ function ($scope, $state, StackService, Authentication, Notifications, FormValid
|
|||
RepositoryUsername: $scope.formValues.RepositoryUsername,
|
||||
RepositoryPassword: $scope.formValues.RepositoryPassword
|
||||
};
|
||||
return StackService.createComposeStackFromGitRepository(name, repositoryOptions, endpointId);
|
||||
return StackService.createComposeStackFromGitRepository(name, repositoryOptions, env, endpointId);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -160,7 +160,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<!-- environment-variables -->
|
||||
<div ng-if="state.StackType === 1">
|
||||
<div>
|
||||
<div class="col-sm-12 form-section-title">
|
||||
Environment
|
||||
</div>
|
||||
|
|
|
@ -94,13 +94,20 @@ function ($scope, $q, $state, $transition$, $anchorScroll, ContainerService, Ima
|
|||
function createComposeStackFromTemplate(template, userId, accessControlData) {
|
||||
var stackName = $scope.formValues.name;
|
||||
|
||||
for (var i = 0; i < template.Env.length; i++) {
|
||||
var envvar = template.Env[i];
|
||||
if (envvar.preset) {
|
||||
envvar.value = envvar.default;
|
||||
}
|
||||
}
|
||||
|
||||
var repositoryOptions = {
|
||||
RepositoryURL: template.Repository.url,
|
||||
ComposeFilePathInRepository: template.Repository.stackfile
|
||||
};
|
||||
|
||||
var endpointId = EndpointProvider.endpointID();
|
||||
StackService.createComposeStackFromGitRepository(stackName, repositoryOptions, endpointId)
|
||||
StackService.createComposeStackFromGitRepository(stackName, repositoryOptions, template.Env, endpointId)
|
||||
.then(function success(data) {
|
||||
return ResourceControlService.applyResourceControl('stack', stackName, userId, accessControlData, []);
|
||||
})
|
||||
|
@ -121,8 +128,8 @@ function ($scope, $q, $state, $transition$, $anchorScroll, ContainerService, Ima
|
|||
|
||||
for (var i = 0; i < template.Env.length; i++) {
|
||||
var envvar = template.Env[i];
|
||||
if (envvar.set) {
|
||||
envvar.value = envvar.set;
|
||||
if (envvar.preset) {
|
||||
envvar.value = envvar.default;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue