1
0
Fork 0
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:
Chaim Lev-Ari 2023-05-31 01:33:22 +07:00 committed by GitHub
parent 0ec7dfce69
commit 93bf630105
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
53 changed files with 1572 additions and 424 deletions

View file

@ -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 -->

View file

@ -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();
}
}

View file

@ -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>

View file

@ -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();
}
}

View file

@ -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: '=',
},
});