@rancher/shell 0.3.0 → 0.3.1
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/styles/global/_button.scss +5 -1
- package/assets/styles/global/_columns.scss +4 -0
- package/assets/styles/global/_layout.scss +1 -2
- package/assets/styles/global/_select.scss +1 -4
- package/assets/styles/themes/_dark.scss +4 -4
- package/assets/styles/themes/_light.scss +4 -3
- package/assets/styles/themes/_suse.scss +1 -1
- package/assets/styles/vendor/vue-select.scss +4 -3
- package/assets/translations/en-us.yaml +669 -73
- package/assets/translations/zh-hans.yaml +547 -165
- package/chart/monitoring/steps/uninstall-v1.vue +2 -2
- package/cloud-credential/azure.vue +23 -0
- package/cloud-credential/harvester.vue +25 -62
- package/cloud-credential/pnap.vue +80 -0
- package/components/.DS_Store +0 -0
- package/components/AdvancedSection.vue +9 -2
- package/components/Alert.vue +2 -2
- package/components/ButtonDropdown.vue +0 -2
- package/components/ButtonGroup.vue +1 -0
- package/components/CollapsibleCard.vue +0 -1
- package/components/CruResource.vue +41 -4
- package/components/DetailTop.vue +58 -3
- package/components/DisableAuthProviderModal.vue +106 -0
- package/{rancher-components/components/Utils/DraggableZone → components}/DraggableZone.vue +0 -0
- package/components/ExplorerMembers.vue +253 -30
- package/components/ExplorerProjectsNamespaces.vue +77 -33
- package/components/GrowlManager.vue +3 -3
- package/components/IconOrSvg.vue +149 -0
- package/components/LogItem.vue +69 -0
- package/components/PodSecurityAdmission.vue +302 -0
- package/components/PromptModal.vue +1 -0
- package/components/ResourceDetail/Masthead.vue +54 -2
- package/components/ResourceDetail/index.vue +12 -5
- package/components/ResourceList/Masthead.vue +11 -1
- package/components/ResourceList/ResourceLoadingIndicator.vue +12 -2
- package/components/ResourceList/index.vue +53 -12
- package/components/ResourceList/resource-list.config.js +7 -0
- package/components/ResourceTable.vue +31 -6
- package/components/SimpleBox.vue +1 -1
- package/components/SortableTable/THead.vue +15 -5
- package/components/SortableTable/index.vue +21 -10
- package/components/Tabbed/index.vue +20 -15
- package/components/__tests__/.DS_Store +0 -0
- package/components/__tests__/AsyncButton.test.ts +140 -0
- package/components/__tests__/BackLink.test.ts +33 -0
- package/components/__tests__/ButtonGroup.test.ts +124 -0
- package/components/__tests__/ClusterBadge.test.ts +32 -0
- package/components/__tests__/CollapsibleCard.test.ts +64 -0
- package/components/__tests__/ConsumptionGauge.test.ts +88 -0
- package/components/__tests__/CruResource.test.ts +3 -2
- package/components/__tests__/FixedBanner.test.ts +129 -0
- package/components/__tests__/GrowlManager.test.ts +147 -0
- package/components/__tests__/NamespaceFilter.test.ts +33 -25
- package/components/__tests__/PercentageBar.test.ts +32 -0
- package/components/__tests__/PodSecurityAdmission.test.ts +398 -0
- package/components/auth/AuthBanner.vue +20 -10
- package/components/auth/RoleDetailEdit.vue +26 -17
- package/components/auth/SelectPrincipal.vue +36 -5
- package/components/form/ArrayList.vue +3 -35
- package/components/form/ArrayListGrouped.vue +13 -4
- package/components/form/ArrayListSelect.vue +5 -5
- package/components/form/Error.vue +8 -0
- package/components/form/KeyValue.vue +39 -7
- package/components/form/LabeledSelect.vue +5 -2
- package/components/form/Labels.vue +46 -16
- package/components/form/Members/ClusterPermissionsEditor.vue +17 -17
- package/components/form/Members/MembershipEditor.vue +12 -12
- package/components/form/NameNsDescription.vue +1 -1
- package/components/form/NodeScheduling.vue +1 -1
- package/components/form/Probe.vue +3 -3
- package/components/form/ResourceQuota/Project.vue +6 -6
- package/components/form/ResourceTabs/index.vue +1 -6
- package/components/form/Security.vue +7 -6
- package/components/form/Select.vue +3 -2
- package/components/form/SelectOrCreateAuthSecret.vue +22 -29
- package/components/form/ServicePorts.vue +8 -0
- package/components/form/WorkloadPorts.vue +7 -1
- package/components/form/__tests__/ArrayList.test.ts +74 -0
- package/components/form/__tests__/ArrayListGrouped.test.ts +6 -4
- package/components/formatter/Checked.vue +1 -1
- package/components/formatter/ClusterLink.vue +5 -0
- package/components/formatter/IconIsDefault.vue +2 -2
- package/components/formatter/InternalExternalIP.vue +11 -8
- package/components/formatter/LiveDuration.vue +78 -0
- package/components/formatter/WorkloadHealthScale.vue +5 -3
- package/components/nav/Header.vue +6 -3
- package/components/nav/NamespaceFilter.vue +146 -63
- package/components/nav/TopLevelMenu.vue +22 -19
- package/components/nav/WindowManager/ContainerLogs.vue +83 -126
- package/components/nav/WindowManager/ContainerShell.vue +9 -7
- package/components/nav/WindowManager/Window.vue +2 -0
- package/components/nav/WindowManager/index.vue +10 -0
- package/config/elemental-types.js +9 -0
- package/config/features.js +2 -0
- package/config/home-links.js +4 -1
- package/config/pod-security-admission.ts +82 -0
- package/config/product/apps.js +1 -1
- package/config/product/auth.js +6 -5
- package/config/product/explorer.js +6 -6
- package/config/product/fleet.js +1 -1
- package/config/product/manager.js +6 -2
- package/config/secret.js +0 -1
- package/config/settings.ts +26 -9
- package/config/table-headers.js +22 -11
- package/config/types.js +4 -1
- package/content/docs/zh-hans/getting-started.md +113 -137
- package/content/docs/zh-hans/whats-new.md +8 -46
- package/creators/pkg/package-lock.json +37 -0
- package/creators/pkg/package.json +1 -1
- package/detail/catalog.cattle.io.app.vue +1 -1
- package/detail/pod.vue +1 -1
- package/detail/provisioning.cattle.io.cluster.vue +35 -9
- package/detail/service.vue +2 -9
- package/detail/workload/index.vue +0 -1
- package/dialog/AddClusterMemberDialog.vue +22 -28
- package/dialog/AddProjectMemberDialog.vue +53 -9
- package/dialog/DiagnosticTimingsDialog.vue +8 -7
- package/dialog/DrainNode.vue +44 -48
- package/dialog/ForceMachineRemoveDialog.vue +5 -7
- package/dialog/GenericPrompt.vue +15 -20
- package/dialog/RollbackWorkloadDialog.vue +15 -46
- package/dialog/RotateCertificatesDialog.vue +5 -7
- package/dialog/RotateEncryptionKeyDialog.vue +5 -9
- package/dialog/SaveAsRKETemplateDialog.vue +5 -13
- package/dialog/ScaleMachineDownDialog.vue +1 -1
- package/dialog/ScalePoolDownDialog.vue +121 -0
- package/edit/__tests__/management.cattle.io.setting.test.ts +3 -3
- package/edit/auth/azuread.vue +16 -16
- package/edit/auth/github.vue +8 -0
- package/edit/auth/googleoauth.vue +10 -1
- package/edit/auth/ldap/index.vue +10 -0
- package/edit/auth/oidc.vue +10 -0
- package/edit/auth/saml.vue +10 -0
- package/edit/autoscaling.horizontalpodautoscaler/index.vue +1 -1
- package/edit/cloudcredential.vue +3 -7
- package/edit/logging-flow/Match.vue +39 -8
- package/edit/logging-flow/index.vue +27 -4
- package/edit/management.cattle.io.podsecurityadmissionconfigurationtemplate.vue +107 -0
- package/edit/management.cattle.io.project.vue +8 -1
- package/edit/management.cattle.io.setting.vue +5 -2
- package/edit/management.cattle.io.user.vue +7 -1
- package/edit/monitoring.coreos.com.alertmanagerconfig/receiverConfig.vue +23 -7
- package/edit/monitoring.coreos.com.alertmanagerconfig/types/email.vue +2 -2
- package/edit/monitoring.coreos.com.prometheusrule/GroupRules.vue +14 -6
- package/edit/namespace.vue +18 -4
- package/edit/networking.k8s.io.ingress/Certificate.vue +1 -0
- package/edit/networking.k8s.io.ingress/IngressClass.vue +8 -6
- package/edit/networking.k8s.io.ingress/RulePath.vue +12 -6
- package/edit/networking.k8s.io.ingress/index.vue +8 -6
- package/edit/persistentvolume/index.vue +30 -27
- package/edit/persistentvolume/plugins/cephfs.vue +29 -29
- package/edit/persistentvolume/plugins/csi.vue +102 -62
- package/edit/persistentvolume/plugins/fc.vue +19 -19
- package/edit/persistentvolume/plugins/iscsi.vue +45 -45
- package/edit/persistentvolume/plugins/rbd.vue +39 -39
- package/edit/persistentvolumeclaim.vue +78 -75
- package/edit/provisioning.cattle.io.cluster/MachinePool.vue +11 -7
- package/edit/provisioning.cattle.io.cluster/RegistryConfigs.vue +10 -1
- package/edit/provisioning.cattle.io.cluster/RegistryMirrors.vue +87 -27
- package/edit/provisioning.cattle.io.cluster/SelectCredential.vue +3 -6
- package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +93 -0
- package/edit/provisioning.cattle.io.cluster/import.vue +1 -1
- package/edit/provisioning.cattle.io.cluster/index.vue +29 -6
- package/edit/provisioning.cattle.io.cluster/rke2.vue +440 -152
- package/edit/secret/index.vue +3 -7
- package/edit/service.vue +3 -1
- package/edit/storage.k8s.io.storageclass/index.vue +100 -16
- package/edit/storage.k8s.io.storageclass/provisioners/driver.harvesterhci.io.vue +114 -0
- package/edit/workload/__tests__/index.test.ts +98 -0
- package/edit/workload/index.vue +58 -8
- package/edit/workload/mixins/workload.js +107 -70
- package/edit/workload/storage/ContainerMountPaths.vue +0 -10
- package/edit/workload/storage/emptyDir.vue +88 -0
- package/edit/workload/storage/ephemeralVolume/index.vue +1 -1
- package/edit/workload/storage/index.vue +8 -0
- package/edit/workload/storage/persistentVolumeClaim/index.vue +1 -1
- package/layouts/default.vue +57 -44
- package/list/__tests__/workload.test.ts +5 -2
- package/list/catalog.cattle.io.app.vue +1 -0
- package/list/cis.cattle.io.clusterscan.vue +1 -0
- package/list/fleet.cattle.io.bundle.vue +5 -6
- package/list/fleet.cattle.io.cluster.vue +6 -3
- package/list/fleet.cattle.io.clusterregistrationtoken.vue +5 -6
- package/list/fleet.cattle.io.gitrepo.vue +4 -9
- package/list/helm.cattle.io.projecthelmchart.vue +1 -5
- package/list/logging.banzaicloud.io.clusterflow.vue +4 -1
- package/list/logging.banzaicloud.io.flow.vue +6 -5
- package/list/management.cattle.io.cluster.vue +1 -0
- package/list/management.cattle.io.feature.vue +3 -4
- package/list/management.cattle.io.podsecurityadmissionconfigurationtemplate.vue +47 -0
- package/list/management.cattle.io.setting.vue +2 -2
- package/list/management.cattle.io.user.vue +4 -10
- package/list/monitoring.coreos.com.alertmanagerconfig.vue +2 -7
- package/list/node.vue +8 -5
- package/list/persistentvolume.vue +3 -3
- package/list/persistentvolumeclaim.vue +3 -4
- package/list/provisioning.cattle.io.cluster.vue +18 -19
- package/list/service.vue +6 -14
- package/list/workload.vue +43 -38
- package/machine-config/azure.vue +429 -60
- package/machine-config/pnap.vue +288 -0
- package/mixins/auth-config.js +1 -3
- package/mixins/browser-tab-visibility.js +8 -14
- package/mixins/chart.js +1 -1
- package/mixins/create-edit-view/impl.js +4 -0
- package/mixins/create-edit-view/index.js +4 -2
- package/mixins/resource-fetch-namespaced.js +98 -0
- package/mixins/resource-fetch.js +79 -45
- package/mixins/resource-manager.js +1 -23
- package/models/apps.controllerrevision.js +7 -0
- package/models/apps.daemonset.js +18 -0
- package/models/apps.deployment.js +44 -0
- package/models/apps.replicaset.js +7 -0
- package/models/apps.statefulset.js +18 -0
- package/models/batch.job.js +7 -14
- package/models/cluster/node.js +10 -2
- package/models/cluster.x-k8s.io.machine.js +26 -4
- package/models/cluster.x-k8s.io.machinedeployment.js +12 -2
- package/models/event.js +7 -0
- package/models/logging.banzaicloud.io.flow.js +4 -0
- package/models/management.cattle.io.cluster.js +1 -1
- package/models/management.cattle.io.clusterroletemplatebinding.js +1 -1
- package/models/management.cattle.io.globalrole.js +2 -2
- package/models/management.cattle.io.node.js +37 -2
- package/models/management.cattle.io.podsecurityadmissionconfigurationtemplate.ts +4 -0
- package/models/management.cattle.io.project.js +30 -11
- package/models/management.cattle.io.setting.js +1 -1
- package/models/management.cattle.io.user.js +37 -1
- package/models/namespace.js +42 -5
- package/models/persistentvolume.js +14 -2
- package/models/pod.js +15 -0
- package/models/projectroletemplatebinding.js +7 -0
- package/models/provisioning.cattle.io.cluster.js +61 -10
- package/models/rke-machine.cattle.io.pnapmachinetemplate.js +15 -0
- package/models/service.js +14 -13
- package/models/storage.k8s.io.storageclass.js +33 -18
- package/models/workload.js +38 -7
- package/nuxt.config.js +27 -17
- package/package.json +7 -7
- package/pages/about.vue +14 -2
- package/pages/c/_cluster/apps/charts/index.vue +4 -3
- package/pages/c/_cluster/apps/charts/install.vue +59 -22
- package/pages/c/_cluster/auth/config/_id.vue +6 -0
- package/pages/c/_cluster/auth/config/index.vue +8 -6
- package/pages/c/_cluster/auth/group.principal/assign-edit.vue +1 -1
- package/pages/c/_cluster/auth/roles/index.vue +1 -1
- package/pages/c/_cluster/explorer/index.vue +12 -6
- package/pages/c/_cluster/longhorn/index.vue +1 -1
- package/pages/c/_cluster/monitoring/alertmanagerconfig/_alertmanagerconfigid/receiver.vue +15 -4
- package/pages/c/_cluster/monitoring/index.vue +1 -1
- package/pages/c/_cluster/neuvector/index.vue +1 -1
- package/pages/c/_cluster/settings/performance.vue +48 -2
- package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +34 -1
- package/pages/c/_cluster/uiplugins/index.vue +28 -2
- package/pages/diagnostic.vue +5 -4
- package/pages/home.vue +105 -30
- package/pages/prefs.vue +23 -12
- package/pages/rio/mesh.vue +1 -1
- package/pkg/dynamic-importer.lib.js +8 -0
- package/pkg/vue.config.js +4 -0
- package/plugins/dashboard-store/__tests__/mutations.spec.js +406 -0
- package/plugins/dashboard-store/actions.js +32 -25
- package/plugins/dashboard-store/getters.js +50 -33
- package/plugins/dashboard-store/mutations.js +134 -28
- package/plugins/dashboard-store/resource-class.js +21 -41
- package/plugins/steve/actions.js +30 -0
- package/plugins/steve/caches/resourceCache.js +60 -0
- package/plugins/steve/getters.js +44 -1
- package/plugins/steve/mutations.js +97 -36
- package/plugins/steve/resourceWatcher.js +277 -0
- package/plugins/steve/schema.utils.js +25 -0
- package/plugins/steve/subscribe.js +288 -115
- package/plugins/steve/worker/index.js +17 -0
- package/plugins/steve/worker/web-worker.advanced.js +302 -0
- package/plugins/steve/{web-worker.steve-sub-worker.js → worker/web-worker.basic.js} +3 -44
- package/rancher-components/Card/Card.vue +3 -3
- package/rancher-components/Form/TextArea/TextAreaAutoGrow.vue +1 -0
- package/rancher-components/StringList/StringList.test.ts +45 -420
- package/rancher-components/StringList/StringList.vue +1 -10
- package/rancher-components/components/Banner/Banner.test.ts +44 -0
- package/rancher-components/components/Banner/Banner.vue +129 -61
- package/rancher-components/components/Form/Checkbox/Checkbox.test.ts +13 -22
- package/rancher-components/components/Form/Checkbox/Checkbox.vue +8 -6
- package/rancher-components/components/Form/ToggleSwitch/ToggleSwitch.test.ts +9 -9
- package/rancher-components/components/LabeledTooltip/LabeledTooltip.vue +0 -1
- package/rancher-components/components/StringList/StringList.test.ts +7 -7
- package/rancher-components/components/StringList/StringList.vue +21 -15
- package/scripts/test-plugins-build.sh +8 -0
- package/static/loading-indicator.html +1 -1
- package/store/index.js +54 -3
- package/store/plugins.js +0 -17
- package/store/pnap.js +128 -0
- package/store/prefs.js +4 -2
- package/store/type-map.js +55 -13
- package/types/pod-security-admission.ts +36 -0
- package/types/shell/index.d.ts +496 -396
- package/utils/__tests__/object.test.ts +17 -1
- package/utils/__tests__/pod-security-admission.test.ts +61 -0
- package/utils/async.ts +36 -0
- package/utils/color.js +45 -0
- package/utils/crypto/browserHashUtils.js +18 -0
- package/utils/dynamic-importer.js +8 -0
- package/utils/install-redirect.js +1 -1
- package/utils/object.js +24 -0
- package/utils/pod-security-admission.ts +39 -0
- package/utils/socket.js +61 -24
- package/utils/string.js +2 -0
- package/utils/svg-filter.js +301 -0
- package/utils/time.js +49 -0
- package/utils/validators/cidr.js +4 -0
- package/utils/validators/formRules/__tests__/index.test.ts +23 -3
- package/utils/validators/formRules/index.ts +14 -0
- package/config/product/harvester-manager.js +0 -162
- package/edit/harvesterhci.io.management.cluster.vue +0 -153
- package/list/harvesterhci.io.management.cluster.vue +0 -241
- package/machine-config/harvester.vue +0 -693
- package/models/harvesterhci.io.management.cluster.js +0 -228
- package/pages/c/_cluster/harvesterManager/index.vue +0 -24
- package/rancher-components/Card/Card.test.ts +0 -39
- package/rancher-components/Utils/DraggableZone/DraggableZone.vue +0 -181
- package/rancher-components/Utils/DraggableZone/index.ts +0 -1
- package/rancher-components/components/Utils/DraggableZone/index.ts +0 -1
|
@@ -35,11 +35,7 @@ export default {
|
|
|
35
35
|
let url = schema.links.collection;
|
|
36
36
|
|
|
37
37
|
if (schema?.attributes?.namespaced && namespace) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
parts.splice(parts.length - 2, 0, `api`);
|
|
41
|
-
parts.splice(parts.length - 1, 0, `namespaces/${ namespace }`);
|
|
42
|
-
url = parts.join('/');
|
|
38
|
+
url = `${ url }/${ namespace }`;
|
|
43
39
|
} else if (onlyNamespaced) {
|
|
44
40
|
// Type isn't namespaced and we've been requested to only fetch namespaced types
|
|
45
41
|
return;
|
|
@@ -60,30 +56,12 @@ export default {
|
|
|
60
56
|
const status = hash[type].status;
|
|
61
57
|
// if it's namespaced, we get the data on 'items' prop, for non-namespaced it's 'data' prop...
|
|
62
58
|
const requestData = hash[type].value.items || hash[type].value.data || hash[type].value;
|
|
63
|
-
const schema = this.$store.getters['cluster/schemaFor'](type);
|
|
64
59
|
|
|
65
60
|
if (status === 'fulfilled' && resourceData.data[type] && resourceData.data[type].applyTo?.length) {
|
|
66
61
|
for (let y = 0; y < resourceData.data[type].applyTo.length; y++) {
|
|
67
62
|
const apply = resourceData.data[type].applyTo[y];
|
|
68
63
|
let resources = requestData;
|
|
69
64
|
|
|
70
|
-
if (schema?.attributes?.namespaced) {
|
|
71
|
-
// The resources returned when requesting namespaced types do not contain id, type and links properties.
|
|
72
|
-
// This isn't perfect, or universally applicable, but will work for the current set of use cases
|
|
73
|
-
// To make this more generic
|
|
74
|
-
// - id param = this.$store.getters['cluster/keyFieldForType'](type)
|
|
75
|
-
// - id value = new dashboard-store getter, overwritten by steve store getter
|
|
76
|
-
requestData.forEach((item) => {
|
|
77
|
-
// if there's already a prop type, don't overwrite it without storing it first...
|
|
78
|
-
// only do this operation once in multiple apply's because the requestData is the same!
|
|
79
|
-
if (item.type && !item._type) {
|
|
80
|
-
item._type = item.type;
|
|
81
|
-
}
|
|
82
|
-
item.type = type;
|
|
83
|
-
item.id = `${ item.metadata.namespace }/${ item.metadata.name }`;
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
|
|
87
65
|
if (apply.classify) {
|
|
88
66
|
resources = await this.$store.dispatch('cluster/createMany', requestData);
|
|
89
67
|
}
|
package/models/apps.daemonset.js
CHANGED
|
@@ -1,4 +1,22 @@
|
|
|
1
1
|
import Workload from './workload';
|
|
2
2
|
|
|
3
3
|
export default class DaemonSet extends Workload {
|
|
4
|
+
async rollBack(cluster, daemonSet, revision) {
|
|
5
|
+
const body = [
|
|
6
|
+
{
|
|
7
|
+
op: 'replace',
|
|
8
|
+
path: '/spec/template',
|
|
9
|
+
value: {
|
|
10
|
+
metadata: revision.data.spec.template.metadata,
|
|
11
|
+
spec: revision.data.spec.template.spec
|
|
12
|
+
}
|
|
13
|
+
}, {
|
|
14
|
+
op: 'replace',
|
|
15
|
+
path: '/metadata/generation',
|
|
16
|
+
value: revision.revision,
|
|
17
|
+
}
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
await this.rollBackWorkload(cluster, daemonSet, 'daemonsets', body);
|
|
21
|
+
}
|
|
4
22
|
}
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import { WORKLOAD_TYPES } from '@shell/config/types';
|
|
2
2
|
import Workload from './workload';
|
|
3
3
|
|
|
4
|
+
const IGNORED_ANNOTATIONS = [
|
|
5
|
+
'kubectl.kubernetes.io/last-applied-configuration',
|
|
6
|
+
'deployment.kubernetes.io/revision',
|
|
7
|
+
'deployment.kubernetes.io/revision-history',
|
|
8
|
+
'deployment.kubernetes.io/desired-replicas',
|
|
9
|
+
'deployment.kubernetes.io/max-replicas',
|
|
10
|
+
'deprecated.deployment.rollback.to',
|
|
11
|
+
];
|
|
12
|
+
|
|
4
13
|
export default class Deployment extends Workload {
|
|
5
14
|
get replicaSetId() {
|
|
6
15
|
const set = this.metadata?.relationships?.find((relationship) => {
|
|
@@ -10,4 +19,39 @@ export default class Deployment extends Workload {
|
|
|
10
19
|
|
|
11
20
|
return set?.toId?.replace(`${ this.namespace }/`, '');
|
|
12
21
|
}
|
|
22
|
+
|
|
23
|
+
async rollBack(cluster, deployment, revision) {
|
|
24
|
+
const body = [
|
|
25
|
+
{
|
|
26
|
+
op: 'replace',
|
|
27
|
+
path: '/spec/template',
|
|
28
|
+
value: {
|
|
29
|
+
metadata: {
|
|
30
|
+
creationTimestamp: null,
|
|
31
|
+
labels: Object.keys(revision.spec.template.metadata?.labels || {}).reduce((prev, key) => {
|
|
32
|
+
if (key !== 'pod-template-hash') {
|
|
33
|
+
prev[key] = revision.spec.template.metadata.labels[key];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return prev;
|
|
37
|
+
}, {}),
|
|
38
|
+
annotations: Object.keys(revision.spec.template.metadata?.annotations || {}).reduce((prev, key) => {
|
|
39
|
+
if (!IGNORED_ANNOTATIONS.includes(key)) {
|
|
40
|
+
prev[key] = revision.spec.template.metadata.annotations[key];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return prev;
|
|
44
|
+
}, {}),
|
|
45
|
+
},
|
|
46
|
+
spec: revision.spec.template.spec
|
|
47
|
+
}
|
|
48
|
+
}, {
|
|
49
|
+
op: 'replace',
|
|
50
|
+
path: '/metadata/annotations',
|
|
51
|
+
value: { 'deployment.kubernetes.io/revision': revision.metadata.annotations['deployment.kubernetes.io/revision'] }
|
|
52
|
+
}
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
await this.rollBackWorkload(cluster, deployment, 'deployments', body);
|
|
56
|
+
}
|
|
13
57
|
}
|
|
@@ -1,4 +1,22 @@
|
|
|
1
1
|
import Workload from './workload';
|
|
2
2
|
|
|
3
3
|
export default class StatefulSet extends Workload {
|
|
4
|
+
async rollBack(cluster, statefulSet, revision) {
|
|
5
|
+
const body = [
|
|
6
|
+
{
|
|
7
|
+
op: 'replace',
|
|
8
|
+
path: '/spec/template',
|
|
9
|
+
value: {
|
|
10
|
+
metadata: revision.data.spec.template.metadata,
|
|
11
|
+
spec: revision.data.spec.template.spec
|
|
12
|
+
}
|
|
13
|
+
}, {
|
|
14
|
+
op: 'replace',
|
|
15
|
+
path: '/metadata/generation',
|
|
16
|
+
value: revision.revision,
|
|
17
|
+
}
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
await this.rollBackWorkload(cluster, statefulSet, 'statefulsets', body);
|
|
21
|
+
}
|
|
4
22
|
}
|
package/models/batch.job.js
CHANGED
|
@@ -6,21 +6,14 @@ export default class Job extends Workload {
|
|
|
6
6
|
const schema = this.$getters['schemaFor'](this.type);
|
|
7
7
|
const rowValueGetter = this.$rootGetters['type-map/rowValueGetter'];
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
const value = rowValueGetter(schema, 'Duration')(this);
|
|
11
|
-
const { completionTime, startTime } = this.status;
|
|
12
|
-
let seconds = 0;
|
|
9
|
+
const { completionTime, startTime } = this.status;
|
|
13
10
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
11
|
+
const staticValue = schema && rowValueGetter ? rowValueGetter(schema, 'Duration')(this) : null;
|
|
12
|
+
const seconds = staticValue && startTime ? getSecondsDiff(startTime, completionTime || new Date()) : 0;
|
|
17
13
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
return {};
|
|
14
|
+
return {
|
|
15
|
+
value: completionTime ? { staticValue } : { startTime },
|
|
16
|
+
seconds,
|
|
17
|
+
};
|
|
25
18
|
}
|
|
26
19
|
}
|
package/models/cluster/node.js
CHANGED
|
@@ -201,7 +201,9 @@ export default class ClusterNode extends SteveModel {
|
|
|
201
201
|
}
|
|
202
202
|
|
|
203
203
|
get podConsumed() {
|
|
204
|
-
|
|
204
|
+
const runningPods = this.pods.filter(pod => pod.state === 'running');
|
|
205
|
+
|
|
206
|
+
return runningPods.length || 0;
|
|
205
207
|
}
|
|
206
208
|
|
|
207
209
|
get podRequests() {
|
|
@@ -310,7 +312,13 @@ export default class ClusterNode extends SteveModel {
|
|
|
310
312
|
}
|
|
311
313
|
|
|
312
314
|
drain(resources) {
|
|
313
|
-
this.$dispatch('promptModal', {
|
|
315
|
+
this.$dispatch('promptModal', {
|
|
316
|
+
component: 'DrainNode',
|
|
317
|
+
componentProps: {
|
|
318
|
+
kubeNodes: resources || [this],
|
|
319
|
+
normanNodeId: this.normanNodeId
|
|
320
|
+
}
|
|
321
|
+
});
|
|
314
322
|
}
|
|
315
323
|
|
|
316
324
|
async stopDrain(resources) {
|
|
@@ -114,8 +114,8 @@ export default class CapiMachine extends SteveModel {
|
|
|
114
114
|
|
|
115
115
|
toggleForceRemoveModal(resources = this) {
|
|
116
116
|
this.$dispatch('promptModal', {
|
|
117
|
-
resources,
|
|
118
|
-
component:
|
|
117
|
+
componentProps: { machine: resources },
|
|
118
|
+
component: 'ForceMachineRemoveDialog'
|
|
119
119
|
});
|
|
120
120
|
}
|
|
121
121
|
|
|
@@ -242,7 +242,29 @@ export default class CapiMachine extends SteveModel {
|
|
|
242
242
|
return this.status?.phase === 'Running';
|
|
243
243
|
}
|
|
244
244
|
|
|
245
|
-
get
|
|
246
|
-
|
|
245
|
+
get internalIp() {
|
|
246
|
+
// This shows in the IP address column for RKE2 nodes in the
|
|
247
|
+
// list of nodes in the cluster detail page of Cluster Management.
|
|
248
|
+
const internal = this.status?.addresses?.find(({ type }) => {
|
|
249
|
+
return type === ADDRESSES.INTERNAL_IP;
|
|
250
|
+
})?.address;
|
|
251
|
+
|
|
252
|
+
if (internal) {
|
|
253
|
+
return internal;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return this.t('generic.none');
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
get externalIp() {
|
|
260
|
+
const external = this.status?.addresses?.find(({ type }) => {
|
|
261
|
+
return type === ADDRESSES.EXTERNAL_IP;
|
|
262
|
+
})?.address;
|
|
263
|
+
|
|
264
|
+
if (external) {
|
|
265
|
+
return external;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
return this.t('generic.none');
|
|
247
269
|
}
|
|
248
270
|
}
|
|
@@ -6,6 +6,7 @@ import { exceptionToErrorsArray } from '@shell/utils/error';
|
|
|
6
6
|
import { handleConflict } from '@shell/plugins/dashboard-store/normalize';
|
|
7
7
|
import { MACHINE_ROLES } from '@shell/config/labels-annotations';
|
|
8
8
|
import { notOnlyOfRole } from '@shell/models/cluster.x-k8s.io.machine';
|
|
9
|
+
import { KIND } from '../config/elemental-types';
|
|
9
10
|
|
|
10
11
|
export default class CapiMachineDeployment extends SteveModel {
|
|
11
12
|
get cluster() {
|
|
@@ -34,6 +35,10 @@ export default class CapiMachineDeployment extends SteveModel {
|
|
|
34
35
|
return `${ this.$rootGetters['i18n/t']('resourceTable.groupLabel.machinePool', { name: escapeHtml(this.nameDisplay) }) }`;
|
|
35
36
|
}
|
|
36
37
|
|
|
38
|
+
get infrastructureRefKind() {
|
|
39
|
+
return this.spec?.template?.spec?.infrastructureRef?.kind;
|
|
40
|
+
}
|
|
41
|
+
|
|
37
42
|
get templateType() {
|
|
38
43
|
return this.spec.template.spec.infrastructureRef.kind ? `rke-machine.cattle.io.${ this.spec.template.spec.infrastructureRef.kind.toLowerCase() }` : null;
|
|
39
44
|
}
|
|
@@ -94,7 +99,7 @@ export default class CapiMachineDeployment extends SteveModel {
|
|
|
94
99
|
|
|
95
100
|
// use this pool's definition in the cluster's rkeConfig to scale, not this.spec.replicas
|
|
96
101
|
get inClusterSpec() {
|
|
97
|
-
const machineConfigName = this.template
|
|
102
|
+
const machineConfigName = this.template?.metadata?.annotations['rke.cattle.io/cloned-from-name'];
|
|
98
103
|
const machinePools = this.cluster.spec.rkeConfig.machinePools;
|
|
99
104
|
|
|
100
105
|
return machinePools.find(pool => pool.machineConfigRef.name === machineConfigName);
|
|
@@ -147,7 +152,7 @@ export default class CapiMachineDeployment extends SteveModel {
|
|
|
147
152
|
|
|
148
153
|
// prevent scaling pool to 0 if it would scale down the only etcd or control plane node
|
|
149
154
|
canScaleDownPool() {
|
|
150
|
-
if (!this.canUpdate || this.inClusterSpec?.quantity === 0) {
|
|
155
|
+
if (!this.canUpdate || this.inClusterSpec?.quantity === 0 || this.infrastructureRefKind === KIND.MACHINE_INV_SELECTOR_TEMPLATES) {
|
|
151
156
|
return false;
|
|
152
157
|
}
|
|
153
158
|
|
|
@@ -159,7 +164,12 @@ export default class CapiMachineDeployment extends SteveModel {
|
|
|
159
164
|
return notOnlyOfRole(this, this.cluster.machines);
|
|
160
165
|
}
|
|
161
166
|
|
|
167
|
+
// prevent scaling up pool for Elemental machines
|
|
162
168
|
canScaleUpPool() {
|
|
169
|
+
if (this.infrastructureRefKind === KIND.MACHINE_INV_SELECTOR_TEMPLATES) {
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
|
|
163
173
|
return true;
|
|
164
174
|
}
|
|
165
175
|
|
package/models/event.js
CHANGED
|
@@ -24,4 +24,11 @@ export default class K8sEvent extends SteveModel {
|
|
|
24
24
|
get eventType() {
|
|
25
25
|
return this._type;
|
|
26
26
|
}
|
|
27
|
+
|
|
28
|
+
get lastSeen() {
|
|
29
|
+
const schema = this.$getters['schemaFor'](this.type);
|
|
30
|
+
const rowValueGetter = this.$rootGetters['type-map/rowValueGetter'];
|
|
31
|
+
|
|
32
|
+
return schema && rowValueGetter ? rowValueGetter(schema, 'Last Seen')(this) : null;
|
|
33
|
+
}
|
|
27
34
|
}
|
|
@@ -9,7 +9,7 @@ import jsyaml from 'js-yaml';
|
|
|
9
9
|
import { eachLimit } from '@shell/utils/promise';
|
|
10
10
|
import { addParams } from '@shell/utils/url';
|
|
11
11
|
import { isEmpty } from '@shell/utils/object';
|
|
12
|
-
import { HARVESTER_NAME as HARVESTER } from '@shell/config/
|
|
12
|
+
import { HARVESTER_NAME as HARVESTER } from '@shell/config/features';
|
|
13
13
|
import { isHarvesterCluster } from '@shell/utils/cluster';
|
|
14
14
|
import HybridModel from '@shell/plugins/steve/hybrid-class';
|
|
15
15
|
import { LINUX, WINDOWS } from '@shell/store/catalog';
|
|
@@ -2,7 +2,7 @@ import { CREATOR_ID } from '@shell/config/labels-annotations';
|
|
|
2
2
|
import { _CREATE } from '@shell/config/query-params';
|
|
3
3
|
import { MANAGEMENT, NORMAN } from '@shell/config/types';
|
|
4
4
|
import HybridModel from '@shell/plugins/steve/hybrid-class';
|
|
5
|
-
import { HARVESTER_NAME } from '@shell/config/
|
|
5
|
+
import { HARVESTER_NAME } from '@shell/config/features';
|
|
6
6
|
|
|
7
7
|
export default class CRTB extends HybridModel {
|
|
8
8
|
detailPageHeaderActionOverride(realMode) {
|
|
@@ -3,7 +3,7 @@ import { SCHEMA, NORMAN } from '@shell/config/types';
|
|
|
3
3
|
import { CATTLE_API_GROUP, SUBTYPE_MAPPING, CREATE_VERBS } from '@shell/models/management.cattle.io.roletemplate';
|
|
4
4
|
import { uniq } from '@shell/utils/array';
|
|
5
5
|
import { get } from '@shell/utils/object';
|
|
6
|
-
import
|
|
6
|
+
import SteveDescriptionModel from '@shell/plugins/steve/steve-description-class';
|
|
7
7
|
import Role from './rbac.authorization.k8s.io.role';
|
|
8
8
|
import { AS, MODE, _CLONE, _UNFLAG } from '@shell/config/query-params';
|
|
9
9
|
|
|
@@ -14,7 +14,7 @@ const SPECIAL = [BASE, ADMIN, USER];
|
|
|
14
14
|
|
|
15
15
|
const GLOBAL = SUBTYPE_MAPPING.GLOBAL.key;
|
|
16
16
|
|
|
17
|
-
export default class GlobalRole extends
|
|
17
|
+
export default class GlobalRole extends SteveDescriptionModel {
|
|
18
18
|
get customValidationRules() {
|
|
19
19
|
return Role.customValidationRules();
|
|
20
20
|
}
|
|
@@ -6,6 +6,7 @@ import { NAME as EXPLORER } from '@shell/config/product/explorer';
|
|
|
6
6
|
import { listNodeRoles } from '@shell/models/cluster/node';
|
|
7
7
|
import { insertAt } from '@shell/utils/array';
|
|
8
8
|
import { downloadUrl } from '@shell/utils/download';
|
|
9
|
+
import findLast from 'lodash/findLast';
|
|
9
10
|
import HybridModel from '@shell/plugins/steve/hybrid-class';
|
|
10
11
|
|
|
11
12
|
export default class MgmtNode extends HybridModel {
|
|
@@ -124,8 +125,42 @@ export default class MgmtNode extends HybridModel {
|
|
|
124
125
|
return false;
|
|
125
126
|
}
|
|
126
127
|
|
|
127
|
-
get
|
|
128
|
-
|
|
128
|
+
get internalIp() {
|
|
129
|
+
// This shows in the IP address column for RKE1 nodes in the
|
|
130
|
+
// list of nodes in the cluster detail page of Cluster Management.
|
|
131
|
+
|
|
132
|
+
const internal = this.status?.addresses?.find(({ type }) => {
|
|
133
|
+
return type === ADDRESSES.INTERNAL_IP;
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
if (internal) {
|
|
137
|
+
return internal.address;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// For RKE1 clusters in EC2, node addresses are
|
|
141
|
+
// under status.rkeNode.address and status.rkeNode.internalAddress
|
|
142
|
+
if (!internal && this.status.rkeNode) {
|
|
143
|
+
return this.status.rkeNode.internalAddress;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return this.t('generic.none');
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
get externalIp() {
|
|
150
|
+
const addresses = this.status?.addresses || [];
|
|
151
|
+
const statusAddress = findLast(addresses, address => address.type === 'ExternalIP')?.address;
|
|
152
|
+
|
|
153
|
+
if (statusAddress) {
|
|
154
|
+
return statusAddress;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// For RKE1 clusters in EC2, node addresses are
|
|
158
|
+
// under status.rkeNode.address and status.rkeNode.internalAddress
|
|
159
|
+
if (!statusAddress && this.status.rkeNode) {
|
|
160
|
+
return this.status.rkeNode.address;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return this.t('generic.none');
|
|
129
164
|
}
|
|
130
165
|
|
|
131
166
|
get canScaleDown() {
|
|
@@ -2,7 +2,7 @@ import { DEFAULT_PROJECT, SYSTEM_PROJECT } from '@shell/config/labels-annotation
|
|
|
2
2
|
import { MANAGEMENT, NAMESPACE, NORMAN } from '@shell/config/types';
|
|
3
3
|
import HybridModel from '@shell/plugins/steve/hybrid-class';
|
|
4
4
|
import isEmpty from 'lodash/isEmpty';
|
|
5
|
-
import { HARVESTER_NAME as HARVESTER } from '@shell/config/
|
|
5
|
+
import { HARVESTER_NAME as HARVESTER } from '@shell/config/features';
|
|
6
6
|
|
|
7
7
|
function clearUnusedResourceQuotas(spec, types) {
|
|
8
8
|
types.forEach((type) => {
|
|
@@ -99,18 +99,36 @@ export default class Project extends HybridModel {
|
|
|
99
99
|
// and the PUT request should have a query param _replace=true.
|
|
100
100
|
const newValue = await norman.save({ replace: forceReplaceOnReq });
|
|
101
101
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
// The backend updates each new project soon after it is created,
|
|
107
|
-
// so there is a chance of a resource conflict or forbidden error. If that happens,
|
|
108
|
-
// retry the action.
|
|
102
|
+
let retryCount = 0;
|
|
103
|
+
|
|
104
|
+
const finishProjectCreation = async() => {
|
|
105
|
+
try {
|
|
109
106
|
await newValue.doAction('setpodsecuritypolicytemplate', { podSecurityPolicyTemplateId: this.spec.podSecurityPolicyTemplateId || null });
|
|
110
|
-
}
|
|
111
|
-
|
|
107
|
+
} catch (err) {
|
|
108
|
+
if ( err.status === 409 || err.status === 403 ) {
|
|
109
|
+
// The backend updates each new project soon after it is created,
|
|
110
|
+
// so there is a chance of a 409 resource conflict or forbidden error. If that happens,
|
|
111
|
+
// retry the action.
|
|
112
|
+
|
|
113
|
+
// The 403 permission error can happen due to the user requesting
|
|
114
|
+
// the project before the project is fully created and the project
|
|
115
|
+
// permissions are assigned to the user so we allow some
|
|
116
|
+
// time for that process to complete.
|
|
117
|
+
|
|
118
|
+
if (retryCount < 3) {
|
|
119
|
+
retryCount++;
|
|
120
|
+
await setTimeout(() => {
|
|
121
|
+
// Delay for three seconds to avoid another failure due to latency.
|
|
122
|
+
finishProjectCreation();
|
|
123
|
+
}, '3000');
|
|
124
|
+
} else {
|
|
125
|
+
throw err;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
112
128
|
}
|
|
113
|
-
}
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
await finishProjectCreation();
|
|
114
132
|
|
|
115
133
|
return newValue;
|
|
116
134
|
}
|
|
@@ -163,6 +181,7 @@ export default class Project extends HybridModel {
|
|
|
163
181
|
normanProject.setLabels(this.metadata.labels);
|
|
164
182
|
normanProject.setResourceQuotas(clearedResourceQuotas);
|
|
165
183
|
normanProject.description = this.spec.description;
|
|
184
|
+
normanProject.name = this.spec.displayName;
|
|
166
185
|
normanProject.containerDefaultResourceLimit = this.spec.containerDefaultResourceLimit;
|
|
167
186
|
|
|
168
187
|
return normanProject;
|
|
@@ -1,7 +1,25 @@
|
|
|
1
1
|
import { NORMAN } from '@shell/config/types';
|
|
2
|
-
import HybridModel from '@shell/plugins/steve/hybrid-class';
|
|
2
|
+
import HybridModel, { cleanHybridResources } from '@shell/plugins/steve/hybrid-class';
|
|
3
3
|
|
|
4
4
|
export default class User extends HybridModel {
|
|
5
|
+
// Preserve description
|
|
6
|
+
constructor(data, ctx, rehydrateNamespace = null, setClone = false) {
|
|
7
|
+
const _description = data.description;
|
|
8
|
+
|
|
9
|
+
super(data, ctx, rehydrateNamespace, setClone);
|
|
10
|
+
this.description = _description;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Clean the Norman properties, but keep description
|
|
14
|
+
cleanResource(data) {
|
|
15
|
+
const desc = data.description;
|
|
16
|
+
const clean = cleanHybridResources(data);
|
|
17
|
+
|
|
18
|
+
clean._description = desc;
|
|
19
|
+
|
|
20
|
+
return clean;
|
|
21
|
+
}
|
|
22
|
+
|
|
5
23
|
get isSystem() {
|
|
6
24
|
for ( const p of this.principalIds || [] ) {
|
|
7
25
|
if ( p.startsWith('system://') ) {
|
|
@@ -89,6 +107,24 @@ export default class User extends HybridModel {
|
|
|
89
107
|
return this.metadata?.state?.name || 'unknown';
|
|
90
108
|
}
|
|
91
109
|
|
|
110
|
+
get description() {
|
|
111
|
+
return this._description;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
set description(value) {
|
|
115
|
+
this._description = value;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Ensure when we clone that we preserve the description
|
|
119
|
+
toJSON() {
|
|
120
|
+
const data = super.toJSON();
|
|
121
|
+
|
|
122
|
+
data.description = this._description;
|
|
123
|
+
delete data._description;
|
|
124
|
+
|
|
125
|
+
return data;
|
|
126
|
+
}
|
|
127
|
+
|
|
92
128
|
async save(opt) {
|
|
93
129
|
const clone = await this.$dispatch('clone', { resource: this });
|
|
94
130
|
|
package/models/namespace.js
CHANGED
|
@@ -9,7 +9,9 @@ import { escapeHtml } from '@shell/utils/string';
|
|
|
9
9
|
import { insertAt, isArray } from '@shell/utils/array';
|
|
10
10
|
import SteveModel from '@shell/plugins/steve/steve-class';
|
|
11
11
|
import Vue from 'vue';
|
|
12
|
-
import { HARVESTER_NAME as HARVESTER } from '@shell/config/
|
|
12
|
+
import { HARVESTER_NAME as HARVESTER } from '@shell/config/features';
|
|
13
|
+
import { hasPSALabels, getPSATooltipsDescription, getPSALabels } from '@shell/utils/pod-security-admission';
|
|
14
|
+
import { PSAIconsDisplay, PSALabelsNamespaceVersion } from '@shell/config/pod-security-admission';
|
|
13
15
|
|
|
14
16
|
const OBSCURE_NAMESPACE_PREFIX = [
|
|
15
17
|
'c-', // cluster namespace
|
|
@@ -185,11 +187,10 @@ export default class Namespace extends SteveModel {
|
|
|
185
187
|
}
|
|
186
188
|
|
|
187
189
|
get _detailLocation() {
|
|
188
|
-
|
|
190
|
+
let _detailLocation = super._detailLocation;
|
|
189
191
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
_detailLocation.name = `${ HARVESTER }-${ _detailLocation.name }`.replace('-product', '');
|
|
192
|
+
if (this.$rootGetters['currentProduct'].hideNamespaceLocation) {
|
|
193
|
+
_detailLocation = false;
|
|
193
194
|
}
|
|
194
195
|
|
|
195
196
|
return _detailLocation;
|
|
@@ -211,6 +212,42 @@ export default class Namespace extends SteveModel {
|
|
|
211
212
|
Vue.set(this.metadata.annotations, RESOURCE_QUOTA, JSON.stringify(value));
|
|
212
213
|
}
|
|
213
214
|
|
|
215
|
+
get detailTopTooltips() {
|
|
216
|
+
return this.psaTooltipsDescription;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
get detailTopIcons() {
|
|
220
|
+
return PSAIconsDisplay;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Check if resource contains PSA labels
|
|
225
|
+
*/
|
|
226
|
+
get hasSystemLabels() {
|
|
227
|
+
return hasPSALabels(this);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
get filteredSystemLabels() {
|
|
231
|
+
return Object.entries(this.labels).reduce((res, [key, value]) => {
|
|
232
|
+
if (!PSALabelsNamespaceVersion.includes(key)) {
|
|
233
|
+
res[key] = value;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return res;
|
|
237
|
+
}, {});
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Generate list of present keys which can be filtered based on existing label keys and system keys
|
|
242
|
+
*/
|
|
243
|
+
get systemLabels() {
|
|
244
|
+
return getPSALabels(this);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
get psaTooltipsDescription() {
|
|
248
|
+
return getPSATooltipsDescription(this);
|
|
249
|
+
}
|
|
250
|
+
|
|
214
251
|
// Preserve the project label - ensures we preserve project when cloning a namespace
|
|
215
252
|
cleanForNew() {
|
|
216
253
|
const project = this.metadata?.labels?.[PROJECT];
|
|
@@ -112,10 +112,22 @@ export const LONGHORN_DRIVER = 'driver.longhorn.io';
|
|
|
112
112
|
export const LONGHORN_PLUGIN = VOLUME_PLUGINS.find(plugin => plugin.value === 'longhorn');
|
|
113
113
|
|
|
114
114
|
export default class PV extends SteveModel {
|
|
115
|
+
// plugin display value table
|
|
115
116
|
get source() {
|
|
116
|
-
const
|
|
117
|
+
const csiDriver = this.spec?.csi?.driver;
|
|
118
|
+
const fallback = `${ csiDriver } ${ this.t('persistentVolume.csi.drivers.suffix') }`;
|
|
117
119
|
|
|
118
|
-
|
|
120
|
+
if (csiDriver) {
|
|
121
|
+
return this.$rootGetters['i18n/withFallback'](`persistentVolume.csi.drivers.${ csiDriver.replaceAll('.', '-') }`, null, fallback);
|
|
122
|
+
}
|
|
123
|
+
const pluginDef = VOLUME_PLUGINS.find(plugin => this.spec[plugin.value]);
|
|
124
|
+
|
|
125
|
+
if (pluginDef) {
|
|
126
|
+
return this.t(pluginDef.labelKey);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// every source should be a csi driver or listed in VOLUME_PLUGIN but just in case..
|
|
130
|
+
return this.t('generic.unknown');
|
|
119
131
|
}
|
|
120
132
|
|
|
121
133
|
get isLonghorn() {
|