@rancher/shell 0.1.3 → 0.1.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/brand/suse/dark/rancher-logo.svg +1 -148
- package/assets/brand/suse/favicon.png +0 -0
- package/assets/brand/suse/rancher-logo.svg +1 -130
- package/assets/images/featured/img1.jpg +0 -0
- package/assets/images/featured.jpg +0 -0
- package/assets/images/generic-plugin.svg +1 -0
- package/assets/styles/themes/_dark.scss +3 -0
- package/assets/styles/themes/_light.scss +3 -0
- package/assets/styles/themes/_suse.scss +1 -1
- package/assets/translations/en-us.yaml +219 -47
- package/assets/translations/zh-hans.yaml +21 -24
- package/components/AsyncButton.vue +17 -2
- package/components/ButtonDropdown.vue +4 -0
- package/components/Carousel.vue +291 -0
- package/components/CommunityLinks.vue +64 -22
- package/components/CruResource.vue +11 -3
- package/components/Dialog.vue +102 -0
- package/components/ExplorerMembers.vue +2 -4
- package/components/ExplorerProjectsNamespaces.vue +25 -9
- package/components/IconMessage.vue +9 -1
- package/components/LazyImage.vue +21 -8
- package/components/LocaleSelector.vue +62 -29
- package/components/PromptRemove.vue +2 -2
- package/components/ResourceList/Masthead.vue +21 -1
- package/components/ResourceList/ResourceLoadingIndicator.vue +0 -8
- package/components/ResourceList/index.vue +9 -23
- package/components/ResourceTable.vue +7 -2
- package/components/SimpleBox.vue +6 -4
- package/components/SortableTable/index.vue +18 -25
- package/components/Tabbed/Tab.vue +5 -0
- package/components/Tabbed/index.vue +54 -9
- package/components/TypeDescription.vue +10 -1
- package/components/auth/Principal.vue +1 -0
- package/components/fleet/FleetBundles.vue +8 -3
- package/components/fleet/FleetClusters.vue +6 -0
- package/components/fleet/FleetRepos.vue +7 -1
- package/components/fleet/FleetSummary.vue +6 -0
- package/components/form/Command.vue +5 -0
- package/components/form/EnvVars.vue +5 -0
- package/components/form/KeyValue.vue +80 -58
- package/components/form/NameNsDescription.vue +13 -5
- package/components/form/NodeScheduling.vue +6 -1
- package/components/form/PodAffinity.vue +5 -0
- package/components/form/ResourceTabs/index.vue +5 -1
- package/components/form/ServiceNameSelect.vue +5 -0
- package/components/form/ValueFromResource.vue +7 -1
- package/components/formatter/ClusterLink.vue +3 -7
- package/components/nav/NamespaceFilter.vue +3 -3
- package/components/nav/TopLevelMenu.vue +12 -29
- package/config/home-links.js +155 -0
- package/config/labels-annotations.js +2 -1
- package/config/private-label.js +1 -1
- package/config/product/explorer.js +5 -4
- package/config/product/legacy.js +0 -47
- package/config/product/manager.js +0 -2
- package/config/product/multi-cluster-apps.js +0 -12
- package/config/product/settings.js +12 -1
- package/config/product/uiplugins.js +17 -0
- package/config/settings.js +23 -2
- package/config/types.js +5 -1
- package/config/uiplugins.js +117 -0
- package/config/version.js +17 -0
- package/content/docs/en-us/getting-started.md +1 -26
- package/core/plugin.ts +12 -0
- package/core/plugins.js +38 -2
- package/core/types.ts +6 -0
- package/creators/app/{.eslintignore → files/.eslintignore} +0 -0
- package/creators/app/{.eslintrc.js → files/.eslintrc.js} +0 -0
- package/creators/app/{.vscode → files/.vscode}/settings.json +0 -0
- package/creators/app/{babel.config.js → files/babel.config.js} +0 -0
- package/creators/app/{nuxt.config.js → files/nuxt.config.js} +0 -0
- package/creators/app/{tsconfig.json → files/tsconfig.json} +2 -1
- package/creators/app/init +16 -17
- package/creators/app/package.json +6 -0
- package/creators/pkg/{babel.config.js → files/babel.config.js} +0 -0
- package/creators/pkg/{index.ts → files/index.ts} +0 -0
- package/creators/pkg/{tsconfig.json → files/tsconfig.json} +13 -12
- package/creators/pkg/{vue.config.js → files/vue.config.js} +0 -0
- package/creators/pkg/init +1 -1
- package/creators/update/init +54 -0
- package/creators/update/package.json +20 -0
- package/creators/update/upgrade +56 -0
- package/creators/update/yarn-error.log +54 -0
- package/detail/provisioning.cattle.io.cluster.vue +3 -3
- package/detail/workload/index.vue +3 -2
- package/dialog/DiagnosticTimingsDialog.vue +116 -0
- package/dialog/RotateCertificatesDialog.vue +9 -3
- package/edit/auth/azuread.vue +28 -9
- package/edit/networking.k8s.io.ingress/index.vue +2 -2
- package/edit/persistentvolume/index.vue +51 -13
- package/edit/persistentvolumeclaim.vue +31 -13
- package/edit/pod.vue +27 -0
- package/edit/provisioning.cattle.io.cluster/rke2.vue +103 -24
- package/edit/service.vue +7 -5
- package/edit/workload/__tests__/Upgrading.test.ts +1 -0
- package/edit/workload/index.vue +32 -10
- package/edit/workload/mixins/workload.js +121 -126
- package/edit/workload/storage/ContainerMountPaths.vue +240 -0
- package/edit/workload/storage/Mount.vue +1 -0
- package/edit/workload/storage/awsElasticBlockStore.vue +20 -1
- package/edit/workload/storage/azureDisk.vue +22 -2
- package/edit/workload/storage/azureFile.vue +20 -2
- package/edit/workload/storage/csi/index.vue +23 -1
- package/edit/workload/storage/gcePersistentDisk.vue +20 -2
- package/edit/workload/storage/index.vue +33 -65
- package/edit/workload/storage/persistentVolumeClaim/index.vue +5 -0
- package/edit/workload/storage/secret.vue +6 -1
- package/edit/workload/storage/vsphereVolume.vue +11 -1
- package/layouts/default.vue +14 -8
- package/layouts/home.vue +9 -4
- package/layouts/plain.vue +10 -5
- package/list/catalog.cattle.io.app.vue +10 -9
- package/list/catalog.cattle.io.clusterrepo.vue +6 -61
- package/list/cis.cattle.io.clusterscan.vue +12 -12
- package/list/fleet.cattle.io.bundle.vue +33 -28
- package/list/fleet.cattle.io.cluster.vue +26 -22
- package/list/fleet.cattle.io.clustergroup.vue +6 -0
- package/list/fleet.cattle.io.clusterregistrationtoken.vue +28 -24
- package/list/fleet.cattle.io.gitrepo.vue +25 -14
- package/list/helm.cattle.io.projecthelmchart.vue +52 -33
- package/list/logging.banzaicloud.io.clusterflow.vue +7 -12
- package/list/logging.banzaicloud.io.flow.vue +7 -14
- package/list/management.cattle.io.cluster.vue +26 -15
- package/list/management.cattle.io.feature.vue +13 -8
- package/list/management.cattle.io.setting.vue +3 -3
- package/list/management.cattle.io.user.vue +38 -19
- package/list/monitoring.coreos.com.alertmanagerconfig.vue +8 -15
- package/list/namespace.vue +14 -1
- package/list/node.vue +13 -16
- package/list/persistentvolume.vue +16 -9
- package/list/persistentvolumeclaim.vue +5 -8
- package/list/provisioning.cattle.io.cluster.vue +35 -9
- package/list/service.vue +24 -12
- package/list/ui.cattle.io.navlink.vue +6 -0
- package/list/workload.vue +2 -2
- package/machine-config/harvester.vue +5 -3
- package/middleware/authenticated.js +6 -0
- package/mixins/resource-fetch.js +12 -18
- package/mixins/resource-manager.js +126 -0
- package/models/catalog.cattle.io.uiplugin.js +38 -0
- package/models/cluster/node.js +25 -2
- package/models/fleet.cattle.io.bundle.js +1 -1
- package/models/harvesterhci.io.management.cluster.js +11 -5
- package/models/pod.js +15 -5
- package/models/provisioning.cattle.io.cluster.js +16 -6
- package/models/workload.js +5 -3
- package/models/workload.service.js +10 -0
- package/nuxt.config.js +70 -25
- package/package.json +108 -109
- package/pages/auth/login.vue +11 -1
- package/pages/auth/verify.vue +9 -0
- package/pages/c/_cluster/apps/charts/index.vue +46 -1
- package/pages/c/_cluster/apps/charts/install.vue +10 -9
- package/pages/c/_cluster/explorer/index.vue +72 -9
- package/pages/c/_cluster/explorer/tools/index.vue +12 -5
- package/pages/c/_cluster/mcapps/index.vue +1 -1
- package/pages/c/_cluster/settings/DefaultLinksEditor.vue +108 -0
- package/pages/c/_cluster/settings/brand.vue +0 -40
- package/pages/c/_cluster/settings/links.vue +152 -0
- package/pages/c/_cluster/settings/performance.vue +90 -7
- package/pages/c/_cluster/uiplugins/DeveloperInstallDialog.vue +232 -0
- package/pages/c/_cluster/uiplugins/InstallDialog.vue +293 -0
- package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +300 -0
- package/pages/c/_cluster/uiplugins/RemoveUIPlugins.vue +125 -0
- package/pages/c/_cluster/uiplugins/SetupUIPlugins.vue +261 -0
- package/pages/c/_cluster/uiplugins/UninstallDialog.vue +122 -0
- package/pages/c/_cluster/uiplugins/index.vue +808 -0
- package/pages/diagnostic.vue +185 -101
- package/pages/docs/_doc.vue +3 -1
- package/pages/home.vue +21 -56
- package/pages/prefs.vue +108 -88
- package/pages/safeMode.vue +17 -0
- package/pages/support/index.vue +34 -137
- package/pkg/dynamic-importer.lib.js +4 -0
- package/plugins/dashboard-store/actions.js +19 -0
- package/plugins/dashboard-store/getters.js +20 -3
- package/plugins/dashboard-store/mutations.js +13 -7
- package/plugins/dashboard-store/resource-class.js +2 -2
- package/plugins/formatters.js +15 -0
- package/plugins/plugin.js +61 -6
- package/plugins/steve/getters.js +12 -0
- package/plugins/steve/mutations.js +1 -1
- package/plugins/steve/subscribe.js +94 -72
- package/plugins/steve/web-worker.steve-sub-worker.js +24 -15
- package/plugins/version.js +21 -0
- package/promptRemove/management.cattle.io.globalrole.vue +47 -0
- package/promptRemove/management.cattle.io.roletemplate.vue +47 -0
- package/promptRemove/mixin/roleDeletionCheck.js +97 -0
- package/rancher-components/Form/TextArea/TextAreaAutoGrow.vue +6 -7
- package/rancher-components/components/BadgeState/BadgeState.spec.ts +12 -0
- package/rancher-components/components/BadgeState/BadgeState.vue +107 -0
- package/rancher-components/components/BadgeState/index.ts +1 -0
- package/rancher-components/components/Banner/Banner.test.ts +13 -0
- package/rancher-components/components/Banner/Banner.vue +163 -0
- package/rancher-components/components/Banner/index.ts +1 -0
- package/rancher-components/components/Card/Card.vue +150 -0
- package/rancher-components/components/Card/index.ts +1 -0
- package/rancher-components/components/Form/Checkbox/Checkbox.test.ts +77 -0
- package/rancher-components/components/Form/Checkbox/Checkbox.vue +395 -0
- package/rancher-components/components/Form/Checkbox/index.ts +1 -0
- package/rancher-components/components/Form/LabeledInput/LabeledInput.test.ts +29 -0
- package/rancher-components/components/Form/LabeledInput/LabeledInput.vue +343 -0
- package/rancher-components/components/Form/LabeledInput/index.ts +1 -0
- package/rancher-components/components/Form/Radio/RadioButton.vue +270 -0
- package/rancher-components/components/Form/Radio/RadioGroup.vue +235 -0
- package/rancher-components/components/Form/Radio/index.ts +2 -0
- package/rancher-components/components/Form/TextArea/TextAreaAutoGrow.vue +168 -0
- package/rancher-components/components/Form/TextArea/index.ts +1 -0
- package/rancher-components/components/Form/ToggleSwitch/ToggleSwitch.test.ts +107 -0
- package/rancher-components/components/Form/ToggleSwitch/ToggleSwitch.vue +137 -0
- package/rancher-components/components/Form/ToggleSwitch/index.ts +1 -0
- package/rancher-components/components/Form/index.ts +5 -0
- package/rancher-components/components/LabeledTooltip/LabeledTooltip.vue +137 -0
- package/rancher-components/components/LabeledTooltip/index.ts +1 -0
- package/scripts/publish-shell.sh +40 -7
- package/scripts/record-deps.js +37 -0
- package/scripts/sync-shell-deps +37 -0
- package/scripts/test-plugins-build.sh +8 -5
- package/scripts/typegen.sh +84 -0
- package/store/auth.js +3 -0
- package/store/catalog.js +9 -8
- package/store/i18n.js +10 -1
- package/store/index.js +12 -3
- package/store/prefs.js +16 -0
- package/store/type-map.js +32 -5
- package/store/uiplugins.ts +15 -61
- package/types/shell/index.d.ts +3046 -0
- package/utils/__tests__/object.test.ts +0 -24
- package/utils/__tests__/selector.test.ts +1 -1
- package/utils/dynamic-importer.js +4 -0
- package/utils/favicon.js +8 -2
- package/utils/gc/gc-interval.ts +40 -0
- package/utils/gc/gc-root-store.js +76 -0
- package/utils/gc/gc-route-changed.ts +44 -0
- package/utils/gc/gc-types.ts +21 -0
- package/utils/gc/gc.ts +282 -0
- package/utils/grafana.js +2 -6
- package/utils/socket.js +41 -20
- package/utils/string.js +1 -7
- package/utils/validators/formRules/__tests__/index.test.ts +108 -0
- package/utils/validators/formRules/index.ts +9 -1
- package/config/footer.js +0 -19
- package/creators/pkg/nuxt.config.js +0 -6
- package/pages/plugins.vue +0 -387
- package/server/verdaccio-middleware.js +0 -56
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { mapGetters } from 'vuex';
|
|
1
2
|
import omitBy from 'lodash/omitBy';
|
|
2
3
|
import { cleanUp } from '@shell/utils/object';
|
|
3
4
|
import {
|
|
@@ -9,10 +10,11 @@ import {
|
|
|
9
10
|
PVC,
|
|
10
11
|
SERVICE_ACCOUNT,
|
|
11
12
|
CAPI,
|
|
13
|
+
POD,
|
|
12
14
|
} from '@shell/config/types';
|
|
13
15
|
import Tab from '@shell/components/Tabbed/Tab';
|
|
14
16
|
import CreateEditView from '@shell/mixins/create-edit-view';
|
|
15
|
-
import
|
|
17
|
+
import ResourceManager from '@shell/mixins/resource-manager';
|
|
16
18
|
import LabeledSelect from '@shell/components/form/LabeledSelect';
|
|
17
19
|
import { LabeledInput } from '@components/Form/LabeledInput';
|
|
18
20
|
import ServiceNameSelect from '@shell/components/form/ServiceNameSelect';
|
|
@@ -28,7 +30,7 @@ import WorkloadPorts from '@shell/components/form/WorkloadPorts';
|
|
|
28
30
|
import ContainerResourceLimit from '@shell/components/ContainerResourceLimit';
|
|
29
31
|
import KeyValue from '@shell/components/form/KeyValue';
|
|
30
32
|
import Tabbed from '@shell/components/Tabbed';
|
|
31
|
-
|
|
33
|
+
|
|
32
34
|
import NodeScheduling from '@shell/components/form/NodeScheduling';
|
|
33
35
|
import PodAffinity from '@shell/components/form/PodAffinity';
|
|
34
36
|
import Tolerations from '@shell/components/form/Tolerations';
|
|
@@ -36,6 +38,7 @@ import CruResource from '@shell/components/CruResource';
|
|
|
36
38
|
import Command from '@shell/components/form/Command';
|
|
37
39
|
import LifecycleHooks from '@shell/components/form/LifecycleHooks';
|
|
38
40
|
import Storage from '@shell/edit/workload/storage';
|
|
41
|
+
import ContainerMountPaths from '@shell/edit/workload/storage/ContainerMountPaths.vue';
|
|
39
42
|
import Labels from '@shell/components/form/Labels';
|
|
40
43
|
import { RadioGroup } from '@components/Form/Radio';
|
|
41
44
|
import { UI_MANAGED } from '@shell/config/labels-annotations';
|
|
@@ -89,9 +92,10 @@ export default {
|
|
|
89
92
|
Upgrading,
|
|
90
93
|
VolumeClaimTemplate,
|
|
91
94
|
WorkloadPorts,
|
|
95
|
+
ContainerMountPaths
|
|
92
96
|
},
|
|
93
97
|
|
|
94
|
-
mixins: [CreateEditView],
|
|
98
|
+
mixins: [CreateEditView, ResourceManager],
|
|
95
99
|
|
|
96
100
|
props: {
|
|
97
101
|
value: {
|
|
@@ -115,40 +119,14 @@ export default {
|
|
|
115
119
|
},
|
|
116
120
|
|
|
117
121
|
async fetch() {
|
|
118
|
-
|
|
119
|
-
const needed = {
|
|
120
|
-
configMaps: CONFIG_MAP,
|
|
121
|
-
nodes: NODE,
|
|
122
|
-
services: SERVICE,
|
|
123
|
-
pvcs: PVC,
|
|
124
|
-
sas: SERVICE_ACCOUNT,
|
|
125
|
-
secrets: SECRET,
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
// Only fetch types if the user can see them
|
|
129
|
-
Object.keys(needed).forEach((key) => {
|
|
130
|
-
const type = needed[key];
|
|
131
|
-
|
|
132
|
-
if (this.$store.getters['cluster/schemaFor'](type)) {
|
|
133
|
-
requests[key] = this.$store.dispatch('cluster/findAll', { type });
|
|
134
|
-
}
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
const hash = await allHash(requests);
|
|
122
|
+
await this.$store.dispatch('management/findAll', { type: CAPI.RANCHER_CLUSTER });
|
|
138
123
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
this.
|
|
142
|
-
this.allConfigMaps = hash.configMaps || [];
|
|
143
|
-
this.allNodeObjects = hash.nodes || [];
|
|
144
|
-
this.allNodes = this.allNodeObjects.map(node => node.id);
|
|
145
|
-
this.allServices = hash.services || [];
|
|
146
|
-
this.pvcs = hash.pvcs || [];
|
|
147
|
-
this.sas = hash.sas || [];
|
|
124
|
+
// don't block UI for these resources
|
|
125
|
+
this.resourceManagerFetchSecondaryResources(this.secondaryResourceData);
|
|
126
|
+
this.servicesOwned = await this.value.getServicesOwned();
|
|
148
127
|
},
|
|
149
128
|
|
|
150
129
|
data() {
|
|
151
|
-
let defaultTab;
|
|
152
130
|
let type = this.$route.params.resource;
|
|
153
131
|
const createSidecar = !!this.$route.query.sidecar;
|
|
154
132
|
const isInitContainer = !!this.$route.query.init;
|
|
@@ -159,28 +137,27 @@ export default {
|
|
|
159
137
|
|
|
160
138
|
if (!this.value.spec) {
|
|
161
139
|
this.value.spec = {};
|
|
162
|
-
if (this.value.type ===
|
|
140
|
+
if (this.value.type === POD) {
|
|
163
141
|
const podContainers = [{
|
|
164
142
|
imagePullPolicy: 'Always',
|
|
165
143
|
name: `container-0`,
|
|
166
144
|
}];
|
|
167
145
|
|
|
168
|
-
|
|
146
|
+
const metadata = { ...this.value.metadata };
|
|
169
147
|
|
|
170
|
-
const podSpec = { template: { spec: { containers: podContainers, initContainers: [] } } };
|
|
148
|
+
const podSpec = { template: { spec: { containers: podContainers, initContainers: [] }, metadata } };
|
|
171
149
|
|
|
172
150
|
this.$set(this.value, 'spec', podSpec);
|
|
173
151
|
}
|
|
174
152
|
}
|
|
175
153
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
}
|
|
179
|
-
|
|
154
|
+
// EDIT view for POD
|
|
155
|
+
// Transform it from POD world to workload
|
|
180
156
|
if ((this.mode === _EDIT || this.mode === _VIEW ) && this.value.type === 'pod' ) {
|
|
181
157
|
const podSpec = { ...this.value.spec };
|
|
158
|
+
const metadata = { ...this.value.metadata };
|
|
182
159
|
|
|
183
|
-
this.$set(this.value.spec, 'template', { spec: podSpec });
|
|
160
|
+
this.$set(this.value.spec, 'template', { spec: podSpec, metadata });
|
|
184
161
|
}
|
|
185
162
|
|
|
186
163
|
const spec = this.value.spec;
|
|
@@ -214,7 +191,6 @@ export default {
|
|
|
214
191
|
imagePullPolicy: 'Always',
|
|
215
192
|
name: `container-${ allContainers.length }`,
|
|
216
193
|
});
|
|
217
|
-
defaultTab = 'container-0';
|
|
218
194
|
|
|
219
195
|
containers = podTemplateSpec.initContainers;
|
|
220
196
|
}
|
|
@@ -224,8 +200,6 @@ export default {
|
|
|
224
200
|
name: `container-${ allContainers.length }`,
|
|
225
201
|
};
|
|
226
202
|
|
|
227
|
-
defaultTab = 'container-0';
|
|
228
|
-
|
|
229
203
|
containers.push(container);
|
|
230
204
|
} else {
|
|
231
205
|
container = containers[0];
|
|
@@ -235,42 +209,93 @@ export default {
|
|
|
235
209
|
this.selectContainer(container);
|
|
236
210
|
|
|
237
211
|
return {
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
212
|
+
secondaryResourceData: {
|
|
213
|
+
namespace: this.value?.metadata?.namespace || null,
|
|
214
|
+
data: {
|
|
215
|
+
[CONFIG_MAP]: { applyTo: [{ var: 'namespacedConfigMaps' }] },
|
|
216
|
+
[PVC]: { applyTo: [{ var: 'pvcs' }] },
|
|
217
|
+
[SERVICE_ACCOUNT]: { applyTo: [{ var: 'namespacedServiceNames' }] },
|
|
218
|
+
[SECRET]: {
|
|
219
|
+
applyTo: [
|
|
220
|
+
{ var: 'namespacedSecrets' },
|
|
221
|
+
{
|
|
222
|
+
var: 'imagePullNamespacedSecrets',
|
|
223
|
+
parsingFunc: (data) => {
|
|
224
|
+
return data.filter(secret => (secret._type === SECRET_TYPES.DOCKER || secret._type === SECRET_TYPES.DOCKER_JSON));
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
]
|
|
228
|
+
},
|
|
229
|
+
[NODE]: {
|
|
230
|
+
applyTo: [
|
|
231
|
+
{ var: 'allNodeObjects' },
|
|
232
|
+
{
|
|
233
|
+
var: 'allNodes',
|
|
234
|
+
parsingFunc: (data) => {
|
|
235
|
+
return data.map(node => node.id);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
]
|
|
239
|
+
},
|
|
240
|
+
[SERVICE]: {
|
|
241
|
+
applyTo: [
|
|
242
|
+
{ var: 'allServices' },
|
|
243
|
+
{
|
|
244
|
+
var: 'headlessServices',
|
|
245
|
+
parsingFunc: (data) => {
|
|
246
|
+
return data.filter(service => service.spec.clusterIP === 'None');
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
]
|
|
250
|
+
},
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
namespacedConfigMaps: [],
|
|
254
|
+
allNodes: null,
|
|
255
|
+
allNodeObjects: [],
|
|
256
|
+
namespacedSecrets: [],
|
|
257
|
+
imagePullNamespacedSecrets: [],
|
|
258
|
+
allServices: [],
|
|
259
|
+
headlessServices: [],
|
|
260
|
+
name: this.value?.metadata?.name || null,
|
|
261
|
+
pvcs: [],
|
|
262
|
+
namespacedServiceNames: [],
|
|
263
|
+
showTabs: false,
|
|
264
|
+
pullPolicyOptions: ['Always', 'IfNotPresent', 'Never'],
|
|
248
265
|
spec,
|
|
249
266
|
type,
|
|
250
|
-
servicesOwned:
|
|
251
|
-
servicesToRemove:
|
|
252
|
-
portsForServices:
|
|
267
|
+
servicesOwned: [],
|
|
268
|
+
servicesToRemove: [],
|
|
269
|
+
portsForServices: [],
|
|
253
270
|
isInitContainer,
|
|
254
271
|
container,
|
|
255
|
-
containerChange:
|
|
256
|
-
tabChange:
|
|
257
|
-
podFsGroup:
|
|
258
|
-
savePvcHookName:
|
|
259
|
-
tabWeightMap:
|
|
260
|
-
fvFormRuleSets:
|
|
272
|
+
containerChange: 0,
|
|
273
|
+
tabChange: 0,
|
|
274
|
+
podFsGroup: podTemplateSpec.securityContext?.fsGroup,
|
|
275
|
+
savePvcHookName: 'savePvcHook',
|
|
276
|
+
tabWeightMap: TAB_WEIGHT_MAP,
|
|
277
|
+
fvFormRuleSets: [{
|
|
261
278
|
path: 'image', rootObject: this.container, rules: ['required'], translationKey: 'workload.container.image'
|
|
262
279
|
}],
|
|
263
280
|
fvReportedValidationPaths: ['spec'],
|
|
264
|
-
|
|
265
|
-
|
|
281
|
+
isNamespaceNew: false,
|
|
266
282
|
};
|
|
267
283
|
},
|
|
268
284
|
|
|
269
285
|
computed: {
|
|
286
|
+
...mapGetters(['currentCluster']),
|
|
270
287
|
tabErrors() {
|
|
271
288
|
return { general: this.fvGetPathErrors(['image'])?.length > 0 };
|
|
272
289
|
},
|
|
273
290
|
|
|
291
|
+
defaultTab() {
|
|
292
|
+
if (!!this.$route.query.sidecar || this.$route.query.init || this.mode === _CREATE) {
|
|
293
|
+
return 'container-0';
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
return this.allContainers.length ? this.allContainers[0].name : '';
|
|
297
|
+
},
|
|
298
|
+
|
|
274
299
|
isEdit() {
|
|
275
300
|
return this.mode === _EDIT;
|
|
276
301
|
},
|
|
@@ -297,7 +322,7 @@ export default {
|
|
|
297
322
|
},
|
|
298
323
|
|
|
299
324
|
isPod() {
|
|
300
|
-
return this.value.type ===
|
|
325
|
+
return this.value.type === POD;
|
|
301
326
|
},
|
|
302
327
|
|
|
303
328
|
isStatefulSet() {
|
|
@@ -326,13 +351,13 @@ export default {
|
|
|
326
351
|
}
|
|
327
352
|
|
|
328
353
|
return this.spec.jobTemplate.metadata.labels;
|
|
329
|
-
}
|
|
330
|
-
if (!this.spec.template.metadata) {
|
|
331
|
-
this.$set(this.spec.template, 'metadata', { labels: {} });
|
|
332
|
-
}
|
|
354
|
+
}
|
|
333
355
|
|
|
334
|
-
|
|
356
|
+
if (!this.spec.template.metadata) {
|
|
357
|
+
this.$set(this.spec.template, 'metadata', { labels: {} });
|
|
335
358
|
}
|
|
359
|
+
|
|
360
|
+
return this.spec.template.metadata.labels;
|
|
336
361
|
},
|
|
337
362
|
set(neu) {
|
|
338
363
|
if (this.isCronJob) {
|
|
@@ -351,13 +376,12 @@ export default {
|
|
|
351
376
|
}
|
|
352
377
|
|
|
353
378
|
return this.spec.jobTemplate.metadata.annotations;
|
|
354
|
-
} else {
|
|
355
|
-
if (!this.spec.template.metadata) {
|
|
356
|
-
this.$set(this.spec.template, 'metadata', { annotations: {} });
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
return this.spec.template.metadata.annotations;
|
|
360
379
|
}
|
|
380
|
+
if (!this.spec.template.metadata) {
|
|
381
|
+
this.$set(this.spec.template, 'metadata', { annotations: {} });
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
return this.spec.template.metadata.annotations;
|
|
361
385
|
},
|
|
362
386
|
set(neu) {
|
|
363
387
|
if (this.isCronJob) {
|
|
@@ -467,55 +491,6 @@ export default {
|
|
|
467
491
|
return this.$store.getters['cluster/schemaFor'](this.type);
|
|
468
492
|
},
|
|
469
493
|
|
|
470
|
-
namespacedSecrets() {
|
|
471
|
-
const namespace = this.value?.metadata?.namespace;
|
|
472
|
-
|
|
473
|
-
if (namespace) {
|
|
474
|
-
return this.allSecrets.filter(
|
|
475
|
-
secret => secret.metadata.namespace === namespace
|
|
476
|
-
);
|
|
477
|
-
} else {
|
|
478
|
-
return this.allSecrets;
|
|
479
|
-
}
|
|
480
|
-
},
|
|
481
|
-
|
|
482
|
-
imagePullNamespacedSecrets() {
|
|
483
|
-
const namespace = this.value?.metadata?.namespace;
|
|
484
|
-
|
|
485
|
-
return this.allSecrets.filter(secret => secret.metadata.namespace === namespace && (secret._type === SECRET_TYPES.DOCKER || secret._type === SECRET_TYPES.DOCKER_JSON));
|
|
486
|
-
},
|
|
487
|
-
|
|
488
|
-
namespacedConfigMaps() {
|
|
489
|
-
const namespace = this.value?.metadata?.namespace;
|
|
490
|
-
|
|
491
|
-
if (namespace) {
|
|
492
|
-
return this.allConfigMaps.filter(
|
|
493
|
-
configMap => configMap.metadata.namespace === namespace
|
|
494
|
-
);
|
|
495
|
-
} else {
|
|
496
|
-
return this.allConfigMaps;
|
|
497
|
-
}
|
|
498
|
-
},
|
|
499
|
-
|
|
500
|
-
namespacedServiceNames() {
|
|
501
|
-
const { namespace } = this.value?.metadata;
|
|
502
|
-
|
|
503
|
-
if (namespace) {
|
|
504
|
-
return this.sas.filter(
|
|
505
|
-
serviceName => serviceName.metadata.namespace === namespace
|
|
506
|
-
);
|
|
507
|
-
} else {
|
|
508
|
-
return this.sas;
|
|
509
|
-
}
|
|
510
|
-
},
|
|
511
|
-
|
|
512
|
-
headlessServices() {
|
|
513
|
-
return this.allServices.filter(
|
|
514
|
-
service => service.spec.clusterIP === 'None' &&
|
|
515
|
-
service.metadata.namespace === this.value.metadata.namespace
|
|
516
|
-
);
|
|
517
|
-
},
|
|
518
|
-
|
|
519
494
|
workloadTypes() {
|
|
520
495
|
return omitBy(WORKLOAD_TYPES, (type) => {
|
|
521
496
|
return (
|
|
@@ -558,6 +533,25 @@ export default {
|
|
|
558
533
|
},
|
|
559
534
|
|
|
560
535
|
watch: {
|
|
536
|
+
async 'value.metadata.namespace'(neu) {
|
|
537
|
+
if (this.isNamespaceNew) {
|
|
538
|
+
// we don't need to re-fetch namespace specific (or non-namespace specific) resources when the namespace hasn't been created yet
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
541
|
+
this.secondaryResourceData.namespace = neu;
|
|
542
|
+
// Fetch resources that are namespace specific, we don't need to re-fetch non-namespaced resources on namespace change
|
|
543
|
+
this.resourceManagerFetchSecondaryResources(this.secondaryResourceData, true);
|
|
544
|
+
|
|
545
|
+
this.servicesOwned = await this.value.getServicesOwned();
|
|
546
|
+
},
|
|
547
|
+
|
|
548
|
+
isNamespaceNew(neu, old) {
|
|
549
|
+
if (!old && neu) {
|
|
550
|
+
// As the namespace is new any resource that's been fetched with a namespace is now invalid
|
|
551
|
+
this.resourceManagerClearSecondaryResources(this.secondaryResourceData, true);
|
|
552
|
+
}
|
|
553
|
+
},
|
|
554
|
+
|
|
561
555
|
type(neu, old) {
|
|
562
556
|
const template =
|
|
563
557
|
old === WORKLOAD_TYPES.CRON_JOB ? this.spec?.jobTemplate?.spec?.template : this.spec?.template;
|
|
@@ -689,6 +683,7 @@ export default {
|
|
|
689
683
|
template = this.spec.template;
|
|
690
684
|
}
|
|
691
685
|
|
|
686
|
+
// WORKLOADS
|
|
692
687
|
if (
|
|
693
688
|
this.type !== WORKLOAD_TYPES.JOB &&
|
|
694
689
|
this.type !== WORKLOAD_TYPES.CRON_JOB &&
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { PVC } from '@shell/config/types';
|
|
3
|
+
import ButtonDropdown from '@shell/components/ButtonDropdown';
|
|
4
|
+
import Mount from '@shell/edit/workload/storage/Mount';
|
|
5
|
+
import { _VIEW } from '@shell/config/query-params';
|
|
6
|
+
import ArrayListGrouped from '@shell/components/form/ArrayListGrouped';
|
|
7
|
+
import { randomStr } from '@shell/utils/string';
|
|
8
|
+
|
|
9
|
+
export default {
|
|
10
|
+
name: 'ContainerMountPaths',
|
|
11
|
+
components: {
|
|
12
|
+
ArrayListGrouped, ButtonDropdown, Mount
|
|
13
|
+
},
|
|
14
|
+
|
|
15
|
+
props: {
|
|
16
|
+
mode: {
|
|
17
|
+
type: String,
|
|
18
|
+
default: 'create',
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
// pod spec
|
|
22
|
+
value: {
|
|
23
|
+
type: Object,
|
|
24
|
+
default: () => {
|
|
25
|
+
return {};
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
container: {
|
|
30
|
+
type: Object,
|
|
31
|
+
default: () => {
|
|
32
|
+
return {};
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
async fetch() {
|
|
38
|
+
if ( this.$store.getters['cluster/schemaFor'](PVC) ) {
|
|
39
|
+
this.pvcs = await this.$store.dispatch('cluster/findAll', { type: PVC });
|
|
40
|
+
} else {
|
|
41
|
+
this.pvcs = [];
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
data() {
|
|
46
|
+
this.initializeStorage();
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
containerVolumes: [],
|
|
50
|
+
pvcs: [],
|
|
51
|
+
storageVolumes: this.getStorageVolumes(),
|
|
52
|
+
selectedContainerVolumes: this.getSelectedContainerVolumes()
|
|
53
|
+
};
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
computed: {
|
|
57
|
+
isView() {
|
|
58
|
+
return this.mode === _VIEW;
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
availableVolumeOptions() {
|
|
62
|
+
const containerVolumes = this.container.volumeMounts.map(item => item.name);
|
|
63
|
+
|
|
64
|
+
return this.value.volumes.filter(vol => !containerVolumes.includes(vol.name)).map((item) => {
|
|
65
|
+
return {
|
|
66
|
+
label: `${ item.name } (${ this.headerFor(item) })`,
|
|
67
|
+
action: this.selectVolume,
|
|
68
|
+
value: item.name
|
|
69
|
+
};
|
|
70
|
+
});
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
watch: {
|
|
75
|
+
value(neu, old) {
|
|
76
|
+
this.selectedVolumes = this.getSelectedContainerVolumes();
|
|
77
|
+
},
|
|
78
|
+
storageVolumes(neu, old) {
|
|
79
|
+
// removeObjects(this.value.volumes, old);
|
|
80
|
+
// addObjects(this.value.volumes, neu);
|
|
81
|
+
const names = neu.reduce((all, each) => {
|
|
82
|
+
all.push(each.name);
|
|
83
|
+
|
|
84
|
+
return all;
|
|
85
|
+
}, []);
|
|
86
|
+
|
|
87
|
+
this.container.volumeMounts = this.container.volumeMounts.filter(mount => names.includes(mount.name));
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
selectedContainerVolumes(neu, old) {
|
|
91
|
+
// removeObjects(this.value.volumes, old);
|
|
92
|
+
// addObjects(this.value.volumes, neu);
|
|
93
|
+
const names = neu.map(item => item.name);
|
|
94
|
+
|
|
95
|
+
this.container.volumeMounts = this.container.volumeMounts.filter(mount => names.includes(mount.name));
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
methods: {
|
|
101
|
+
/**
|
|
102
|
+
* Initialize missing values for the container
|
|
103
|
+
*/
|
|
104
|
+
initializeStorage() {
|
|
105
|
+
if (!this.container.volumeMounts) {
|
|
106
|
+
this.$set(this.container, 'volumeMounts', []);
|
|
107
|
+
}
|
|
108
|
+
if (!this.value.volumes) {
|
|
109
|
+
this.$set(this.value, 'volumes', []);
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Get existing paired storage volumes
|
|
115
|
+
*/
|
|
116
|
+
getStorageVolumes() {
|
|
117
|
+
// Extract volume mounts to map storage volumes
|
|
118
|
+
const { volumeMounts = [] } = this.container;
|
|
119
|
+
const names = volumeMounts.map(({ name }) => name);
|
|
120
|
+
|
|
121
|
+
// Extract storage volumes to allow mutation, if matches mount map
|
|
122
|
+
return this.value.volumes.filter(volume => names.includes(volume.name));
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
getSelectedContainerVolumes() {
|
|
126
|
+
// Extract volume mounts to map storage volumes
|
|
127
|
+
const { volumeMounts = [] } = this.container;
|
|
128
|
+
const names = volumeMounts.map(({ name }) => name);
|
|
129
|
+
|
|
130
|
+
// Extract storage volumes to allow mutation, if matches mount map
|
|
131
|
+
return this.value.volumes.filter(volume => names.includes(volume.name));
|
|
132
|
+
},
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Remove all mounts for given storage volume
|
|
136
|
+
*/
|
|
137
|
+
removeVolume(volume) {
|
|
138
|
+
const removeName = volume.row.value.name;
|
|
139
|
+
|
|
140
|
+
this.selectedContainerVolumes = this.selectedContainerVolumes.filter(({ name }) => name !== removeName);
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
selectVolume(event) {
|
|
144
|
+
const selectedVolume = this.value.volumes.find(vol => vol.name === event.value);
|
|
145
|
+
|
|
146
|
+
this.selectedContainerVolumes.push(selectedVolume);
|
|
147
|
+
|
|
148
|
+
const { name } = selectedVolume;
|
|
149
|
+
|
|
150
|
+
this.container.volumeMounts.push(name);
|
|
151
|
+
},
|
|
152
|
+
|
|
153
|
+
addVolume(type) {
|
|
154
|
+
const name = `vol-${ randomStr(5).toLowerCase() }`;
|
|
155
|
+
|
|
156
|
+
if (type === 'createPVC') {
|
|
157
|
+
this.storageVolumes.push({
|
|
158
|
+
_type: 'createPVC',
|
|
159
|
+
persistentVolumeClaim: {},
|
|
160
|
+
name,
|
|
161
|
+
});
|
|
162
|
+
} else if (type === 'csi') {
|
|
163
|
+
this.storageVolumes.push({
|
|
164
|
+
_type: type,
|
|
165
|
+
csi: { volumeAttributes: {} },
|
|
166
|
+
name,
|
|
167
|
+
});
|
|
168
|
+
} else {
|
|
169
|
+
this.storageVolumes.push({
|
|
170
|
+
_type: type,
|
|
171
|
+
[type]: {},
|
|
172
|
+
name,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
this.container.volumeMounts.push({ name });
|
|
177
|
+
},
|
|
178
|
+
|
|
179
|
+
headerFor(value) {
|
|
180
|
+
const type = Object.keys(value).filter(
|
|
181
|
+
key => typeof value[key] === 'object'
|
|
182
|
+
)[0];
|
|
183
|
+
|
|
184
|
+
if (
|
|
185
|
+
this.$store.getters['i18n/exists'](`workload.storage.subtypes.${ type }`)
|
|
186
|
+
) {
|
|
187
|
+
return this.t(`workload.storage.subtypes.${ type }`);
|
|
188
|
+
} else {
|
|
189
|
+
return type;
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
|
|
193
|
+
openPopover() {
|
|
194
|
+
const button = this.$refs.buttonDropdown;
|
|
195
|
+
|
|
196
|
+
try {
|
|
197
|
+
button.togglePopover();
|
|
198
|
+
} catch (e) {}
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
</script>
|
|
203
|
+
|
|
204
|
+
<template>
|
|
205
|
+
<div>
|
|
206
|
+
<!-- Storage Volumes -->
|
|
207
|
+
<ArrayListGrouped
|
|
208
|
+
:key="selectedContainerVolumes.length"
|
|
209
|
+
v-model="selectedContainerVolumes"
|
|
210
|
+
:mode="mode"
|
|
211
|
+
@remove="removeVolume"
|
|
212
|
+
>
|
|
213
|
+
<!-- Custom/default storage volume form -->
|
|
214
|
+
<template #default="props">
|
|
215
|
+
<h3>{{ props.row.value.name }} ({{ headerFor(props.row.value) }})</h3>
|
|
216
|
+
<Mount
|
|
217
|
+
:container="container"
|
|
218
|
+
:name="props.row.value.name"
|
|
219
|
+
:mode="mode"
|
|
220
|
+
/>
|
|
221
|
+
</template>
|
|
222
|
+
|
|
223
|
+
<!-- Add Storage Volume -->
|
|
224
|
+
<template #add>
|
|
225
|
+
<ButtonDropdown
|
|
226
|
+
v-if="!isView"
|
|
227
|
+
id="add-volume"
|
|
228
|
+
:button-label="t('workload.storage.selectVolume')"
|
|
229
|
+
:dropdown-options="availableVolumeOptions"
|
|
230
|
+
size="sm"
|
|
231
|
+
@click-action="e=>selectVolume(e)"
|
|
232
|
+
>
|
|
233
|
+
<template #no-options>
|
|
234
|
+
{{ t('workload.storage.noVolumes') }}
|
|
235
|
+
</template>
|
|
236
|
+
</ButtonDropdown>
|
|
237
|
+
</template>
|
|
238
|
+
</ArrayListGrouped>
|
|
239
|
+
</div>
|
|
240
|
+
</template>
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import { LabeledInput } from '@components/Form/LabeledInput';
|
|
3
|
+
import { Checkbox } from '@components/Form/Checkbox';
|
|
4
|
+
|
|
3
5
|
import { mapGetters } from 'vuex';
|
|
4
6
|
|
|
5
7
|
export default {
|
|
6
|
-
components: { LabeledInput },
|
|
8
|
+
components: { LabeledInput, Checkbox },
|
|
7
9
|
props: {
|
|
8
10
|
// volumeAttributes object
|
|
9
11
|
value: {
|
|
@@ -24,6 +26,23 @@ export default {
|
|
|
24
26
|
|
|
25
27
|
<template>
|
|
26
28
|
<div>
|
|
29
|
+
<div class="row mb-10">
|
|
30
|
+
<div class="col span-6">
|
|
31
|
+
<LabeledInput
|
|
32
|
+
v-model="value.name"
|
|
33
|
+
:required="true"
|
|
34
|
+
:mode="mode"
|
|
35
|
+
:label="t('workload.storage.volumeName')"
|
|
36
|
+
/>
|
|
37
|
+
</div>
|
|
38
|
+
<div class="col span-6">
|
|
39
|
+
<Checkbox
|
|
40
|
+
v-model="value.awsElasticBlockStore.readOnly"
|
|
41
|
+
:mode="mode"
|
|
42
|
+
:label="t('workload.storage.readOnly')"
|
|
43
|
+
/>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
27
46
|
<div class="row mb-10">
|
|
28
47
|
<div class="col span-6">
|
|
29
48
|
<LabeledInput
|