fix(stack): validate original containers names [EE-4520] (#7978)

pull/7996/head
Chaim Lev-Ari 2 years ago committed by GitHub
parent ff10588383
commit 2868da296a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -23,28 +23,45 @@ angular.module('portainer.app').factory('StackHelper', [
);
}
helper.validateYAML = function (yaml, containerNames) {
let yamlObject;
helper.validateYAML = validateYAML;
try {
yamlObject = YAML.parse(yaml);
} catch (err) {
return 'There is an error in the yaml syntax: ' + err;
}
return helper;
},
]);
const names = _.uniq(GenericHelper.findDeepAll(yamlObject, 'container_name'));
const duplicateContainers = _.intersection(containerNames, names);
function validateYAML(yaml, containerNames, originalContainersNames = []) {
let yamlObject;
if (duplicateContainers.length === 0) return;
try {
yamlObject = YAML.parse(yaml);
} catch (err) {
return 'There is an error in the yaml syntax: ' + err;
}
return (
(duplicateContainers.length === 1 ? 'This container name is' : 'These container names are') +
' already used by another container running in this environment: ' +
_.join(duplicateContainers, ', ') +
'.'
);
};
const names = _.uniq(GenericHelper.findDeepAll(yamlObject, 'container_name'));
return helper;
},
]);
const duplicateContainers = _.intersection(_.difference(containerNames, originalContainersNames), names);
if (duplicateContainers.length === 0) {
return '';
}
return (
(duplicateContainers.length === 1 ? 'This container name is' : 'These container names are') +
' already used by another container running in this environment: ' +
_.join(duplicateContainers, ', ') +
'.'
);
}
export function extractContainerNames(yaml = '') {
let yamlObject;
try {
yamlObject = YAML.parse(yaml);
} catch (err) {
return [];
}
return _.uniq(GenericHelper.findDeepAll(yamlObject, 'container_name'));
}

@ -141,6 +141,9 @@
<span class="col-sm-12 text-muted small">
You can get more information about Compose file format in the <a href="https://docs.docker.com/compose/compose-file/" target="_blank">official documentation</a>.
</span>
<div class="col-sm-12" ng-if="state.yamlError">
<span class="text-danger small">{{ state.yamlError }}</span>
</div>
</div>
<div class="form-group">
<div class="col-sm-12">

@ -3,6 +3,7 @@ import { AccessControlFormData } from 'Portainer/components/accessControlForm/po
import { FeatureId } from 'Portainer/feature-flags/enums';
import { getEnvironments } from '@/react/portainer/environments/environment.service';
import { StackStatus, StackType } from '@/react/docker/stacks/types';
import { extractContainerNames } from '@/portainer/helpers/stackHelper';
angular.module('portainer.app').controller('StackController', [
'$async',
@ -275,7 +276,7 @@ angular.module('portainer.app').controller('StackController', [
if ($scope.stackFileContent.replace(/(\r\n|\n|\r)/gm, '') !== cm.getValue().replace(/(\r\n|\n|\r)/gm, '')) {
$scope.state.isEditorDirty = true;
$scope.stackFileContent = cm.getValue();
$scope.state.yamlError = StackHelper.validateYAML($scope.stackFileContent, $scope.containerNames);
$scope.state.yamlError = StackHelper.validateYAML($scope.stackFileContent, $scope.containerNames, $scope.state.originalContainerNames);
}
};
@ -365,8 +366,9 @@ angular.module('portainer.app').controller('StackController', [
if (isSwarm && $scope.stack.Status === StackStatus.Active) {
assignSwarmStackResources(data.resources, agentProxy);
}
$scope.state.originalContainerNames = extractContainerNames($scope.stackFileContent);
$scope.state.yamlError = StackHelper.validateYAML($scope.stackFileContent, $scope.containerNames);
$scope.state.yamlError = StackHelper.validateYAML($scope.stackFileContent, $scope.containerNames, $scope.state.originalContainerNames);
})
.catch(function error(err) {
Notifications.error('Failure', err, 'Unable to retrieve stack details');

Loading…
Cancel
Save