@rancher/shell 3.0.12-rc.4 → 3.0.12-rc.5
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 +1 -1
- package/assets/translations/en-us.yaml +39 -10
- package/components/ActionDropdownShell.vue +5 -3
- package/components/ButtonGroup.vue +26 -1
- package/components/CruResource.vue +51 -2
- package/components/PromptRestore.vue +93 -32
- package/components/Questions/index.vue +1 -0
- package/components/ResourceTable.vue +1 -0
- package/components/SortableTable/index.vue +4 -3
- package/components/Wizard.vue +14 -1
- package/components/__tests__/ButtonGroup.test.ts +56 -0
- package/components/__tests__/PromptRestore.test.ts +169 -19
- package/components/fleet/GitRepoAdvancedTab.vue +1 -0
- package/components/fleet/GitRepoMetadataTab.vue +5 -0
- package/components/fleet/HelmOpAppCoConfigTab.vue +4 -0
- package/components/fleet/HelmOpMetadataTab.vue +5 -0
- package/components/form/FileSelector.vue +39 -1
- package/components/form/PrivateRegistry.constants.ts +7 -0
- package/components/form/PrivateRegistry.vue +253 -18
- package/components/form/SelectOrCreateAuthSecret.vue +140 -17
- package/components/form/__tests__/FileSelector.test.ts +23 -0
- package/components/form/__tests__/PrivateRegistry.test.ts +463 -73
- package/components/form/__tests__/SelectOrCreateAuthSecret.test.ts +122 -0
- package/components/formatter/EtcdSnapshotName.vue +73 -0
- package/components/nav/Header.vue +8 -1
- package/components/templates/default.vue +7 -0
- package/config/features.js +1 -0
- package/config/labels-annotations.js +2 -0
- package/config/product/manager.js +6 -0
- package/config/secret.ts +10 -0
- package/config/settings.ts +6 -2
- package/config/types.js +7 -0
- package/detail/provisioning.cattle.io.cluster.vue +79 -3
- package/dialog/RotateEncryptionKeyDialog.vue +33 -9
- package/dialog/__tests__/RotateEncryptionKeyDialog.test.ts +78 -0
- package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +92 -0
- package/edit/__tests__/fleet.cattle.io.helmop.test.ts +101 -0
- package/edit/__tests__/management.cattle.io.setting.test.ts +2 -1
- package/edit/compliance.cattle.io.clusterscanprofile.vue +39 -41
- package/edit/fleet.cattle.io.gitrepo.vue +70 -16
- package/edit/fleet.cattle.io.helmop.vue +51 -5
- package/edit/helm.cattle.io.projecthelmchart.vue +1 -0
- package/edit/{management.cattle.io.setting.vue → management.cattle.io.setting/index.vue} +32 -9
- package/edit/management.cattle.io.setting/system-default-registry-pull-secrets.vue +81 -0
- package/edit/provisioning.cattle.io.cluster/SelectCredential.vue +3 -12
- package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +18 -0
- package/edit/provisioning.cattle.io.cluster/rke2.vue +5 -1
- package/edit/provisioning.cattle.io.cluster/tabs/etcd/index.vue +0 -1
- package/edit/provisioning.cattle.io.cluster/tabs/registries/index.vue +14 -55
- package/models/__tests__/provisioning.cattle.io.cluster.test.ts +156 -0
- package/models/__tests__/secret.test.ts +68 -1
- package/models/management.cattle.io.cluster.js +21 -3
- package/models/pod.js +13 -2
- package/models/provisioning.cattle.io.cluster.js +59 -9
- package/models/rke.cattle.io.etcdsnapshot.js +17 -9
- package/models/secret.js +19 -0
- package/models/workload.js +12 -7
- package/package.json +1 -1
- package/pages/c/_cluster/apps/charts/__tests__/install.test.ts +485 -107
- package/pages/c/_cluster/apps/charts/install.vue +114 -28
- package/pkg/require-asset.lib.js +25 -0
- package/pkg/vue.config.js +7 -0
- package/plugins/dashboard-store/__tests__/resource-class.test.ts +84 -0
- package/plugins/dashboard-store/getters.js +0 -1
- package/plugins/dashboard-store/resource-class.js +52 -12
- package/rancher-components/Form/TextArea/TextAreaAutoGrow.vue +30 -0
- package/rancher-components/Form/TextArea/__tests__/TextAreaAutoGrow.test.ts +95 -0
- package/rancher-components/RcButton/index.ts +1 -1
- package/rancher-components/RcDropdown/RcDropdownTrigger.vue +6 -1
- package/store/__tests__/features.test.ts +131 -0
- package/store/__tests__/growl.test.ts +374 -0
- package/store/__tests__/modal.test.ts +131 -0
- package/store/__tests__/slideInPanel.test.ts +88 -0
- package/store/__tests__/type-map.utils.test.ts +433 -0
- package/store/features.js +4 -0
- package/types/shell/index.d.ts +62 -0
- package/utils/__tests__/operation-cr.test.ts +34 -0
- package/utils/operation-cr.js +19 -0
- package/utils/require-asset.ts +7 -0
- package/utils/validators/__tests__/private-registry.test.ts +27 -15
- package/utils/validators/private-registry.ts +15 -4
|
@@ -72,6 +72,7 @@ generic:
|
|
|
72
72
|
warning: Warning
|
|
73
73
|
error: Error
|
|
74
74
|
ok: OK
|
|
75
|
+
or: or
|
|
75
76
|
other: |-
|
|
76
77
|
{count, plural,
|
|
77
78
|
one {other}
|
|
@@ -1007,6 +1008,7 @@ asyncButton:
|
|
|
1007
1008
|
action: Snapshot Now
|
|
1008
1009
|
waiting: Snapshot Initiated…
|
|
1009
1010
|
success: Snapshot Creating
|
|
1011
|
+
day2OpsNotEnabled: Day 2 Operations are not enabled for this cluster
|
|
1010
1012
|
timing:
|
|
1011
1013
|
action: Generate Response Times
|
|
1012
1014
|
waiting: Generating…
|
|
@@ -1138,9 +1140,15 @@ catalog:
|
|
|
1138
1140
|
label: Container Registry
|
|
1139
1141
|
tooltip: Container images are pulled from the Cluster Container Registry or, failing that, the System Container Registry Setting. To change this default behavior enter or update the registry here
|
|
1140
1142
|
custom:
|
|
1141
|
-
checkBoxLabel:
|
|
1143
|
+
checkBoxLabel: Override the Default Container Registry
|
|
1142
1144
|
inputLabel: Container Registry
|
|
1143
1145
|
placeholder: Registry domain and ports, ex. registry.io:5000
|
|
1146
|
+
pullSecret:
|
|
1147
|
+
skipOption: Do not use image pull secrets
|
|
1148
|
+
defaultLabel: 'Use default pull secret ({name})'
|
|
1149
|
+
defaultLabelGeneric: Use default pull secrets
|
|
1150
|
+
existingValuesBanner: '{secrets} are configured as image pull secrets in the chart values. To modify them, edit the values YAML directly.'
|
|
1151
|
+
defaultSecretsBanner: '{secrets} are configured as default pull secrets. Select or create an image pull secret here to override the default.'
|
|
1144
1152
|
header:
|
|
1145
1153
|
charts: Charts
|
|
1146
1154
|
info:
|
|
@@ -2680,6 +2688,7 @@ cluster:
|
|
|
2680
2688
|
other {A snapshot has been requested for {count} clusters}
|
|
2681
2689
|
}
|
|
2682
2690
|
groupLabel: Location
|
|
2691
|
+
predatesImportTooltip: The restore action is not currently supported for this snapshot as it predates the import into Rancher.
|
|
2683
2692
|
failed: "Snapshot from {time} failed"
|
|
2684
2693
|
rke1:
|
|
2685
2694
|
local: local
|
|
@@ -2744,6 +2753,7 @@ cluster:
|
|
|
2744
2753
|
upgrade: Upgrade Strategy
|
|
2745
2754
|
registration: Registration
|
|
2746
2755
|
nodePools: Node Pools
|
|
2756
|
+
operations: Operations
|
|
2747
2757
|
rotateCertificates:
|
|
2748
2758
|
label: Rotate Certificates
|
|
2749
2759
|
modalTitle: Rotate Cluster Certificates
|
|
@@ -2984,10 +2994,10 @@ fleet:
|
|
|
2984
2994
|
title: Continuous Delivery Settings
|
|
2985
2995
|
info: Rancher will reboot Fleet agent and controller on settings change.
|
|
2986
2996
|
apply: Apply changes
|
|
2987
|
-
noPermissions: You have no permissions to modify
|
|
2997
|
+
noPermissions: You have no permissions to modify Continuous Delivery Settings
|
|
2988
2998
|
parseError: 'Cannot parse values from "{ path }" in "{ id }" ConfigMap'
|
|
2989
2999
|
fields:
|
|
2990
|
-
ariaLabel:
|
|
3000
|
+
ariaLabel: Continuous Delivery {name} setting
|
|
2991
3001
|
agentTLSMode:
|
|
2992
3002
|
label: TLS Mode
|
|
2993
3003
|
description: "Determines whether the agent should trust CA bundles from the operating system's trust store when connecting to a management cluster."
|
|
@@ -3064,13 +3074,13 @@ fleet:
|
|
|
3064
3074
|
description: 'Agent deployment settings.'
|
|
3065
3075
|
replicas:
|
|
3066
3076
|
label: Replicas
|
|
3067
|
-
description: 'Number of replicas of
|
|
3077
|
+
description: 'Number of replicas of pods.'
|
|
3068
3078
|
annotations:
|
|
3069
3079
|
label: Extra Annotations
|
|
3070
|
-
description: 'Extra annotations passed to the
|
|
3080
|
+
description: 'Extra annotations passed to the pods.'
|
|
3071
3081
|
developer:
|
|
3072
3082
|
label: Developer
|
|
3073
|
-
description: 'Enable debug info
|
|
3083
|
+
description: 'Enable debug info.'
|
|
3074
3084
|
|
|
3075
3085
|
tableHeaders:
|
|
3076
3086
|
applicationType: Type
|
|
@@ -3081,7 +3091,7 @@ fleet:
|
|
|
3081
3091
|
dashboard:
|
|
3082
3092
|
pageTitle: Continuous Delivery Dashboard
|
|
3083
3093
|
menuLabel: Dashboard
|
|
3084
|
-
welcome: Welcome to
|
|
3094
|
+
welcome: Welcome to Continuous Delivery
|
|
3085
3095
|
gitOpsScale: GitOps at scale.
|
|
3086
3096
|
learnMore: Learn More.
|
|
3087
3097
|
learnMoreLink: https://fleet.rancher.io
|
|
@@ -3204,7 +3214,7 @@ fleet:
|
|
|
3204
3214
|
groupBy: Group By Type
|
|
3205
3215
|
subTypes:
|
|
3206
3216
|
fleet.cattle.io.gitrepo:
|
|
3207
|
-
description: GitRepo describes a git repository that is watched
|
|
3217
|
+
description: GitRepo describes a git repository that is watched. The resource contains the necessary information to deploy the repo, or parts of it, to target clusters.
|
|
3208
3218
|
fleet.cattle.io.helmop:
|
|
3209
3219
|
description: HelmOp is a simplified way of creating bundles by directly pointing to a Helm repository or to an OCI registry, without needing to set up a git repository.
|
|
3210
3220
|
suse-application-collection:
|
|
@@ -6025,6 +6035,13 @@ promptRestore:
|
|
|
6025
6035
|
fromS3: Restore from S3
|
|
6026
6036
|
label: Snapshot
|
|
6027
6037
|
placeholder: Select a snapshot to restore
|
|
6038
|
+
error:
|
|
6039
|
+
unableToResolveTargetCluster: Unable to resolve target cluster for snapshot restore
|
|
6040
|
+
restoreMode:
|
|
6041
|
+
label: Restore Type
|
|
6042
|
+
onlyEtcd: Only etcd
|
|
6043
|
+
kubernetesVersionAndEtcd: Kubernetes version and etcd
|
|
6044
|
+
clusterConfigKubernetesVersionAndEtcd: Cluster config, Kubernetes version and etcd
|
|
6028
6045
|
notification:
|
|
6029
6046
|
title: Restore Snapshot
|
|
6030
6047
|
message: Restoring snapshot { selectedSnapshot } has started...
|
|
@@ -6048,7 +6065,9 @@ promptRotateEncryptionKey:
|
|
|
6048
6065
|
title: Rotate Encryption Keys
|
|
6049
6066
|
description: The last backup {name} was performed on {date}
|
|
6050
6067
|
warning: Before proceeding, ensure a successful ETCD backup of the cluster has been completed.
|
|
6051
|
-
error:
|
|
6068
|
+
error:
|
|
6069
|
+
noBackup: No backup found
|
|
6070
|
+
unableToResolveTargetCluster: Unable to resolve target cluster for encryption key rotation
|
|
6052
6071
|
|
|
6053
6072
|
rancherAlertingDrivers:
|
|
6054
6073
|
msTeams: Enable Microsoft Teams
|
|
@@ -6333,6 +6352,8 @@ resourceYaml:
|
|
|
6333
6352
|
|
|
6334
6353
|
secret:
|
|
6335
6354
|
authentication: Authentication
|
|
6355
|
+
githubApp:
|
|
6356
|
+
label: GitHub App
|
|
6336
6357
|
certificate:
|
|
6337
6358
|
certificate: Certificate
|
|
6338
6359
|
certificates: Certificates
|
|
@@ -6469,14 +6490,19 @@ selectOrCreateAuthSecret:
|
|
|
6469
6490
|
passwordPersonalAccessToken: Password/Personal Access Token
|
|
6470
6491
|
rke:
|
|
6471
6492
|
info: "An RKE Auth Config secret contains the username and password concatenated and base64 encoded into the secret's 'auth' key"
|
|
6493
|
+
githubApp:
|
|
6494
|
+
appId: GitHub App ID
|
|
6495
|
+
installationId: GitHub App Installation ID
|
|
6496
|
+
privateKey: GitHub App Private Key
|
|
6472
6497
|
namespaceGroup: "Namespace: {name}"
|
|
6473
6498
|
chooseExisting: "Choose an existing secret:"
|
|
6474
6499
|
createSsh: Create an SSH Key Secret
|
|
6475
6500
|
createBasic: Create an HTTP Basic Auth Secret
|
|
6476
6501
|
createS3: Create an S3-Compatible Auth Secret
|
|
6477
6502
|
createRKE: Create an RKE Auth Config Secret
|
|
6503
|
+
createGithubApp: Create a GitHub App Auth Secret
|
|
6478
6504
|
createImagePullSecretBasedOnAuth: Create an Image Pull Secret based on Authentication Secret
|
|
6479
|
-
createImagePullSecret: Create
|
|
6505
|
+
createImagePullSecret: Create an Image Pull Secret with a Username and Password
|
|
6480
6506
|
|
|
6481
6507
|
serviceAccount:
|
|
6482
6508
|
automount: Automount Service Account Token
|
|
@@ -7363,6 +7389,7 @@ validation:
|
|
|
7363
7389
|
betweenValues: '"{key}" must be between {min} and {max}'
|
|
7364
7390
|
noSchema: No schema found to validate
|
|
7365
7391
|
noType: No type to validate
|
|
7392
|
+
createResourceFailed: 'Failed to create resource: insufficient permissions or resource type not found'
|
|
7366
7393
|
number:
|
|
7367
7394
|
requiredInt: '"{key}" must be integer'
|
|
7368
7395
|
isPositive: '"{key}" must be positive'
|
|
@@ -8966,6 +8993,7 @@ advancedSettings:
|
|
|
8966
8993
|
'ingress-ip-domain': 'Wildcard DNS domain to use for automatically generated Ingress hostnames. <ingress-name>.<namespace-name>.<ip address of ingress controller> will be added to the domain.'
|
|
8967
8994
|
'server-url': 'Default {appName} install url. Must be HTTPS. All nodes in your cluster must be able to reach this.'
|
|
8968
8995
|
'system-default-registry': 'Private registry to be used for all Rancher System Container Images. If no value is specified, the default registry for the container runtime is used. For Docker and containerd, the default is `docker.io`.'
|
|
8996
|
+
'system-default-registry-pull-secrets': 'List of image pull secrets to authenticate into registry from which Rancher System Container Images are pulled. By default, these secrets will be copied into each Rancher chart namespace. Secrets must be in the `cattle-system` namespace. The first valid secret listed here will be used.'
|
|
8969
8997
|
'ui-dashboard-index': 'HTML index location for the {appName} UI.'
|
|
8970
8998
|
'ui-offline-preferred': 'Controls whether UI assets are served locally by the server container or from the remote URL defined in the ui-dashboard-index setting. The `Dynamic` option will use local assets in production builds of {appName}.'
|
|
8971
8999
|
'ui-pl': 'Private-Label company name.'
|
|
@@ -8988,6 +9016,7 @@ advancedSettings:
|
|
|
8988
9016
|
'k3s-based-upgrader-uninstall-concurrency': Defines the maximum number of clusters in which Rancher can concurrently uninstall the legacy `rancher-k3s-upgrader` or `rancher-rke2-upgrader` app from imported or node-driver K3s or RKE2 clusters.
|
|
8989
9017
|
'system-agent-upgrader-install-concurrency': Defines the maximum number of clusters in which Rancher can concurrently install the resources required for upgrading system-agent.
|
|
8990
9018
|
'imported-cluster-version-management': Enables version management for imported RKE2/K3s clusters, and the local cluster if it is an RKE2/K3s cluster. The per-cluster version management setting overrides this global setting at the cluster level. For existing clusters where the cluster-level version management is set to 'system-default', changing this flag will trigger a redeployment of the cluster agent during the next reconciliation (by default every 5 minutes, or as soon as the cluster is edited, whichever comes first).
|
|
9019
|
+
'imported-cluster-day2-ops-enabled': Controls whether newly imported RKE2/K3s clusters will have day 2 operations (etcd snapshots, restores, encryption key rotations) enabled by default. This does not affect previously imported clusters.
|
|
8991
9020
|
warnings:
|
|
8992
9021
|
'agent-tls-mode': 'Changing this setting will cause all agents to be redeployed.'
|
|
8993
9022
|
editHelp:
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { RcDropdown, RcDropdownTrigger, RcDropdownItem } from '@components/RcDropdown';
|
|
3
|
+
import { ButtonSize } from '@components/RcButton';
|
|
3
4
|
type HiddenAction = {
|
|
4
5
|
action: string;
|
|
5
6
|
enabled: boolean;
|
|
@@ -11,11 +12,12 @@ type HiddenAction = {
|
|
|
11
12
|
anyEnabled: boolean;
|
|
12
13
|
}
|
|
13
14
|
|
|
14
|
-
defineProps<{
|
|
15
|
+
withDefaults(defineProps<{
|
|
15
16
|
disabled: boolean,
|
|
16
17
|
hiddenActions: HiddenAction[],
|
|
17
18
|
actionTooltip: unknown,
|
|
18
|
-
|
|
19
|
+
size?: ButtonSize,
|
|
20
|
+
}>(), { size: 'large' });
|
|
19
21
|
|
|
20
22
|
const emit = defineEmits(['click', 'mouseover', 'mouseleave']);
|
|
21
23
|
|
|
@@ -35,7 +37,7 @@ const setBulkActionOfInterest = (act: HiddenAction | null, event: 'mouseover' |
|
|
|
35
37
|
>
|
|
36
38
|
<rc-dropdown-trigger
|
|
37
39
|
class="bulk-actions-dropdown"
|
|
38
|
-
size="
|
|
40
|
+
:size="size"
|
|
39
41
|
:disabled="disabled"
|
|
40
42
|
>
|
|
41
43
|
<template #before>
|
|
@@ -31,11 +31,25 @@ export default {
|
|
|
31
31
|
disabled: {
|
|
32
32
|
type: Boolean,
|
|
33
33
|
default: false,
|
|
34
|
-
}
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
size: {
|
|
37
|
+
type: String,
|
|
38
|
+
default: 'large',
|
|
39
|
+
validator: (value) => ['small', 'medium', 'large'].includes(value),
|
|
40
|
+
},
|
|
35
41
|
|
|
36
42
|
},
|
|
37
43
|
|
|
38
44
|
computed: {
|
|
45
|
+
sizeClass() {
|
|
46
|
+
return {
|
|
47
|
+
small: 'btn-sm',
|
|
48
|
+
medium: 'btn-md',
|
|
49
|
+
large: null,
|
|
50
|
+
}[this.size];
|
|
51
|
+
},
|
|
52
|
+
|
|
39
53
|
optionObjects() {
|
|
40
54
|
const value = this.value;
|
|
41
55
|
|
|
@@ -52,6 +66,7 @@ export default {
|
|
|
52
66
|
|
|
53
67
|
out.class = {
|
|
54
68
|
btn: true,
|
|
69
|
+
[this.sizeClass]: !!this.sizeClass,
|
|
55
70
|
[this.inactiveClass]: !active,
|
|
56
71
|
[this.activeClass]: active,
|
|
57
72
|
};
|
|
@@ -122,3 +137,13 @@ export default {
|
|
|
122
137
|
</button>
|
|
123
138
|
</div>
|
|
124
139
|
</template>
|
|
140
|
+
|
|
141
|
+
<style lang="scss" scoped>
|
|
142
|
+
.btn-group {
|
|
143
|
+
.btn-md {
|
|
144
|
+
padding: 0 12px;
|
|
145
|
+
min-height: 32px;
|
|
146
|
+
line-height: 32px;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
</style>
|
|
@@ -127,6 +127,12 @@ export default {
|
|
|
127
127
|
default: () => []
|
|
128
128
|
},
|
|
129
129
|
|
|
130
|
+
// Used to be called before going to the next step in the wizard.
|
|
131
|
+
beforeNext: {
|
|
132
|
+
type: Function,
|
|
133
|
+
default: null
|
|
134
|
+
},
|
|
135
|
+
|
|
130
136
|
stepsOptions: {
|
|
131
137
|
type: Object,
|
|
132
138
|
default: () => ({ editFirstStep: true })
|
|
@@ -200,6 +206,7 @@ export default {
|
|
|
200
206
|
tocContainerHeight: 0,
|
|
201
207
|
mainLayoutEl: null,
|
|
202
208
|
throttledComputeTocContainerHeight: null,
|
|
209
|
+
nextValidating: false,
|
|
203
210
|
/**
|
|
204
211
|
* Initialised on demand (given that it needs to make a request to fetch schema definition)
|
|
205
212
|
*/
|
|
@@ -488,6 +495,47 @@ export default {
|
|
|
488
495
|
return slot !== 'default' && typeof this.$slots[slot] === 'function';
|
|
489
496
|
},
|
|
490
497
|
|
|
498
|
+
async wizardBeforeGoToStep(fromStep, toStep) {
|
|
499
|
+
if (!this.beforeNext) {
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
const fromIdx = this.steps.findIndex((s) => s.name === fromStep.name);
|
|
504
|
+
const toIdx = this.steps.findIndex((s) => s.name === toStep.name);
|
|
505
|
+
|
|
506
|
+
if (toIdx <= fromIdx) {
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
try {
|
|
511
|
+
await this.beforeNext(fromStep);
|
|
512
|
+
this.$emit('error', []);
|
|
513
|
+
} catch (err) {
|
|
514
|
+
this.$emit('error', exceptionToErrorsArray(err));
|
|
515
|
+
throw err;
|
|
516
|
+
}
|
|
517
|
+
},
|
|
518
|
+
|
|
519
|
+
async handleNext(nextFn, activeStep) {
|
|
520
|
+
if (!this.beforeNext) {
|
|
521
|
+
nextFn();
|
|
522
|
+
|
|
523
|
+
return;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
this.nextValidating = true;
|
|
527
|
+
|
|
528
|
+
try {
|
|
529
|
+
await this.beforeNext(activeStep);
|
|
530
|
+
this.$emit('error', []);
|
|
531
|
+
nextFn();
|
|
532
|
+
} catch (err) {
|
|
533
|
+
this.$emit('error', exceptionToErrorsArray(err));
|
|
534
|
+
} finally {
|
|
535
|
+
this.nextValidating = false;
|
|
536
|
+
}
|
|
537
|
+
},
|
|
538
|
+
|
|
491
539
|
formatError(err) {
|
|
492
540
|
if ( typeof err === 'string') {
|
|
493
541
|
return err;
|
|
@@ -751,6 +799,7 @@ export default {
|
|
|
751
799
|
:edit-first-step="stepsOptions.editFirstStep"
|
|
752
800
|
:errors="errors"
|
|
753
801
|
:finish-mode="finishMode"
|
|
802
|
+
:before-go-to-step="wizardBeforeGoToStep"
|
|
754
803
|
class="wizard"
|
|
755
804
|
@error="e=>errors = e"
|
|
756
805
|
>
|
|
@@ -834,10 +883,10 @@ export default {
|
|
|
834
883
|
name="next"
|
|
835
884
|
>
|
|
836
885
|
<button
|
|
837
|
-
:disabled="!canNext"
|
|
886
|
+
:disabled="!canNext || nextValidating"
|
|
838
887
|
type="button"
|
|
839
888
|
class="btn role-primary"
|
|
840
|
-
@click="next
|
|
889
|
+
@click="handleNext(next, activeStep)"
|
|
841
890
|
>
|
|
842
891
|
<t k="wizard.next" />
|
|
843
892
|
</button>
|
|
@@ -7,16 +7,15 @@ import Date from '@shell/components/formatter/Date.vue';
|
|
|
7
7
|
import RadioGroup from '@components/Form/Radio/RadioGroup.vue';
|
|
8
8
|
import LabeledSelect from '@shell/components/form/LabeledSelect.vue';
|
|
9
9
|
import { exceptionToErrorsArray } from '@shell/utils/error';
|
|
10
|
-
import { CAPI, SNAPSHOT } from '@shell/config/types';
|
|
10
|
+
import { CAPI, SNAPSHOT, OPERATION, MANAGEMENT } from '@shell/config/types';
|
|
11
11
|
import { set } from '@shell/utils/object';
|
|
12
12
|
import ChildHook, { BEFORE_SAVE_HOOKS } from '@shell/mixins/child-hook';
|
|
13
13
|
import { DATE_FORMAT, TIME_FORMAT } from '@shell/store/prefs';
|
|
14
14
|
import { escapeHtml } from '@shell/utils/string';
|
|
15
15
|
import day from 'dayjs';
|
|
16
16
|
import { sortBy } from '@shell/utils/sort';
|
|
17
|
-
import { STATES_ENUM } from '@shell/plugins/dashboard-store/resource-class';
|
|
18
17
|
import AppModal from '@shell/components/AppModal.vue';
|
|
19
|
-
|
|
18
|
+
import { createOperationCR } from '@shell/utils/operation-cr';
|
|
20
19
|
export default {
|
|
21
20
|
components: {
|
|
22
21
|
Card,
|
|
@@ -66,8 +65,41 @@ export default {
|
|
|
66
65
|
return !!this.snapshot;
|
|
67
66
|
},
|
|
68
67
|
|
|
69
|
-
|
|
70
|
-
|
|
68
|
+
targetCluster() {
|
|
69
|
+
if (this.isCluster) {
|
|
70
|
+
return this.toRestore?.[0] || null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (this.snapshot?.cluster) {
|
|
74
|
+
return this.snapshot.cluster;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const snapshotClusterName = this.snapshot?.spec?.clusterName || this.snapshot?.clusterName;
|
|
78
|
+
const snapshotClusterId = this.snapshot?.clusterId || (snapshotClusterName ? `${ this.snapshot?.metadata?.namespace }/${ snapshotClusterName }` : null);
|
|
79
|
+
|
|
80
|
+
if (!snapshotClusterId) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return this.$store.getters['management/byId'](CAPI.RANCHER_CLUSTER, snapshotClusterId);
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
targetMgmtCluster() {
|
|
88
|
+
if (this.targetCluster?.mgmt) {
|
|
89
|
+
return this.targetCluster.mgmt;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const mgmtClusterId = this.snapshot?.spec?.clusterName;
|
|
93
|
+
|
|
94
|
+
if (!mgmtClusterId) {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return this.$store.getters['management/byId'](MANAGEMENT.CLUSTER, mgmtClusterId);
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
isImported() {
|
|
102
|
+
return !!(this.targetCluster?.isImported || this.targetMgmtCluster?.isImported);
|
|
71
103
|
},
|
|
72
104
|
|
|
73
105
|
clusterSnapshots() {
|
|
@@ -77,6 +109,13 @@ export default {
|
|
|
77
109
|
return [];
|
|
78
110
|
}
|
|
79
111
|
},
|
|
112
|
+
restoreModeLabels() {
|
|
113
|
+
return [
|
|
114
|
+
this.t('promptRestore.restoreMode.onlyEtcd'),
|
|
115
|
+
this.t('promptRestore.restoreMode.kubernetesVersionAndEtcd'),
|
|
116
|
+
this.t('promptRestore.restoreMode.clusterConfigKubernetesVersionAndEtcd')
|
|
117
|
+
];
|
|
118
|
+
},
|
|
80
119
|
restoreModeOptions() {
|
|
81
120
|
return ['none', 'kubernetesVersion', 'all'];
|
|
82
121
|
}
|
|
@@ -112,7 +151,7 @@ export default {
|
|
|
112
151
|
const promise = this.$store.dispatch('management/findAll', { type: SNAPSHOT }).then((snapshots) => {
|
|
113
152
|
const toRestoreClusterName = cluster?.clusterName || cluster?.metadata?.name;
|
|
114
153
|
|
|
115
|
-
return snapshots.filter((s) => s?.
|
|
154
|
+
return snapshots.filter((s) => s?.restoreEnabled && s.clusterName === toRestoreClusterName
|
|
116
155
|
);
|
|
117
156
|
});
|
|
118
157
|
|
|
@@ -143,19 +182,41 @@ export default {
|
|
|
143
182
|
|
|
144
183
|
async apply(buttonDone) {
|
|
145
184
|
try {
|
|
146
|
-
const cluster = this
|
|
185
|
+
const cluster = this.targetCluster;
|
|
186
|
+
const mgmtCluster = cluster?.mgmt || this.targetMgmtCluster;
|
|
147
187
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
const now = cluster.spec?.rkeConfig?.etcdSnapshotRestore?.generation || 0;
|
|
188
|
+
const isImportedWithDayTwoOps = cluster?.isImportedWithDayTwoOps || mgmtCluster?.isDayTwoOpsEnabled;
|
|
151
189
|
|
|
152
|
-
|
|
153
|
-
generation: now + 1,
|
|
154
|
-
name: this.snapshot.name,
|
|
155
|
-
restoreRKEConfig: this.restoreMode,
|
|
156
|
-
});
|
|
190
|
+
await this.applyHooks(BEFORE_SAVE_HOOKS);
|
|
157
191
|
|
|
158
|
-
|
|
192
|
+
// For imported clusters with day 2 ops enabled, create an operation CR
|
|
193
|
+
if (isImportedWithDayTwoOps) {
|
|
194
|
+
if (!mgmtCluster) {
|
|
195
|
+
throw new Error(this.t('promptRestore.error.unableToResolveTargetCluster'));
|
|
196
|
+
}
|
|
197
|
+
const namespace = mgmtCluster?.id;
|
|
198
|
+
const safePrefix = mgmtCluster?.id;
|
|
199
|
+
const spec = {
|
|
200
|
+
clusterRef: {
|
|
201
|
+
apiVersion: 'management.cattle.io/v3',
|
|
202
|
+
kind: 'Cluster',
|
|
203
|
+
name: mgmtCluster?.id,
|
|
204
|
+
},
|
|
205
|
+
args: { name: this.snapshot?.snapshotFile?.name },
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
createOperationCR(this.$store.dispatch, OPERATION.ETCD_SNAPSHOT_RESTORE, spec, namespace, safePrefix);
|
|
209
|
+
} else {
|
|
210
|
+
const now = cluster.spec?.rkeConfig?.etcdSnapshotRestore?.generation || 0;
|
|
211
|
+
|
|
212
|
+
set(cluster, 'spec.rkeConfig.etcdSnapshotRestore', {
|
|
213
|
+
generation: now + 1,
|
|
214
|
+
name: this.snapshot.name,
|
|
215
|
+
restoreRKEConfig: this.restoreMode,
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
await cluster.save();
|
|
219
|
+
}
|
|
159
220
|
|
|
160
221
|
this.$store.dispatch('growl/success', {
|
|
161
222
|
title: this.t('promptRestore.notification.title'),
|
|
@@ -233,18 +294,25 @@ export default {
|
|
|
233
294
|
/>
|
|
234
295
|
</p>
|
|
235
296
|
</div>
|
|
236
|
-
<div
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
297
|
+
<div v-if="!isImported">
|
|
298
|
+
<div class="spacer" />
|
|
299
|
+
<RadioGroup
|
|
300
|
+
v-model:value="restoreMode"
|
|
301
|
+
name="restoreMode"
|
|
302
|
+
:label="t('promptRestore.restoreMode.label')"
|
|
303
|
+
:labels="restoreModeLabels"
|
|
304
|
+
:options="restoreModeOptions"
|
|
305
|
+
/>
|
|
306
|
+
</div>
|
|
244
307
|
</form>
|
|
245
308
|
</div>
|
|
246
309
|
</template>
|
|
247
|
-
|
|
310
|
+
<Banner
|
|
311
|
+
v-for="(err, i) in errors"
|
|
312
|
+
:key="i"
|
|
313
|
+
color="error"
|
|
314
|
+
:label="err"
|
|
315
|
+
/>
|
|
248
316
|
<template #actions>
|
|
249
317
|
<div class="dialog-actions">
|
|
250
318
|
<button
|
|
@@ -259,13 +327,6 @@ export default {
|
|
|
259
327
|
:disabled="!hasSnapshot"
|
|
260
328
|
@click="apply"
|
|
261
329
|
/>
|
|
262
|
-
|
|
263
|
-
<Banner
|
|
264
|
-
v-for="(err, i) in errors"
|
|
265
|
-
:key="i"
|
|
266
|
-
color="error"
|
|
267
|
-
:label="err"
|
|
268
|
-
/>
|
|
269
330
|
</div>
|
|
270
331
|
</template>
|
|
271
332
|
</Card>
|
|
@@ -1125,7 +1125,6 @@ export default {
|
|
|
1125
1125
|
v-clean-tooltip="actionTooltip"
|
|
1126
1126
|
type="button"
|
|
1127
1127
|
variant="primary"
|
|
1128
|
-
size="large"
|
|
1129
1128
|
:class="{[bulkActionClass]:true}"
|
|
1130
1129
|
:disabled="!act.enabled"
|
|
1131
1130
|
:data-testid="componentTestid + '-' + act.action"
|
|
@@ -1146,6 +1145,7 @@ export default {
|
|
|
1146
1145
|
:disabled="!selectedRows.length"
|
|
1147
1146
|
:hidden-actions="hiddenActions"
|
|
1148
1147
|
:action-tooltip="actionTooltip"
|
|
1148
|
+
size="medium"
|
|
1149
1149
|
@click="applyTableAction"
|
|
1150
1150
|
@mouseover="setBulkActionOfInterest"
|
|
1151
1151
|
@mouseleave="setBulkActionOfInterest"
|
|
@@ -1158,10 +1158,11 @@ export default {
|
|
|
1158
1158
|
:disable-button="!selectedRows.length"
|
|
1159
1159
|
size="sm"
|
|
1160
1160
|
>
|
|
1161
|
-
<template #button-content>
|
|
1161
|
+
<template #button-content="{ buttonSize }">
|
|
1162
1162
|
<button
|
|
1163
1163
|
ref="actionDropDown"
|
|
1164
1164
|
class="btn bg-primary mr-0"
|
|
1165
|
+
:class="buttonSize"
|
|
1165
1166
|
:disabled="!selectedRows.length"
|
|
1166
1167
|
>
|
|
1167
1168
|
<i class="icon icon-gear" />
|
|
@@ -1874,7 +1875,7 @@ export default {
|
|
|
1874
1875
|
}
|
|
1875
1876
|
|
|
1876
1877
|
.search-box {
|
|
1877
|
-
height:
|
|
1878
|
+
height: 32px;
|
|
1878
1879
|
margin-left: 10px;
|
|
1879
1880
|
min-width: 180px;
|
|
1880
1881
|
}
|
package/components/Wizard.vue
CHANGED
|
@@ -124,6 +124,11 @@ export default {
|
|
|
124
124
|
errors: {
|
|
125
125
|
type: Array,
|
|
126
126
|
default: null,
|
|
127
|
+
},
|
|
128
|
+
|
|
129
|
+
beforeGoToStep: {
|
|
130
|
+
type: Function,
|
|
131
|
+
default: null
|
|
127
132
|
}
|
|
128
133
|
},
|
|
129
134
|
|
|
@@ -217,7 +222,7 @@ export default {
|
|
|
217
222
|
},
|
|
218
223
|
|
|
219
224
|
methods: {
|
|
220
|
-
goToStep(number, fromNav) {
|
|
225
|
+
async goToStep(number, fromNav) {
|
|
221
226
|
if (number < 1) {
|
|
222
227
|
return;
|
|
223
228
|
}
|
|
@@ -233,6 +238,14 @@ export default {
|
|
|
233
238
|
return;
|
|
234
239
|
}
|
|
235
240
|
|
|
241
|
+
if (this.beforeGoToStep && fromNav) {
|
|
242
|
+
try {
|
|
243
|
+
await this.beforeGoToStep(this.activeStep, selected);
|
|
244
|
+
} catch {
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
236
249
|
this.activeStep = selected;
|
|
237
250
|
|
|
238
251
|
this.$emit('next', { step: selected });
|