mirror of
https://github.com/portainer/portainer.git
synced 2025-07-24 07:49:41 +02:00
feat(stacks): add the ability to specify env vars when deploying stacks (#1345)
This commit is contained in:
parent
42347d714f
commit
693f1319a4
11 changed files with 173 additions and 30 deletions
|
@ -2,6 +2,7 @@ package exec
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path"
|
"path"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
@ -27,7 +28,7 @@ func (manager *StackManager) Login(dockerhub *portainer.DockerHub, registries []
|
||||||
for _, registry := range registries {
|
for _, registry := range registries {
|
||||||
if registry.Authentication {
|
if registry.Authentication {
|
||||||
registryArgs := append(args, "login", "--username", registry.Username, "--password", registry.Password, registry.URL)
|
registryArgs := append(args, "login", "--username", registry.Username, "--password", registry.Password, registry.URL)
|
||||||
err := runCommandAndCaptureStdErr(command, registryArgs)
|
err := runCommandAndCaptureStdErr(command, registryArgs, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -36,7 +37,7 @@ func (manager *StackManager) Login(dockerhub *portainer.DockerHub, registries []
|
||||||
|
|
||||||
if dockerhub.Authentication {
|
if dockerhub.Authentication {
|
||||||
dockerhubArgs := append(args, "login", "--username", dockerhub.Username, "--password", dockerhub.Password)
|
dockerhubArgs := append(args, "login", "--username", dockerhub.Username, "--password", dockerhub.Password)
|
||||||
err := runCommandAndCaptureStdErr(command, dockerhubArgs)
|
err := runCommandAndCaptureStdErr(command, dockerhubArgs, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -49,7 +50,7 @@ func (manager *StackManager) Login(dockerhub *portainer.DockerHub, registries []
|
||||||
func (manager *StackManager) Logout(endpoint *portainer.Endpoint) error {
|
func (manager *StackManager) Logout(endpoint *portainer.Endpoint) error {
|
||||||
command, args := prepareDockerCommandAndArgs(manager.binaryPath, endpoint)
|
command, args := prepareDockerCommandAndArgs(manager.binaryPath, endpoint)
|
||||||
args = append(args, "logout")
|
args = append(args, "logout")
|
||||||
return runCommandAndCaptureStdErr(command, args)
|
return runCommandAndCaptureStdErr(command, args, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deploy executes the docker stack deploy command.
|
// Deploy executes the docker stack deploy command.
|
||||||
|
@ -57,21 +58,32 @@ func (manager *StackManager) Deploy(stack *portainer.Stack, endpoint *portainer.
|
||||||
stackFilePath := path.Join(stack.ProjectPath, stack.EntryPoint)
|
stackFilePath := path.Join(stack.ProjectPath, stack.EntryPoint)
|
||||||
command, args := prepareDockerCommandAndArgs(manager.binaryPath, endpoint)
|
command, args := prepareDockerCommandAndArgs(manager.binaryPath, endpoint)
|
||||||
args = append(args, "stack", "deploy", "--with-registry-auth", "--compose-file", stackFilePath, stack.Name)
|
args = append(args, "stack", "deploy", "--with-registry-auth", "--compose-file", stackFilePath, stack.Name)
|
||||||
return runCommandAndCaptureStdErr(command, args)
|
|
||||||
|
env := make([]string, 0)
|
||||||
|
for _, envvar := range stack.Env {
|
||||||
|
env = append(env, envvar.Name+"="+envvar.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
return runCommandAndCaptureStdErr(command, args, env)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove executes the docker stack rm command.
|
// Remove executes the docker stack rm command.
|
||||||
func (manager *StackManager) Remove(stack *portainer.Stack, endpoint *portainer.Endpoint) error {
|
func (manager *StackManager) Remove(stack *portainer.Stack, endpoint *portainer.Endpoint) error {
|
||||||
command, args := prepareDockerCommandAndArgs(manager.binaryPath, endpoint)
|
command, args := prepareDockerCommandAndArgs(manager.binaryPath, endpoint)
|
||||||
args = append(args, "stack", "rm", stack.Name)
|
args = append(args, "stack", "rm", stack.Name)
|
||||||
return runCommandAndCaptureStdErr(command, args)
|
return runCommandAndCaptureStdErr(command, args, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runCommandAndCaptureStdErr(command string, args []string) error {
|
func runCommandAndCaptureStdErr(command string, args []string, env []string) error {
|
||||||
var stderr bytes.Buffer
|
var stderr bytes.Buffer
|
||||||
cmd := exec.Command(command, args...)
|
cmd := exec.Command(command, args...)
|
||||||
cmd.Stderr = &stderr
|
cmd.Stderr = &stderr
|
||||||
|
|
||||||
|
if env != nil {
|
||||||
|
cmd.Env = os.Environ()
|
||||||
|
cmd.Env = append(cmd.Env, env...)
|
||||||
|
}
|
||||||
|
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return portainer.Error(stderr.String())
|
return portainer.Error(stderr.String())
|
||||||
|
|
|
@ -62,11 +62,12 @@ func NewStackHandler(bouncer *security.RequestBouncer) *StackHandler {
|
||||||
|
|
||||||
type (
|
type (
|
||||||
postStacksRequest struct {
|
postStacksRequest struct {
|
||||||
Name string `valid:"required"`
|
Name string `valid:"required"`
|
||||||
SwarmID string `valid:"required"`
|
SwarmID string `valid:"required"`
|
||||||
StackFileContent string `valid:""`
|
StackFileContent string `valid:""`
|
||||||
GitRepository string `valid:""`
|
GitRepository string `valid:""`
|
||||||
PathInRepository string `valid:""`
|
PathInRepository string `valid:""`
|
||||||
|
Env []portainer.Pair `valid:""`
|
||||||
}
|
}
|
||||||
postStacksResponse struct {
|
postStacksResponse struct {
|
||||||
ID string `json:"Id"`
|
ID string `json:"Id"`
|
||||||
|
@ -75,7 +76,8 @@ type (
|
||||||
StackFileContent string `json:"StackFileContent"`
|
StackFileContent string `json:"StackFileContent"`
|
||||||
}
|
}
|
||||||
putStackRequest struct {
|
putStackRequest struct {
|
||||||
StackFileContent string `valid:"required"`
|
StackFileContent string `valid:"required"`
|
||||||
|
Env []portainer.Pair `valid:""`
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -165,6 +167,7 @@ func (handler *StackHandler) handlePostStacksStringMethod(w http.ResponseWriter,
|
||||||
Name: stackName,
|
Name: stackName,
|
||||||
SwarmID: swarmID,
|
SwarmID: swarmID,
|
||||||
EntryPoint: file.ComposeFileDefaultName,
|
EntryPoint: file.ComposeFileDefaultName,
|
||||||
|
Env: req.Env,
|
||||||
}
|
}
|
||||||
|
|
||||||
projectPath, err := handler.FileService.StoreStackFileFromString(string(stack.ID), stackFileContent)
|
projectPath, err := handler.FileService.StoreStackFileFromString(string(stack.ID), stackFileContent)
|
||||||
|
@ -282,6 +285,7 @@ func (handler *StackHandler) handlePostStacksRepositoryMethod(w http.ResponseWri
|
||||||
Name: stackName,
|
Name: stackName,
|
||||||
SwarmID: swarmID,
|
SwarmID: swarmID,
|
||||||
EntryPoint: req.PathInRepository,
|
EntryPoint: req.PathInRepository,
|
||||||
|
Env: req.Env,
|
||||||
}
|
}
|
||||||
|
|
||||||
projectPath := handler.FileService.GetStackProjectPath(string(stack.ID))
|
projectPath := handler.FileService.GetStackProjectPath(string(stack.ID))
|
||||||
|
@ -369,6 +373,13 @@ func (handler *StackHandler) handlePostStacksFileMethod(w http.ResponseWriter, r
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
envParam := r.FormValue("Env")
|
||||||
|
var env []portainer.Pair
|
||||||
|
if err = json.Unmarshal([]byte(envParam), &env); err != nil {
|
||||||
|
httperror.WriteErrorResponse(w, ErrInvalidRequestFormat, http.StatusBadRequest, handler.Logger)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
stackFile, _, err := r.FormFile("file")
|
stackFile, _, err := r.FormFile("file")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
httperror.WriteErrorResponse(w, err, http.StatusInternalServerError, handler.Logger)
|
httperror.WriteErrorResponse(w, err, http.StatusInternalServerError, handler.Logger)
|
||||||
|
@ -394,6 +405,7 @@ func (handler *StackHandler) handlePostStacksFileMethod(w http.ResponseWriter, r
|
||||||
Name: stackName,
|
Name: stackName,
|
||||||
SwarmID: swarmID,
|
SwarmID: swarmID,
|
||||||
EntryPoint: file.ComposeFileDefaultName,
|
EntryPoint: file.ComposeFileDefaultName,
|
||||||
|
Env: env,
|
||||||
}
|
}
|
||||||
|
|
||||||
projectPath, err := handler.FileService.StoreStackFileFromReader(string(stack.ID), stackFile)
|
projectPath, err := handler.FileService.StoreStackFileFromReader(string(stack.ID), stackFile)
|
||||||
|
@ -587,6 +599,7 @@ func (handler *StackHandler) handlePutStack(w http.ResponseWriter, r *http.Reque
|
||||||
httperror.WriteErrorResponse(w, ErrInvalidRequestFormat, http.StatusBadRequest, handler.Logger)
|
httperror.WriteErrorResponse(w, ErrInvalidRequestFormat, http.StatusBadRequest, handler.Logger)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
stack.Env = req.Env
|
||||||
|
|
||||||
_, err = handler.FileService.StoreStackFileFromString(string(stack.ID), req.StackFileContent)
|
_, err = handler.FileService.StoreStackFileFromString(string(stack.ID), req.StackFileContent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -594,6 +607,12 @@ func (handler *StackHandler) handlePutStack(w http.ResponseWriter, r *http.Reque
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = handler.StackService.UpdateStack(stack.ID, stack)
|
||||||
|
if err != nil {
|
||||||
|
httperror.WriteErrorResponse(w, err, http.StatusInternalServerError, handler.Logger)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
securityContext, err := security.RetrieveRestrictedRequestContext(r)
|
securityContext, err := security.RetrieveRestrictedRequestContext(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
httperror.WriteErrorResponse(w, err, http.StatusInternalServerError, handler.Logger)
|
httperror.WriteErrorResponse(w, err, http.StatusInternalServerError, handler.Logger)
|
||||||
|
|
|
@ -138,6 +138,7 @@ type (
|
||||||
EntryPoint string `json:"EntryPoint"`
|
EntryPoint string `json:"EntryPoint"`
|
||||||
SwarmID string `json:"SwarmId"`
|
SwarmID string `json:"SwarmId"`
|
||||||
ProjectPath string
|
ProjectPath string
|
||||||
|
Env []Pair `json:"Env"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegistryID represents a registry identifier.
|
// RegistryID represents a registry identifier.
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
angular.module('createStack', [])
|
angular.module('createStack', [])
|
||||||
.controller('CreateStackController', ['$scope', '$state', '$document', 'StackService', 'CodeMirrorService', 'Authentication', 'Notifications', 'FormValidator', 'ResourceControlService',
|
.controller('CreateStackController', ['$scope', '$state', '$document', 'StackService', 'CodeMirrorService', 'Authentication', 'Notifications', 'FormValidator', 'ResourceControlService', 'FormHelper',
|
||||||
function ($scope, $state, $document, StackService, CodeMirrorService, Authentication, Notifications, FormValidator, ResourceControlService) {
|
function ($scope, $state, $document, StackService, CodeMirrorService, Authentication, Notifications, FormValidator, ResourceControlService, FormHelper) {
|
||||||
|
|
||||||
// Store the editor content when switching builder methods
|
// Store the editor content when switching builder methods
|
||||||
var editorContent = '';
|
var editorContent = '';
|
||||||
|
@ -11,6 +11,7 @@ function ($scope, $state, $document, StackService, CodeMirrorService, Authentica
|
||||||
StackFileContent: '# Define or paste the content of your docker-compose file here',
|
StackFileContent: '# Define or paste the content of your docker-compose file here',
|
||||||
StackFile: null,
|
StackFile: null,
|
||||||
RepositoryURL: '',
|
RepositoryURL: '',
|
||||||
|
Env: [],
|
||||||
RepositoryPath: 'docker-compose.yml',
|
RepositoryPath: 'docker-compose.yml',
|
||||||
AccessControlData: new AccessControlFormData()
|
AccessControlData: new AccessControlFormData()
|
||||||
};
|
};
|
||||||
|
@ -20,6 +21,14 @@ function ($scope, $state, $document, StackService, CodeMirrorService, Authentica
|
||||||
formValidationError: ''
|
formValidationError: ''
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.addEnvironmentVariable = function() {
|
||||||
|
$scope.formValues.Env.push({ name: '', value: ''});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.removeEnvironmentVariable = function(index) {
|
||||||
|
$scope.formValues.Env.splice(index, 1);
|
||||||
|
};
|
||||||
|
|
||||||
function validateForm(accessControlData, isAdmin) {
|
function validateForm(accessControlData, isAdmin) {
|
||||||
$scope.state.formValidationError = '';
|
$scope.state.formValidationError = '';
|
||||||
var error = '';
|
var error = '';
|
||||||
|
@ -34,20 +43,21 @@ function ($scope, $state, $document, StackService, CodeMirrorService, Authentica
|
||||||
|
|
||||||
function createStack(name) {
|
function createStack(name) {
|
||||||
var method = $scope.state.Method;
|
var method = $scope.state.Method;
|
||||||
|
var env = FormHelper.removeInvalidEnvVars($scope.formValues.Env);
|
||||||
|
|
||||||
if (method === 'editor') {
|
if (method === 'editor') {
|
||||||
// The codemirror editor does not work with ng-model so we need to retrieve
|
// The codemirror editor does not work with ng-model so we need to retrieve
|
||||||
// the value directly from the editor.
|
// the value directly from the editor.
|
||||||
var stackFileContent = $scope.editor.getValue();
|
var stackFileContent = $scope.editor.getValue();
|
||||||
|
|
||||||
return StackService.createStackFromFileContent(name, stackFileContent);
|
return StackService.createStackFromFileContent(name, stackFileContent, env);
|
||||||
} else if (method === 'upload') {
|
} else if (method === 'upload') {
|
||||||
var stackFile = $scope.formValues.StackFile;
|
var stackFile = $scope.formValues.StackFile;
|
||||||
return StackService.createStackFromFileUpload(name, stackFile);
|
return StackService.createStackFromFileUpload(name, stackFile, env);
|
||||||
} else if (method === 'repository') {
|
} else if (method === 'repository') {
|
||||||
var gitRepository = $scope.formValues.RepositoryURL;
|
var gitRepository = $scope.formValues.RepositoryURL;
|
||||||
var pathInRepository = $scope.formValues.RepositoryPath;
|
var pathInRepository = $scope.formValues.RepositoryPath;
|
||||||
return StackService.createStackFromGitRepository(name, gitRepository, pathInRepository);
|
return StackService.createStackFromGitRepository(name, gitRepository, pathInRepository, env);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -131,6 +131,36 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-sm-12 form-section-title">
|
||||||
|
Environment
|
||||||
|
</div>
|
||||||
|
<!-- environment-variables -->
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-12" style="margin-top: 5px;">
|
||||||
|
<label class="control-label text-left">Environment variables</label>
|
||||||
|
<span class="label label-default interactive" style="margin-left: 10px;" ng-click="addEnvironmentVariable()">
|
||||||
|
<i class="fa fa-plus-circle" aria-hidden="true"></i> add environment variable
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<!-- environment-variable-input-list -->
|
||||||
|
<div class="col-sm-12 form-inline" style="margin-top: 10px;">
|
||||||
|
<div ng-repeat="variable in formValues.Env" style="margin-top: 2px;">
|
||||||
|
<div class="input-group col-sm-5 input-group-sm">
|
||||||
|
<span class="input-group-addon">name</span>
|
||||||
|
<input type="text" class="form-control" ng-model="variable.name" placeholder="e.g. FOO">
|
||||||
|
</div>
|
||||||
|
<div class="input-group col-sm-5 input-group-sm">
|
||||||
|
<span class="input-group-addon">value</span>
|
||||||
|
<input type="text" class="form-control" ng-model="variable.value" placeholder="e.g. bar">
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-sm btn-danger" type="button" ng-click="removeEnvironmentVariable($index)">
|
||||||
|
<i class="fa fa-trash" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- !environment-variable-input-list -->
|
||||||
|
</div>
|
||||||
|
<!-- !environment-variables -->
|
||||||
<!-- !repository -->
|
<!-- !repository -->
|
||||||
<por-access-control-form form-data="formValues.AccessControlData" ng-if="applicationState.application.authentication"></por-access-control-form>
|
<por-access-control-form form-data="formValues.AccessControlData" ng-if="applicationState.application.authentication"></por-access-control-form>
|
||||||
<!-- actions -->
|
<!-- actions -->
|
||||||
|
|
|
@ -38,6 +38,36 @@
|
||||||
<textarea id="web-editor" class="form-control" ng-model="stackFileContent" placeholder='version: "3"'></textarea>
|
<textarea id="web-editor" class="form-control" ng-model="stackFileContent" placeholder='version: "3"'></textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-sm-12 form-section-title">
|
||||||
|
Environment
|
||||||
|
</div>
|
||||||
|
<!-- environment-variables -->
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-12" style="margin-top: 5px;">
|
||||||
|
<label class="control-label text-left">Environment variables</label>
|
||||||
|
<span class="label label-default interactive" style="margin-left: 10px;" ng-click="addEnvironmentVariable()">
|
||||||
|
<i class="fa fa-plus-circle" aria-hidden="true"></i> add environment variable
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<!-- environment-variable-input-list -->
|
||||||
|
<div class="col-sm-12 form-inline" style="margin-top: 10px;">
|
||||||
|
<div ng-repeat="variable in stack.Env" style="margin-top: 2px;">
|
||||||
|
<div class="input-group col-sm-5 input-group-sm">
|
||||||
|
<span class="input-group-addon">name</span>
|
||||||
|
<input type="text" class="form-control" ng-model="variable.name" placeholder="e.g. FOO">
|
||||||
|
</div>
|
||||||
|
<div class="input-group col-sm-5 input-group-sm">
|
||||||
|
<span class="input-group-addon">value</span>
|
||||||
|
<input type="text" class="form-control" ng-model="variable.value" placeholder="e.g. bar">
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-sm btn-danger" type="button" ng-click="removeEnvironmentVariable($index)">
|
||||||
|
<i class="fa fa-trash" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- !environment-variable-input-list -->
|
||||||
|
</div>
|
||||||
|
<!-- !environment-variables -->
|
||||||
<div class="col-sm-12 form-section-title">
|
<div class="col-sm-12 form-section-title">
|
||||||
Actions
|
Actions
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
angular.module('stack', [])
|
angular.module('stack', [])
|
||||||
.controller('StackController', ['$q', '$scope', '$state', '$stateParams', '$document', 'StackService', 'NodeService', 'ServiceService', 'TaskService', 'ServiceHelper', 'CodeMirrorService', 'Notifications',
|
.controller('StackController', ['$q', '$scope', '$state', '$stateParams', '$document', 'StackService', 'NodeService', 'ServiceService', 'TaskService', 'ServiceHelper', 'CodeMirrorService', 'Notifications', 'FormHelper',
|
||||||
function ($q, $scope, $state, $stateParams, $document, StackService, NodeService, ServiceService, TaskService, ServiceHelper, CodeMirrorService, Notifications) {
|
function ($q, $scope, $state, $stateParams, $document, StackService, NodeService, ServiceService, TaskService, ServiceHelper, CodeMirrorService, Notifications, FormHelper) {
|
||||||
|
|
||||||
$scope.deployStack = function () {
|
$scope.deployStack = function () {
|
||||||
$('#createResourceSpinner').show();
|
$('#createResourceSpinner').show();
|
||||||
|
@ -8,8 +8,9 @@ function ($q, $scope, $state, $stateParams, $document, StackService, NodeService
|
||||||
// The codemirror editor does not work with ng-model so we need to retrieve
|
// The codemirror editor does not work with ng-model so we need to retrieve
|
||||||
// the value directly from the editor.
|
// the value directly from the editor.
|
||||||
var stackFile = $scope.editor.getValue();
|
var stackFile = $scope.editor.getValue();
|
||||||
|
var env = FormHelper.removeInvalidEnvVars($scope.stack.Env);
|
||||||
|
|
||||||
StackService.updateStack($scope.stack.Id, stackFile)
|
StackService.updateStack($scope.stack.Id, stackFile, env)
|
||||||
.then(function success(data) {
|
.then(function success(data) {
|
||||||
Notifications.success('Stack successfully deployed');
|
Notifications.success('Stack successfully deployed');
|
||||||
$state.reload();
|
$state.reload();
|
||||||
|
@ -22,6 +23,14 @@ function ($q, $scope, $state, $stateParams, $document, StackService, NodeService
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.addEnvironmentVariable = function() {
|
||||||
|
$scope.stack.Env.push({ name: '', value: ''});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.removeEnvironmentVariable = function(index) {
|
||||||
|
$scope.stack.Env.splice(index, 1);
|
||||||
|
};
|
||||||
|
|
||||||
function initView() {
|
function initView() {
|
||||||
$('#loadingViewSpinner').show();
|
$('#loadingViewSpinner').show();
|
||||||
var stackId = $stateParams.id;
|
var stackId = $stateParams.id;
|
||||||
|
|
18
app/helpers/formHelper.js
Normal file
18
app/helpers/formHelper.js
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
angular.module('portainer.helpers')
|
||||||
|
.factory('FormHelper', [function FormHelperFactory() {
|
||||||
|
'use strict';
|
||||||
|
var helper = {};
|
||||||
|
|
||||||
|
helper.removeInvalidEnvVars = function(env) {
|
||||||
|
for (var i = env.length - 1; i >= 0; i--) {
|
||||||
|
var envvar = env[i];
|
||||||
|
if (!envvar.value || !envvar.name) {
|
||||||
|
env.splice(i, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return env;
|
||||||
|
};
|
||||||
|
|
||||||
|
return helper;
|
||||||
|
}]);
|
|
@ -2,6 +2,7 @@ function StackViewModel(data) {
|
||||||
this.Id = data.Id;
|
this.Id = data.Id;
|
||||||
this.Name = data.Name;
|
this.Name = data.Name;
|
||||||
this.Checked = false;
|
this.Checked = false;
|
||||||
|
this.Env = data.Env;
|
||||||
if (data.ResourceControl && data.ResourceControl.Id !== 0) {
|
if (data.ResourceControl && data.ResourceControl.Id !== 0) {
|
||||||
this.ResourceControl = new ResourceControlViewModel(data.ResourceControl);
|
this.ResourceControl = new ResourceControlViewModel(data.ResourceControl);
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,13 +100,19 @@ function StackServiceFactory($q, Stack, ResourceControlService, FileUploadServic
|
||||||
return deferred.promise;
|
return deferred.promise;
|
||||||
};
|
};
|
||||||
|
|
||||||
service.createStackFromFileContent = function(name, stackFileContent) {
|
service.createStackFromFileContent = function(name, stackFileContent, env) {
|
||||||
var deferred = $q.defer();
|
var deferred = $q.defer();
|
||||||
|
|
||||||
SwarmService.swarm()
|
SwarmService.swarm()
|
||||||
.then(function success(data) {
|
.then(function success(data) {
|
||||||
var swarm = data;
|
var swarm = data;
|
||||||
return Stack.create({ method: 'string' }, { Name: name, SwarmID: swarm.Id, StackFileContent: stackFileContent }).$promise;
|
var payload = {
|
||||||
|
Name: name,
|
||||||
|
SwarmID: swarm.Id,
|
||||||
|
StackFileContent: stackFileContent,
|
||||||
|
Env: env
|
||||||
|
};
|
||||||
|
return Stack.create({ method: 'string' }, payload).$promise;
|
||||||
})
|
})
|
||||||
.then(function success(data) {
|
.then(function success(data) {
|
||||||
deferred.resolve(data);
|
deferred.resolve(data);
|
||||||
|
@ -118,13 +124,20 @@ function StackServiceFactory($q, Stack, ResourceControlService, FileUploadServic
|
||||||
return deferred.promise;
|
return deferred.promise;
|
||||||
};
|
};
|
||||||
|
|
||||||
service.createStackFromGitRepository = function(name, gitRepository, pathInRepository) {
|
service.createStackFromGitRepository = function(name, gitRepository, pathInRepository, env) {
|
||||||
var deferred = $q.defer();
|
var deferred = $q.defer();
|
||||||
|
|
||||||
SwarmService.swarm()
|
SwarmService.swarm()
|
||||||
.then(function success(data) {
|
.then(function success(data) {
|
||||||
var swarm = data;
|
var swarm = data;
|
||||||
return Stack.create({ method: 'repository' }, { Name: name, SwarmID: swarm.Id, GitRepository: gitRepository, PathInRepository: pathInRepository }).$promise;
|
var payload = {
|
||||||
|
Name: name,
|
||||||
|
SwarmID: swarm.Id,
|
||||||
|
GitRepository: gitRepository,
|
||||||
|
PathInRepository: pathInRepository,
|
||||||
|
Env: env
|
||||||
|
};
|
||||||
|
return Stack.create({ method: 'repository' }, payload).$promise;
|
||||||
})
|
})
|
||||||
.then(function success(data) {
|
.then(function success(data) {
|
||||||
deferred.resolve(data);
|
deferred.resolve(data);
|
||||||
|
@ -136,13 +149,13 @@ function StackServiceFactory($q, Stack, ResourceControlService, FileUploadServic
|
||||||
return deferred.promise;
|
return deferred.promise;
|
||||||
};
|
};
|
||||||
|
|
||||||
service.createStackFromFileUpload = function(name, stackFile) {
|
service.createStackFromFileUpload = function(name, stackFile, env) {
|
||||||
var deferred = $q.defer();
|
var deferred = $q.defer();
|
||||||
|
|
||||||
SwarmService.swarm()
|
SwarmService.swarm()
|
||||||
.then(function success(data) {
|
.then(function success(data) {
|
||||||
var swarm = data;
|
var swarm = data;
|
||||||
return FileUploadService.createStack(name, swarm.Id, stackFile);
|
return FileUploadService.createStack(name, swarm.Id, stackFile, env);
|
||||||
})
|
})
|
||||||
.then(function success(data) {
|
.then(function success(data) {
|
||||||
deferred.resolve(data.data);
|
deferred.resolve(data.data);
|
||||||
|
@ -154,8 +167,8 @@ function StackServiceFactory($q, Stack, ResourceControlService, FileUploadServic
|
||||||
return deferred.promise;
|
return deferred.promise;
|
||||||
};
|
};
|
||||||
|
|
||||||
service.updateStack = function(id, stackFile) {
|
service.updateStack = function(id, stackFile, env) {
|
||||||
return Stack.update({ id: id, StackFileContent: stackFile }).$promise;
|
return Stack.update({ id: id, StackFileContent: stackFile, Env: env }).$promise;
|
||||||
};
|
};
|
||||||
|
|
||||||
return service;
|
return service;
|
||||||
|
|
|
@ -8,9 +8,9 @@ angular.module('portainer.services')
|
||||||
return Upload.upload({ url: url, data: { file: file }});
|
return Upload.upload({ url: url, data: { file: file }});
|
||||||
}
|
}
|
||||||
|
|
||||||
service.createStack = function(stackName, swarmId, file) {
|
service.createStack = function(stackName, swarmId, file, env) {
|
||||||
var endpointID = EndpointProvider.endpointID();
|
var endpointID = EndpointProvider.endpointID();
|
||||||
return Upload.upload({ url: 'api/endpoints/' + endpointID + '/stacks?method=file', data: { file: file, Name: stackName, SwarmID: swarmId } });
|
return Upload.upload({ url: 'api/endpoints/' + endpointID + '/stacks?method=file', data: { file: file, Name: stackName, SwarmID: swarmId, Env: Upload.json(env) } });
|
||||||
};
|
};
|
||||||
|
|
||||||
service.uploadLDAPTLSFiles = function(TLSCAFile, TLSCertFile, TLSKeyFile) {
|
service.uploadLDAPTLSFiles = function(TLSCAFile, TLSCertFile, TLSKeyFile) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue