@rancher/shell 2.0.2-rc.1 → 2.0.3
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/translations/en-us.yaml +53 -31
- package/components/PromptRemove.vue +8 -3
- package/components/ResourceDetail/Masthead.vue +1 -0
- package/components/ResourceDetail/index.vue +2 -1
- package/components/SideNav.vue +1 -1
- package/components/TableDataUserIcon.vue +1 -1
- package/components/fleet/FleetClusters.vue +0 -3
- package/components/fleet/FleetRepos.vue +0 -7
- package/components/formatter/CloudCredExpired.vue +69 -0
- package/components/formatter/ClusterProvider.vue +3 -3
- package/components/formatter/Date.vue +1 -1
- package/components/nav/Header.vue +9 -5
- package/components/nav/TopLevelMenu.vue +127 -63
- package/components/nav/__tests__/TopLevelMenu.test.ts +53 -27
- package/config/labels-annotations.js +3 -0
- package/core/types-provisioning.ts +5 -0
- package/core/types.ts +26 -1
- package/detail/catalog.cattle.io.app.vue +17 -4
- package/detail/fleet.cattle.io.bundle.vue +5 -68
- package/detail/fleet.cattle.io.cluster.vue +11 -9
- package/detail/fleet.cattle.io.gitrepo.vue +3 -2
- package/edit/provisioning.cattle.io.cluster/__tests__/DirectoryConfig.test.ts +109 -24
- package/edit/provisioning.cattle.io.cluster/index.vue +10 -4
- package/edit/provisioning.cattle.io.cluster/rke2.vue +13 -2
- package/edit/provisioning.cattle.io.cluster/tabs/Advanced.vue +1 -0
- package/edit/provisioning.cattle.io.cluster/tabs/DirectoryConfig.vue +177 -26
- package/list/provisioning.cattle.io.cluster.vue +56 -5
- package/mixins/chart.js +6 -2
- package/models/__tests__/management.cattle.io.cluster.test.ts +3 -3
- package/models/__tests__/provisioning.cattle.io.cluster.test.ts +0 -86
- package/models/catalog.cattle.io.app.js +108 -21
- package/models/cloudcredential.js +159 -2
- package/models/fleet.cattle.io.bundle.js +3 -1
- package/models/fleet.cattle.io.gitrepo.js +50 -61
- package/models/management.cattle.io.cluster.js +15 -7
- package/models/provisioning.cattle.io.cluster.js +62 -15
- package/package.json +1 -1
- package/pages/c/_cluster/apps/charts/install.vue +2 -1
- package/pages/c/_cluster/explorer/__tests__/index.test.ts +1 -1
- package/pages/c/_cluster/explorer/index.vue +1 -2
- package/pages/c/_cluster/fleet/index.vue +12 -5
- package/pages/c/_cluster/manager/cloudCredential/index.vue +68 -4
- package/pages/c/_cluster/uiplugins/index.vue +4 -2
- package/pages/home.vue +1 -0
- package/scripts/extension/bundle +1 -1
- package/scripts/extension/helm/charts/ui-plugin-server/Chart.yaml +0 -2
- package/scripts/extension/parse-tag-name +21 -12
- package/scripts/publish-shell.sh +10 -4
- package/scripts/typegen.sh +27 -22
- package/store/features.js +1 -0
- package/types/resources/fleet.d.ts +40 -0
- package/types/shell/index.d.ts +4692 -0
- package/utils/auth.js +1 -1
- package/utils/cluster.js +1 -1
- package/utils/fleet.ts +159 -0
- package/utils/string.js +9 -0
- package/utils/v-sphere.ts +282 -0
- package/vue.config.js +3 -3
- package/shell/types/shell/index.d.ts +0 -2
package/utils/auth.js
CHANGED
|
@@ -99,7 +99,7 @@ export const checkSchemasForFindAllHash = (types, store) => {
|
|
|
99
99
|
const validSchema = value.schemaValidator ? value.schemaValidator(schema) : !!schema;
|
|
100
100
|
|
|
101
101
|
if (validSchema) {
|
|
102
|
-
hash[key] = store.dispatch(`${ value.inStoreType }/findAll`, { type: value.type } );
|
|
102
|
+
hash[key] = store.dispatch(`${ value.inStoreType }/findAll`, { type: value.type, opt: value.opt } );
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
105
|
|
package/utils/cluster.js
CHANGED
|
@@ -94,7 +94,7 @@ export function abbreviateClusterName(input) {
|
|
|
94
94
|
|
|
95
95
|
export function labelForAddon(name, configuration = true) {
|
|
96
96
|
const addon = camelToTitle(name.replace(/^(rke|rke2|rancher)-/, ''));
|
|
97
|
-
const fallback = `${
|
|
97
|
+
const fallback = `${ configuration ? '' : 'Add-on: ' }${ addon }`;
|
|
98
98
|
const key = `cluster.addonChart."${ name }"${ configuration ? '.configuration' : '.label' }`;
|
|
99
99
|
|
|
100
100
|
return this.$store.getters['i18n/withFallback'](key, null, fallback);
|
package/utils/fleet.ts
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BundleDeploymentResource,
|
|
3
|
+
BundleResourceKey,
|
|
4
|
+
BundleDeploymentStatus,
|
|
5
|
+
BundleStatus,
|
|
6
|
+
} from '@shell/types/resources/fleet';
|
|
7
|
+
import { STATES_ENUM } from '@shell/plugins/dashboard-store/resource-class';
|
|
8
|
+
import { FLEET as FLEET_ANNOTATIONS } from '@shell/config/labels-annotations';
|
|
9
|
+
|
|
10
|
+
interface Resource extends BundleDeploymentResource {
|
|
11
|
+
state: string,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
type Labels = {
|
|
15
|
+
[key: string]: string,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface StatesCounter { [state: string]: number }
|
|
19
|
+
|
|
20
|
+
function incr(counter: StatesCounter, state: string) {
|
|
21
|
+
if (!counter[state]) {
|
|
22
|
+
counter[state] = 0;
|
|
23
|
+
}
|
|
24
|
+
counter[state]++;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function resourceKey(r: BundleResourceKey): string {
|
|
28
|
+
return `${ r.kind }/${ r.namespace }/${ r.name }`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
class Fleet {
|
|
32
|
+
resourceId(r: BundleResourceKey): string {
|
|
33
|
+
return r.namespace ? `${ r.namespace }/${ r.name }` : r.name;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* resourceType normalizes APIVersion and Kind from a Resources into a single string
|
|
38
|
+
*/
|
|
39
|
+
resourceType(r: Resource): string {
|
|
40
|
+
// ported from https://github.com/rancher/fleet/blob/v0.10.0/internal/cmd/controller/grutil/resourcekey.go#L116-L128
|
|
41
|
+
const type = r.kind.toLowerCase();
|
|
42
|
+
|
|
43
|
+
if (!r.apiVersion || r.apiVersion === 'v1') {
|
|
44
|
+
return type;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return `${ r.apiVersion.split('/', 2)[0] }.${ type }`;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* resourcesFromBundleDeploymentStatus extracts the list of resources deployed by a BundleDeployment
|
|
52
|
+
*/
|
|
53
|
+
resourcesFromBundleDeploymentStatus(status: BundleDeploymentStatus): Resource[] {
|
|
54
|
+
// status.resources includes of resources that were deployed by Fleet *and still exist in the cluster*
|
|
55
|
+
// Use a map to avoid `find` over and over again
|
|
56
|
+
const resources = (status?.resources || []).reduce((res, r) => {
|
|
57
|
+
res[resourceKey(r)] = Object.assign({ state: STATES_ENUM.READY }, r);
|
|
58
|
+
|
|
59
|
+
return res;
|
|
60
|
+
}, {} as { [resourceKey: string]: Resource });
|
|
61
|
+
|
|
62
|
+
const modified: Resource[] = [];
|
|
63
|
+
|
|
64
|
+
for (const r of status?.modifiedStatus || []) {
|
|
65
|
+
const state = r.missing ? STATES_ENUM.MISSING : r.delete ? STATES_ENUM.ORPHANED : STATES_ENUM.MODIFIED;
|
|
66
|
+
const found: Resource = resources[resourceKey(r)];
|
|
67
|
+
|
|
68
|
+
// Depending on the state, the same resource can appear in both fields
|
|
69
|
+
if (found) {
|
|
70
|
+
found.state = state;
|
|
71
|
+
} else {
|
|
72
|
+
modified.push(Object.assign({ state }, r));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
for (const r of status?.nonReadyStatus || []) {
|
|
76
|
+
const state = r.summary?.state || STATES_ENUM.UNKNOWN;
|
|
77
|
+
const found: Resource = resources[resourceKey(r)];
|
|
78
|
+
|
|
79
|
+
if (found) {
|
|
80
|
+
found.state = state;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return modified.concat(Object.values(resources));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* resourcesFromBundleStatus extracts the list of resources deployed by a Bundle
|
|
89
|
+
*/
|
|
90
|
+
resourcesFromBundleStatus(status: BundleStatus): Resource[] {
|
|
91
|
+
// The state of every resource is spread all over the bundle status.
|
|
92
|
+
// resourceKey contains one entry per resource AND cluster (built by Fleet from all the child BundleDeployments).
|
|
93
|
+
// However, those entries do not contain the cluster that they belong to, leading to duplicate entries
|
|
94
|
+
|
|
95
|
+
// 1. Fold resourceKey by using a unique key, initializing counters for multiple occurrences of the same resource
|
|
96
|
+
const resources = (status.resourceKey || []).reduce((res, r) => {
|
|
97
|
+
const k = resourceKey(r);
|
|
98
|
+
|
|
99
|
+
if (!res[k]) {
|
|
100
|
+
res[k] = { r, count: {} };
|
|
101
|
+
}
|
|
102
|
+
incr(res[k].count, STATES_ENUM.READY);
|
|
103
|
+
|
|
104
|
+
return res;
|
|
105
|
+
}, {} as { [resourceKey: string]: { r: BundleResourceKey, count: StatesCounter } });
|
|
106
|
+
|
|
107
|
+
// 2. Non-ready resources are counted differently and may also appear in resourceKey, depending on their state
|
|
108
|
+
for (const bundle of status.summary?.nonReadyResources || []) {
|
|
109
|
+
for (const r of bundle.modifiedStatus || []) {
|
|
110
|
+
const k = resourceKey(r);
|
|
111
|
+
|
|
112
|
+
if (!resources[k]) {
|
|
113
|
+
resources[k] = { r, count: {} };
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (r.missing) {
|
|
117
|
+
incr(resources[k].count, STATES_ENUM.MISSING);
|
|
118
|
+
} else if (r.delete) {
|
|
119
|
+
resources[k].count[STATES_ENUM.READY]--;
|
|
120
|
+
incr(resources[k].count, STATES_ENUM.ORPHANED);
|
|
121
|
+
} else {
|
|
122
|
+
resources[k].count[STATES_ENUM.READY]--;
|
|
123
|
+
incr(resources[k].count, STATES_ENUM.MODIFIED);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
for (const r of bundle.nonReadyStatus || []) {
|
|
127
|
+
const k = resourceKey(r);
|
|
128
|
+
const state = r.summary?.state || STATES_ENUM.UNKNOWN;
|
|
129
|
+
|
|
130
|
+
resources[k].count[STATES_ENUM.READY]--;
|
|
131
|
+
incr(resources[k].count, state);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// 3. Unfold back to an array of resources for display
|
|
136
|
+
return Object.values(resources).reduce((res, e) => {
|
|
137
|
+
const { r, count } = e;
|
|
138
|
+
|
|
139
|
+
for (const state in count) {
|
|
140
|
+
for (let x = 0; x < count[state]; x++) {
|
|
141
|
+
res.push(Object.assign({ state }, r));
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return res;
|
|
146
|
+
}, [] as Resource[]);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
clusterIdFromBundleDeploymentLabels(labels?: Labels): string {
|
|
150
|
+
const clusterNamespace = labels?.[FLEET_ANNOTATIONS.CLUSTER_NAMESPACE];
|
|
151
|
+
const clusterName = labels?.[FLEET_ANNOTATIONS.CLUSTER];
|
|
152
|
+
|
|
153
|
+
return `${ clusterNamespace }/${ clusterName }`;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const instance = new Fleet();
|
|
158
|
+
|
|
159
|
+
export default instance;
|
package/utils/string.js
CHANGED
|
@@ -321,3 +321,12 @@ export function sanitizeValue(v) {
|
|
|
321
321
|
export function sanitizeIP(v) {
|
|
322
322
|
return (v || '').replace(/[^a-z0-9.:_-]/ig, '');
|
|
323
323
|
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Return the string `<x> / <y>`
|
|
327
|
+
*
|
|
328
|
+
* Each param should be a number, otherwise `?` is used
|
|
329
|
+
*/
|
|
330
|
+
export function xOfy(x, y) {
|
|
331
|
+
return `${ typeof x === 'number' ? x : '?' }/${ typeof y === 'number' ? y : '?' }`;
|
|
332
|
+
}
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import merge from 'lodash/merge';
|
|
2
|
+
import { SECRET } from '@shell/config/types';
|
|
3
|
+
import { PROVISIONING_PRE_BOOTSTRAP } from '@shell/store/features';
|
|
4
|
+
|
|
5
|
+
export const VMWARE_VSPHERE = 'vmwarevsphere';
|
|
6
|
+
|
|
7
|
+
type Rke2Component = {
|
|
8
|
+
versionInfo: any;
|
|
9
|
+
userChartValues: any;
|
|
10
|
+
chartVersionKey: (chartName: string) => string;
|
|
11
|
+
value: any;
|
|
12
|
+
isEdit: boolean;
|
|
13
|
+
provider: string;
|
|
14
|
+
$store: any,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
type SecretDetails = {
|
|
18
|
+
generateName: string,
|
|
19
|
+
upstreamClusterName: string,
|
|
20
|
+
upstreamNamespace: string,
|
|
21
|
+
downstreamName: string,
|
|
22
|
+
downstreamNamespace: string,
|
|
23
|
+
json?: object,
|
|
24
|
+
}
|
|
25
|
+
type Values = any;
|
|
26
|
+
|
|
27
|
+
type ChartValues = {
|
|
28
|
+
defaultValues: Values,
|
|
29
|
+
userValues: Values,
|
|
30
|
+
combined: Values,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const rootGenerateName = 'vsphere-secret-';
|
|
34
|
+
|
|
35
|
+
type SecretJson = any;
|
|
36
|
+
|
|
37
|
+
class VSphereUtils {
|
|
38
|
+
private async findSecret(
|
|
39
|
+
{ $store }: Rke2Component, {
|
|
40
|
+
generateName, upstreamClusterName, upstreamNamespace, downstreamName, downstreamNamespace
|
|
41
|
+
}: SecretDetails): Promise<SecretJson | undefined> {
|
|
42
|
+
const secrets = await $store.dispatch('management/request', { url: `/v1/${ SECRET }/${ upstreamNamespace }?filter=metadata.name=${ generateName }` });
|
|
43
|
+
|
|
44
|
+
const applicableSecret = secrets.data?.filter((s: any) => {
|
|
45
|
+
return s.metadata.annotations['provisioning.cattle.io/sync-target-namespace'] === downstreamNamespace &&
|
|
46
|
+
s.metadata.annotations['provisioning.cattle.io/sync-target-name'] === downstreamName &&
|
|
47
|
+
s.metadata.annotations['rke.cattle.io/object-authorized-for-clusters'].includes(upstreamClusterName);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
if (applicableSecret.length > 1) {
|
|
51
|
+
return Promise.reject(new Error(`Found multiple matching secrets (${ upstreamNamespace }/${ upstreamNamespace } for ${ upstreamClusterName }), this will cause synchronizing mishaps. Consider removing stale secrets from old clusters`));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return applicableSecret[0];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
private async findOrCreateSecret(
|
|
58
|
+
rke2Component: Rke2Component,
|
|
59
|
+
{
|
|
60
|
+
generateName, upstreamClusterName, upstreamNamespace, downstreamName, downstreamNamespace, json
|
|
61
|
+
}: SecretDetails
|
|
62
|
+
) {
|
|
63
|
+
const { $store } = rke2Component;
|
|
64
|
+
|
|
65
|
+
const secretJson = await this.findSecret(rke2Component, {
|
|
66
|
+
generateName,
|
|
67
|
+
upstreamClusterName,
|
|
68
|
+
upstreamNamespace,
|
|
69
|
+
downstreamName,
|
|
70
|
+
downstreamNamespace
|
|
71
|
+
}) || json;
|
|
72
|
+
|
|
73
|
+
return await $store.dispatch('management/create', secretJson);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
private findChartValues({
|
|
77
|
+
versionInfo,
|
|
78
|
+
userChartValues,
|
|
79
|
+
chartVersionKey,
|
|
80
|
+
}: Rke2Component, chartName: string): ChartValues | undefined {
|
|
81
|
+
const chartValues = versionInfo[chartName]?.values;
|
|
82
|
+
|
|
83
|
+
if (!chartValues) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const userValues = userChartValues[chartVersionKey(chartName)];
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
defaultValues: chartValues,
|
|
90
|
+
userValues,
|
|
91
|
+
combined: merge({}, chartValues || {}, userValues || {})
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Check that system is setup to handle vsphere secrets syncing downstream
|
|
97
|
+
*
|
|
98
|
+
* Do this via checking the provider and that the required FF is enabled.
|
|
99
|
+
*/
|
|
100
|
+
private handleVsphereSecret({ $store, provider }: { $store: any, provider: string}): boolean {
|
|
101
|
+
if (provider !== VMWARE_VSPHERE) {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const isPrebootstrapEnabled = $store.getters['features/get'](PROVISIONING_PRE_BOOTSTRAP);
|
|
106
|
+
|
|
107
|
+
if (!isPrebootstrapEnabled) {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Create upstream vsphere cpi secret to sync downstream
|
|
116
|
+
*/
|
|
117
|
+
async handleVsphereCpiSecret(rke2Component: Rke2Component) {
|
|
118
|
+
if (!this.handleVsphereSecret(rke2Component)) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const generateName = `${ rootGenerateName }cpi-`;
|
|
123
|
+
const downstreamName = 'rancher-vsphere-cpi-credentials';
|
|
124
|
+
const downstreamNamespace = 'kube-system';
|
|
125
|
+
const { value } = rke2Component;
|
|
126
|
+
|
|
127
|
+
// check values for cpi chart has 'use our method' checkbox
|
|
128
|
+
const { userValues, combined } = this.findChartValues(rke2Component, 'rancher-vsphere-cpi') || {};
|
|
129
|
+
|
|
130
|
+
if (!combined?.vCenter?.credentialsSecret?.generate) {
|
|
131
|
+
if (userValues?.vCenter?.username) {
|
|
132
|
+
userValues.vCenter.username = '';
|
|
133
|
+
}
|
|
134
|
+
if (userValues?.vCenter?.password) {
|
|
135
|
+
userValues.vCenter.password = '';
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// find values needed in cpi chart value - https://github.com/rancher/vsphere-charts/blob/main/charts/rancher-vsphere-cpi/questions.yaml#L16-L42
|
|
142
|
+
const { username, password, host } = combined.vCenter;
|
|
143
|
+
|
|
144
|
+
if (!username || !password || !host) {
|
|
145
|
+
throw new Error('vSphere CPI username, password and host are all required when generating a new secret');
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// create secret as per https://github.com/rancher/vsphere-charts/blob/main/charts/rancher-vsphere-cpi/templates/secret.yaml
|
|
149
|
+
const upstreamClusterName = value.metadata.name;
|
|
150
|
+
const upstreamNamespace = value.metadata.namespace;
|
|
151
|
+
const secret = await this.findOrCreateSecret(rke2Component, {
|
|
152
|
+
generateName,
|
|
153
|
+
upstreamClusterName,
|
|
154
|
+
upstreamNamespace,
|
|
155
|
+
downstreamName,
|
|
156
|
+
downstreamNamespace,
|
|
157
|
+
json: {
|
|
158
|
+
type: SECRET,
|
|
159
|
+
metadata: {
|
|
160
|
+
namespace: upstreamNamespace,
|
|
161
|
+
generateName,
|
|
162
|
+
labels: {
|
|
163
|
+
'vsphere-cpi-infra': 'secret',
|
|
164
|
+
component: 'rancher-vsphere-cpi-cloud-controller-manager'
|
|
165
|
+
},
|
|
166
|
+
annotations: {
|
|
167
|
+
'provisioning.cattle.io/sync-target-namespace': downstreamNamespace,
|
|
168
|
+
'provisioning.cattle.io/sync-target-name': downstreamName,
|
|
169
|
+
'rke.cattle.io/object-authorized-for-clusters': upstreamClusterName,
|
|
170
|
+
'provisioning.cattle.io/sync-bootstrap': 'true'
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
secret.setData(`${ host }.username`, username);
|
|
177
|
+
secret.setData(`${ host }.password`, password);
|
|
178
|
+
|
|
179
|
+
await secret.save();
|
|
180
|
+
|
|
181
|
+
// reset cpi chart values
|
|
182
|
+
if (!userValues.vCenter.credentialsSecret) {
|
|
183
|
+
userValues.vCenter.credentialsSecret = {};
|
|
184
|
+
}
|
|
185
|
+
userValues.vCenter.credentialsSecret.generate = false;
|
|
186
|
+
userValues.vCenter.credentialsSecret.name = downstreamName;
|
|
187
|
+
userValues.vCenter.username = '';
|
|
188
|
+
userValues.vCenter.password = '';
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Create upstream vsphere csi secret to sync downstream
|
|
193
|
+
*/
|
|
194
|
+
async handleVsphereCsiSecret(rke2Component: Rke2Component) {
|
|
195
|
+
if (!this.handleVsphereSecret(rke2Component)) {
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const generateName = `${ rootGenerateName }csi-`;
|
|
200
|
+
const downstreamName = 'rancher-vsphere-csi-credentials';
|
|
201
|
+
const downstreamNamespace = 'kube-system';
|
|
202
|
+
const { value } = rke2Component;
|
|
203
|
+
|
|
204
|
+
// check values for cpi chart has 'use our method' checkbox
|
|
205
|
+
const { userValues, combined } = this.findChartValues(rke2Component, 'rancher-vsphere-csi') || {};
|
|
206
|
+
|
|
207
|
+
if (!combined?.vCenter?.configSecret?.generate) {
|
|
208
|
+
if (userValues?.vCenter?.username) {
|
|
209
|
+
userValues.vCenter.username = '';
|
|
210
|
+
}
|
|
211
|
+
if (userValues?.vCenter?.password) {
|
|
212
|
+
userValues.vCenter.password = '';
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// find values needed in cpi chart value - https://github.com/rancher/vsphere-charts/blob/main/charts/rancher-vsphere-csi/questions.yaml#L1-L36
|
|
219
|
+
const {
|
|
220
|
+
username, password, host, datacenters, port, insecureFlag
|
|
221
|
+
} = combined.vCenter;
|
|
222
|
+
|
|
223
|
+
if (!username || !password || !host || !datacenters) {
|
|
224
|
+
throw new Error('vSphere CSI username, password, host and datacenters are all required when generating a new secret');
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// This is a copy of https://github.com/rancher/vsphere-charts/blob/a5c99d716df960dc50cf417d9ecffad6b55ca0ad/charts/rancher-vsphere-csi/values.yaml#L12-L21
|
|
228
|
+
// Which makes it's way into the secret via https://github.com/rancher/vsphere-charts/blob/main/charts/rancher-vsphere-csi/templates/secret.yaml#L8
|
|
229
|
+
let configTemplateString = ' [Global]\n cluster-id = {{ required \".Values.vCenter.clusterId must be provided\" (default .Values.vCenter.clusterId .Values.global.cattle.clusterId) | quote }}\n user = {{ .Values.vCenter.username | quote }}\n password = {{ .Values.vCenter.password | quote }}\n port = {{ .Values.vCenter.port | quote }}\n insecure-flag = {{ .Values.vCenter.insecureFlag | quote }}\n\n [VirtualCenter {{ .Values.vCenter.host | quote }}]\n datacenters = {{ .Values.vCenter.datacenters | quote }}';
|
|
230
|
+
|
|
231
|
+
configTemplateString = configTemplateString.replace('{{ required \".Values.vCenter.clusterId must be provided\" (default .Values.vCenter.clusterId .Values.global.cattle.clusterId) | quote }}', `"{{clusterId}}"`);
|
|
232
|
+
configTemplateString = configTemplateString.replace('{{ .Values.vCenter.username | quote }}', `"${ username }"`);
|
|
233
|
+
configTemplateString = configTemplateString.replace('{{ .Values.vCenter.password | quote }}', `"${ password }"`);
|
|
234
|
+
configTemplateString = configTemplateString.replace('{{ .Values.vCenter.port | quote }}', `"${ port }"`);
|
|
235
|
+
configTemplateString = configTemplateString.replace('{{ .Values.vCenter.insecureFlag | quote }}', `"${ insecureFlag }"`);
|
|
236
|
+
configTemplateString = configTemplateString.replace('{{ .Values.vCenter.host | quote }}', `"${ host }"`);
|
|
237
|
+
configTemplateString = configTemplateString.replace('{{ .Values.vCenter.datacenters | quote }}', `"${ datacenters }"`);
|
|
238
|
+
// create secret as per https://github.com/rancher/vsphere-charts/blob/main/charts/rancher-vsphere-csi/templates/secret.yaml
|
|
239
|
+
const upstreamClusterName = value.metadata.name;
|
|
240
|
+
const upstreamNamespace = value.metadata.namespace;
|
|
241
|
+
|
|
242
|
+
const secret = await this.findOrCreateSecret(rke2Component, {
|
|
243
|
+
generateName,
|
|
244
|
+
upstreamClusterName,
|
|
245
|
+
upstreamNamespace,
|
|
246
|
+
downstreamName,
|
|
247
|
+
downstreamNamespace,
|
|
248
|
+
json: {
|
|
249
|
+
type: SECRET,
|
|
250
|
+
metadata: {
|
|
251
|
+
namespace: upstreamNamespace,
|
|
252
|
+
generateName,
|
|
253
|
+
annotations: {
|
|
254
|
+
'provisioning.cattle.io/sync-target-namespace': downstreamNamespace,
|
|
255
|
+
'provisioning.cattle.io/sync-target-name': downstreamName,
|
|
256
|
+
'rke.cattle.io/object-authorized-for-clusters': upstreamClusterName,
|
|
257
|
+
'provisioning.cattle.io/sync-bootstrap': 'true'
|
|
258
|
+
}
|
|
259
|
+
},
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
secret.setData(`csi-vsphere.conf`, configTemplateString);
|
|
264
|
+
|
|
265
|
+
await secret.save();
|
|
266
|
+
|
|
267
|
+
// reset csi chart values
|
|
268
|
+
if (!userValues.vCenter.configSecret) {
|
|
269
|
+
userValues.vCenter.configSecret = {};
|
|
270
|
+
}
|
|
271
|
+
userValues.vCenter.configSecret.generate = false;
|
|
272
|
+
userValues.vCenter.configSecret.name = downstreamName;
|
|
273
|
+
userValues.vCenter.username = '';
|
|
274
|
+
userValues.vCenter.password = '';
|
|
275
|
+
userValues.vCenter.host = '';
|
|
276
|
+
userValues.vCenter.datacenters = '';
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const utils = new VSphereUtils();
|
|
281
|
+
|
|
282
|
+
export default utils;
|
package/vue.config.js
CHANGED
|
@@ -120,11 +120,11 @@ const getLoaders = (SHELL_ABS) => {
|
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
return [
|
|
123
|
-
//
|
|
123
|
+
// no fallback for pre-2013 browsers https://caniuse.com/webworkers
|
|
124
124
|
{
|
|
125
125
|
test: /web-worker.[a-z-]+.js/i,
|
|
126
126
|
loader: 'worker-loader',
|
|
127
|
-
options: { inline: 'fallback' },
|
|
127
|
+
options: { inline: 'no-fallback' },
|
|
128
128
|
},
|
|
129
129
|
// Handler for csv files (e.g. ec2 instance data)
|
|
130
130
|
{
|
|
@@ -512,7 +512,7 @@ module.exports = function(dir, _appConfig) {
|
|
|
512
512
|
config.resolve.alias['@pkg'] = path.join(dir, 'pkg');
|
|
513
513
|
config.resolve.alias['./node_modules'] = path.join(dir, 'node_modules');
|
|
514
514
|
config.resolve.alias['@components'] = COMPONENTS_DIR;
|
|
515
|
-
config.resolve.alias['vue$'] = path.resolve(process.cwd(), 'node_modules', 'vue', 'dist',
|
|
515
|
+
config.resolve.alias['vue$'] = path.resolve(process.cwd(), 'node_modules', 'vue', 'dist', 'vue.js');
|
|
516
516
|
config.resolve.modules.push(__dirname);
|
|
517
517
|
config.plugins.push(getVirtualModules(dir, includePkg));
|
|
518
518
|
config.plugins.push(getAutoImport());
|