mirror of
https://github.com/portainer/portainer.git
synced 2025-07-24 15:59:41 +02:00
feat(services): add support for placement preferences (#1003)
This commit is contained in:
parent
8dc6d05ed6
commit
25ed6a71fb
12 changed files with 254 additions and 144 deletions
|
@ -1,6 +1,6 @@
|
|||
angular.module('createNetwork', [])
|
||||
.controller('CreateNetworkController', ['$scope', '$state', 'Notifications', 'Network',
|
||||
function ($scope, $state, Notifications, Network) {
|
||||
.controller('CreateNetworkController', ['$scope', '$state', 'Notifications', 'Network', 'LabelHelper',
|
||||
function ($scope, $state, Notifications, Network, LabelHelper) {
|
||||
$scope.formValues = {
|
||||
DriverOptions: [],
|
||||
Subnet: '',
|
||||
|
@ -30,7 +30,7 @@ function ($scope, $state, Notifications, Network) {
|
|||
};
|
||||
|
||||
$scope.addLabel = function() {
|
||||
$scope.formValues.Labels.push({ name: '', value: ''});
|
||||
$scope.formValues.Labels.push({ key: '', value: ''});
|
||||
};
|
||||
|
||||
$scope.removeLabel = function(index) {
|
||||
|
@ -74,13 +74,7 @@ function ($scope, $state, Notifications, Network) {
|
|||
}
|
||||
|
||||
function prepareLabelsConfig(config) {
|
||||
var labels = {};
|
||||
$scope.formValues.Labels.forEach(function (label) {
|
||||
if (label.name && label.value) {
|
||||
labels[label.name] = label.value;
|
||||
}
|
||||
});
|
||||
config.Labels = labels;
|
||||
config.Labels = LabelHelper.fromKeyValueToLabelHash($scope.formValues.Labels);
|
||||
}
|
||||
|
||||
function prepareConfiguration() {
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
<div ng-repeat="label in formValues.Labels" 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="label.name" placeholder="e.g. com.example.foo">
|
||||
<input type="text" class="form-control" ng-model="label.key" placeholder="e.g. com.example.foo">
|
||||
</div>
|
||||
<div class="input-group col-sm-5 input-group-sm">
|
||||
<span class="input-group-addon">value</span>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
angular.module('createSecret', [])
|
||||
.controller('CreateSecretController', ['$scope', '$state', 'Notifications', 'SecretService',
|
||||
function ($scope, $state, Notifications, SecretService) {
|
||||
.controller('CreateSecretController', ['$scope', '$state', 'Notifications', 'SecretService', 'LabelHelper',
|
||||
function ($scope, $state, Notifications, SecretService, LabelHelper) {
|
||||
$scope.formValues = {
|
||||
Name: '',
|
||||
Data: '',
|
||||
|
@ -9,7 +9,7 @@ function ($scope, $state, Notifications, SecretService) {
|
|||
};
|
||||
|
||||
$scope.addLabel = function() {
|
||||
$scope.formValues.Labels.push({ name: '', value: ''});
|
||||
$scope.formValues.Labels.push({ key: '', value: ''});
|
||||
};
|
||||
|
||||
$scope.removeLabel = function(index) {
|
||||
|
@ -17,13 +17,7 @@ function ($scope, $state, Notifications, SecretService) {
|
|||
};
|
||||
|
||||
function prepareLabelsConfig(config) {
|
||||
var labels = {};
|
||||
$scope.formValues.Labels.forEach(function (label) {
|
||||
if (label.name && label.value) {
|
||||
labels[label.name] = label.value;
|
||||
}
|
||||
});
|
||||
config.Labels = labels;
|
||||
config.Labels = LabelHelper.fromKeyValueToLabelHash($scope.formValues.Labels);
|
||||
}
|
||||
|
||||
function prepareSecretData(config) {
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
<div ng-repeat="label in formValues.Labels" 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="label.name" placeholder="e.g. com.example.foo">
|
||||
<input type="text" class="form-control" ng-model="label.key" placeholder="e.g. com.example.foo">
|
||||
</div>
|
||||
<div class="input-group col-sm-5 input-group-sm">
|
||||
<span class="input-group-addon">value</span>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
// @@OLD_SERVICE_CONTROLLER: this service should be rewritten to use services.
|
||||
// See app/components/templates/templatesController.js as a reference.
|
||||
angular.module('createService', [])
|
||||
.controller('CreateServiceController', ['$q', '$scope', '$state', 'Service', 'ServiceHelper', 'SecretHelper', 'SecretService', 'VolumeService', 'NetworkService', 'ImageHelper', 'Authentication', 'ResourceControlService', 'Notifications', 'ControllerDataPipeline', 'FormValidator', 'RegistryService', 'HttpRequestHelper',
|
||||
function ($q, $scope, $state, Service, ServiceHelper, SecretHelper, SecretService, VolumeService, NetworkService, ImageHelper, Authentication, ResourceControlService, Notifications, ControllerDataPipeline, FormValidator, RegistryService, HttpRequestHelper) {
|
||||
.controller('CreateServiceController', ['$q', '$scope', '$state', 'Service', 'ServiceHelper', 'SecretHelper', 'SecretService', 'VolumeService', 'NetworkService', 'ImageHelper', 'LabelHelper', 'Authentication', 'ResourceControlService', 'Notifications', 'ControllerDataPipeline', 'FormValidator', 'RegistryService', 'HttpRequestHelper',
|
||||
function ($q, $scope, $state, Service, ServiceHelper, SecretHelper, SecretService, VolumeService, NetworkService, ImageHelper, LabelHelper, Authentication, ResourceControlService, Notifications, ControllerDataPipeline, FormValidator, RegistryService, HttpRequestHelper) {
|
||||
|
||||
$scope.formValues = {
|
||||
Name: '',
|
||||
|
@ -23,6 +23,7 @@ function ($q, $scope, $state, Service, ServiceHelper, SecretHelper, SecretServic
|
|||
Ports: [],
|
||||
Parallelism: 1,
|
||||
PlacementConstraints: [],
|
||||
PlacementPreferences: [],
|
||||
UpdateDelay: 0,
|
||||
FailureAction: 'pause',
|
||||
Secrets: []
|
||||
|
@ -81,7 +82,7 @@ function ($q, $scope, $state, Service, ServiceHelper, SecretHelper, SecretServic
|
|||
};
|
||||
|
||||
$scope.addPlacementPreference = function() {
|
||||
$scope.formValues.PlacementPreferences.push({ key: '', operator: '==', value: '' });
|
||||
$scope.formValues.PlacementPreferences.push({ strategy: 'spread', value: '' });
|
||||
};
|
||||
|
||||
$scope.removePlacementPreference = function(index) {
|
||||
|
@ -89,7 +90,7 @@ function ($q, $scope, $state, Service, ServiceHelper, SecretHelper, SecretServic
|
|||
};
|
||||
|
||||
$scope.addLabel = function() {
|
||||
$scope.formValues.Labels.push({ name: '', value: ''});
|
||||
$scope.formValues.Labels.push({ key: '', value: ''});
|
||||
};
|
||||
|
||||
$scope.removeLabel = function(index) {
|
||||
|
@ -97,7 +98,7 @@ function ($q, $scope, $state, Service, ServiceHelper, SecretHelper, SecretServic
|
|||
};
|
||||
|
||||
$scope.addContainerLabel = function() {
|
||||
$scope.formValues.ContainerLabels.push({ name: '', value: ''});
|
||||
$scope.formValues.ContainerLabels.push({ key: '', value: ''});
|
||||
};
|
||||
|
||||
$scope.removeContainerLabel = function(index) {
|
||||
|
@ -170,21 +171,8 @@ function ($q, $scope, $state, Service, ServiceHelper, SecretHelper, SecretServic
|
|||
}
|
||||
|
||||
function prepareLabelsConfig(config, input) {
|
||||
var labels = {};
|
||||
input.Labels.forEach(function (label) {
|
||||
if (label.name && label.value) {
|
||||
labels[label.name] = label.value;
|
||||
}
|
||||
});
|
||||
config.Labels = labels;
|
||||
|
||||
var containerLabels = {};
|
||||
input.ContainerLabels.forEach(function (label) {
|
||||
if (label.name && label.value) {
|
||||
containerLabels[label.name] = label.value;
|
||||
}
|
||||
});
|
||||
config.TaskTemplate.ContainerSpec.Labels = containerLabels;
|
||||
config.Labels = LabelHelper.fromKeyValueToLabelHash(input.Labels);
|
||||
config.TaskTemplate.ContainerSpec.Labels = LabelHelper.fromKeyValueToLabelHash(input.ContainerLabels);
|
||||
}
|
||||
|
||||
function prepareVolumes(config, input) {
|
||||
|
@ -213,8 +201,10 @@ function ($q, $scope, $state, Service, ServiceHelper, SecretHelper, SecretServic
|
|||
FailureAction: input.FailureAction
|
||||
};
|
||||
}
|
||||
|
||||
function preparePlacementConfig(config, input) {
|
||||
config.TaskTemplate.Placement.Constraints = ServiceHelper.translateKeyValueToPlacementConstraints(input.PlacementConstraints);
|
||||
config.TaskTemplate.Placement.Preferences = ServiceHelper.translateKeyValueToPlacementPreferences(input.PlacementPreferences);
|
||||
}
|
||||
|
||||
function prepareSecretConfig(config, input) {
|
||||
|
|
|
@ -328,7 +328,7 @@
|
|||
<div ng-repeat="label in formValues.Labels" 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="label.name" placeholder="e.g. com.example.foo">
|
||||
<input type="text" class="form-control" ng-model="label.key" placeholder="e.g. com.example.foo">
|
||||
</div>
|
||||
<div class="input-group col-sm-5 input-group-sm">
|
||||
<span class="input-group-addon">value</span>
|
||||
|
@ -355,7 +355,7 @@
|
|||
<div ng-repeat="label in formValues.ContainerLabels" 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="label.name" placeholder="e.g. com.example.foo">
|
||||
<input type="text" class="form-control" ng-model="label.key" placeholder="e.g. com.example.foo">
|
||||
</div>
|
||||
<div class="input-group col-sm-5 input-group-sm">
|
||||
<span class="input-group-addon">value</span>
|
||||
|
|
|
@ -29,3 +29,29 @@
|
|||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<form class="form-horizontal" style="margin-top: 15px;" ng-if="applicationState.endpoint.apiVersion >= 1.30">
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12" style="margin-top: 5px;">
|
||||
<label class="control-label text-left">Placement preferences</label>
|
||||
<span class="label label-default interactive" style="margin-left: 10px;" ng-click="addPlacementPreference()">
|
||||
<i class="fa fa-plus-circle" aria-hidden="true"></i> placement preference
|
||||
</span>
|
||||
</div>
|
||||
<div class="col-sm-12 form-inline" style="margin-top: 10px;">
|
||||
<div ng-repeat="preference in formValues.PlacementPreferences" style="margin-top: 2px;">
|
||||
<div class="input-group col-sm-4 input-group-sm">
|
||||
<span class="input-group-addon">strategy</span>
|
||||
<input type="text" class="form-control" ng-model="preference.strategy" placeholder="e.g. spread">
|
||||
</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="preference.value" placeholder="e.g. node.labels.datacenter">
|
||||
</div>
|
||||
<button class="btn btn-sm btn-danger" type="button" ng-click="removePlacementPreference($index)">
|
||||
<i class="fa fa-trash" aria-hidden="true"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
|
57
app/components/service/includes/placementPreferences.html
Normal file
57
app/components/service/includes/placementPreferences.html
Normal file
|
@ -0,0 +1,57 @@
|
|||
<div ng-if="service.ServicePreferences && applicationState.endpoint.apiVersion >= 1.30" id="service-placement-preferences">
|
||||
<rd-widget>
|
||||
<rd-widget-header icon="fa-tasks" title="Placement preferences">
|
||||
<div class="nopadding">
|
||||
<a class="btn btn-default btn-sm pull-right" ng-click="isUpdating || addPlacementPreference(service)" ng-disabled="isUpdating">
|
||||
<i class="fa fa-plus-circle" aria-hidden="true"></i> placement preference
|
||||
</a>
|
||||
</div>
|
||||
</rd-widget-header>
|
||||
<rd-widget-body ng-if="service.ServicePreferences.length === 0">
|
||||
<p>There are no placement preferences for this service.</p>
|
||||
</rd-widget-body>
|
||||
<rd-widget-body ng-if="service.ServicePreferences.length > 0" classes="no-padding">
|
||||
<table class="table" >
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Strategy</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="preference in service.ServicePreferences">
|
||||
<td>
|
||||
<div class="input-group input-group-sm">
|
||||
<input type="text" class="form-control" ng-model="preference.strategy" placeholder="e.g. node.role" ng-change="updatePlacementPreference(service, preference)" ng-disabled="isUpdating">
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="input-group input-group-sm">
|
||||
<input type="text" class="form-control" ng-model="preference.value" placeholder="e.g. manager" ng-change="updatePlacementPreference(service, preference)" ng-disabled="isUpdating">
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-sm btn-danger" type="button" ng-click="removePlacementPreference(service, $index)" ng-disabled="isUpdating">
|
||||
<i class="fa fa-trash" aria-hidden="true"></i>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</rd-widget-body>
|
||||
<rd-widget-footer>
|
||||
<div class="btn-toolbar" role="toolbar">
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!hasChanges(service, ['ServicePreferences'])" ng-click="updateService(service)">Apply changes</button>
|
||||
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a ng-click="cancelChanges(service, ['ServicePreferences'])">Reset changes</a></li>
|
||||
<li><a ng-click="cancelChanges(service)">Reset all changes</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</rd-widget-footer>
|
||||
</rd-widget>
|
||||
</div>
|
|
@ -113,6 +113,7 @@
|
|||
<li><a href ng-click="goToItem('service-network-specs')">Network & published ports</a></li>
|
||||
<li><a href ng-click="goToItem('service-resources')">Resource limits & reservations</a></li>
|
||||
<li><a href ng-click="goToItem('service-placement-constraints')">Placement constraints</a></li>
|
||||
<li><a href ng-click="goToItem('service-placement-preferences')" ng-if="applicationState.endpoint.apiVersion >= 1.30">Placement preferences</a></li>
|
||||
<li><a href ng-click="goToItem('service-restart-policy')">Restart policy</a></li>
|
||||
<li><a href ng-click="goToItem('service-update-config')">Update configuration</a></li>
|
||||
<li><a href ng-click="goToItem('service-labels')">Service labels</a></li>
|
||||
|
@ -152,6 +153,7 @@
|
|||
<h3 id="service-specs">Service specification</h3>
|
||||
<div id="service-resources" class="padding-top" ng-include="'app/components/service/includes/resources.html'"></div>
|
||||
<div id="service-placement-constraints" class="padding-top" ng-include="'app/components/service/includes/constraints.html'"></div>
|
||||
<div id="service-placement-preferences" class="padding-top" ng-include="'app/components/service/includes/placementPreferences.html'"></div>
|
||||
<div id="service-restart-policy" class="padding-top" ng-include="'app/components/service/includes/restart.html'"></div>
|
||||
<div id="service-update-config" class="padding-top" ng-include="'app/components/service/includes/updateconfig.html'"></div>
|
||||
<div id="service-labels" class="padding-top" ng-include="'app/components/service/includes/servicelabels.html'"></div>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
angular.module('service', [])
|
||||
.controller('ServiceController', ['$q', '$scope', '$stateParams', '$state', '$location', '$timeout', '$anchorScroll', 'ServiceService', 'Secret', 'SecretHelper', 'Service', 'ServiceHelper', 'TaskService', 'NodeService', 'Notifications', 'Pagination', 'ModalService', 'ControllerDataPipeline',
|
||||
function ($q, $scope, $stateParams, $state, $location, $timeout, $anchorScroll, ServiceService, Secret, SecretHelper, Service, ServiceHelper, TaskService, NodeService, Notifications, Pagination, ModalService, ControllerDataPipeline) {
|
||||
.controller('ServiceController', ['$q', '$scope', '$stateParams', '$state', '$location', '$timeout', '$anchorScroll', 'ServiceService', 'Secret', 'SecretHelper', 'Service', 'ServiceHelper', 'LabelHelper', 'TaskService', 'NodeService', 'Notifications', 'Pagination', 'ModalService', 'ControllerDataPipeline',
|
||||
function ($q, $scope, $stateParams, $state, $location, $timeout, $anchorScroll, ServiceService, Secret, SecretHelper, Service, ServiceHelper, LabelHelper, TaskService, NodeService, Notifications, Pagination, ModalService, ControllerDataPipeline) {
|
||||
|
||||
$scope.state = {};
|
||||
$scope.state.pagination_count = Pagination.getPaginationCount('service_tasks');
|
||||
|
@ -124,10 +124,24 @@ function ($q, $scope, $stateParams, $state, $location, $timeout, $anchorScroll,
|
|||
updateServiceArray(service, 'ServiceConstraints', service.ServiceConstraints);
|
||||
}
|
||||
};
|
||||
$scope.updatePlacementConstraint = function updatePlacementConstraint(service, constraint) {
|
||||
$scope.updatePlacementConstraint = function(service, constraint) {
|
||||
updateServiceArray(service, 'ServiceConstraints', service.ServiceConstraints);
|
||||
};
|
||||
|
||||
$scope.addPlacementPreference = function(service) {
|
||||
service.ServicePreferences.push({ strategy: 'spread', value: '' });
|
||||
updateServiceArray(service, 'ServicePreferences', service.ServicePreferences);
|
||||
};
|
||||
$scope.removePlacementPreference = function(service, index) {
|
||||
var removedElement = service.ServicePreferences.splice(index, 1);
|
||||
if (removedElement !== null) {
|
||||
updateServiceArray(service, 'ServicePreferences', service.ServicePreferences);
|
||||
}
|
||||
};
|
||||
$scope.updatePlacementPreference = function(service, constraint) {
|
||||
updateServiceArray(service, 'ServicePreferences', service.ServicePreferences);
|
||||
};
|
||||
|
||||
$scope.addPublishedPort = function addPublishedPort(service) {
|
||||
if (!service.Ports) {
|
||||
service.Ports = [];
|
||||
|
@ -174,9 +188,9 @@ function ($q, $scope, $stateParams, $state, $location, $timeout, $anchorScroll,
|
|||
$('#loadingViewSpinner').show();
|
||||
var config = ServiceHelper.serviceToConfig(service.Model);
|
||||
config.Name = service.Name;
|
||||
config.Labels = translateServiceLabelsToLabels(service.ServiceLabels);
|
||||
config.TaskTemplate.ContainerSpec.Env = translateEnvironmentVariablesToEnv(service.EnvironmentVariables);
|
||||
config.TaskTemplate.ContainerSpec.Labels = translateServiceLabelsToLabels(service.ServiceContainerLabels);
|
||||
config.Labels = LabelHelper.fromKeyValueToLabelHash(service.ServiceLabels);
|
||||
config.TaskTemplate.ContainerSpec.Env = ServiceHelper.translateEnvironmentVariablesToEnv(service.EnvironmentVariables);
|
||||
config.TaskTemplate.ContainerSpec.Labels = LabelHelper.fromKeyValueToLabelHash(service.ServiceContainerLabels);
|
||||
config.TaskTemplate.ContainerSpec.Image = service.Image;
|
||||
config.TaskTemplate.ContainerSpec.Secrets = service.ServiceSecrets ? service.ServiceSecrets.map(SecretHelper.secretConfig) : [];
|
||||
|
||||
|
@ -188,6 +202,7 @@ function ($q, $scope, $stateParams, $state, $location, $timeout, $anchorScroll,
|
|||
config.TaskTemplate.Placement = {};
|
||||
}
|
||||
config.TaskTemplate.Placement.Constraints = ServiceHelper.translateKeyValueToPlacementConstraints(service.ServiceConstraints);
|
||||
config.TaskTemplate.Placement.Preferences = ServiceHelper.translateKeyValueToPlacementPreferences(service.ServicePreferences);
|
||||
|
||||
config.TaskTemplate.Resources = {
|
||||
Limits: {
|
||||
|
@ -263,11 +278,12 @@ function ($q, $scope, $stateParams, $state, $location, $timeout, $anchorScroll,
|
|||
|
||||
function translateServiceArrays(service) {
|
||||
service.ServiceSecrets = service.Secrets ? service.Secrets.map(SecretHelper.flattenSecret) : [];
|
||||
service.EnvironmentVariables = translateEnvironmentVariables(service.Env);
|
||||
service.ServiceLabels = translateLabelsToServiceLabels(service.Labels);
|
||||
service.ServiceContainerLabels = translateLabelsToServiceLabels(service.ContainerLabels);
|
||||
service.EnvironmentVariables = ServiceHelper.translateEnvironmentVariables(service.Env);
|
||||
service.ServiceLabels = LabelHelper.fromLabelHashToKeyValue(service.Labels);
|
||||
service.ServiceContainerLabels = LabelHelper.fromLabelHashToKeyValue(service.ContainerLabels);
|
||||
service.ServiceMounts = angular.copy(service.Mounts);
|
||||
service.ServiceConstraints = translateConstraintsToKeyValue(service.Constraints);
|
||||
service.ServiceConstraints = ServiceHelper.translateConstraintsToKeyValue(service.Constraints);
|
||||
service.ServicePreferences = ServiceHelper.translatePreferencesToKeyValue(service.Preferences);
|
||||
}
|
||||
|
||||
function initView() {
|
||||
|
@ -310,7 +326,6 @@ function ($q, $scope, $stateParams, $state, $location, $timeout, $anchorScroll,
|
|||
Notifications.error('Failure', err, 'Unable to retrieve service details');
|
||||
})
|
||||
.finally(function final() {
|
||||
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
}
|
||||
|
@ -341,80 +356,5 @@ function ($q, $scope, $stateParams, $state, $location, $timeout, $anchorScroll,
|
|||
service.hasChanges = true;
|
||||
}
|
||||
|
||||
function translateEnvironmentVariables(env) {
|
||||
if (env) {
|
||||
var variables = [];
|
||||
env.forEach(function(variable) {
|
||||
var idx = variable.indexOf('=');
|
||||
var keyValue = [variable.slice(0,idx), variable.slice(idx+1)];
|
||||
var originalValue = (keyValue.length > 1) ? keyValue[1] : '';
|
||||
variables.push({ key: keyValue[0], value: originalValue, originalKey: keyValue[0], originalValue: originalValue, added: true});
|
||||
});
|
||||
return variables;
|
||||
}
|
||||
return [];
|
||||
}
|
||||
function translateEnvironmentVariablesToEnv(env) {
|
||||
if (env) {
|
||||
var variables = [];
|
||||
env.forEach(function(variable) {
|
||||
if (variable.key && variable.key !== '') {
|
||||
variables.push(variable.key + '=' + variable.value);
|
||||
}
|
||||
});
|
||||
return variables;
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
function translateLabelsToServiceLabels(Labels) {
|
||||
var labels = [];
|
||||
if (Labels) {
|
||||
Object.keys(Labels).forEach(function(key) {
|
||||
labels.push({ key: key, value: Labels[key], originalKey: key, originalValue: Labels[key], added: true});
|
||||
});
|
||||
}
|
||||
return labels;
|
||||
}
|
||||
function translateServiceLabelsToLabels(labels) {
|
||||
var Labels = {};
|
||||
if (labels) {
|
||||
labels.forEach(function(label) {
|
||||
Labels[label.key] = label.value;
|
||||
});
|
||||
}
|
||||
return Labels;
|
||||
}
|
||||
|
||||
function translateConstraintsToKeyValue(constraints) {
|
||||
function getOperator(constraint) {
|
||||
var indexEquals = constraint.indexOf('==');
|
||||
if (indexEquals >= 0) {
|
||||
return [indexEquals, '=='];
|
||||
}
|
||||
return [constraint.indexOf('!='), '!='];
|
||||
}
|
||||
if (constraints) {
|
||||
var keyValueConstraints = [];
|
||||
constraints.forEach(function(constraint) {
|
||||
var operatorIndices = getOperator(constraint);
|
||||
|
||||
var key = constraint.slice(0, operatorIndices[0]);
|
||||
var operator = operatorIndices[1];
|
||||
var value = constraint.slice(operatorIndices[0] + 2);
|
||||
|
||||
keyValueConstraints.push({
|
||||
key: key,
|
||||
value: value,
|
||||
operator: operator,
|
||||
originalKey: key,
|
||||
originalValue: value
|
||||
});
|
||||
});
|
||||
return keyValueConstraints;
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
initView();
|
||||
}]);
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
angular.module('portainer.helpers')
|
||||
.factory('ServiceHelper', [function ServiceHelperFactory() {
|
||||
angular.module('portainer.helpers').factory('ServiceHelper', [function ServiceHelperFactory() {
|
||||
'use strict';
|
||||
return {
|
||||
serviceToConfig: function(service) {
|
||||
|
@ -13,17 +12,113 @@ angular.module('portainer.helpers')
|
|||
EndpointSpec: service.Spec.EndpointSpec
|
||||
};
|
||||
},
|
||||
translateKeyValueToPlacementPreferences: function(keyValuePreferences) {
|
||||
if (keyValuePreferences) {
|
||||
var preferences = [];
|
||||
keyValuePreferences.forEach(function(preference) {
|
||||
if (preference.strategy && preference.strategy !== '' && preference.value && preference.value !== '') {
|
||||
switch (preference.strategy.toLowerCase()) {
|
||||
case 'spread':
|
||||
preferences.push({
|
||||
'Spread': {
|
||||
'SpreadDescriptor': preference.value
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
return preferences;
|
||||
}
|
||||
return [];
|
||||
},
|
||||
translateKeyValueToPlacementConstraints: function(keyValueConstraints) {
|
||||
if (keyValueConstraints) {
|
||||
var constraints = [];
|
||||
keyValueConstraints.forEach(function(keyValueConstraint) {
|
||||
if (keyValueConstraint.key && keyValueConstraint.key !== '' && keyValueConstraint.value && keyValueConstraint.value !== '') {
|
||||
constraints.push(keyValueConstraint.key + keyValueConstraint.operator + keyValueConstraint.value);
|
||||
keyValueConstraints.forEach(function(constraint) {
|
||||
if (constraint.key && constraint.key !== '' && constraint.value && constraint.value !== '') {
|
||||
constraints.push(constraint.key + constraint.operator + constraint.value);
|
||||
}
|
||||
});
|
||||
return constraints;
|
||||
}
|
||||
return [];
|
||||
},
|
||||
translateEnvironmentVariables: function(env) {
|
||||
if (env) {
|
||||
var variables = [];
|
||||
env.forEach(function(variable) {
|
||||
var idx = variable.indexOf('=');
|
||||
var keyValue = [variable.slice(0, idx), variable.slice(idx + 1)];
|
||||
var originalValue = (keyValue.length > 1) ? keyValue[1] : '';
|
||||
variables.push({
|
||||
key: keyValue[0],
|
||||
value: originalValue,
|
||||
originalKey: keyValue[0],
|
||||
originalValue: originalValue,
|
||||
added: true
|
||||
});
|
||||
});
|
||||
return variables;
|
||||
}
|
||||
return [];
|
||||
},
|
||||
translateEnvironmentVariablesToEnv: function(env) {
|
||||
if (env) {
|
||||
var variables = [];
|
||||
env.forEach(function(variable) {
|
||||
if (variable.key && variable.key !== '') {
|
||||
variables.push(variable.key + '=' + variable.value);
|
||||
}
|
||||
});
|
||||
return variables;
|
||||
}
|
||||
return [];
|
||||
},
|
||||
translatePreferencesToKeyValue: function(preferences) {
|
||||
if (preferences) {
|
||||
var keyValuePreferences = [];
|
||||
preferences.forEach(function(preference) {
|
||||
if (preference.Spread) {
|
||||
keyValuePreferences.push({
|
||||
strategy: 'Spread',
|
||||
value: preference.Spread.SpreadDescriptor
|
||||
});
|
||||
}
|
||||
});
|
||||
return keyValuePreferences;
|
||||
}
|
||||
return [];
|
||||
},
|
||||
translateConstraintsToKeyValue: function(constraints) {
|
||||
function getOperator(constraint) {
|
||||
var indexEquals = constraint.indexOf('==');
|
||||
if (indexEquals >= 0) {
|
||||
return [indexEquals, '=='];
|
||||
}
|
||||
return [constraint.indexOf('!='), '!='];
|
||||
}
|
||||
if (constraints) {
|
||||
var keyValueConstraints = [];
|
||||
constraints.forEach(function(constraint) {
|
||||
var operatorIndices = getOperator(constraint);
|
||||
|
||||
var key = constraint.slice(0, operatorIndices[0]);
|
||||
var operator = operatorIndices[1];
|
||||
var value = constraint.slice(operatorIndices[0] + 2);
|
||||
|
||||
keyValueConstraints.push({
|
||||
key: key,
|
||||
value: value,
|
||||
operator: operator,
|
||||
originalKey: key,
|
||||
originalValue: value
|
||||
});
|
||||
});
|
||||
return keyValueConstraints;
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
};
|
||||
}]);
|
||||
|
|
|
@ -41,27 +41,37 @@ function ServiceViewModel(data, runningTasks, nodes) {
|
|||
this.RestartWindow = 0;
|
||||
}
|
||||
this.Constraints = data.Spec.TaskTemplate.Placement ? data.Spec.TaskTemplate.Placement.Constraints || [] : [];
|
||||
this.Preferences = data.Spec.TaskTemplate.Placement ? data.Spec.TaskTemplate.Placement.Preferences || [] : [];
|
||||
this.Platforms = data.Spec.TaskTemplate.Placement ? data.Spec.TaskTemplate.Placement.Platforms || [] : [];
|
||||
this.Labels = data.Spec.Labels;
|
||||
|
||||
var containerSpec = data.Spec.TaskTemplate.ContainerSpec;
|
||||
if (containerSpec) {
|
||||
this.ContainerLabels = containerSpec.Labels;
|
||||
this.Env = containerSpec.Env;
|
||||
this.Mounts = containerSpec.Mounts || [];
|
||||
this.User = containerSpec.User;
|
||||
this.Dir = containerSpec.Dir;
|
||||
this.Command = containerSpec.Command;
|
||||
this.Arguments = containerSpec.Args;
|
||||
this.Hostname = containerSpec.Hostname;
|
||||
this.Env = containerSpec.Env;
|
||||
this.Dir = containerSpec.Dir;
|
||||
this.User = containerSpec.User;
|
||||
this.Groups = containerSpec.Groups;
|
||||
this.TTY = containerSpec.TTY;
|
||||
this.OpenStdin = containerSpec.OpenStdin;
|
||||
this.ReadOnly = containerSpec.ReadOnly;
|
||||
this.Mounts = containerSpec.Mounts || [];
|
||||
this.StopSignal = containerSpec.StopSignal;
|
||||
this.StopGracePeriod = containerSpec.StopGracePeriod;
|
||||
this.HealthCheck = containerSpec.HealthCheck || {};
|
||||
this.Hosts = containerSpec.Hosts;
|
||||
this.DNSConfig = containerSpec.DNSConfig;
|
||||
this.Secrets = containerSpec.Secrets;
|
||||
}
|
||||
if (data.Endpoint) {
|
||||
this.Ports = data.Endpoint.Ports;
|
||||
}
|
||||
|
||||
this.Mounts = [];
|
||||
if (data.Spec.TaskTemplate.ContainerSpec.Mounts) {
|
||||
this.Mounts = data.Spec.TaskTemplate.ContainerSpec.Mounts;
|
||||
}
|
||||
this.LogDriver = data.Spec.TaskTemplate.LogDriver;
|
||||
this.Runtime = data.Spec.TaskTemplate.Runtime;
|
||||
|
||||
this.VirtualIPs = data.Endpoint ? data.Endpoint.VirtualIPs : [];
|
||||
|
||||
|
@ -75,6 +85,8 @@ function ServiceViewModel(data, runningTasks, nodes) {
|
|||
this.UpdateFailureAction = 'pause';
|
||||
}
|
||||
|
||||
this.RollbackConfig = data.Spec.RollbackConfig;
|
||||
|
||||
this.Checked = false;
|
||||
this.Scale = false;
|
||||
this.EditName = false;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue