mirror of https://github.com/portainer/portainer
feat(container): add sysctls setting in the container view (#4910)
* feat(container): add sysctls in the container view (#2756) * feat(container): add setting to restrict sysctl access * feat(endpoint): move sysctl disable setting to security settings * feat(container): add sysctls to container edit view * fix(container) remove unnecessary migration setting Co-authored-by: Owen Kirby <oskirby@gmail.com>pull/4982/head
parent
ac7d819620
commit
d09ae22ba8
|
@ -25,6 +25,8 @@ type endpointSettingsUpdatePayload struct {
|
||||||
AllowStackManagementForRegularUsers *bool `json:"allowStackManagementForRegularUsers" example:"true"`
|
AllowStackManagementForRegularUsers *bool `json:"allowStackManagementForRegularUsers" example:"true"`
|
||||||
// Whether non-administrator should be able to use container capabilities
|
// Whether non-administrator should be able to use container capabilities
|
||||||
AllowContainerCapabilitiesForRegularUsers *bool `json:"allowContainerCapabilitiesForRegularUsers" example:"true"`
|
AllowContainerCapabilitiesForRegularUsers *bool `json:"allowContainerCapabilitiesForRegularUsers" example:"true"`
|
||||||
|
// Whether non-administrator should be able to use sysctl settings
|
||||||
|
AllowSysctlSettingForRegularUsers *bool `json:"allowSysctlSettingForRegularUsers" example:"true"`
|
||||||
// Whether host management features are enabled
|
// Whether host management features are enabled
|
||||||
EnableHostManagementFeatures *bool `json:"enableHostManagementFeatures" example:"true"`
|
EnableHostManagementFeatures *bool `json:"enableHostManagementFeatures" example:"true"`
|
||||||
}
|
}
|
||||||
|
@ -97,6 +99,10 @@ func (handler *Handler) endpointSettingsUpdate(w http.ResponseWriter, r *http.Re
|
||||||
securitySettings.AllowVolumeBrowserForRegularUsers = *payload.AllowVolumeBrowserForRegularUsers
|
securitySettings.AllowVolumeBrowserForRegularUsers = *payload.AllowVolumeBrowserForRegularUsers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if payload.AllowSysctlSettingForRegularUsers != nil {
|
||||||
|
securitySettings.AllowSysctlSettingForRegularUsers = *payload.AllowSysctlSettingForRegularUsers
|
||||||
|
}
|
||||||
|
|
||||||
if payload.EnableHostManagementFeatures != nil {
|
if payload.EnableHostManagementFeatures != nil {
|
||||||
securitySettings.EnableHostManagementFeatures = *payload.EnableHostManagementFeatures
|
securitySettings.EnableHostManagementFeatures = *payload.EnableHostManagementFeatures
|
||||||
}
|
}
|
||||||
|
|
|
@ -356,6 +356,7 @@ func (handler *Handler) deployComposeStack(config *composeStackDeploymentConfig)
|
||||||
!securitySettings.AllowPrivilegedModeForRegularUsers ||
|
!securitySettings.AllowPrivilegedModeForRegularUsers ||
|
||||||
!securitySettings.AllowHostNamespaceForRegularUsers ||
|
!securitySettings.AllowHostNamespaceForRegularUsers ||
|
||||||
!securitySettings.AllowDeviceMappingForRegularUsers ||
|
!securitySettings.AllowDeviceMappingForRegularUsers ||
|
||||||
|
!securitySettings.AllowSysctlSettingForRegularUsers ||
|
||||||
!securitySettings.AllowContainerCapabilitiesForRegularUsers) &&
|
!securitySettings.AllowContainerCapabilitiesForRegularUsers) &&
|
||||||
!isAdminOrEndpointAdmin {
|
!isAdminOrEndpointAdmin {
|
||||||
|
|
||||||
|
|
|
@ -192,6 +192,10 @@ func (handler *Handler) isValidStackFile(stackFileContent []byte, securitySettin
|
||||||
return errors.New("device mapping disabled for non administrator users")
|
return errors.New("device mapping disabled for non administrator users")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !securitySettings.AllowSysctlSettingForRegularUsers && service.Sysctls != nil && len(service.Sysctls) > 0 {
|
||||||
|
return errors.New("sysctl setting disabled for non administrator users")
|
||||||
|
}
|
||||||
|
|
||||||
if !securitySettings.AllowContainerCapabilitiesForRegularUsers && (len(service.CapAdd) > 0 || len(service.CapDrop) > 0) {
|
if !securitySettings.AllowContainerCapabilitiesForRegularUsers && (len(service.CapAdd) > 0 || len(service.CapDrop) > 0) {
|
||||||
return errors.New("container capabilities disabled for non administrator users")
|
return errors.New("container capabilities disabled for non administrator users")
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,12 +152,13 @@ func containerHasBlackListedLabel(containerLabels map[string]interface{}, labelB
|
||||||
func (transport *Transport) decorateContainerCreationOperation(request *http.Request, resourceIdentifierAttribute string, resourceType portainer.ResourceControlType) (*http.Response, error) {
|
func (transport *Transport) decorateContainerCreationOperation(request *http.Request, resourceIdentifierAttribute string, resourceType portainer.ResourceControlType) (*http.Response, error) {
|
||||||
type PartialContainer struct {
|
type PartialContainer struct {
|
||||||
HostConfig struct {
|
HostConfig struct {
|
||||||
Privileged bool `json:"Privileged"`
|
Privileged bool `json:"Privileged"`
|
||||||
PidMode string `json:"PidMode"`
|
PidMode string `json:"PidMode"`
|
||||||
Devices []interface{} `json:"Devices"`
|
Devices []interface{} `json:"Devices"`
|
||||||
CapAdd []string `json:"CapAdd"`
|
Sysctls map[string]interface{} `json:"Sysctls"`
|
||||||
CapDrop []string `json:"CapDrop"`
|
CapAdd []string `json:"CapAdd"`
|
||||||
Binds []string `json:"Binds"`
|
CapDrop []string `json:"CapDrop"`
|
||||||
|
Binds []string `json:"Binds"`
|
||||||
} `json:"HostConfig"`
|
} `json:"HostConfig"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,6 +205,10 @@ func (transport *Transport) decorateContainerCreationOperation(request *http.Req
|
||||||
return forbiddenResponse, errors.New("forbidden to use device mapping")
|
return forbiddenResponse, errors.New("forbidden to use device mapping")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !securitySettings.AllowSysctlSettingForRegularUsers && len(partialContainer.HostConfig.Sysctls) > 0 {
|
||||||
|
return forbiddenResponse, errors.New("forbidden to use sysctl settings")
|
||||||
|
}
|
||||||
|
|
||||||
if !securitySettings.AllowContainerCapabilitiesForRegularUsers && (len(partialContainer.HostConfig.CapAdd) > 0 || len(partialContainer.HostConfig.CapDrop) > 0) {
|
if !securitySettings.AllowContainerCapabilitiesForRegularUsers && (len(partialContainer.HostConfig.CapAdd) > 0 || len(partialContainer.HostConfig.CapDrop) > 0) {
|
||||||
return nil, errors.New("forbidden to use container capabilities")
|
return nil, errors.New("forbidden to use container capabilities")
|
||||||
}
|
}
|
||||||
|
|
|
@ -335,6 +335,8 @@ type (
|
||||||
AllowStackManagementForRegularUsers bool `json:"allowStackManagementForRegularUsers" example:"true"`
|
AllowStackManagementForRegularUsers bool `json:"allowStackManagementForRegularUsers" example:"true"`
|
||||||
// Whether non-administrator should be able to use container capabilities
|
// Whether non-administrator should be able to use container capabilities
|
||||||
AllowContainerCapabilitiesForRegularUsers bool `json:"allowContainerCapabilitiesForRegularUsers" example:"true"`
|
AllowContainerCapabilitiesForRegularUsers bool `json:"allowContainerCapabilitiesForRegularUsers" example:"true"`
|
||||||
|
// Whether non-administrator should be able to use sysctl settings
|
||||||
|
AllowSysctlSettingForRegularUsers bool `json:"AllowSysctlSettingForRegularUsers" example:"true"`
|
||||||
// Whether host management features are enabled
|
// Whether host management features are enabled
|
||||||
EnableHostManagementFeatures bool `json:"enableHostManagementFeatures" example:"true"`
|
EnableHostManagementFeatures bool `json:"enableHostManagementFeatures" example:"true"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,6 +80,7 @@ angular.module('portainer.docker').controller('CreateContainerController', [
|
||||||
EntrypointMode: 'default',
|
EntrypointMode: 'default',
|
||||||
NodeName: null,
|
NodeName: null,
|
||||||
capabilities: [],
|
capabilities: [],
|
||||||
|
Sysctls: [],
|
||||||
LogDriverName: '',
|
LogDriverName: '',
|
||||||
LogDriverOpts: [],
|
LogDriverOpts: [],
|
||||||
RegistryModel: new PorImageRegistryModel(),
|
RegistryModel: new PorImageRegistryModel(),
|
||||||
|
@ -136,6 +137,7 @@ angular.module('portainer.docker').controller('CreateContainerController', [
|
||||||
Devices: [],
|
Devices: [],
|
||||||
CapAdd: [],
|
CapAdd: [],
|
||||||
CapDrop: [],
|
CapDrop: [],
|
||||||
|
Sysctls: {},
|
||||||
},
|
},
|
||||||
NetworkingConfig: {
|
NetworkingConfig: {
|
||||||
EndpointsConfig: {},
|
EndpointsConfig: {},
|
||||||
|
@ -191,6 +193,14 @@ angular.module('portainer.docker').controller('CreateContainerController', [
|
||||||
$scope.config.HostConfig.Devices.splice(index, 1);
|
$scope.config.HostConfig.Devices.splice(index, 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.addSysctl = function () {
|
||||||
|
$scope.formValues.Sysctls.push({ name: '', value: '' });
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.removeSysctl = function (index) {
|
||||||
|
$scope.formValues.Sysctls.splice(index, 1);
|
||||||
|
};
|
||||||
|
|
||||||
$scope.addLogDriverOpt = function () {
|
$scope.addLogDriverOpt = function () {
|
||||||
$scope.formValues.LogDriverOpts.push({ name: '', value: '' });
|
$scope.formValues.LogDriverOpts.push({ name: '', value: '' });
|
||||||
};
|
};
|
||||||
|
@ -344,6 +354,16 @@ angular.module('portainer.docker').controller('CreateContainerController', [
|
||||||
config.HostConfig.Devices = path;
|
config.HostConfig.Devices = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function prepareSysctls(config) {
|
||||||
|
var sysctls = {};
|
||||||
|
$scope.formValues.Sysctls.forEach(function (sysctl) {
|
||||||
|
if (sysctl.name && sysctl.value) {
|
||||||
|
sysctls[sysctl.name] = sysctl.value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
config.HostConfig.Sysctls = sysctls;
|
||||||
|
}
|
||||||
|
|
||||||
function prepareResources(config) {
|
function prepareResources(config) {
|
||||||
// Memory Limit - Round to 0.125
|
// Memory Limit - Round to 0.125
|
||||||
if ($scope.formValues.MemoryLimit >= 0) {
|
if ($scope.formValues.MemoryLimit >= 0) {
|
||||||
|
@ -412,6 +432,7 @@ angular.module('portainer.docker').controller('CreateContainerController', [
|
||||||
prepareResources(config);
|
prepareResources(config);
|
||||||
prepareLogDriver(config);
|
prepareLogDriver(config);
|
||||||
prepareCapabilities(config);
|
prepareCapabilities(config);
|
||||||
|
prepareSysctls(config);
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -557,6 +578,14 @@ angular.module('portainer.docker').controller('CreateContainerController', [
|
||||||
$scope.config.HostConfig.Devices = path;
|
$scope.config.HostConfig.Devices = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function loadFromContainerSysctls() {
|
||||||
|
for (var s in $scope.config.HostConfig.Sysctls) {
|
||||||
|
if ({}.hasOwnProperty.call($scope.config.HostConfig.Sysctls, s)) {
|
||||||
|
$scope.formValues.Sysctls.push({ name: s, value: $scope.config.HostConfig.Sysctls[s] });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function loadFromContainerImageConfig() {
|
function loadFromContainerImageConfig() {
|
||||||
RegistryService.retrievePorRegistryModelFromRepository($scope.config.Image)
|
RegistryService.retrievePorRegistryModelFromRepository($scope.config.Image)
|
||||||
.then((model) => {
|
.then((model) => {
|
||||||
|
@ -632,6 +661,7 @@ angular.module('portainer.docker').controller('CreateContainerController', [
|
||||||
loadFromContainerImageConfig(d);
|
loadFromContainerImageConfig(d);
|
||||||
loadFromContainerResources(d);
|
loadFromContainerResources(d);
|
||||||
loadFromContainerCapabilities(d);
|
loadFromContainerCapabilities(d);
|
||||||
|
loadFromContainerSysctls(d);
|
||||||
})
|
})
|
||||||
.catch(function error(err) {
|
.catch(function error(err) {
|
||||||
Notifications.error('Failure', err, 'Unable to retrieve container');
|
Notifications.error('Failure', err, 'Unable to retrieve container');
|
||||||
|
@ -656,6 +686,7 @@ angular.module('portainer.docker').controller('CreateContainerController', [
|
||||||
|
|
||||||
$scope.isAdmin = Authentication.isAdmin();
|
$scope.isAdmin = Authentication.isAdmin();
|
||||||
$scope.showDeviceMapping = await shouldShowDevices();
|
$scope.showDeviceMapping = await shouldShowDevices();
|
||||||
|
$scope.showSysctls = await shouldShowSysctls();
|
||||||
$scope.areContainerCapabilitiesEnabled = await checkIfContainerCapabilitiesEnabled();
|
$scope.areContainerCapabilitiesEnabled = await checkIfContainerCapabilitiesEnabled();
|
||||||
$scope.isAdminOrEndpointAdmin = Authentication.isAdmin();
|
$scope.isAdminOrEndpointAdmin = Authentication.isAdmin();
|
||||||
|
|
||||||
|
@ -940,6 +971,12 @@ angular.module('portainer.docker').controller('CreateContainerController', [
|
||||||
return endpoint.SecuritySettings.allowDeviceMappingForRegularUsers || Authentication.isAdmin();
|
return endpoint.SecuritySettings.allowDeviceMappingForRegularUsers || Authentication.isAdmin();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function shouldShowSysctls() {
|
||||||
|
const { allowSysctlSettingForRegularUsers } = $scope.applicationState.application;
|
||||||
|
|
||||||
|
return allowSysctlSettingForRegularUsers || Authentication.isAdmin();
|
||||||
|
}
|
||||||
|
|
||||||
async function checkIfContainerCapabilitiesEnabled() {
|
async function checkIfContainerCapabilitiesEnabled() {
|
||||||
return endpoint.SecuritySettings.allowContainerCapabilitiesForRegularUsers || Authentication.isAdmin();
|
return endpoint.SecuritySettings.allowContainerCapabilitiesForRegularUsers || Authentication.isAdmin();
|
||||||
}
|
}
|
||||||
|
|
|
@ -706,6 +706,33 @@
|
||||||
<!-- !devices-input-list -->
|
<!-- !devices-input-list -->
|
||||||
</div>
|
</div>
|
||||||
<!-- !devices-->
|
<!-- !devices-->
|
||||||
|
<!-- sysctls -->
|
||||||
|
<div ng-if="showSysctls" class="form-group">
|
||||||
|
<div class="col-sm-12" style="margin-top: 5px;">
|
||||||
|
<label class="control-label text-left">Sysctls</label>
|
||||||
|
<span class="label label-default interactive" style="margin-left: 10px;" ng-click="addSysctl()">
|
||||||
|
<i class="fa fa-plus-circle" aria-hidden="true"></i> add sysctl
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<!-- sysctls-input-list -->
|
||||||
|
<div class="col-sm-12 form-inline" style="margin-top: 10px;">
|
||||||
|
<div ng-repeat="sysctl in formValues.Sysctls" 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="sysctl.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="sysctl.value" placeholder="e.g. bar" />
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-sm btn-danger" type="button" ng-click="removeSysctl($index)">
|
||||||
|
<i class="fa fa-trash" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- !sysctls-input-list -->
|
||||||
|
</div>
|
||||||
|
<!-- !sysctls -->
|
||||||
<div class="col-sm-12 form-section-title">
|
<div class="col-sm-12 form-section-title">
|
||||||
Resources
|
Resources
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -274,6 +274,17 @@
|
||||||
</container-restart-policy>
|
</container-restart-policy>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr ng-if="!(container.HostConfig.Sysctls | emptyobject)">
|
||||||
|
<td>Sysctls</td>
|
||||||
|
<td>
|
||||||
|
<table class="table table-bordered table-condensed">
|
||||||
|
<tr ng-repeat="(k, v) in container.HostConfig.Sysctls">
|
||||||
|
<td>{{ k }}</td>
|
||||||
|
<td>{{ v }}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</rd-widget-body>
|
</rd-widget-body>
|
||||||
|
|
|
@ -104,6 +104,7 @@ angular.module('portainer.docker').controller('ContainerController', [
|
||||||
allowContainerCapabilitiesForRegularUsers,
|
allowContainerCapabilitiesForRegularUsers,
|
||||||
allowHostNamespaceForRegularUsers,
|
allowHostNamespaceForRegularUsers,
|
||||||
allowDeviceMappingForRegularUsers,
|
allowDeviceMappingForRegularUsers,
|
||||||
|
allowSysctlSettingForRegularUsers,
|
||||||
allowBindMountsForRegularUsers,
|
allowBindMountsForRegularUsers,
|
||||||
allowPrivilegedModeForRegularUsers,
|
allowPrivilegedModeForRegularUsers,
|
||||||
} = endpoint.SecuritySettings;
|
} = endpoint.SecuritySettings;
|
||||||
|
@ -112,6 +113,7 @@ angular.module('portainer.docker').controller('ContainerController', [
|
||||||
!allowContainerCapabilitiesForRegularUsers ||
|
!allowContainerCapabilitiesForRegularUsers ||
|
||||||
!allowBindMountsForRegularUsers ||
|
!allowBindMountsForRegularUsers ||
|
||||||
!allowDeviceMappingForRegularUsers ||
|
!allowDeviceMappingForRegularUsers ||
|
||||||
|
!allowSysctlSettingForRegularUsers ||
|
||||||
!allowHostNamespaceForRegularUsers ||
|
!allowHostNamespaceForRegularUsers ||
|
||||||
!allowPrivilegedModeForRegularUsers;
|
!allowPrivilegedModeForRegularUsers;
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ export default class DockerFeaturesConfigurationController {
|
||||||
disableStackManagementForRegularUsers: false,
|
disableStackManagementForRegularUsers: false,
|
||||||
disableDeviceMappingForRegularUsers: false,
|
disableDeviceMappingForRegularUsers: false,
|
||||||
disableContainerCapabilitiesForRegularUsers: false,
|
disableContainerCapabilitiesForRegularUsers: false,
|
||||||
|
disableSysctlSettingForRegularUsers: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.isAgent = false;
|
this.isAgent = false;
|
||||||
|
@ -33,13 +34,15 @@ export default class DockerFeaturesConfigurationController {
|
||||||
disablePrivilegedModeForRegularUsers,
|
disablePrivilegedModeForRegularUsers,
|
||||||
disableDeviceMappingForRegularUsers,
|
disableDeviceMappingForRegularUsers,
|
||||||
disableContainerCapabilitiesForRegularUsers,
|
disableContainerCapabilitiesForRegularUsers,
|
||||||
|
disableSysctlSettingForRegularUsers,
|
||||||
} = this.formValues;
|
} = this.formValues;
|
||||||
return (
|
return (
|
||||||
disableBindMountsForRegularUsers ||
|
disableBindMountsForRegularUsers ||
|
||||||
disableHostNamespaceForRegularUsers ||
|
disableHostNamespaceForRegularUsers ||
|
||||||
disablePrivilegedModeForRegularUsers ||
|
disablePrivilegedModeForRegularUsers ||
|
||||||
disableDeviceMappingForRegularUsers ||
|
disableDeviceMappingForRegularUsers ||
|
||||||
disableContainerCapabilitiesForRegularUsers
|
disableContainerCapabilitiesForRegularUsers ||
|
||||||
|
disableSysctlSettingForRegularUsers
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,6 +59,7 @@ export default class DockerFeaturesConfigurationController {
|
||||||
allowDeviceMappingForRegularUsers: !this.formValues.disableDeviceMappingForRegularUsers,
|
allowDeviceMappingForRegularUsers: !this.formValues.disableDeviceMappingForRegularUsers,
|
||||||
allowStackManagementForRegularUsers: !this.formValues.disableStackManagementForRegularUsers,
|
allowStackManagementForRegularUsers: !this.formValues.disableStackManagementForRegularUsers,
|
||||||
allowContainerCapabilitiesForRegularUsers: !this.formValues.disableContainerCapabilitiesForRegularUsers,
|
allowContainerCapabilitiesForRegularUsers: !this.formValues.disableContainerCapabilitiesForRegularUsers,
|
||||||
|
allowSysctlSettingForRegularUsers: !this.formValues.disableSysctlSettingForRegularUsers,
|
||||||
};
|
};
|
||||||
|
|
||||||
await this.EndpointService.updateSecuritySettings(this.endpoint.Id, securitySettings);
|
await this.EndpointService.updateSecuritySettings(this.endpoint.Id, securitySettings);
|
||||||
|
@ -89,6 +93,7 @@ export default class DockerFeaturesConfigurationController {
|
||||||
disableDeviceMappingForRegularUsers: !securitySettings.allowDeviceMappingForRegularUsers,
|
disableDeviceMappingForRegularUsers: !securitySettings.allowDeviceMappingForRegularUsers,
|
||||||
disableStackManagementForRegularUsers: !securitySettings.allowStackManagementForRegularUsers,
|
disableStackManagementForRegularUsers: !securitySettings.allowStackManagementForRegularUsers,
|
||||||
disableContainerCapabilitiesForRegularUsers: !securitySettings.allowContainerCapabilitiesForRegularUsers,
|
disableContainerCapabilitiesForRegularUsers: !securitySettings.allowContainerCapabilitiesForRegularUsers,
|
||||||
|
disableSysctlSettingForRegularUsers: !securitySettings.allowSysctlSettingForRegularUsers,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,6 +108,16 @@
|
||||||
></por-switch-field>
|
></por-switch-field>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<por-switch-field
|
||||||
|
ng-model="$ctrl.formValues.disableSysctlSettingForRegularUsers"
|
||||||
|
name="disableSysctlSettingForRegularUsers"
|
||||||
|
label="Disable sysctl settings for non-administrators"
|
||||||
|
label-class="col-sm-7 col-lg-4"
|
||||||
|
></por-switch-field>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group" ng-if="$ctrl.isContainerEditDisabled()">
|
<div class="form-group" ng-if="$ctrl.isContainerEditDisabled()">
|
||||||
<span class="col-sm-12 text-muted small">
|
<span class="col-sm-12 text-muted small">
|
||||||
|
|
|
@ -53,7 +53,11 @@
|
||||||
<div
|
<div
|
||||||
class="col-sm-11 small text-warning"
|
class="col-sm-11 small text-warning"
|
||||||
style="margin-top: 5px;"
|
style="margin-top: 5px;"
|
||||||
ng-show="kubernetesConfigurationDataCreationForm['configuration_data_key_' + index].$invalid || (!entry.Used && $ctrl.state.duplicateKeys[index] !== undefined) || $ctrl.state.invalidKeys[index]"
|
ng-show="
|
||||||
|
kubernetesConfigurationDataCreationForm['configuration_data_key_' + index].$invalid ||
|
||||||
|
(!entry.Used && $ctrl.state.duplicateKeys[index] !== undefined) ||
|
||||||
|
$ctrl.state.invalidKeys[index]
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<ng-messages for="kubernetesConfigurationDataCreationForm['configuration_data_key_' + index].$error">
|
<ng-messages for="kubernetesConfigurationDataCreationForm['configuration_data_key_' + index].$error">
|
||||||
<p ng-message="required"><i class="fa fa-exclamation-triangle" aria-hidden="true"></i> This field is required.</p>
|
<p ng-message="required"><i class="fa fa-exclamation-triangle" aria-hidden="true"></i> This field is required.</p>
|
||||||
|
|
|
@ -9,8 +9,8 @@ import {
|
||||||
KubernetesPortainerApplicationNote,
|
KubernetesPortainerApplicationNote,
|
||||||
} from 'Kubernetes/models/application/models';
|
} from 'Kubernetes/models/application/models';
|
||||||
|
|
||||||
import { createPayloadFactory } from './payloads/create';
|
|
||||||
import { KubernetesPod, KubernetesPodToleration, KubernetesPodAffinity, KubernetesPodContainer, KubernetesPodContainerTypes, KubernetesPodEviction } from 'Kubernetes/pod/models';
|
import { KubernetesPod, KubernetesPodToleration, KubernetesPodAffinity, KubernetesPodContainer, KubernetesPodContainerTypes, KubernetesPodEviction } from 'Kubernetes/pod/models';
|
||||||
|
import { createPayloadFactory } from './payloads/create';
|
||||||
|
|
||||||
function computeStatus(statuses) {
|
function computeStatus(statuses) {
|
||||||
const containerStatuses = _.map(statuses, 'state');
|
const containerStatuses = _.map(statuses, 'state');
|
||||||
|
|
|
@ -213,6 +213,7 @@ describe('startContainerController', function () {
|
||||||
CgroupPermissions: 'mrw',
|
CgroupPermissions: 'mrw',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
Sysctls: { 'net.ipv6.conf.all.disable_ipv6': '0' },
|
||||||
LxcConf: { 'lxc.utsname': 'docker' },
|
LxcConf: { 'lxc.utsname': 'docker' },
|
||||||
ExtraHosts: ['hostname:127.0.0.1'],
|
ExtraHosts: ['hostname:127.0.0.1'],
|
||||||
RestartPolicy: { name: 'always', MaximumRetryCount: 5 },
|
RestartPolicy: { name: 'always', MaximumRetryCount: 5 },
|
||||||
|
@ -255,6 +256,7 @@ describe('startContainerController', function () {
|
||||||
CgroupPermissions: 'mrw',
|
CgroupPermissions: 'mrw',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
scope.config.HostConfig.Sysctls = [{ name: 'net.ipv6.conf.all.disable_ipv6', value: '0' }];
|
||||||
scope.config.HostConfig.LxcConf = [{ name: 'lxc.utsname', value: 'docker' }];
|
scope.config.HostConfig.LxcConf = [{ name: 'lxc.utsname', value: 'docker' }];
|
||||||
scope.config.HostConfig.ExtraHosts = [{ host: 'hostname', ip: '127.0.0.1' }];
|
scope.config.HostConfig.ExtraHosts = [{ host: 'hostname', ip: '127.0.0.1' }];
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue