mirror of https://github.com/portainer/portainer
chore(kompose): remove from settings [EE-4741] (#8375)
parent
00bbf4ac63
commit
5640cce4d6
|
@ -1,23 +0,0 @@
|
||||||
import { compose, kubernetes } from '@@/BoxSelector/common-options/deployment-methods';
|
|
||||||
|
|
||||||
export default class EdgeStackDeploymentTypeSelectorController {
|
|
||||||
/* @ngInject */
|
|
||||||
constructor() {
|
|
||||||
this.deploymentOptions = [
|
|
||||||
{
|
|
||||||
...compose,
|
|
||||||
value: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
...kubernetes,
|
|
||||||
value: 1,
|
|
||||||
disabled: () => {
|
|
||||||
return this.hasDockerEndpoint();
|
|
||||||
},
|
|
||||||
tooltip: () => {
|
|
||||||
return this.hasDockerEndpoint() ? 'Cannot use this option with Edge Docker endpoints' : '';
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,2 +0,0 @@
|
||||||
<div class="col-sm-12 form-section-title"> Deployment type </div>
|
|
||||||
<box-selector radio-name="'deploymentType'" value="$ctrl.value" options="$ctrl.deploymentOptions" on-change="($ctrl.onChange)"></box-selector>
|
|
|
@ -1,15 +0,0 @@
|
||||||
import angular from 'angular';
|
|
||||||
import controller from './edge-stack-deployment-type-selector.controller.js';
|
|
||||||
|
|
||||||
export const edgeStackDeploymentTypeSelector = {
|
|
||||||
templateUrl: './edge-stack-deployment-type-selector.html',
|
|
||||||
controller,
|
|
||||||
|
|
||||||
bindings: {
|
|
||||||
value: '<',
|
|
||||||
onChange: '<',
|
|
||||||
hasDockerEndpoint: '<',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
angular.module('portainer.edge').component('edgeStackDeploymentTypeSelector', edgeStackDeploymentTypeSelector);
|
|
|
@ -4,30 +4,36 @@
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<edge-groups-selector value="$ctrl.model.EdgeGroups" items="$ctrl.edgeGroups" on-change="($ctrl.onChangeGroups)"></edge-groups-selector>
|
<edge-groups-selector value="$ctrl.model.EdgeGroups" items="$ctrl.edgeGroups" on-change="($ctrl.onChangeGroups)"></edge-groups-selector>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group" ng-if="!$ctrl.validateEndpointsForDeployment()">
|
<p class="col-sm-12 vertical-center help-block small text-warning" ng-if="$ctrl.model.DeploymentType === undefined">
|
||||||
<div class="col-sm-12">
|
<pr-icon icon="'alert-triangle'" mode="'warning'"></pr-icon> There are no available deployment types when there is more than one type of environment in your edge group
|
||||||
<div class="small text-muted space-right text-warning">
|
selection (e.g. Kubernetes and Docker environments). Please select edge groups that have environments of the same type.
|
||||||
<pr-icon icon="'alert-triangle'" mode="'warning'"></pr-icon>
|
</p>
|
||||||
One or more of the selected Edge group contains Edge Docker endpoints that cannot be used with a Kubernetes Edge stack.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<edge-stack-deployment-type-selector
|
<edge-stack-deployment-type-selector
|
||||||
value="$ctrl.model.DeploymentType"
|
value="$ctrl.model.DeploymentType"
|
||||||
has-docker-endpoint="$ctrl.hasDockerEndpoint"
|
has-docker-endpoint="$ctrl.hasDockerEndpoint()"
|
||||||
|
has-kube-endpoint="$ctrl.hasKubeEndpoint()"
|
||||||
on-change="($ctrl.onChangeDeploymentType)"
|
on-change="($ctrl.onChangeDeploymentType)"
|
||||||
></edge-stack-deployment-type-selector>
|
></edge-stack-deployment-type-selector>
|
||||||
|
|
||||||
<div class="form-group" ng-if="$ctrl.model.DeploymentType === 0 && $ctrl.hasKubeEndpoint()">
|
<div class="flex gap-1 text-muted small" ng-show="!$ctrl.model.DeploymentType && $ctrl.hasKubeEndpoint()">
|
||||||
<div class="col-sm-12">
|
<pr-icon icon="'alert-circle'" mode="'warning'" class-name="'!mt-1'"></pr-icon>
|
||||||
<div class="small text-muted space-right">
|
<div>
|
||||||
<pr-icon icon="'alert-triangle'" mode="'warning'"></pr-icon>
|
<p>
|
||||||
Portainer uses <a href="https://kompose.io/" target="_blank">Kompose</a> to convert your Compose manifest to a Kubernetes compliant manifest. Be wary that not all the
|
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
|
||||||
Compose format options are supported by Kompose at the moment.
|
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
|
||||||
</div>
|
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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -38,6 +44,7 @@
|
||||||
identifier="compose-editor"
|
identifier="compose-editor"
|
||||||
placeholder="# Define or paste the content of your docker compose file here"
|
placeholder="# Define or paste the content of your docker compose file here"
|
||||||
on-change="($ctrl.onChangeComposeConfig)"
|
on-change="($ctrl.onChangeComposeConfig)"
|
||||||
|
read-only="$ctrl.hasKubeEndpoint()"
|
||||||
>
|
>
|
||||||
<editor-description>
|
<editor-description>
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { PortainerEndpointTypes } from '@/portainer/models/endpoint/models';
|
import { PortainerEndpointTypes } from '@/portainer/models/endpoint/models';
|
||||||
import { EditorType } from '@/react/edge/edge-stacks/types';
|
import { EditorType } from '@/react/edge/edge-stacks/types';
|
||||||
|
import { getValidEditorTypes } from '@/react/edge/edge-stacks/utils';
|
||||||
export class EditEdgeStackFormController {
|
export class EditEdgeStackFormController {
|
||||||
/* @ngInject */
|
/* @ngInject */
|
||||||
constructor($scope) {
|
constructor($scope) {
|
||||||
|
@ -57,6 +57,15 @@ export class EditEdgeStackFormController {
|
||||||
checkEndpointTypes(groups) {
|
checkEndpointTypes(groups) {
|
||||||
const edgeGroups = groups.map((id) => this.edgeGroups.find((e) => e.Id === id));
|
const edgeGroups = groups.map((id) => this.edgeGroups.find((e) => e.Id === id));
|
||||||
this.state.endpointTypes = edgeGroups.flatMap((group) => group.EndpointTypes);
|
this.state.endpointTypes = edgeGroups.flatMap((group) => group.EndpointTypes);
|
||||||
|
this.selectValidDeploymentType();
|
||||||
|
}
|
||||||
|
|
||||||
|
selectValidDeploymentType() {
|
||||||
|
const validTypes = getValidEditorTypes(this.state.endpointTypes);
|
||||||
|
|
||||||
|
if (!validTypes.includes(this.model.DeploymentType)) {
|
||||||
|
this.onChangeDeploymentType(validTypes[0]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
removeLineBreaks(value) {
|
removeLineBreaks(value) {
|
||||||
|
@ -81,9 +90,10 @@ export class EditEdgeStackFormController {
|
||||||
}
|
}
|
||||||
|
|
||||||
onChangeDeploymentType(deploymentType) {
|
onChangeDeploymentType(deploymentType) {
|
||||||
this.model.DeploymentType = deploymentType;
|
return this.$scope.$evalAsync(() => {
|
||||||
|
this.model.DeploymentType = deploymentType;
|
||||||
this.model.StackFileContent = this.fileContents[deploymentType];
|
this.model.StackFileContent = this.fileContents[deploymentType];
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
validateEndpointsForDeployment() {
|
validateEndpointsForDeployment() {
|
||||||
|
@ -92,5 +102,6 @@ export class EditEdgeStackFormController {
|
||||||
|
|
||||||
$onInit() {
|
$onInit() {
|
||||||
this.checkEndpointTypes(this.model.EdgeGroups);
|
this.checkEndpointTypes(this.model.EdgeGroups);
|
||||||
|
this.fileContents[this.model.DeploymentType] = this.model.StackFileContent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { withReactQuery } from '@/react-tools/withReactQuery';
|
||||||
import { EdgeCheckinIntervalField } from '@/react/edge/components/EdgeCheckInIntervalField';
|
import { EdgeCheckinIntervalField } from '@/react/edge/components/EdgeCheckInIntervalField';
|
||||||
import { EdgeScriptForm } from '@/react/edge/components/EdgeScriptForm';
|
import { EdgeScriptForm } from '@/react/edge/components/EdgeScriptForm';
|
||||||
import { EdgeAsyncIntervalsForm } from '@/react/edge/components/EdgeAsyncIntervalsForm';
|
import { EdgeAsyncIntervalsForm } from '@/react/edge/components/EdgeAsyncIntervalsForm';
|
||||||
|
import { EdgeStackDeploymentTypeSelector } from '@/react/edge/edge-stacks/components/EdgeStackDeploymentTypeSelector';
|
||||||
|
|
||||||
export const componentsModule = angular
|
export const componentsModule = angular
|
||||||
.module('portainer.edge.react.components', [])
|
.module('portainer.edge.react.components', [])
|
||||||
|
@ -43,4 +44,13 @@ export const componentsModule = angular
|
||||||
'readonly',
|
'readonly',
|
||||||
'fieldSettings',
|
'fieldSettings',
|
||||||
])
|
])
|
||||||
|
)
|
||||||
|
.component(
|
||||||
|
'edgeStackDeploymentTypeSelector',
|
||||||
|
r2a(withReactQuery(EdgeStackDeploymentTypeSelector), [
|
||||||
|
'value',
|
||||||
|
'onChange',
|
||||||
|
'hasDockerEndpoint',
|
||||||
|
'hasKubeEndpoint',
|
||||||
|
])
|
||||||
).name;
|
).name;
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
import { EditorType } from '@/react/edge/edge-stacks/types';
|
import { EditorType } from '@/react/edge/edge-stacks/types';
|
||||||
|
import { PortainerEndpointTypes } from '@/portainer/models/endpoint/models';
|
||||||
|
import { getValidEditorTypes } from '@/react/edge/edge-stacks/utils';
|
||||||
|
|
||||||
export default class CreateEdgeStackViewController {
|
export default class CreateEdgeStackViewController {
|
||||||
/* @ngInject */
|
/* @ngInject */
|
||||||
|
@ -43,6 +45,7 @@ export default class CreateEdgeStackViewController {
|
||||||
this.createStackFromGitRepository = this.createStackFromGitRepository.bind(this);
|
this.createStackFromGitRepository = this.createStackFromGitRepository.bind(this);
|
||||||
this.onChangeGroups = this.onChangeGroups.bind(this);
|
this.onChangeGroups = this.onChangeGroups.bind(this);
|
||||||
this.hasDockerEndpoint = this.hasDockerEndpoint.bind(this);
|
this.hasDockerEndpoint = this.hasDockerEndpoint.bind(this);
|
||||||
|
this.hasKubeEndpoint = this.hasKubeEndpoint.bind(this);
|
||||||
this.onChangeDeploymentType = this.onChangeDeploymentType.bind(this);
|
this.onChangeDeploymentType = this.onChangeDeploymentType.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,18 +137,23 @@ export default class CreateEdgeStackViewController {
|
||||||
checkIfEndpointTypes(groups) {
|
checkIfEndpointTypes(groups) {
|
||||||
const edgeGroups = groups.map((id) => this.edgeGroups.find((e) => e.Id === id));
|
const edgeGroups = groups.map((id) => this.edgeGroups.find((e) => e.Id === id));
|
||||||
this.state.endpointTypes = edgeGroups.flatMap((group) => group.EndpointTypes);
|
this.state.endpointTypes = edgeGroups.flatMap((group) => group.EndpointTypes);
|
||||||
|
this.selectValidDeploymentType();
|
||||||
|
}
|
||||||
|
|
||||||
if (this.hasDockerEndpoint() && this.formValues.DeploymentType == 1) {
|
selectValidDeploymentType() {
|
||||||
this.onChangeDeploymentType(0);
|
const validTypes = getValidEditorTypes(this.state.endpointTypes);
|
||||||
|
|
||||||
|
if (!validTypes.includes(this.formValues.DeploymentType)) {
|
||||||
|
this.onChangeDeploymentType(validTypes[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hasKubeEndpoint() {
|
hasKubeEndpoint() {
|
||||||
return this.state.endpointTypes.includes(7);
|
return this.state.endpointTypes.includes(PortainerEndpointTypes.EdgeAgentOnKubernetesEnvironment);
|
||||||
}
|
}
|
||||||
|
|
||||||
hasDockerEndpoint() {
|
hasDockerEndpoint() {
|
||||||
return this.state.endpointTypes.includes(4);
|
return this.state.endpointTypes.includes(PortainerEndpointTypes.EdgeAgentOnDockerEnvironment);
|
||||||
}
|
}
|
||||||
|
|
||||||
validateForm(method) {
|
validateForm(method) {
|
||||||
|
@ -217,9 +225,11 @@ export default class CreateEdgeStackViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
onChangeDeploymentType(deploymentType) {
|
onChangeDeploymentType(deploymentType) {
|
||||||
this.formValues.DeploymentType = deploymentType;
|
return this.$scope.$evalAsync(() => {
|
||||||
this.state.Method = 'editor';
|
this.formValues.DeploymentType = deploymentType;
|
||||||
this.formValues.StackFileContent = '';
|
this.state.Method = 'editor';
|
||||||
|
this.formValues.StackFileContent = '';
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
formIsInvalid() {
|
formIsInvalid() {
|
||||||
|
|
|
@ -39,24 +39,19 @@
|
||||||
<div ng-if="$ctrl.noGroups" class="col-sm-12 small text-muted">
|
<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.
|
No Edge groups are available. Head over to the <a ui-sref="edge.groups">Edge groups view</a> to create one.
|
||||||
</div>
|
</div>
|
||||||
|
<p class="col-sm-12 vertical-center help-block small text-warning" ng-if="$ctrl.formValues.DeploymentType === undefined">
|
||||||
|
<pr-icon icon="'alert-triangle'" mode="'warning'"></pr-icon> There are no available deployment types when there is more than one type of environment in your edge
|
||||||
|
group selection (e.g. Kubernetes and Docker environments). Please select edge groups that have environments of the same type.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<edge-stack-deployment-type-selector
|
<edge-stack-deployment-type-selector
|
||||||
value="$ctrl.formValues.DeploymentType"
|
value="$ctrl.formValues.DeploymentType"
|
||||||
has-docker-endpoint="$ctrl.hasDockerEndpoint"
|
has-docker-endpoint="$ctrl.hasDockerEndpoint()"
|
||||||
|
has-kube-endpoint="$ctrl.hasKubeEndpoint()"
|
||||||
on-change="($ctrl.onChangeDeploymentType)"
|
on-change="($ctrl.onChangeDeploymentType)"
|
||||||
></edge-stack-deployment-type-selector>
|
></edge-stack-deployment-type-selector>
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<div class="col-sm-12">
|
|
||||||
<div class="small text-muted space-right" ng-if="$ctrl.formValues.DeploymentType === 0 && $ctrl.hasKubeEndpoint()">
|
|
||||||
<pr-icon icon="'alert-triangle'" mode="'warning'"></pr-icon>
|
|
||||||
Portainer uses <a href="https://kompose.io/" target="_blank">Kompose</a> to convert your Compose manifest to a Kubernetes compliant manifest. Be wary that not all
|
|
||||||
the Compose format options are supported by Kompose at the moment.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<edge-stacks-docker-compose-form
|
<edge-stacks-docker-compose-form
|
||||||
ng-if="$ctrl.formValues.DeploymentType == $ctrl.EditorType.Compose"
|
ng-if="$ctrl.formValues.DeploymentType == $ctrl.EditorType.Compose"
|
||||||
form-values="$ctrl.formValues"
|
form-values="$ctrl.formValues"
|
||||||
|
|
|
@ -59,7 +59,11 @@ export class EditEdgeStackViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
async uiCanExit() {
|
async uiCanExit() {
|
||||||
if (this.formValues.StackFileContent.replace(/(\r\n|\n|\r)/gm, '') !== this.oldFileContent.replace(/(\r\n|\n|\r)/gm, '') && this.state.isEditorDirty) {
|
if (
|
||||||
|
this.formValues.StackFileContent &&
|
||||||
|
this.formValues.StackFileContent.replace(/(\r\n|\n|\r)/gm, '') !== this.oldFileContent.replace(/(\r\n|\n|\r)/gm, '') &&
|
||||||
|
this.state.isEditorDirty
|
||||||
|
) {
|
||||||
return this.ModalService.confirmWebEditorDiscard();
|
return this.ModalService.confirmWebEditorDiscard();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
export const KubernetesDeployManifestTypes = Object.freeze({
|
export const KubernetesDeployManifestTypes = Object.freeze({
|
||||||
KUBERNETES: 1,
|
KUBERNETES: 1,
|
||||||
COMPOSE: 2,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export const KubernetesDeployBuildMethods = Object.freeze({
|
export const KubernetesDeployBuildMethods = Object.freeze({
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<page-header
|
<page-header
|
||||||
ng-if="!ctrl.state.isEdit"
|
ng-if="!ctrl.state.isEdit && !ctrl.stack.IsComposeFormat && ctrl.state.viewReady"
|
||||||
title="'Create application'"
|
title="'Create application'"
|
||||||
breadcrumbs="[
|
breadcrumbs="[
|
||||||
{ label:'Applications', link:'kubernetes.applications' },
|
{ label:'Applications', link:'kubernetes.applications' },
|
||||||
|
@ -10,7 +10,7 @@
|
||||||
</page-header>
|
</page-header>
|
||||||
|
|
||||||
<page-header
|
<page-header
|
||||||
ng-if="ctrl.state.isEdit"
|
ng-if="ctrl.state.isEdit && !ctrl.stack.IsComposeFormat && ctrl.state.viewReady"
|
||||||
title="'Edit application'"
|
title="'Edit application'"
|
||||||
breadcrumbs="[
|
breadcrumbs="[
|
||||||
{ label:'Namespaces', link:'kubernetes.resourcePools' },
|
{ label:'Namespaces', link:'kubernetes.resourcePools' },
|
||||||
|
@ -31,6 +31,17 @@
|
||||||
>
|
>
|
||||||
</page-header>
|
</page-header>
|
||||||
|
|
||||||
|
<page-header
|
||||||
|
ng-if="ctrl.stack.IsComposeFormat"
|
||||||
|
title="'View application'"
|
||||||
|
breadcrumbs="[
|
||||||
|
{ label:'Applications', link:'kubernetes.applications' },
|
||||||
|
'View application'
|
||||||
|
]"
|
||||||
|
reload="true"
|
||||||
|
>
|
||||||
|
</page-header>
|
||||||
|
|
||||||
<kubernetes-view-loading view-ready="ctrl.state.viewReady"></kubernetes-view-loading>
|
<kubernetes-view-loading view-ready="ctrl.state.viewReady"></kubernetes-view-loading>
|
||||||
<div ng-if="ctrl.state.viewReady">
|
<div ng-if="ctrl.state.viewReady">
|
||||||
<div class="row kubernetes-create">
|
<div class="row kubernetes-create">
|
||||||
|
@ -88,6 +99,7 @@
|
||||||
|
|
||||||
<!-- #region web editor -->
|
<!-- #region web editor -->
|
||||||
<web-editor-form
|
<web-editor-form
|
||||||
|
read-only="ctrl.stack.IsComposeFormat"
|
||||||
ng-if="ctrl.state.appType === ctrl.KubernetesDeploymentTypes.CONTENT"
|
ng-if="ctrl.state.appType === ctrl.KubernetesDeploymentTypes.CONTENT"
|
||||||
value="ctrl.stackFileContent"
|
value="ctrl.stackFileContent"
|
||||||
yml="true"
|
yml="true"
|
||||||
|
@ -96,27 +108,24 @@
|
||||||
on-change="(ctrl.onChangeFileContent)"
|
on-change="(ctrl.onChangeFileContent)"
|
||||||
>
|
>
|
||||||
<editor-description>
|
<editor-description>
|
||||||
<span class="text-muted small" ng-show="ctrl.stack.IsComposeFormat">
|
<div class="flex gap-1 text-muted small" ng-show="ctrl.stack.IsComposeFormat">
|
||||||
<p class="vertical-center">
|
<pr-icon icon="'alert-circle'" mode="'warning'" class-name="'!mt-1'"></pr-icon>
|
||||||
<pr-icon icon="'alert-circle'" mode="'warning'"></pr-icon>
|
<div>
|
||||||
<span>
|
<p>
|
||||||
Portainer uses <a href="https://kompose.io/" target="_blank">Kompose</a> to convert your Compose manifest to a Kubernetes compliant manifest. Be wary that
|
Portainer no longer supports <a href="https://docs.docker.com/compose/compose-file/" target="_blank">docker-compose</a> format manifests for Kubernetes
|
||||||
not all the Compose format options are supported by Kompose at the moment.
|
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
|
||||||
</span>
|
because Kompose now poses a security risk, since it has a number of Common Vulnerabilities and Exposures (CVEs).
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p
|
||||||
You can get more information about Compose file format in the
|
>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
|
||||||
<a href="https://docs.docker.com/compose/compose-file/" target="_blank">official documentation</a>.
|
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>
|
>
|
||||||
<p
|
<p>
|
||||||
>In a forthcoming Portainer release, we plan to remove support for docker-compose format manifests for Kubernetes deployments, and the Kompose conversion tool
|
We advise installing your own instance of Kompose in a sandbox environment, performing conversions of your Docker Compose files to Kubernetes manifests and
|
||||||
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
|
using those manifests to set up applications.
|
||||||
>
|
</p>
|
||||||
<p
|
</div>
|
||||||
>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
|
</div>
|
||||||
pull requests to the project (including ones we've submitted) are taking months to be merged, with new CVEs arising in the meantime.</p
|
|
||||||
>
|
|
||||||
</span>
|
|
||||||
<span class="text-muted small" ng-show="!ctrl.stack.IsComposeFormat">
|
<span class="text-muted small" ng-show="!ctrl.stack.IsComposeFormat">
|
||||||
<p class="vertical-center">
|
<p class="vertical-center">
|
||||||
<pr-icon icon="'info'" mode="'primary'"></pr-icon>
|
<pr-icon icon="'info'" mode="'primary'"></pr-icon>
|
||||||
|
@ -1345,9 +1354,9 @@
|
||||||
<!-- kubernetes summary for external application -->
|
<!-- kubernetes summary for external application -->
|
||||||
<kubernetes-summary-view ng-if="ctrl.isExternalApplication()" form-values="ctrl.formValues" old-form-values="ctrl.savedFormValues"></kubernetes-summary-view>
|
<kubernetes-summary-view ng-if="ctrl.isExternalApplication()" form-values="ctrl.formValues" old-form-values="ctrl.savedFormValues"></kubernetes-summary-view>
|
||||||
<!-- kubernetes summary for external application -->
|
<!-- kubernetes summary for external application -->
|
||||||
<div class="col-sm-12 form-section-title" ng-if="ctrl.state.appType !== ctrl.KubernetesDeploymentTypes.GIT"> Actions </div>
|
<div class="col-sm-12 form-section-title" ng-if="ctrl.state.appType !== ctrl.KubernetesDeploymentTypes.GIT" ng-hide="ctrl.stack.IsComposeFormat"> Actions </div>
|
||||||
<!-- #region ACTIONS -->
|
<!-- #region ACTIONS -->
|
||||||
<div class="form-group">
|
<div class="form-group" ng-hide="ctrl.stack.IsComposeFormat">
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<button
|
<button
|
||||||
ng-if="ctrl.state.appType === ctrl.KubernetesDeploymentTypes.APPLICATION_FORM"
|
ng-if="ctrl.state.appType === ctrl.KubernetesDeploymentTypes.APPLICATION_FORM"
|
||||||
|
|
|
@ -223,7 +223,7 @@
|
||||||
style="margin-left: 0"
|
style="margin-left: 0"
|
||||||
data-cy="k8sAppDetail-editAppButton"
|
data-cy="k8sAppDetail-editAppButton"
|
||||||
>
|
>
|
||||||
<pr-icon icon="'pencil'" class="mr-1"></pr-icon>Edit this application
|
<pr-icon icon="'pencil'" class="mr-1"></pr-icon>{{ ctrl.stack.IsComposeFormat ? 'View this application' : 'Edit this application' }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
authorization="K8sApplicationDetailsW"
|
authorization="K8sApplicationDetailsW"
|
||||||
|
|
|
@ -323,6 +323,9 @@ class KubernetesApplicationController {
|
||||||
this.KubernetesNodeService.get(),
|
this.KubernetesNodeService.get(),
|
||||||
]);
|
]);
|
||||||
this.application = application;
|
this.application = application;
|
||||||
|
if (this.application.StackId) {
|
||||||
|
this.stack = await this.StackService.stack(application.StackId);
|
||||||
|
}
|
||||||
this.allContainers = KubernetesApplicationHelper.associateAllContainersAndApplication(application);
|
this.allContainers = KubernetesApplicationHelper.associateAllContainersAndApplication(application);
|
||||||
this.formValues.Note = this.application.Note;
|
this.formValues.Note = this.application.Note;
|
||||||
this.formValues.Services = this.application.Services;
|
this.formValues.Services = this.application.Services;
|
||||||
|
|
|
@ -116,20 +116,7 @@
|
||||||
placeholder="# Define or paste the content of your manifest file here"
|
placeholder="# Define or paste the content of your manifest file here"
|
||||||
>
|
>
|
||||||
<editor-description>
|
<editor-description>
|
||||||
<span class="col-sm-12 text-muted small" ng-show="ctrl.state.DeployType === ctrl.ManifestDeployTypes.COMPOSE">
|
<span class="col-sm-12 text-muted small">
|
||||||
<p class="vertical-center">
|
|
||||||
<pr-icon icon="'alert-circle'" mode="'warning'"></pr-icon>
|
|
||||||
<span>
|
|
||||||
Portainer uses <a href="https://kompose.io/" target="_blank">Kompose</a> to convert your Compose manifest to a Kubernetes compliant manifest. Be wary
|
|
||||||
that not all the Compose format options are supported by Kompose at the moment.
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
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>.
|
|
||||||
</p>
|
|
||||||
</span>
|
|
||||||
<span class="col-sm-12 text-muted small" ng-show="ctrl.state.DeployType === ctrl.ManifestDeployTypes.KUBERNETES">
|
|
||||||
<p class="vertical-center">
|
<p class="vertical-center">
|
||||||
<pr-icon icon="'info'" mode="'primary'"></pr-icon>
|
<pr-icon icon="'info'" mode="'primary'"></pr-icon>
|
||||||
This feature allows you to deploy any kind of Kubernetes resource in this environment (Deployment, Secret, ConfigMap...).
|
This feature allows you to deploy any kind of Kubernetes resource in this environment (Deployment, Secret, ConfigMap...).
|
||||||
|
|
|
@ -7,9 +7,8 @@ import PortainerError from '@/portainer/error';
|
||||||
import { KubernetesDeployManifestTypes, KubernetesDeployBuildMethods, KubernetesDeployRequestMethods, RepositoryMechanismTypes } from 'Kubernetes/models/deploy';
|
import { KubernetesDeployManifestTypes, KubernetesDeployBuildMethods, KubernetesDeployRequestMethods, RepositoryMechanismTypes } from 'Kubernetes/models/deploy';
|
||||||
import { renderTemplate } from '@/react/portainer/custom-templates/components/utils';
|
import { renderTemplate } from '@/react/portainer/custom-templates/components/utils';
|
||||||
import { isBE } from '@/react/portainer/feature-flags/feature-flags.service';
|
import { isBE } from '@/react/portainer/feature-flags/feature-flags.service';
|
||||||
import { compose, kubernetes } from '@@/BoxSelector/common-options/deployment-methods';
|
import { kubernetes } from '@@/BoxSelector/common-options/deployment-methods';
|
||||||
import { editor, git, template, url } from '@@/BoxSelector/common-options/build-methods';
|
import { editor, git, template, url } from '@@/BoxSelector/common-options/build-methods';
|
||||||
import { getPublicSettings } from '@/react/portainer/settings/settings.service';
|
|
||||||
|
|
||||||
class KubernetesDeployController {
|
class KubernetesDeployController {
|
||||||
/* @ngInject */
|
/* @ngInject */
|
||||||
|
@ -339,16 +338,6 @@ class KubernetesDeployController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
|
||||||
const publicSettings = await getPublicSettings();
|
|
||||||
this.showKomposeBuildOption = publicSettings.ShowKomposeBuildOption;
|
|
||||||
} catch (err) {
|
|
||||||
this.Notifications.error('Failure', err, 'Unable to get public settings');
|
|
||||||
}
|
|
||||||
if (this.showKomposeBuildOption) {
|
|
||||||
this.deployOptions = [...this.deployOptions, { ...compose, value: KubernetesDeployManifestTypes.COMPOSE }];
|
|
||||||
}
|
|
||||||
|
|
||||||
this.state.viewReady = true;
|
this.state.viewReady = true;
|
||||||
|
|
||||||
this.$window.onbeforeunload = () => {
|
this.$window.onbeforeunload = () => {
|
||||||
|
|
|
@ -20,7 +20,6 @@ export function SettingsViewModel(data) {
|
||||||
this.EnforceEdgeID = data.EnforceEdgeID;
|
this.EnforceEdgeID = data.EnforceEdgeID;
|
||||||
this.AgentSecret = data.AgentSecret;
|
this.AgentSecret = data.AgentSecret;
|
||||||
this.EdgePortainerUrl = data.EdgePortainerUrl;
|
this.EdgePortainerUrl = data.EdgePortainerUrl;
|
||||||
this.ShowKomposeBuildOption = data.ShowKomposeBuildOption;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function PublicSettingsViewModel(settings) {
|
export function PublicSettingsViewModel(settings) {
|
||||||
|
@ -37,7 +36,6 @@ export function PublicSettingsViewModel(settings) {
|
||||||
this.Features = settings.Features;
|
this.Features = settings.Features;
|
||||||
this.Edge = new EdgeSettingsViewModel(settings.Edge);
|
this.Edge = new EdgeSettingsViewModel(settings.Edge);
|
||||||
this.DefaultRegistry = settings.DefaultRegistry;
|
this.DefaultRegistry = settings.DefaultRegistry;
|
||||||
this.ShowKomposeBuildOption = settings.ShowKomposeBuildOption;
|
|
||||||
this.IsAMTEnabled = settings.IsAMTEnabled;
|
this.IsAMTEnabled = settings.IsAMTEnabled;
|
||||||
this.IsFDOEnabled = settings.IsFDOEnabled;
|
this.IsFDOEnabled = settings.IsFDOEnabled;
|
||||||
}
|
}
|
||||||
|
|
|
@ -184,16 +184,6 @@
|
||||||
tooltip="'Hides the \'Add with form\' buttons and prevents adding/editing of resources via forms'"
|
tooltip="'Hides the \'Add with form\' buttons and prevents adding/editing of resources via forms'"
|
||||||
></por-switch-field>
|
></por-switch-field>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
|
||||||
<por-switch-field
|
|
||||||
label="'Allow docker-compose format Kubernetes manifests'"
|
|
||||||
checked="formValues.ShowKomposeBuildOption"
|
|
||||||
name="'toggle_showKomposeBuildOption'"
|
|
||||||
on-change="(onToggleShowKompose)"
|
|
||||||
field-class="'col-sm-12'"
|
|
||||||
label-class="'col-sm-3 col-lg-2'"
|
|
||||||
></por-switch-field>
|
|
||||||
</div>
|
|
||||||
<!-- !deployment options -->
|
<!-- !deployment options -->
|
||||||
<!-- actions -->
|
<!-- actions -->
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
|
|
@ -1,14 +1,10 @@
|
||||||
import angular from 'angular';
|
import angular from 'angular';
|
||||||
|
|
||||||
import { FeatureId } from '@/react/portainer/feature-flags/enums';
|
import { FeatureId } from '@/react/portainer/feature-flags/enums';
|
||||||
// import trackEvent directly because the event only fires once with $analytics.trackEvent
|
|
||||||
import { trackEvent } from '@/angulartics.matomo/analytics-services';
|
|
||||||
import { options } from './options';
|
import { options } from './options';
|
||||||
|
|
||||||
angular.module('portainer.app').controller('SettingsController', [
|
angular.module('portainer.app').controller('SettingsController', [
|
||||||
'$scope',
|
'$scope',
|
||||||
'$analytics',
|
|
||||||
'$state',
|
|
||||||
'Notifications',
|
'Notifications',
|
||||||
'SettingsService',
|
'SettingsService',
|
||||||
'ModalService',
|
'ModalService',
|
||||||
|
@ -16,7 +12,7 @@ angular.module('portainer.app').controller('SettingsController', [
|
||||||
'BackupService',
|
'BackupService',
|
||||||
'FileSaver',
|
'FileSaver',
|
||||||
'Blob',
|
'Blob',
|
||||||
function ($scope, $analytics, $state, Notifications, SettingsService, ModalService, StateManager, BackupService, FileSaver) {
|
function ($scope, Notifications, SettingsService, ModalService, StateManager, BackupService, FileSaver) {
|
||||||
$scope.customBannerFeatureId = FeatureId.CUSTOM_LOGIN_BANNER;
|
$scope.customBannerFeatureId = FeatureId.CUSTOM_LOGIN_BANNER;
|
||||||
$scope.s3BackupFeatureId = FeatureId.S3_BACKUP_SETTING;
|
$scope.s3BackupFeatureId = FeatureId.S3_BACKUP_SETTING;
|
||||||
$scope.enforceDeploymentOptions = FeatureId.ENFORCE_DEPLOYMENT_OPTIONS;
|
$scope.enforceDeploymentOptions = FeatureId.ENFORCE_DEPLOYMENT_OPTIONS;
|
||||||
|
@ -57,7 +53,6 @@ angular.module('portainer.app').controller('SettingsController', [
|
||||||
|
|
||||||
$scope.formValues = {
|
$scope.formValues = {
|
||||||
customLogo: false,
|
customLogo: false,
|
||||||
ShowKomposeBuildOption: false,
|
|
||||||
KubeconfigExpiry: undefined,
|
KubeconfigExpiry: undefined,
|
||||||
HelmRepositoryURL: undefined,
|
HelmRepositoryURL: undefined,
|
||||||
BlackListedLabels: [],
|
BlackListedLabels: [],
|
||||||
|
@ -83,33 +78,6 @@ angular.module('portainer.app').controller('SettingsController', [
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.onToggleShowKompose = async function onToggleShowKompose(checked) {
|
|
||||||
if (checked) {
|
|
||||||
ModalService.confirmWarn({
|
|
||||||
title: 'Are you sure?',
|
|
||||||
message: `<p>In a forthcoming Portainer release, we plan to remove support for docker-compose format manifests for Kubernetes deployments, and the Kompose 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>`,
|
|
||||||
buttons: {
|
|
||||||
confirm: {
|
|
||||||
label: 'Ok',
|
|
||||||
className: 'btn-warning',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
callback: function (confirmed) {
|
|
||||||
$scope.setShowCompose(confirmed);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$scope.setShowCompose(checked);
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.setShowCompose = function setShowCompose(checked) {
|
|
||||||
return $scope.$evalAsync(() => {
|
|
||||||
$scope.formValues.ShowKomposeBuildOption = checked;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.onToggleAutoBackups = function onToggleAutoBackups(checked) {
|
$scope.onToggleAutoBackups = function onToggleAutoBackups(checked) {
|
||||||
$scope.$evalAsync(() => {
|
$scope.$evalAsync(() => {
|
||||||
$scope.formValues.scheduleAutomaticBackups = checked;
|
$scope.formValues.scheduleAutomaticBackups = checked;
|
||||||
|
@ -187,13 +155,8 @@ angular.module('portainer.app').controller('SettingsController', [
|
||||||
KubeconfigExpiry: $scope.formValues.KubeconfigExpiry,
|
KubeconfigExpiry: $scope.formValues.KubeconfigExpiry,
|
||||||
HelmRepositoryURL: $scope.formValues.HelmRepositoryURL,
|
HelmRepositoryURL: $scope.formValues.HelmRepositoryURL,
|
||||||
GlobalDeploymentOptions: $scope.formValues.GlobalDeploymentOptions,
|
GlobalDeploymentOptions: $scope.formValues.GlobalDeploymentOptions,
|
||||||
ShowKomposeBuildOption: $scope.formValues.ShowKomposeBuildOption,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (kubeSettingsPayload.ShowKomposeBuildOption !== $scope.initialFormValues.ShowKomposeBuildOption && $scope.initialFormValues.enableTelemetry) {
|
|
||||||
trackEvent('kubernetes-allow-compose', { category: 'kubernetes', metadata: { 'kubernetes-allow-compose': kubeSettingsPayload.ShowKomposeBuildOption } });
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.state.kubeSettingsActionInProgress = true;
|
$scope.state.kubeSettingsActionInProgress = true;
|
||||||
updateSettings(kubeSettingsPayload, 'Kubernetes settings updated');
|
updateSettings(kubeSettingsPayload, 'Kubernetes settings updated');
|
||||||
};
|
};
|
||||||
|
@ -205,7 +168,6 @@ angular.module('portainer.app').controller('SettingsController', [
|
||||||
StateManager.updateLogo(settings.LogoURL);
|
StateManager.updateLogo(settings.LogoURL);
|
||||||
StateManager.updateSnapshotInterval(settings.SnapshotInterval);
|
StateManager.updateSnapshotInterval(settings.SnapshotInterval);
|
||||||
StateManager.updateEnableTelemetry(settings.EnableTelemetry);
|
StateManager.updateEnableTelemetry(settings.EnableTelemetry);
|
||||||
$scope.initialFormValues.ShowKomposeBuildOption = response.ShowKomposeBuildOption;
|
|
||||||
$scope.initialFormValues.enableTelemetry = response.EnableTelemetry;
|
$scope.initialFormValues.enableTelemetry = response.EnableTelemetry;
|
||||||
$scope.formValues.BlackListedLabels = response.BlackListedLabels;
|
$scope.formValues.BlackListedLabels = response.BlackListedLabels;
|
||||||
})
|
})
|
||||||
|
@ -235,11 +197,6 @@ angular.module('portainer.app').controller('SettingsController', [
|
||||||
$scope.formValues.KubeconfigExpiry = settings.KubeconfigExpiry;
|
$scope.formValues.KubeconfigExpiry = settings.KubeconfigExpiry;
|
||||||
$scope.formValues.HelmRepositoryURL = settings.HelmRepositoryURL;
|
$scope.formValues.HelmRepositoryURL = settings.HelmRepositoryURL;
|
||||||
$scope.formValues.BlackListedLabels = settings.BlackListedLabels;
|
$scope.formValues.BlackListedLabels = settings.BlackListedLabels;
|
||||||
if (settings.ShowKomposeBuildOption) {
|
|
||||||
$scope.formValues.ShowKomposeBuildOption = settings.ShowKomposeBuildOption;
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.initialFormValues.ShowKomposeBuildOption = settings.ShowKomposeBuildOption;
|
|
||||||
$scope.initialFormValues.enableTelemetry = settings.EnableTelemetry;
|
$scope.initialFormValues.enableTelemetry = settings.EnableTelemetry;
|
||||||
})
|
})
|
||||||
.catch(function error(err) {
|
.catch(function error(err) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { PropsWithChildren } from 'react';
|
import { PropsWithChildren } from 'react';
|
||||||
|
|
||||||
import { Tooltip } from '@@/Tip/Tooltip';
|
import { TooltipWithChildren } from '@@/Tip/TooltipWithChildren';
|
||||||
|
|
||||||
import './BoxSelectorItem.css';
|
import './BoxSelectorItem.css';
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ export function BoxOption<T extends number | string>({
|
||||||
type = 'radio',
|
type = 'radio',
|
||||||
children,
|
children,
|
||||||
}: PropsWithChildren<Props<T>>) {
|
}: PropsWithChildren<Props<T>>) {
|
||||||
return (
|
const BoxOption = (
|
||||||
<div className={clsx('box-selector-item', className)}>
|
<div className={clsx('box-selector-item', className)}>
|
||||||
<input
|
<input
|
||||||
type={type}
|
type={type}
|
||||||
|
@ -44,13 +44,13 @@ export function BoxOption<T extends number | string>({
|
||||||
<label htmlFor={option.id} data-cy={`${radioName}_${option.value}`}>
|
<label htmlFor={option.id} data-cy={`${radioName}_${option.value}`}>
|
||||||
{children}
|
{children}
|
||||||
</label>
|
</label>
|
||||||
{tooltip && (
|
|
||||||
<Tooltip
|
|
||||||
position="bottom"
|
|
||||||
className="portainer-tooltip"
|
|
||||||
message={tooltip}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (tooltip) {
|
||||||
|
return (
|
||||||
|
<TooltipWithChildren message={tooltip}>{BoxOption}</TooltipWithChildren>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return BoxOption;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
import { EditorType } from '@/react/edge/edge-stacks/types';
|
||||||
|
|
||||||
|
import { BoxSelector } from '@@/BoxSelector';
|
||||||
|
import { BoxSelectorOption } from '@@/BoxSelector/types';
|
||||||
|
import {
|
||||||
|
compose,
|
||||||
|
kubernetes,
|
||||||
|
} from '@@/BoxSelector/common-options/deployment-methods';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
value: number;
|
||||||
|
onChange(value: number): void;
|
||||||
|
hasDockerEndpoint: boolean;
|
||||||
|
hasKubeEndpoint: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function EdgeStackDeploymentTypeSelector({
|
||||||
|
value,
|
||||||
|
onChange,
|
||||||
|
hasDockerEndpoint,
|
||||||
|
hasKubeEndpoint,
|
||||||
|
}: Props) {
|
||||||
|
const deploymentOptions: BoxSelectorOption<number>[] = [
|
||||||
|
{
|
||||||
|
...compose,
|
||||||
|
value: EditorType.Compose,
|
||||||
|
disabled: () => hasKubeEndpoint,
|
||||||
|
tooltip: () =>
|
||||||
|
hasKubeEndpoint
|
||||||
|
? 'Cannot use this option with Edge Kubernetes environments'
|
||||||
|
: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...kubernetes,
|
||||||
|
value: EditorType.Kubernetes,
|
||||||
|
disabled: () => hasDockerEndpoint,
|
||||||
|
tooltip: () =>
|
||||||
|
hasDockerEndpoint
|
||||||
|
? 'Cannot use this option with Edge Docker environments'
|
||||||
|
: '',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="col-sm-12 form-section-title"> Deployment type</div>
|
||||||
|
<BoxSelector
|
||||||
|
radioName="deploymentType"
|
||||||
|
value={value}
|
||||||
|
options={deploymentOptions}
|
||||||
|
onChange={onChange}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
import { EnvironmentType } from '@/react/portainer/environments/types';
|
||||||
|
|
||||||
|
import { EditorType } from './types';
|
||||||
|
import { getValidEditorTypes } from './utils';
|
||||||
|
|
||||||
|
interface GetValidEditorTypesTest {
|
||||||
|
endpointTypes: EnvironmentType[];
|
||||||
|
expected: EditorType[];
|
||||||
|
title: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('getValidEditorTypes', () => {
|
||||||
|
const tests: GetValidEditorTypesTest[] = [
|
||||||
|
{
|
||||||
|
endpointTypes: [EnvironmentType.EdgeAgentOnDocker],
|
||||||
|
expected: [EditorType.Compose],
|
||||||
|
title: 'should return compose for docker envs',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
endpointTypes: [EnvironmentType.EdgeAgentOnKubernetes],
|
||||||
|
expected: [EditorType.Kubernetes],
|
||||||
|
title: 'should return kubernetes for kubernetes envs',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
endpointTypes: [
|
||||||
|
EnvironmentType.EdgeAgentOnDocker,
|
||||||
|
EnvironmentType.EdgeAgentOnKubernetes,
|
||||||
|
],
|
||||||
|
expected: [],
|
||||||
|
title: 'should return empty for docker and kubernetes envs',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
tests.forEach((test) => {
|
||||||
|
// eslint-disable-next-line jest/valid-title
|
||||||
|
it(test.title, () => {
|
||||||
|
expect(getValidEditorTypes(test.endpointTypes)).toEqual(test.expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,16 @@
|
||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
|
import { EnvironmentType } from '@/react/portainer/environments/types';
|
||||||
|
|
||||||
|
import { EditorType } from './types';
|
||||||
|
|
||||||
|
export function getValidEditorTypes(endpointTypes: EnvironmentType[]) {
|
||||||
|
const right: Partial<Record<EnvironmentType, EditorType[]>> = {
|
||||||
|
[EnvironmentType.EdgeAgentOnDocker]: [EditorType.Compose],
|
||||||
|
[EnvironmentType.EdgeAgentOnKubernetes]: [EditorType.Kubernetes],
|
||||||
|
};
|
||||||
|
|
||||||
|
return endpointTypes.length
|
||||||
|
? _.intersection(...endpointTypes.map((type) => right[type]))
|
||||||
|
: [EditorType.Compose, EditorType.Kubernetes];
|
||||||
|
}
|
|
@ -160,8 +160,6 @@ export interface PublicSettingsResponse {
|
||||||
RequiredPasswordLength: number;
|
RequiredPasswordLength: number;
|
||||||
/** Deployment options for encouraging deployment as code (only on BE) */
|
/** Deployment options for encouraging deployment as code (only on BE) */
|
||||||
GlobalDeploymentOptions: GlobalDeploymentOptions;
|
GlobalDeploymentOptions: GlobalDeploymentOptions;
|
||||||
/** Show the Kompose build option (discontinued in 2.18) */
|
|
||||||
ShowKomposeBuildOption: boolean;
|
|
||||||
/** Whether edge compute features are enabled */
|
/** Whether edge compute features are enabled */
|
||||||
EnableEdgeComputeFeatures: boolean;
|
EnableEdgeComputeFeatures: boolean;
|
||||||
/** Supported feature flags */
|
/** Supported feature flags */
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
if [[ $# -ne 3 ]]; then
|
|
||||||
echo "Illegal number of parameters" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
PLATFORM=$1
|
|
||||||
ARCH=$2
|
|
||||||
KOMPOSE_VERSION=$3
|
|
||||||
|
|
||||||
|
|
||||||
if [[ ${PLATFORM} == "windows" ]]; then
|
|
||||||
wget -O "dist/kompose.exe" "https://github.com/kubernetes/kompose/releases/download/${KOMPOSE_VERSION}/kompose-windows-amd64.exe"
|
|
||||||
chmod +x "dist/kompose.exe"
|
|
||||||
elif [[ ${PLATFORM} == "darwin" ]]; then
|
|
||||||
# kompose 1.22 doesn't have arm support yet, we could merge darwin and linux scripts after upgrading kompose to >= 1.26.0
|
|
||||||
wget -O "dist/kompose" "https://github.com/kubernetes/kompose/releases/download/${KOMPOSE_VERSION}/kompose-${PLATFORM}-amd64"
|
|
||||||
chmod +x "dist/kompose"
|
|
||||||
else
|
|
||||||
wget -O "dist/kompose" "https://github.com/kubernetes/kompose/releases/download/${KOMPOSE_VERSION}/kompose-${PLATFORM}-${ARCH}"
|
|
||||||
chmod +x "dist/kompose"
|
|
||||||
fi
|
|
15
gruntfile.js
15
gruntfile.js
|
@ -29,7 +29,6 @@ module.exports = function (grunt) {
|
||||||
dockerVersion: 'v20.10.21',
|
dockerVersion: 'v20.10.21',
|
||||||
dockerComposePluginVersion: 'v2.13.0',
|
dockerComposePluginVersion: 'v2.13.0',
|
||||||
helmVersion: 'v3.9.3',
|
helmVersion: 'v3.9.3',
|
||||||
komposeVersion: 'v1.22.0',
|
|
||||||
kubectlVersion: 'v1.24.1',
|
kubectlVersion: 'v1.24.1',
|
||||||
},
|
},
|
||||||
env: gruntConfig.env,
|
env: gruntConfig.env,
|
||||||
|
@ -78,7 +77,6 @@ module.exports = function (grunt) {
|
||||||
`shell:download_docker_binary:${platform}:${a}`,
|
`shell:download_docker_binary:${platform}:${a}`,
|
||||||
`shell:download_docker_compose_binary:${platform}:${a}`,
|
`shell:download_docker_compose_binary:${platform}:${a}`,
|
||||||
`shell:download_helm_binary:${platform}:${a}`,
|
`shell:download_helm_binary:${platform}:${a}`,
|
||||||
`shell:download_kompose_binary:${platform}:${a}`,
|
|
||||||
`shell:download_kubectl_binary:${platform}:${a}`,
|
`shell:download_kubectl_binary:${platform}:${a}`,
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
@ -117,7 +115,6 @@ gruntConfig.shell = {
|
||||||
build_binary_azuredevops: { command: shell_build_binary_azuredevops },
|
build_binary_azuredevops: { command: shell_build_binary_azuredevops },
|
||||||
download_docker_binary: { command: shell_download_docker_binary },
|
download_docker_binary: { command: shell_download_docker_binary },
|
||||||
download_helm_binary: { command: shell_download_helm_binary },
|
download_helm_binary: { command: shell_download_helm_binary },
|
||||||
download_kompose_binary: { command: shell_download_kompose_binary },
|
|
||||||
download_kubectl_binary: { command: shell_download_kubectl_binary },
|
download_kubectl_binary: { command: shell_download_kubectl_binary },
|
||||||
download_docker_compose_binary: { command: shell_download_docker_compose_binary },
|
download_docker_compose_binary: { command: shell_download_docker_compose_binary },
|
||||||
run_container: { command: shell_run_container },
|
run_container: { command: shell_run_container },
|
||||||
|
@ -228,18 +225,6 @@ function shell_download_helm_binary(platform, arch) {
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function shell_download_kompose_binary(platform, arch) {
|
|
||||||
const binaryVersion = '<%= binaries.komposeVersion %>';
|
|
||||||
|
|
||||||
return `
|
|
||||||
if [ -f dist/kompose ] || [ -f dist/kompose.exe ]; then
|
|
||||||
echo "kompose binary exists";
|
|
||||||
else
|
|
||||||
build/download_kompose_binary.sh ${platform} ${arch} ${binaryVersion};
|
|
||||||
fi
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function shell_download_kubectl_binary(platform, arch) {
|
function shell_download_kubectl_binary(platform, arch) {
|
||||||
var binaryVersion = '<%= binaries.kubectlVersion %>';
|
var binaryVersion = '<%= binaries.kubectlVersion %>';
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue