@rancher/shell 1.2.3 → 1.2.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.
Files changed (62) hide show
  1. package/assets/translations/en-us.yaml +49 -18
  2. package/assets/translations/zh-hans.yaml +1 -0
  3. package/cloud-credential/__tests__/harvester.test.ts +18 -0
  4. package/cloud-credential/harvester.vue +9 -1
  5. package/components/AlertTable.vue +17 -7
  6. package/components/GrafanaDashboard.vue +6 -4
  7. package/components/nav/Header.vue +9 -5
  8. package/components/nav/TopLevelMenu.vue +1 -4
  9. package/config/product/explorer.js +11 -4
  10. package/config/settings.ts +9 -2
  11. package/config/types.js +1 -1
  12. package/config/uiplugins.js +2 -2
  13. package/detail/catalog.cattle.io.app.vue +17 -4
  14. package/edit/management.cattle.io.setting.vue +15 -2
  15. package/edit/provisioning.cattle.io.cluster/RegistryConfigs.vue +8 -2
  16. package/edit/provisioning.cattle.io.cluster/__tests__/RegistryConfigs.test.ts +61 -0
  17. package/edit/provisioning.cattle.io.cluster/__tests__/utils/cluster.ts +386 -0
  18. package/edit/provisioning.cattle.io.cluster/rke2.vue +73 -77
  19. package/edit/provisioning.cattle.io.cluster/tabs/AddOnAdditionalManifest.vue +45 -0
  20. package/edit/provisioning.cattle.io.cluster/tabs/AddOnConfig.vue +97 -0
  21. package/mixins/chart.js +6 -2
  22. package/models/catalog.cattle.io.app.js +112 -21
  23. package/models/management.cattle.io.cluster.js +18 -6
  24. package/package.json +1 -1
  25. package/pages/c/_cluster/apps/charts/install.vue +2 -1
  26. package/plugins/dashboard-store/actions.js +3 -2
  27. package/scripts/extension/bundle +1 -1
  28. package/scripts/publish-shell.sh +62 -55
  29. package/scripts/test-plugins-build.sh +111 -29
  30. package/scripts/typegen.sh +26 -23
  31. package/store/catalog.js +1 -1
  32. package/store/features.js +1 -0
  33. package/store/type-map.utils.ts +44 -0
  34. package/types/shell/index.d.ts +2 -0
  35. package/types/store/dashboard-store.types.ts +23 -0
  36. package/types/store/vuex.d.ts +9 -0
  37. package/utils/cluster.js +9 -0
  38. package/utils/v-sphere.ts +277 -0
  39. package/.DS_Store +0 -0
  40. package/creators/app/app.package.json +0 -13
  41. package/creators/app/files/.eslintignore +0 -18
  42. package/creators/app/files/.eslintrc.js +0 -173
  43. package/creators/app/files/.gitignore +0 -70
  44. package/creators/app/files/.vscode/settings.json +0 -22
  45. package/creators/app/files/babel.config.js +0 -1
  46. package/creators/app/files/tsconfig.json +0 -42
  47. package/creators/app/files/vue.config.js +0 -6
  48. package/creators/app/init +0 -101
  49. package/creators/app/package.json +0 -25
  50. package/creators/pkg/files/.github/workflows/build-extension-catalog.yml +0 -28
  51. package/creators/pkg/files/.github/workflows/build-extension-charts.yml +0 -26
  52. package/creators/pkg/files/babel.config.js +0 -1
  53. package/creators/pkg/files/index.ts +0 -14
  54. package/creators/pkg/files/tsconfig.json +0 -53
  55. package/creators/pkg/files/vue.config.js +0 -1
  56. package/creators/pkg/init +0 -254
  57. package/creators/pkg/package.json +0 -19
  58. package/creators/pkg/pkg.package.json +0 -21
  59. package/creators/pkg/vue-shim.ts +0 -4
  60. package/creators/update/init +0 -56
  61. package/creators/update/package.json +0 -20
  62. package/creators/update/upgrade +0 -56
@@ -355,9 +355,8 @@ addClusterMemberDialog:
355
355
  title: Add Cluster Member
356
356
 
357
357
  addonConfigConfirmation:
358
- title: Add-On Config Reset
359
- body: Changing the Kubernetes Version can reset the Add-On Config values. You should check that the values are as expected before continuing.
360
-
358
+ title: Add-On Reset
359
+ body: Changing the Kubernetes Version can reset Add-On values. You should check that the values are as expected before continuing.
361
360
  addProjectMemberDialog:
362
361
  title: Add Project Member
363
362
 
@@ -1107,17 +1106,39 @@ cis:
1107
1106
 
1108
1107
  cluster:
1109
1108
  addonChart:
1110
- rancher-vsphere-cpi: vSphere CPI Configuration
1111
- rancher-vsphere-csi: vSphere CSI Configuration
1112
- rke2-calico: Calico Configuration
1113
- rke2-calico-crd: Calico Configuration
1114
- rke2-canal: Canal Configuration
1115
- rke2-cilium: Cilium Configuration
1116
- rke2-coredns: CoreDNS Configuration
1117
- rke2-ingress-nginx: NGINX Ingress Configuration
1118
- rke2-kube-proxy: Kube Proxy Configuration
1119
- rke2-metrics-server: Metrics Server Configuration
1120
- rke2-multus: Multus Configuration
1109
+ rancher-vsphere-cpi:
1110
+ label: "Add-on: vSphere CPI"
1111
+ configuration: vSphere CPI
1112
+ rancher-vsphere-csi:
1113
+ label: "Add-on: vSphere CSI"
1114
+ configuration: vSphere CSI
1115
+ rke2-calico:
1116
+ label: "Add-on: Calico"
1117
+ configuration: Calico
1118
+ rke2-calico-crd:
1119
+ label: "Add-on: Calico"
1120
+ configuration: Calico
1121
+ rke2-canal:
1122
+ label: "Add-on: Canal"
1123
+ configuration: Canal
1124
+ rke2-cilium:
1125
+ label: "Add-on: Cilium"
1126
+ configuration: Cilium
1127
+ rke2-coredns:
1128
+ label: "Add-on: CoreDNS"
1129
+ configuration: CoreDNS
1130
+ rke2-ingress-nginx:
1131
+ label: "Add-on: NGINX"
1132
+ configuration: NGINX Ingress
1133
+ rke2-kube-proxy:
1134
+ label: "Add-on: Kube Proxy"
1135
+ configuration: Kube Proxy
1136
+ rke2-metrics-server:
1137
+ label: "Add-on: Metrics Server"
1138
+ configuration: Metrics Server
1139
+ rke2-multus:
1140
+ label: "Add-on: Multus"
1141
+ configuration: Multus
1121
1142
  agentEnvVars:
1122
1143
  label: Agent Environment
1123
1144
  detail: Add additional environment variables to the agent container. This is most commonly useful for configuring a HTTP proxy.
@@ -1133,7 +1154,7 @@ cluster:
1133
1154
  label: Google
1134
1155
  rancher-vsphere:
1135
1156
  label: vSphere
1136
- note: '<b>Important:</b> Configure the vSphere Cloud Provider and Storage Provider options in the Add-On Config tab.'
1157
+ note: '<b>Important:</b> Configure the vSphere Cloud Provider and Storage Provider options in the Add-on tabs.'
1137
1158
  harvester:
1138
1159
  label: Harvester
1139
1160
  copyConfig: Copy KubeConfig to Clipboard
@@ -1279,8 +1300,10 @@ cluster:
1279
1300
  macAddress: Mac Address
1280
1301
  macFormat: 'Invalid MAC address format.'
1281
1302
  vGpus:
1303
+ warnings:
1304
+ minimumAllocatable: It's highly recommended to select a vGPU with a number of allocatable devices greater than the number of nodes (Machine Count) to avoid "un-schedulable" errors after cluster updates.
1282
1305
  errors:
1283
- notAllocatable: '"VGPUs" not allocatable. There are not enough [{vGpus}] devices to be allocated to each node in machine pool [{pool}]'
1306
+ notAllocatable: '[{vGpu}] vGPU device is not allocatable; required: {allocated}, allocatable: {allocatable}'
1284
1307
  volume:
1285
1308
  title: Volumes
1286
1309
  volume: Volume
@@ -1300,6 +1323,7 @@ cluster:
1300
1323
  placeholder: 'Namespace/Name'
1301
1324
  cluster: Imported Harvester Cluster
1302
1325
  installGuestAgent: Install guest agent
1326
+ tokenExpirationWarning: 'Warning: Harvester Cloud Credentials use an underlying authentication token that may have an expiry time - please see the following <a href="https://harvesterhci.io/kb/renew_harvester_cloud_credentials" target="_blank" rel="noopener nofollow">knowledge base article</a> for possible implications on management operations.'
1303
1327
  description:
1304
1328
  label: Cluster Description
1305
1329
  placeholder: Any text you want that better describes this cluster
@@ -1632,7 +1656,7 @@ cluster:
1632
1656
  serverOs:
1633
1657
  label: OS
1634
1658
  addOns:
1635
- dependencyBanner: Add-On Configurations can vary between Kubernetes versions. Changing the Kubernetes version may reset the values below.
1659
+ dependencyBanner: Add-On Configuration can vary between Kubernetes versions. Changing the Kubernetes version may reset the values below.
1636
1660
  additionalManifest:
1637
1661
  title: Additional Manifest
1638
1662
  tooltip: 'Additional Kubernetes Manifest YAML to be applied to the cluster on startup.'
@@ -1818,6 +1842,7 @@ cluster:
1818
1842
  oracleoke: Oracle OKE
1819
1843
  otc: Open Telekom Cloud
1820
1844
  other: Other
1845
+ ovhcloudmks: OVHcloud MKS
1821
1846
  packet: Equinix Metal
1822
1847
  pinganyunecs: Pinganyun ECS
1823
1848
  pnap: phoenixNAP
@@ -1979,7 +2004,7 @@ cluster:
1979
2004
  s3: s3
1980
2005
  tabs:
1981
2006
  ace: Authorized Endpoint
1982
- addons: Add-On Config
2007
+ addOnAdditionalManifest: Additional Manifest
1983
2008
  advanced: Advanced
1984
2009
  agentEnv: Agent Environment Vars
1985
2010
  basic: Basics
@@ -7128,6 +7153,9 @@ advancedSettings:
7128
7153
  'ui-default-landing': 'The default page users land on after login.'
7129
7154
  'brand': Folder name for an alternative theme defined in '/assets/brand'
7130
7155
  'hide-local-cluster': Hide the local cluster
7156
+ 'agent-tls-mode': "Rancher Certificate Verification. In `strict` mode the agents (system, cluster, fleet, etc) will only trust Rancher installations which are using a certificate signed by the CABundle in the `cacerts` setting. When the mode is system-store, the agents will trust any certificate signed by a CABundle in the operating system’s trust store."
7157
+ warnings:
7158
+ 'agent-tls-mode': 'Changing this setting will cause all agents to be redeployed.'
7131
7159
  editHelp:
7132
7160
  'ui-banners': This setting takes a JSON object containing 3 root parameters; <code>banner</code>, <code>showHeader</code>, <code>showFooter</code>. <code>banner</code> is an object containing; <code>textColor</code>, <code>background</code>, and <code>text</code>, where <code>textColor</code> and <code>background</code> are any valid CSS color value.
7133
7161
  enum:
@@ -7150,6 +7178,9 @@ advancedSettings:
7150
7178
  info: Info
7151
7179
  debug: Debug
7152
7180
  trace: Trace
7181
+ 'agent-tls-mode':
7182
+ strict: 'Strict'
7183
+ system-store: 'System Store'
7153
7184
 
7154
7185
  featureFlags:
7155
7186
  label: Feature Flags
@@ -1803,6 +1803,7 @@ cluster:
1803
1803
  oracleoke: Oracle OKE
1804
1804
  otc: Open Telekom Cloud
1805
1805
  other: 其他
1806
+ ovhcloudmks: OVHcloud MKS
1806
1807
  packet: Equinix Metal
1807
1808
  pinganyunecs: 平安云 ECS
1808
1809
  pnap: phoenixNAP
@@ -0,0 +1,18 @@
1
+ import { mount } from '@vue/test-utils';
2
+ import HarvesterCloudCreds from '@shell/cloud-credential/harvester.vue';
3
+
4
+ const mockStore = { getters: { 'i18n/t': jest.fn() } };
5
+
6
+ describe('cloud credentials: Harvester', () => {
7
+ const wrapper = mount(HarvesterCloudCreds, {
8
+ propsData: { value: {} },
9
+ mocks: { $store: mockStore }
10
+ });
11
+
12
+ it('should display the warning banner for token expiration', async() => {
13
+ const warningBanner = wrapper.find('[data-testid="harvester-token-expiration-warning-banner"]');
14
+
15
+ expect(warningBanner.exists()).toBe(true);
16
+ expect(warningBanner.isVisible()).toBe(true);
17
+ });
18
+ });
@@ -1,12 +1,13 @@
1
1
  <script>
2
2
  import CreateEditView from '@shell/mixins/create-edit-view';
3
3
  import LabeledSelect from '@shell/components/form/LabeledSelect';
4
+ import { Banner } from '@components/Banner';
4
5
 
5
6
  import { get, set } from '@shell/utils/object';
6
7
  import { MANAGEMENT, VIRTUAL_HARVESTER_PROVIDER } from '@shell/config/types';
7
8
 
8
9
  export default {
9
- components: { LabeledSelect },
10
+ components: { LabeledSelect, Banner },
10
11
  mixins: [CreateEditView],
11
12
 
12
13
  async fetch() {
@@ -97,6 +98,13 @@ export default {
97
98
 
98
99
  <template>
99
100
  <div>
101
+ <div class="row mb-10">
102
+ <Banner
103
+ color="warning"
104
+ label-key="cluster.credential.harvester.tokenExpirationWarning"
105
+ data-testid="harvester-token-expiration-warning-banner"
106
+ />
107
+ </div>
100
108
  <div class="row mb-10">
101
109
  <div
102
110
  class="col span-6"
@@ -49,6 +49,7 @@ export default {
49
49
  ];
50
50
 
51
51
  return {
52
+ inStore: this.$store.getters['currentProduct'].inStore,
52
53
  alertManagerPoller: new Poller(
53
54
  this.loadAlertManagerEvents,
54
55
  ALERTMANAGER_POLL_RATE_MS,
@@ -69,15 +70,24 @@ export default {
69
70
  },
70
71
 
71
72
  methods: {
72
- async loadAlertManagerEvents() {
73
- const inStore = this.$store.getters['currentProduct'].inStore;
74
- const alertsEvents = await this.$store.dispatch(
75
- `${ inStore }/request`,
76
- { url: `/k8s/clusters/${ this.currentCluster.id }/api/v1/namespaces/${ this.monitoringNamespace }/services/http:${ this.alertServiceEndpoint }:9093/proxy/api/v1/alerts` }
73
+ async fetchAlertManagerEvents(version) {
74
+ return await this.$store.dispatch(
75
+ `${ this.inStore }/request`,
76
+ { url: `/k8s/clusters/${ this.currentCluster.id }/api/v1/namespaces/${ this.monitoringNamespace }/services/http:${ this.alertServiceEndpoint }:9093/proxy/api/${ version }/alerts` }
77
77
  );
78
+ },
79
+
80
+ async loadAlertManagerEvents() {
81
+ let alertEvents;
82
+
83
+ try {
84
+ alertEvents = await this.fetchAlertManagerEvents('v2');
85
+ } catch (err) {
86
+ alertEvents = await this.fetchAlertManagerEvents('v1').then((res) => res?.data);
87
+ }
78
88
 
79
- if (alertsEvents.data) {
80
- this.allAlerts = alertsEvents.data;
89
+ if (alertEvents) {
90
+ this.allAlerts = alertEvents;
81
91
  }
82
92
  },
83
93
 
@@ -114,10 +114,12 @@ export default {
114
114
  this.interval = setInterval(() => {
115
115
  try {
116
116
  const graphWindow = this.$refs.frame?.contentWindow;
117
- const errorElements = graphWindow.document.getElementsByClassName('alert-error');
118
- const errorCornerElements = graphWindow.document.getElementsByClassName('panel-info-corner--error');
119
- const panelInFullScreenElements = graphWindow.document.getElementsByClassName('panel-in-fullscreen');
120
- const panelContainerElements = graphWindow.document.getElementsByClassName('panel-container');
117
+
118
+ // Note. getElementsByClassName won't work, following a grafana bump class names are now unique - for example css-2qng6u-panel-container
119
+ const errorElements = graphWindow.document.querySelectorAll('[class$="alert-error');
120
+ const errorCornerElements = graphWindow.document.querySelectorAll('[class$="panel-info-corner--error');
121
+ const panelInFullScreenElements = graphWindow.document.querySelectorAll('[class$="panel-in-fullscreen');
122
+ const panelContainerElements = graphWindow.document.querySelectorAll('[class$="panel-container');
121
123
  const error = errorElements.length > 0 || errorCornerElements.length > 0;
122
124
  const loaded = panelInFullScreenElements.length > 0 || panelContainerElements.length > 0;
123
125
  const errorMessageElms = graphWindow.document.getElementsByTagName('pre');
@@ -178,12 +178,16 @@ export default {
178
178
  }
179
179
  },
180
180
  // since the Header is a "persistent component" we need to update it at every route change...
181
- $route(nue) {
182
- if (nue) {
183
- this.extensionHeaderActions = getApplicableExtensionEnhancements(this, ExtensionPoint.ACTION, ActionLocation.HEADER, nue);
181
+ $route: {
182
+ handler(nue) {
183
+ if (nue) {
184
+ this.extensionHeaderActions = getApplicableExtensionEnhancements(this, ExtensionPoint.ACTION, ActionLocation.HEADER, nue);
184
185
 
185
- this.navHeaderRight = this.$plugin?.getDynamic('component', 'NavHeaderRight');
186
- }
186
+ this.navHeaderRight = this.$plugin?.getDynamic('component', 'NavHeaderRight');
187
+ }
188
+ },
189
+ immediate: true,
190
+ deep: true,
187
191
  }
188
192
  },
189
193
 
@@ -855,7 +855,7 @@ export default {
855
855
  }
856
856
  }
857
857
 
858
- > i {
858
+ > i, > img {
859
859
  display: block;
860
860
  width: 42px;
861
861
  font-size: $icon-size;
@@ -867,9 +867,6 @@ export default {
867
867
  margin-right: 16px;
868
868
  fill: var(--link);
869
869
  }
870
- img {
871
- margin-right: 16px;
872
- }
873
870
 
874
871
  &.nuxt-link-active {
875
872
  background: var(--primary-hover-bg);
@@ -22,6 +22,7 @@ import {
22
22
  } from '@shell/config/table-headers';
23
23
 
24
24
  import { DSL } from '@shell/store/type-map';
25
+ import { configureConditionalDepaginate } from '@shell/store/type-map.utils';
25
26
 
26
27
  export const NAME = 'explorer';
27
28
 
@@ -49,7 +50,9 @@ export function init(store) {
49
50
  typeStoreMap: {
50
51
  [MANAGEMENT.PROJECT]: 'management',
51
52
  [MANAGEMENT.CLUSTER_ROLE_TEMPLATE_BINDING]: 'management',
52
- [MANAGEMENT.PROJECT_ROLE_TEMPLATE_BINDING]: 'management'
53
+ [MANAGEMENT.PROJECT_ROLE_TEMPLATE_BINDING]: 'management',
54
+ [NORMAN.CLUSTER_ROLE_TEMPLATE_BINDING]: 'rancher',
55
+ [NORMAN.PROJECT_ROLE_TEMPLATE_BINDING]: 'rancher',
53
56
  }
54
57
  });
55
58
 
@@ -156,12 +159,16 @@ export function init(store) {
156
159
  mapGroup(/^(.*\.)?cluster\.x-k8s\.io$/, 'clusterProvisioning');
157
160
  mapGroup(/^(aks|eks|gke|rke|rke-machine-config|rke-machine|provisioning)\.cattle\.io$/, 'clusterProvisioning');
158
161
 
162
+ const dePaginateBindings = configureConditionalDepaginate({ maxResourceCount: 5000 });
163
+ const dePaginateNormanBindings = configureConditionalDepaginate({ maxResourceCount: 5000, isNorman: true }) ;
164
+
159
165
  configureType(NODE, { isCreatable: false, isEditable: true });
160
166
  configureType(WORKLOAD_TYPES.JOB, { isEditable: false, match: WORKLOAD_TYPES.JOB });
161
- configureType(MANAGEMENT.CLUSTER_ROLE_TEMPLATE_BINDING, { isEditable: false });
162
- configureType(MANAGEMENT.PROJECT_ROLE_TEMPLATE_BINDING, { isEditable: false, depaginate: true });
167
+ configureType(MANAGEMENT.CLUSTER_ROLE_TEMPLATE_BINDING, { isEditable: false, depaginate: dePaginateBindings });
168
+ configureType(MANAGEMENT.PROJECT_ROLE_TEMPLATE_BINDING, { isEditable: false, depaginate: dePaginateBindings });
163
169
  configureType(MANAGEMENT.PROJECT, { displayName: store.getters['i18n/t']('namespace.project.label') });
164
- configureType(NORMAN.PROJECT_ROLE_TEMPLATE_BINDING, { depaginate: true });
170
+ configureType(NORMAN.CLUSTER_ROLE_TEMPLATE_BINDING, { depaginate: dePaginateNormanBindings });
171
+ configureType(NORMAN.PROJECT_ROLE_TEMPLATE_BINDING, { depaginate: dePaginateNormanBindings });
165
172
 
166
173
  configureType(EVENT, { limit: 500 });
167
174
  weightType(EVENT, -1, true);
@@ -19,7 +19,8 @@ interface GlobalSetting {
19
19
  /**
20
20
  * Function used from the form validation
21
21
  */
22
- ruleSet?: GlobalSettingRuleset[],
22
+ ruleSet?: GlobalSettingRuleset[],
23
+ warning?: string
23
24
  };
24
25
  }
25
26
 
@@ -90,8 +91,9 @@ export const SETTING = {
90
91
  FLEET_AGENT_DEFAULT_AFFINITY: 'fleet-agent-default-affinity',
91
92
  /**
92
93
  * manage rancher repositories in extensions (official, partners repos)
93
- */
94
+ */
94
95
  ADD_EXTENSION_REPOS_BANNER_DISPLAY: 'display-add-extension-repos-banner',
96
+ AGENT_TLS_MODE: 'agent-tls-mode',
95
97
  /**
96
98
  * User retention settings
97
99
  */
@@ -152,6 +154,11 @@ export const ALLOWED_SETTINGS: GlobalSetting = {
152
154
  options: ['prompt', 'in', 'out']
153
155
  },
154
156
  [SETTING.HIDE_LOCAL_CLUSTER]: { kind: 'boolean' },
157
+ [SETTING.AGENT_TLS_MODE]: {
158
+ kind: 'enum',
159
+ options: ['strict', 'system-store'],
160
+ warning: 'agent-tls-mode'
161
+ },
155
162
  };
156
163
 
157
164
  /**
package/config/types.js CHANGED
@@ -14,7 +14,7 @@ export const NORMAN = {
14
14
  ETCD_BACKUP: 'etcdbackup',
15
15
  CLUSTER: 'cluster',
16
16
  CLUSTER_TOKEN: 'clusterregistrationtoken',
17
- CLUSTER_ROLE_TEMPLATE_BINDING: 'clusterRoleTemplateBinding',
17
+ CLUSTER_ROLE_TEMPLATE_BINDING: 'clusterroletemplatebinding',
18
18
  CLOUD_CREDENTIAL: 'cloudcredential',
19
19
  FLEET_WORKSPACES: 'fleetworkspace',
20
20
  GLOBAL_ROLE: 'globalRole',
@@ -178,7 +178,7 @@ export function isChartVersionAvailableForInstall(versionsData, returnObj = fals
178
178
 
179
179
  const parsedRancherVersion = rancherVersion.split('-')?.[0];
180
180
  const regexHashString = new RegExp('^[A-Za-z0-9]{9}$');
181
- const isRancherVersionHashString = regexHashString.test(rancherVersion);
181
+ const isRancherVersionHashStringOrHead = regexHashString.test(rancherVersion) || rancherVersion.includes('head');
182
182
  const requiredUiVersion = version.annotations?.[UI_PLUGIN_CHART_ANNOTATIONS.UI_VERSION];
183
183
  const requiredKubeVersion = version.annotations?.[UI_PLUGIN_CHART_ANNOTATIONS.KUBE_VERSION];
184
184
  const versionObj = { ...version };
@@ -187,7 +187,7 @@ export function isChartVersionAvailableForInstall(versionsData, returnObj = fals
187
187
  versionObj.isCompatibleWithKubeVersion = true;
188
188
 
189
189
  // if it's a head version of Rancher, then we skip the validation and enable them all
190
- if (!isRancherVersionHashString && requiredUiVersion && !semver.satisfies(parsedRancherVersion, requiredUiVersion)) {
190
+ if (!isRancherVersionHashStringOrHead && requiredUiVersion && !semver.satisfies(parsedRancherVersion, requiredUiVersion)) {
191
191
  if (!returnObj) {
192
192
  return false;
193
193
  }
@@ -9,7 +9,8 @@ import RelatedResources from '@shell/components/RelatedResources';
9
9
  import jsyaml from 'js-yaml';
10
10
  import merge from 'lodash/merge';
11
11
  import { CATALOG } from '@shell/config/types';
12
- import { sortBy } from '~shell/utils/sort';
12
+ import { sortBy } from '@shell/utils/sort';
13
+ import { allHash } from '@shell/utils/promise';
13
14
 
14
15
  export default {
15
16
  name: 'DetailRelease',
@@ -30,9 +31,15 @@ export default {
30
31
  },
31
32
 
32
33
  async fetch() {
33
- await this.$store.dispatch('catalog/load', { force: true, reset: true });
34
+ const promises = {
35
+ catalog: this.$store.dispatch('catalog/load', { force: true, reset: true }),
36
+ allOperations: this.$store.dispatch('cluster/findAll', { type: CATALOG.OPERATION }),
37
+ secrets: this.value.fetchValues(true),
38
+ };
34
39
 
35
- this.allOperations = await this.$store.dispatch('cluster/findAll', { type: CATALOG.OPERATION });
40
+ const res = await allHash(promises);
41
+
42
+ this.allOperations = res.allOperations;
36
43
  },
37
44
 
38
45
  computed: {
@@ -45,7 +52,7 @@ export default {
45
52
  },
46
53
 
47
54
  valuesYaml() {
48
- const combined = merge(merge({}, this.value?.spec?.chart?.values || {}), this.value?.spec?.values || {});
55
+ const combined = merge(merge({}, this.value?.chartValues || {}), this.value?.values || {});
49
56
 
50
57
  return jsyaml.dump(combined);
51
58
  },
@@ -95,6 +102,12 @@ export default {
95
102
  }
96
103
  },
97
104
  },
105
+
106
+ watch: {
107
+ 'value.secretId'(neu, old) {
108
+ this.value.fetchValues(true);
109
+ }
110
+ },
98
111
  };
99
112
  </script>
100
113
 
@@ -4,6 +4,7 @@ import { LabeledInput } from '@components/Form/LabeledInput';
4
4
  import LabeledSelect from '@shell/components/form/LabeledSelect';
5
5
  import CreateEditView from '@shell/mixins/create-edit-view';
6
6
  import { TextAreaAutoGrow } from '@components/Form/TextArea';
7
+ import { Banner } from '@components/Banner';
7
8
  import formRulesGenerator from '@shell/utils/validators/formRules/index';
8
9
 
9
10
  import { ALLOWED_SETTINGS, SETTING } from '@shell/config/settings';
@@ -18,7 +19,8 @@ export default {
18
19
  LabeledInput,
19
20
  LabeledSelect,
20
21
  RadioGroup,
21
- TextAreaAutoGrow
22
+ TextAreaAutoGrow,
23
+ Banner,
22
24
  },
23
25
 
24
26
  mixins: [CreateEditView, FormValidation],
@@ -63,7 +65,11 @@ export default {
63
65
 
64
66
  return factoryArg ? rule(factoryArg) : rule;
65
67
  }) : {};
66
- }
68
+ },
69
+
70
+ showWarningBanner() {
71
+ return this.setting?.warning;
72
+ },
67
73
  },
68
74
 
69
75
  methods: {
@@ -118,6 +124,13 @@ export default {
118
124
  @finish="saveSettings"
119
125
  @cancel="done"
120
126
  >
127
+ <Banner
128
+ v-if="showWarningBanner"
129
+ color="warning"
130
+ :label="t(`advancedSettings.warnings.${ setting.warning }`)"
131
+ data-testid="advanced_settings_warning_banner"
132
+ />
133
+
121
134
  <h4>{{ description }}</h4>
122
135
 
123
136
  <h5
@@ -7,6 +7,7 @@ import SelectOrCreateAuthSecret from '@shell/components/form/SelectOrCreateAuthS
7
7
  import CreateEditView from '@shell/mixins/create-edit-view';
8
8
  import SecretSelector from '@shell/components/form/SecretSelector';
9
9
  import { SECRET_TYPES as TYPES } from '@shell/config/secret';
10
+ import { base64Decode, base64Encode } from '@shell/utils/crypto';
10
11
 
11
12
  export default {
12
13
  components: {
@@ -55,7 +56,7 @@ export default {
55
56
  if (configMap[hostname]) {
56
57
  configMap[hostname].insecureSkipVerify = configMap[hostname].insecureSkipVerify ?? defaultAddValue.insecureSkipVerify;
57
58
  configMap[hostname].authConfigSecretName = configMap[hostname].authConfigSecretName ?? defaultAddValue.authConfigSecretName;
58
- configMap[hostname].caBundle = configMap[hostname].caBundle ?? defaultAddValue.caBundle;
59
+ configMap[hostname].caBundle = base64Decode(configMap[hostname].caBundle ?? defaultAddValue.caBundle);
59
60
  configMap[hostname].tlsSecretName = configMap[hostname].tlsSecretName ?? defaultAddValue.tlsSecretName;
60
61
  }
61
62
  entries.push({
@@ -94,7 +95,11 @@ export default {
94
95
  continue;
95
96
  }
96
97
 
97
- configs[h] = { ...entry };
98
+ configs[h] = {
99
+ ...entry,
100
+ caBundle: base64Encode(entry.caBundle)
101
+ };
102
+
98
103
  delete configs[h].hostname;
99
104
  }
100
105
 
@@ -174,6 +179,7 @@ export default {
174
179
 
175
180
  <LabeledInput
176
181
  v-model="row.value.caBundle"
182
+ :data-testid="`registry-caBundle-${i}`"
177
183
  class="mt-20"
178
184
  type="multiline"
179
185
  label="CA Cert Bundle"
@@ -0,0 +1,61 @@
1
+ import { mount, Wrapper } from '@vue/test-utils';
2
+ import { clone } from '@shell/utils/object';
3
+ import { _EDIT } from '@shell/config/query-params';
4
+ import { PROV_CLUSTER } from '@shell/edit/provisioning.cattle.io.cluster/__tests__/utils/cluster';
5
+ import RegistryConfigs from '@shell/edit/provisioning.cattle.io.cluster/RegistryConfigs.vue';
6
+
7
+ describe('component: RegistryConfigs', () => {
8
+ let wrapper: Wrapper<InstanceType<typeof RegistryConfigs> & { [key: string]: any }>;
9
+
10
+ const mountOptions = {
11
+ propsData: {
12
+ value: {},
13
+ mode: _EDIT,
14
+ clusterRegisterBeforeHook: () => {}
15
+ },
16
+ stubs: {
17
+ SelectOrCreateAuthSecret: true,
18
+ SecretSelector: true,
19
+ },
20
+ mocks: { $store: { getters: { 'i18n/t': jest.fn() } } }
21
+ };
22
+
23
+ describe('key CA Cert Bundle', () => {
24
+ it('should display default key', () => {
25
+ const value = clone(PROV_CLUSTER);
26
+
27
+ value.spec.rkeConfig.registries.configs = { foo: { caBundle: 'Zm9vYmFy' } };
28
+
29
+ mountOptions.propsData.value = value;
30
+
31
+ wrapper = mount(
32
+ RegistryConfigs,
33
+ mountOptions
34
+ );
35
+
36
+ const registry = wrapper.find('[data-testid^="registry-caBundle"]').element as HTMLTextAreaElement;
37
+
38
+ expect(registry.value).toBe('foobar');
39
+ });
40
+
41
+ it('should update key in base64 format', async() => {
42
+ const value = clone(PROV_CLUSTER);
43
+
44
+ value.spec.rkeConfig.registries.configs = { foo: { caBundle: 'Zm9vYmFy' } };
45
+
46
+ mountOptions.propsData.value = value;
47
+
48
+ wrapper = mount(
49
+ RegistryConfigs,
50
+ mountOptions
51
+ );
52
+
53
+ const registry = wrapper.find('[data-testid^="registry-caBundle"]');
54
+
55
+ await registry.setValue('ssh key');
56
+ wrapper.vm.update();
57
+
58
+ expect(wrapper.emitted('updateConfigs')![0][0]['foo']['caBundle']).toBe('c3NoIGtleQ==');
59
+ });
60
+ });
61
+ });