mirror of
https://github.com/portainer/portainer.git
synced 2025-08-05 13:55:21 +02:00
#516 feat(services) - add the ability to manage cpu/mem limits
This commit is contained in:
parent
d695657711
commit
3cb96235b7
13 changed files with 353 additions and 92 deletions
|
@ -6,31 +6,77 @@
|
|||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>CPU limits</td>
|
||||
<td ng-if="service.LimitNanoCPUs">
|
||||
{{ service.LimitNanoCPUs / 1000000000 }}
|
||||
<td style="vertical-align : middle;">
|
||||
Memory reservation (MB)
|
||||
</td>
|
||||
<td ng-if="!service.LimitNanoCPUs">None</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Memory limits</td>
|
||||
<td ng-if="service.LimitMemoryBytes">{{service.LimitMemoryBytes|humansize}}</td>
|
||||
<td ng-if="!service.LimitMemoryBytes">None</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>CPU reservation</td>
|
||||
<td ng-if="service.ReservationNanoCPUs">
|
||||
{{service.ReservationNanoCPUs / 1000000000}}
|
||||
<td>
|
||||
<input class="input-sm" type="number" step="0.125" min="0" ng-model="service.ReservationMemoryBytes" ng-change="updateServiceAttribute(service, 'ReservationMemoryBytes')" ng-disabled="isUpdating"/>
|
||||
</td>
|
||||
<td style="vertical-align : middle;">
|
||||
<p class="small text-muted">
|
||||
Minimum memory available on a node to run a task (set to 0 for unlimited)
|
||||
</p>
|
||||
</td>
|
||||
<td ng-if="!service.ReservationNanoCPUs">None</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Memory reservation</td>
|
||||
<td ng-if="service.ReservationMemoryBytes">{{service.ReservationMemoryBytes|humansize}}</td>
|
||||
<td ng-if="!service.ReservationMemoryBytes">None</td>
|
||||
<td style="vertical-align : middle;">
|
||||
Memory limit (MB)
|
||||
</td>
|
||||
<td>
|
||||
<input class="input-sm" type="number" step="0.125" min="0" ng-model="service.LimitMemoryBytes" ng-change="updateServiceAttribute(service, 'LimitMemoryBytes')" ng-disabled="isUpdating"/>
|
||||
</td>
|
||||
<td style="vertical-align : middle;">
|
||||
<p class="small text-muted">
|
||||
Maximum memory usage per task (set to 0 for unlimited)
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="vertical-align : middle;">
|
||||
<div>
|
||||
CPU reservation
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<por-slider model="service.ReservationNanoCPUs" floor="0" ceil="state.sliderMaxCpu" step="0.25" precision="2" ng-if="service && state.sliderMaxCpu" on-change="updateServiceAttribute(service, 'ReservationNanoCPUs')"></por-slider>
|
||||
</td>
|
||||
<td style="vertical-align : middle;">
|
||||
<p class="small text-muted">
|
||||
Minimum CPU available on a node to run a task
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="vertical-align : middle;">
|
||||
<div>
|
||||
CPU limit
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<por-slider model="service.LimitNanoCPUs" floor="0" ceil="state.sliderMaxCpu" step="0.25" precision="2" ng-if="service && state.sliderMaxCpu" on-change="updateServiceAttribute(service, 'LimitNanoCPUs')"></por-slider>
|
||||
</td>
|
||||
<td style="vertical-align : middle;">
|
||||
<p class="small text-muted">
|
||||
Maximum CPU usage per task
|
||||
</p>
|
||||
</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, ['LimitNanoCPUs', 'LimitMemoryBytes', 'ReservationNanoCPUs', 'ReservationMemoryBytes'])" 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, ['LimitNanoCPUs', 'LimitMemoryBytes', 'ReservationNanoCPUs', 'ReservationMemoryBytes'])">Reset changes</a></li>
|
||||
<li><a ng-click="cancelChanges(service)">Reset all changes</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</rd-widget-footer>
|
||||
</rd-widget>
|
||||
</div>
|
||||
|
|
|
@ -204,14 +204,19 @@ function ($q, $scope, $stateParams, $state, $location, $timeout, $anchorScroll,
|
|||
config.TaskTemplate.Placement.Constraints = ServiceHelper.translateKeyValueToPlacementConstraints(service.ServiceConstraints);
|
||||
config.TaskTemplate.Placement.Preferences = ServiceHelper.translateKeyValueToPlacementPreferences(service.ServicePreferences);
|
||||
|
||||
// Round memory values to 0.125 and convert MB to B
|
||||
var memoryLimit = (Math.round(service.LimitMemoryBytes * 8) / 8).toFixed(3);
|
||||
memoryLimit *= 1024 * 1024;
|
||||
var memoryReservation = (Math.round(service.ReservationMemoryBytes * 8) / 8).toFixed(3);
|
||||
memoryReservation *= 1024 * 1024;
|
||||
config.TaskTemplate.Resources = {
|
||||
Limits: {
|
||||
NanoCPUs: service.LimitNanoCPUs,
|
||||
MemoryBytes: service.LimitMemoryBytes
|
||||
NanoCPUs: service.LimitNanoCPUs * 1000000000,
|
||||
MemoryBytes: memoryLimit
|
||||
},
|
||||
Reservations: {
|
||||
NanoCPUs: service.ReservationNanoCPUs,
|
||||
MemoryBytes: service.ReservationMemoryBytes
|
||||
NanoCPUs: service.ReservationNanoCPUs * 1000000000,
|
||||
MemoryBytes: memoryReservation
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -244,7 +249,11 @@ function ($q, $scope, $stateParams, $state, $location, $timeout, $anchorScroll,
|
|||
|
||||
Service.update({ id: service.Id, version: service.Version }, config, function (data) {
|
||||
$('#loadingViewSpinner').hide();
|
||||
Notifications.success('Service successfully updated', 'Service updated');
|
||||
if (data.message && data.message.match(/^rpc error:/)) {
|
||||
Notifications.error(data.message, 'Error');
|
||||
} else {
|
||||
Notifications.success('Service successfully updated', 'Service updated');
|
||||
}
|
||||
$scope.cancelChanges({});
|
||||
initView();
|
||||
}, function (e) {
|
||||
|
@ -288,6 +297,13 @@ function ($q, $scope, $stateParams, $state, $location, $timeout, $anchorScroll,
|
|||
service.ServicePreferences = ServiceHelper.translatePreferencesToKeyValue(service.Preferences);
|
||||
}
|
||||
|
||||
function transformResources(service) {
|
||||
service.LimitNanoCPUs = service.LimitNanoCPUs / 1000000000 || 0;
|
||||
service.ReservationNanoCPUs = service.ReservationNanoCPUs / 1000000000 || 0;
|
||||
service.LimitMemoryBytes = service.LimitMemoryBytes / 1024 / 1024 || 0;
|
||||
service.ReservationMemoryBytes = service.ReservationMemoryBytes / 1024 / 1024 || 0;
|
||||
}
|
||||
|
||||
function initView() {
|
||||
$('#loadingViewSpinner').show();
|
||||
var apiVersion = $scope.applicationState.endpoint.apiVersion;
|
||||
|
@ -299,6 +315,7 @@ function ($q, $scope, $stateParams, $state, $location, $timeout, $anchorScroll,
|
|||
$scope.lastVersion = service.Version;
|
||||
}
|
||||
|
||||
transformResources(service);
|
||||
translateServiceArrays(service);
|
||||
$scope.service = service;
|
||||
originalService = angular.copy(service);
|
||||
|
@ -314,6 +331,19 @@ function ($q, $scope, $stateParams, $state, $location, $timeout, $anchorScroll,
|
|||
$scope.nodes = data.nodes;
|
||||
$scope.secrets = data.secrets;
|
||||
|
||||
// Set max cpu value
|
||||
var maxCpus = 0;
|
||||
for (var n in data.nodes) {
|
||||
if (data.nodes[n].CPUs && data.nodes[n].CPUs > maxCpus) {
|
||||
maxCpus = data.nodes[n].CPUs;
|
||||
}
|
||||
}
|
||||
if (maxCpus > 0) {
|
||||
$scope.state.sliderMaxCpu = maxCpus / 1000000000;
|
||||
} else {
|
||||
$scope.state.sliderMaxCpu = 32;
|
||||
}
|
||||
|
||||
$timeout(function() {
|
||||
$anchorScroll();
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue