mirror of
https://github.com/portainer/portainer.git
synced 2025-08-05 05:45:22 +02:00
feat(edge/stacks): sync EE codechanges [EE-498] (#8580)
This commit is contained in:
parent
0ec7dfce69
commit
93bf630105
53 changed files with 1572 additions and 424 deletions
|
@ -169,15 +169,7 @@
|
|||
</div>
|
||||
<!-- !upload -->
|
||||
|
||||
<div class="col-sm-12 form-section-title"> Edge Groups </div>
|
||||
<div class="form-group" ng-if="$ctrl.edgeGroups">
|
||||
<div class="col-sm-12">
|
||||
<edge-groups-selector ng-if="!$ctrl.noGroups" value="$ctrl.model.EdgeGroups" on-change="($ctrl.onChangeGroups)" items="$ctrl.edgeGroups"></edge-groups-selector>
|
||||
</div>
|
||||
<div ng-if="$ctrl.noGroups" class="col-sm-12 small text-muted">
|
||||
No Edge groups are available. Head over to the <a ui-sref="edge.groups">Edge groups view</a> to create one.
|
||||
</div>
|
||||
</div>
|
||||
<edge-groups-selector ng-if="$ctrl.model.EdgeGroups" value="$ctrl.model.EdgeGroups" on-change="($ctrl.onChangeGroups)"></edge-groups-selector>
|
||||
|
||||
<div class="col-sm-12 form-section-title"> Target environments </div>
|
||||
<!-- node-selection -->
|
||||
|
|
|
@ -6,11 +6,9 @@ import { cronMethodOptions } from '@/react/edge/edge-jobs/CreateView/cron-method
|
|||
|
||||
export class EdgeJobFormController {
|
||||
/* @ngInject */
|
||||
constructor($async, $scope, EdgeGroupService, Notifications) {
|
||||
constructor($async, $scope) {
|
||||
this.$scope = $scope;
|
||||
this.$async = $async;
|
||||
this.EdgeGroupService = EdgeGroupService;
|
||||
this.Notifications = Notifications;
|
||||
|
||||
this.cronMethods = cronMethodOptions;
|
||||
this.buildMethods = [editor, upload];
|
||||
|
@ -127,18 +125,8 @@ export class EdgeJobFormController {
|
|||
this.model.Endpoints = _.filter(this.model.Endpoints, (id) => id !== endpoint.Id);
|
||||
}
|
||||
|
||||
async getEdgeGroups() {
|
||||
try {
|
||||
this.edgeGroups = await this.EdgeGroupService.groups();
|
||||
this.noGroups = this.edgeGroups.length === 0;
|
||||
} catch (err) {
|
||||
this.Notifications.error('Failure', err, 'Unable to retrieve Edge groups');
|
||||
}
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
this.onChangeModel(this.model);
|
||||
this.getEdgeGroups();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,95 +0,0 @@
|
|||
<form class="form-horizontal">
|
||||
<edge-groups-selector value="$ctrl.model.EdgeGroups" items="$ctrl.edgeGroups" on-change="($ctrl.onChangeGroups)"></edge-groups-selector>
|
||||
|
||||
<edge-stack-deployment-type-selector
|
||||
allow-kube-to-select-compose="$ctrl.allowKubeToSelectCompose"
|
||||
value="$ctrl.model.DeploymentType"
|
||||
has-docker-endpoint="$ctrl.hasDockerEndpoint()"
|
||||
has-kube-endpoint="$ctrl.hasKubeEndpoint()"
|
||||
on-change="($ctrl.onChangeDeploymentType)"
|
||||
read-only="$ctrl.state.readOnlyCompose"
|
||||
></edge-stack-deployment-type-selector>
|
||||
|
||||
<div class="text-muted small flex gap-1" ng-show="!$ctrl.model.DeploymentType && $ctrl.hasKubeEndpoint()">
|
||||
<pr-icon icon="'alert-circle'" mode="'warning'" class-name="'!mt-1'"></pr-icon>
|
||||
<div>
|
||||
<p>
|
||||
Portainer no longer supports <a href="https://docs.docker.com/compose/compose-file/" target="_blank">docker-compose</a> format manifests for Kubernetes deployments, and we
|
||||
have removed the <a href="https://kompose.io/" target="_blank">Kompose</a> conversion tool which enables this. The reason for this is because Kompose now poses a security
|
||||
risk, since it has a number of Common Vulnerabilities and Exposures (CVEs).
|
||||
</p>
|
||||
<p
|
||||
>Unfortunately, while the Kompose project has a maintainer and is part of the CNCF, it is not being actively maintained. Releases are very infrequent and new pull requests
|
||||
to the project (including ones we've submitted) are taking months to be merged, with new CVEs arising in the meantime.</p
|
||||
>
|
||||
<p>
|
||||
We advise installing your own instance of Kompose in a sandbox environment, performing conversions of your Docker Compose files to Kubernetes manifests and using those
|
||||
manifests to set up applications.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<web-editor-form
|
||||
ng-if="$ctrl.model.DeploymentType === $ctrl.EditorType.Compose"
|
||||
value="$ctrl.model.StackFileContent"
|
||||
yml="true"
|
||||
identifier="compose-editor"
|
||||
placeholder="Define or paste the content of your docker compose file here"
|
||||
on-change="($ctrl.onChangeComposeConfig)"
|
||||
read-only="$ctrl.hasKubeEndpoint()"
|
||||
>
|
||||
<editor-description>
|
||||
<div>
|
||||
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>
|
||||
.
|
||||
</div>
|
||||
</editor-description>
|
||||
</web-editor-form>
|
||||
|
||||
<div ng-if="$ctrl.model.DeploymentType === $ctrl.EditorType.Kubernetes">
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<por-switch-field
|
||||
label="'Use namespace(s) specified from manifest'"
|
||||
tooltip="'If you have defined namespaces in your deployment file turning this on will enforce the use of those only in the deployment'"
|
||||
checked="$ctrl.formValues.UseManifestNamespaces"
|
||||
on-change="($ctrl.onChangeUseManifestNamespaces)"
|
||||
></por-switch-field>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<web-editor-form
|
||||
value="$ctrl.model.StackFileContent"
|
||||
yml="true"
|
||||
identifier="kube-manifest-editor"
|
||||
placeholder="Define or paste the content of your manifest here"
|
||||
on-change="($ctrl.onChangeKubeManifest)"
|
||||
>
|
||||
<editor-description>
|
||||
<p>
|
||||
You can get more information about Kubernetes file format in the
|
||||
<a href="https://kubernetes.io/docs/concepts/overview/working-with-objects/kubernetes-objects/" target="_blank">official documentation</a>.
|
||||
</p>
|
||||
</editor-description>
|
||||
</web-editor-form>
|
||||
</div>
|
||||
|
||||
<!-- actions -->
|
||||
<div class="col-sm-12 form-section-title"> Actions </div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary btn-sm !ml-0"
|
||||
ng-disabled="$ctrl.actionInProgress || !$ctrl.isFormValid() || (!$ctrl.model.DeploymentType && $ctrl.hasKubeEndpoint())"
|
||||
ng-click="$ctrl.submitAction()"
|
||||
button-spinner="$ctrl.actionInProgress"
|
||||
>
|
||||
<span ng-hide="$ctrl.actionInProgress">Update the stack</span>
|
||||
<span ng-show="$ctrl.actionInProgress">Update in progress...</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- !actions -->
|
||||
</form>
|
|
@ -1,116 +0,0 @@
|
|||
import { PortainerEndpointTypes } from '@/portainer/models/endpoint/models';
|
||||
import { EditorType } from '@/react/edge/edge-stacks/types';
|
||||
import { getValidEditorTypes } from '@/react/edge/edge-stacks/utils';
|
||||
export class EditEdgeStackFormController {
|
||||
/* @ngInject */
|
||||
constructor($scope) {
|
||||
this.$scope = $scope;
|
||||
this.state = {
|
||||
endpointTypes: [],
|
||||
readOnlyCompose: false,
|
||||
};
|
||||
|
||||
this.fileContents = {
|
||||
0: '',
|
||||
1: '',
|
||||
};
|
||||
|
||||
this.EditorType = EditorType;
|
||||
|
||||
this.onChangeGroups = this.onChangeGroups.bind(this);
|
||||
this.onChangeFileContent = this.onChangeFileContent.bind(this);
|
||||
this.onChangeComposeConfig = this.onChangeComposeConfig.bind(this);
|
||||
this.onChangeKubeManifest = this.onChangeKubeManifest.bind(this);
|
||||
this.hasDockerEndpoint = this.hasDockerEndpoint.bind(this);
|
||||
this.hasKubeEndpoint = this.hasKubeEndpoint.bind(this);
|
||||
this.onChangeDeploymentType = this.onChangeDeploymentType.bind(this);
|
||||
this.removeLineBreaks = this.removeLineBreaks.bind(this);
|
||||
this.onChangeFileContent = this.onChangeFileContent.bind(this);
|
||||
this.onChangeUseManifestNamespaces = this.onChangeUseManifestNamespaces.bind(this);
|
||||
this.selectValidDeploymentType = this.selectValidDeploymentType.bind(this);
|
||||
}
|
||||
|
||||
onChangeUseManifestNamespaces(value) {
|
||||
this.$scope.$evalAsync(() => {
|
||||
this.model.UseManifestNamespaces = value;
|
||||
});
|
||||
}
|
||||
|
||||
hasKubeEndpoint() {
|
||||
return this.state.endpointTypes.includes(PortainerEndpointTypes.EdgeAgentOnKubernetesEnvironment);
|
||||
}
|
||||
|
||||
hasDockerEndpoint() {
|
||||
return this.state.endpointTypes.includes(PortainerEndpointTypes.EdgeAgentOnDockerEnvironment);
|
||||
}
|
||||
|
||||
onChangeGroups(groups) {
|
||||
return this.$scope.$evalAsync(() => {
|
||||
this.model.EdgeGroups = groups;
|
||||
this.setEnvironmentTypesInSelection(groups);
|
||||
this.selectValidDeploymentType();
|
||||
this.state.readOnlyCompose = this.hasKubeEndpoint();
|
||||
});
|
||||
}
|
||||
|
||||
isFormValid() {
|
||||
return this.model.EdgeGroups.length && this.model.StackFileContent && this.validateEndpointsForDeployment();
|
||||
}
|
||||
|
||||
setEnvironmentTypesInSelection(groups) {
|
||||
const edgeGroups = groups.map((id) => this.edgeGroups.find((e) => e.Id === id));
|
||||
this.state.endpointTypes = edgeGroups.flatMap((group) => group.EndpointTypes);
|
||||
}
|
||||
|
||||
selectValidDeploymentType() {
|
||||
const validTypes = getValidEditorTypes(this.state.endpointTypes, this.allowKubeToSelectCompose);
|
||||
|
||||
if (!validTypes.includes(this.model.DeploymentType)) {
|
||||
this.onChangeDeploymentType(validTypes[0]);
|
||||
}
|
||||
}
|
||||
|
||||
removeLineBreaks(value) {
|
||||
return value.replace(/(\r\n|\n|\r)/gm, '');
|
||||
}
|
||||
|
||||
onChangeFileContent(type, value) {
|
||||
const oldValue = this.fileContents[type];
|
||||
if (this.removeLineBreaks(oldValue) !== this.removeLineBreaks(value)) {
|
||||
this.model.StackFileContent = value;
|
||||
this.fileContents[type] = value;
|
||||
this.isEditorDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
onChangeKubeManifest(value) {
|
||||
this.onChangeFileContent(1, value);
|
||||
}
|
||||
|
||||
onChangeComposeConfig(value) {
|
||||
this.onChangeFileContent(0, value);
|
||||
}
|
||||
|
||||
onChangeDeploymentType(deploymentType) {
|
||||
return this.$scope.$evalAsync(() => {
|
||||
this.model.DeploymentType = deploymentType;
|
||||
this.model.StackFileContent = this.fileContents[deploymentType];
|
||||
});
|
||||
}
|
||||
|
||||
validateEndpointsForDeployment() {
|
||||
return this.model.DeploymentType == 0 || !this.hasDockerEndpoint();
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
this.setEnvironmentTypesInSelection(this.model.EdgeGroups);
|
||||
this.fileContents[this.model.DeploymentType] = this.model.StackFileContent;
|
||||
|
||||
// allow kube to view compose if it's an existing kube compose stack
|
||||
const initiallyContainsKubeEnv = this.hasKubeEndpoint();
|
||||
const isComposeStack = this.model.DeploymentType === 0;
|
||||
this.allowKubeToSelectCompose = initiallyContainsKubeEnv && isComposeStack;
|
||||
this.state.readOnlyCompose = this.allowKubeToSelectCompose;
|
||||
this.selectValidDeploymentType();
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
import angular from 'angular';
|
||||
|
||||
import { EditEdgeStackFormController } from './editEdgeStackFormController';
|
||||
|
||||
angular.module('portainer.edge').component('editEdgeStackForm', {
|
||||
templateUrl: './editEdgeStackForm.html',
|
||||
controller: EditEdgeStackFormController,
|
||||
bindings: {
|
||||
model: '<',
|
||||
actionInProgress: '<',
|
||||
submitAction: '<',
|
||||
edgeGroups: '<',
|
||||
isEditorDirty: '=',
|
||||
},
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue