feat(docker): allow docker container resource settings without restart EE-1942 (#6065)

Co-authored-by: sam <sam@allofword>
Co-authored-by: sam@gemibook <huapox@126.com>
Co-authored-by: Prabhat Khera <prabhat.khera@gmail.com>
pull/6079/head
Prabhat Khera 2021-11-30 11:01:09 +13:00 committed by GitHub
parent c267355759
commit 1e80061186
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 173 additions and 54 deletions

View File

@ -90,11 +90,26 @@ angular.module('portainer.docker').factory('ContainerService', [
};
service.updateRestartPolicy = updateRestartPolicy;
service.updateLimits = updateLimits;
function updateRestartPolicy(id, restartPolicy, maximumRetryCounts) {
return Container.update({ id: id }, { RestartPolicy: { Name: restartPolicy, MaximumRetryCount: maximumRetryCounts } }).$promise;
}
function updateLimits(id, config) {
return Container.update(
{ id: id },
{
// MemorySwap: must be set
// -1: non limits, 0: treated as unset(cause update error).
MemoryReservation: config.HostConfig.MemoryReservation,
Memory: config.HostConfig.Memory,
MemorySwap: -1,
NanoCpus: config.HostConfig.NanoCpus,
}
).$promise;
}
service.createContainer = function (configuration) {
var deferred = $q.defer();
Container.create(configuration)

View File

@ -7,6 +7,8 @@ import { ContainerCapabilities, ContainerCapability } from '../../../models/cont
import { AccessControlFormData } from '../../../../portainer/components/accessControlForm/porAccessControlFormModel';
import { ContainerDetailsViewModel } from '../../../models/container';
import './createcontainer.css';
angular.module('portainer.docker').controller('CreateContainerController', [
'$q',
'$scope',
@ -61,6 +63,7 @@ angular.module('portainer.docker').controller('CreateContainerController', [
endpoint
) {
$scope.create = create;
$scope.update = update;
$scope.endpoint = endpoint;
$scope.formValues = {
@ -97,6 +100,7 @@ angular.module('portainer.docker').controller('CreateContainerController', [
actionInProgress: false,
mode: '',
pullImageValidity: true,
settingUnlimitedResources: false,
};
$scope.handleEnvVarChange = handleEnvVarChange;
@ -758,6 +762,40 @@ angular.module('portainer.docker').controller('CreateContainerController', [
return true;
}
$scope.handleResourceChange = handleResourceChange;
function handleResourceChange() {
$scope.state.settingUnlimitedResources = false;
if (
($scope.config.HostConfig.Memory > 0 && $scope.formValues.MemoryLimit === 0) ||
($scope.config.HostConfig.MemoryReservation > 0 && $scope.formValues.MemoryReservation === 0) ||
($scope.config.HostConfig.NanoCpus > 0 && $scope.formValues.CpuLimit === 0)
) {
$scope.state.settingUnlimitedResources = true;
}
}
async function updateLimits(config) {
try {
if ($scope.state.settingUnlimitedResources) {
create();
} else {
await ContainerService.updateLimits($transition$.params().from, config);
$scope.config = config;
Notifications.success('Limits updated');
}
} catch (err) {
Notifications.error('Failure', err, 'Update Limits fail');
}
}
async function update() {
$scope.state.actionInProgress = true;
var config = angular.copy($scope.config);
prepareResources(config);
await updateLimits(config);
$scope.state.actionInProgress = false;
}
function create() {
var oldContainer = null;
HttpRequestHelper.setPortainerAgentTargetHeader($scope.formValues.NodeName);

View File

@ -0,0 +1,20 @@
.edit-resources {
padding: 20px;
border: 1px solid var(--border-widget-color);
}
.widget .edit-resources button {
margin-left: 0;
}
.mt-20 {
margin-top: 20px;
}
.mt-7 {
margin-top: 7px;
}
.mt-10 {
margin-top: 10px;
}

View File

@ -708,60 +708,106 @@
<!-- !sysctls-input-list -->
</div>
<!-- !sysctls -->
<div class="col-sm-12 form-section-title">
Resources
<div ng-class="{ 'edit-resources': state.mode == 'duplicate' }">
<div class="col-sm-12 form-section-title">
Resources
</div>
<!-- memory-reservation-input -->
<div class="form-group">
<label for="memory-reservation" class="col-sm-3 col-lg-2 control-label text-left mt-20">
Memory reservation
</label>
<div class="col-sm-3">
<slider
on-change="(handleResourceChange)"
model="formValues.MemoryReservation"
floor="0"
ceil="state.sliderMaxMemory"
step="256"
ng-if="state.sliderMaxMemory"
></slider>
</div>
<div class="col-sm-2">
<input type="number" min="0" class="form-control" ng-model="formValues.MemoryReservation" id="memory-reservation" />
</div>
<div class="col-sm-4">
<p class="small text-muted mt-7">
Memory soft limit (<b>MB</b>)
</p>
</div>
</div>
<!-- !memory-reservation-input -->
<!-- memory-limit-input -->
<div class="form-group">
<label for="memory-limit" class="col-sm-3 col-lg-2 control-label text-left mt-20">
Memory limit
</label>
<div class="col-sm-3">
<slider
on-change="(handleResourceChange)"
model="formValues.MemoryLimit"
floor="0"
ceil="state.sliderMaxMemory"
step="256"
ng-if="state.sliderMaxMemory"
></slider>
</div>
<div class="col-sm-2">
<input type="number" min="0" class="form-control" ng-model="formValues.MemoryLimit" id="memory-limit" />
</div>
<div class="col-sm-4">
<p class="small text-muted mt-7">
Memory limit (<b>MB</b>)
</p>
</div>
</div>
<!-- !memory-limit-input -->
<!-- cpu-limit-input -->
<div class="form-group">
<label for="cpu-limit" class="col-sm-3 col-lg-2 control-label text-left mt-20">
CPU limit
</label>
<div class="col-sm-5">
<slider
on-change="(handleResourceChange)"
model="formValues.CpuLimit"
floor="0"
ceil="state.sliderMaxCpu"
step="0.25"
precision="2"
ng-if="state.sliderMaxCpu"
></slider>
</div>
<div class="col-sm-4 mt-20">
<p class="small text-muted">
Maximum CPU usage
</p>
</div>
</div>
<!-- !cpu-limit-input -->
<!-- update-limit-btn -->
<div class="form-group" ng-if="state.mode == 'duplicate'">
<div class="col-sm-12">
<button
type="button"
class="btn btn-primary btn-sm"
ng-disabled="state.actionInProgress || !formValues.RegistryModel.Image || (!formValues.RegistryModel.Registry && fromContainer)"
ng-click="update()"
button-spinner="state.actionInProgress"
>
<span ng-hide="state.actionInProgress">Update Limits</span>
<span ng-show="state.actionInProgress">Update in progress...</span>
</button>
</div>
<div class="col-sm-12" ng-if="state.settingUnlimitedResources">
<p class="text-muted mr-4">
<i class="fa fa-exclamation-circle text-warning mt-10" aria-hidden="true"></i> Updating any resource value to unlimited' will redeploy this container.
</p>
</div>
</div>
<!-- !update-limit-btn -->
</div>
<!-- memory-reservation-input -->
<div class="form-group">
<label for="memory-reservation" class="col-sm-3 col-lg-2 control-label text-left" style="margin-top: 20px;">
Memory reservation
</label>
<div class="col-sm-3">
<slider model="formValues.MemoryReservation" floor="0" ceil="state.sliderMaxMemory" step="256" ng-if="state.sliderMaxMemory"></slider>
</div>
<div class="col-sm-2">
<input type="number" min="0" class="form-control" ng-model="formValues.MemoryReservation" id="memory-reservation" />
</div>
<div class="col-sm-4">
<p class="small text-muted" style="margin-top: 7px;">
Memory soft limit (<b>MB</b>)
</p>
</div>
</div>
<!-- !memory-reservation-input -->
<!-- memory-limit-input -->
<div class="form-group">
<label for="memory-limit" class="col-sm-3 col-lg-2 control-label text-left" style="margin-top: 20px;">
Memory limit
</label>
<div class="col-sm-3">
<slider model="formValues.MemoryLimit" floor="0" ceil="state.sliderMaxMemory" step="256" ng-if="state.sliderMaxMemory"></slider>
</div>
<div class="col-sm-2">
<input type="number" min="0" class="form-control" ng-model="formValues.MemoryLimit" id="memory-limit" />
</div>
<div class="col-sm-4">
<p class="small text-muted" style="margin-top: 7px;">
Memory limit (<b>MB</b>)
</p>
</div>
</div>
<!-- !memory-limit-input -->
<!-- cpu-limit-input -->
<div class="form-group">
<label for="cpu-limit" class="col-sm-3 col-lg-2 control-label text-left" style="margin-top: 20px;">
CPU limit
</label>
<div class="col-sm-5">
<slider model="formValues.CpuLimit" floor="0" ceil="state.sliderMaxCpu" step="0.25" precision="2" ng-if="state.sliderMaxCpu"></slider>
</div>
<div class="col-sm-4" style="margin-top: 20px;">
<p class="small text-muted">
Maximum CPU usage
</p>
</div>
</div>
<!-- !cpu-limit-input -->
</form>
</div>
<!-- !tab-runtime-resources -->

View File

@ -3,7 +3,7 @@ angular.module('portainer.app').component('slider', {
controller: 'SliderController',
bindings: {
model: '=',
onChange: '&',
onChange: '<',
floor: '<',
ceil: '<',
step: '<',