@rancher/shell 3.0.0 → 3.0.1-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/brand/harvester/favicon.png +0 -0
- package/assets/brand/harvester/metadata.json +3 -0
- package/assets/images/pl/harvester.svg +1 -0
- package/assets/translations/en-us.yaml +26 -8
- package/assets/translations/zh-hans.yaml +1 -1
- package/components/BrandImage.vue +5 -1
- package/components/CopyToClipboardText.vue +2 -0
- package/components/CruResourceFooter.vue +1 -0
- package/components/DetailTop.vue +1 -1
- package/components/ExplorerMembers.vue +5 -1
- package/components/ExplorerProjectsNamespaces.vue +39 -15
- package/components/HardwareResourceGauge.vue +12 -2
- package/components/InputOrDisplay.vue +6 -2
- package/components/LandingPagePreference.vue +2 -2
- package/components/MessageLink.vue +1 -1
- package/components/ResourceDetail/Masthead.vue +22 -1
- package/components/ResourceDetail/index.vue +2 -8
- package/components/ResourceTable.vue +14 -6
- package/components/ResourceYaml.vue +1 -1
- package/components/SideNav.vue +6 -4
- package/components/TableDataUserIcon.vue +1 -1
- package/components/fleet/FleetRepos.vue +0 -7
- package/components/form/ArrayList.vue +5 -1
- package/components/form/ArrayListSelect.vue +5 -1
- package/components/form/KeyValue.vue +1 -1
- package/components/form/LabeledSelect.vue +26 -6
- package/components/form/Password.vue +7 -1
- package/components/form/UnitInput.vue +10 -1
- package/components/form/__tests__/UnitInput.test.ts +1 -0
- package/components/formatter/ClusterProvider.vue +3 -3
- package/components/formatter/ImagePercentageBar.vue +1 -1
- package/components/formatter/Si.vue +5 -1
- package/components/formatter/Translate.vue +1 -1
- package/components/nav/Header.vue +29 -5
- package/components/nav/NamespaceFilter.vue +5 -8
- package/components/nav/TopLevelMenu.vue +16 -14
- package/config/labels-annotations.js +2 -0
- package/config/table-headers.js +15 -0
- package/config/types.js +3 -0
- package/detail/fleet.cattle.io.bundle.vue +5 -68
- package/detail/fleet.cattle.io.gitrepo.vue +2 -1
- package/directives/clean-tooltip.js +4 -4
- package/edit/constraints.gatekeeper.sh.constraint/index.vue +5 -2
- package/edit/logging-flow/Match.vue +75 -42
- package/edit/logging-flow/index.vue +89 -10
- package/edit/logging.banzaicloud.io.output/index.vue +2 -2
- package/edit/management.cattle.io.project.vue +2 -2
- package/edit/namespace.vue +1 -1
- package/edit/provisioning.cattle.io.cluster/__tests__/DirectoryConfig.test.ts +17 -7
- package/edit/provisioning.cattle.io.cluster/index.vue +2 -1
- package/edit/provisioning.cattle.io.cluster/rke2.vue +1 -3
- package/edit/provisioning.cattle.io.cluster/tabs/DirectoryConfig.vue +20 -6
- package/edit/provisioning.cattle.io.cluster/tabs/registries/RegistryMirrors.vue +1 -1
- package/list/harvesterhci.io.management.cluster.vue +244 -0
- package/list/namespace.vue +16 -4
- package/models/__tests__/management.cattle.io.cluster.test.ts +45 -3
- package/models/__tests__/provisioning.cattle.io.cluster.test.ts +0 -86
- package/models/fleet.cattle.io.bundle.js +3 -1
- package/models/fleet.cattle.io.gitrepo.js +46 -48
- package/models/k8s.cni.cncf.io.networkattachmentdefinition.js +88 -0
- package/models/management.cattle.io.cluster.js +26 -5
- package/models/management.cattle.io.setting.js +25 -0
- package/models/provisioning.cattle.io.cluster.js +5 -14
- package/models/storage.k8s.io.storageclass.js +15 -4
- package/package.json +8 -6
- package/pages/auth/login.vue +8 -2
- package/pages/auth/setup.vue +1 -1
- package/pages/c/_cluster/fleet/index.vue +2 -4
- package/pages/c/_cluster/settings/brand.vue +4 -1
- package/pages/prefs.vue +22 -10
- package/plugins/dashboard-store/resource-class.js +11 -3
- package/plugins/steve/steve-pagination-utils.ts +1 -1
- package/rancher-components/Form/LabeledInput/LabeledInput.vue +7 -2
- package/scripts/extension/parse-tag-name +19 -12
- package/scripts/publish-shell.sh +10 -2
- package/scripts/test-plugins-build.sh +8 -9
- package/scripts/typegen.sh +2 -0
- package/store/features.js +1 -0
- package/store/i18n.js +5 -1
- package/store/prefs.js +8 -0
- package/types/resources/fleet.d.ts +40 -0
- package/types/shell/index.d.ts +524 -396
- package/utils/auth.js +1 -1
- package/utils/create-yaml.js +1 -1
- package/utils/favicon.js +2 -0
- package/utils/fleet.ts +159 -0
- package/utils/gc/gc.ts +1 -1
- package/utils/v-sphere.ts +31 -0
- package/utils/validators/cron-schedule.js +1 -1
- package/utils/validators/formRules/index.ts +1 -1
- package/utils/version.js +1 -1
- package/vue.config.js +2 -2
package/utils/auth.js
CHANGED
|
@@ -116,7 +116,7 @@ export const checkSchemasForFindAllHash = (types, store) => {
|
|
|
116
116
|
const validSchema = value.schemaValidator ? value.schemaValidator(schema) : !!schema;
|
|
117
117
|
|
|
118
118
|
if (validSchema) {
|
|
119
|
-
hash[key] = store.dispatch(`${ value.inStoreType }/findAll`, { type: value.type } );
|
|
119
|
+
hash[key] = store.dispatch(`${ value.inStoreType }/findAll`, { type: value.type, opt: value.opt } );
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
122
|
|
package/utils/create-yaml.js
CHANGED
|
@@ -176,7 +176,7 @@ export function createYaml(
|
|
|
176
176
|
}
|
|
177
177
|
|
|
178
178
|
// ACTIVELY_REMOVE are fields that should be removed even if they are defined in data
|
|
179
|
-
for ( const entry of ACTIVELY_REMOVE ) {
|
|
179
|
+
for ( const entry of (dataOptions.activelyRemove || ACTIVELY_REMOVE) ) {
|
|
180
180
|
const parts = entry.split(/\./);
|
|
181
181
|
const key = parts[parts.length - 1];
|
|
182
182
|
const prefix = parts.slice(0, -1).join('.');
|
package/utils/favicon.js
CHANGED
|
@@ -19,6 +19,8 @@ export function setFavIcon(store) {
|
|
|
19
19
|
brandImage = require('~shell/assets/brand/suse/favicon.png');
|
|
20
20
|
} else if (brandSetting?.value === 'csp') {
|
|
21
21
|
brandImage = require('~shell/assets/brand/csp/favicon.png');
|
|
22
|
+
} else if (brandSetting?.value === 'harvester') {
|
|
23
|
+
brandImage = require('~shell/assets/brand/harvester/favicon.png');
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
link.href = res?.value || brandImage || defaultFavIcon;
|
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/gc/gc.ts
CHANGED
|
@@ -29,7 +29,7 @@ class GarbageCollect {
|
|
|
29
29
|
* To avoid JSON.parse on the `ui-performance` setting keep a local cache
|
|
30
30
|
*/
|
|
31
31
|
private getUiPerfGarbageCollection = (rootState: any) => {
|
|
32
|
-
const uiPerfSetting = rootState.management.types[MANAGEMENT.SETTING]?.list
|
|
32
|
+
const uiPerfSetting = rootState.management.types[MANAGEMENT.SETTING]?.list?.find((s: any) => s.id === SETTING.UI_PERFORMANCE);
|
|
33
33
|
|
|
34
34
|
if (!uiPerfSetting || !uiPerfSetting.value) {
|
|
35
35
|
// Could be in the process of logging out
|
package/utils/v-sphere.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import merge from 'lodash/merge';
|
|
2
2
|
import { SECRET } from '@shell/config/types';
|
|
3
|
+
import { PROVISIONING_PRE_BOOTSTRAP } from '@shell/store/features';
|
|
4
|
+
|
|
5
|
+
export const VMWARE_VSPHERE = 'vmwarevsphere';
|
|
3
6
|
|
|
4
7
|
type Rke2Component = {
|
|
5
8
|
versionInfo: any;
|
|
@@ -7,6 +10,7 @@ type Rke2Component = {
|
|
|
7
10
|
chartVersionKey: (chartName: string) => string;
|
|
8
11
|
value: any;
|
|
9
12
|
isEdit: boolean;
|
|
13
|
+
provider: string;
|
|
10
14
|
$store: any,
|
|
11
15
|
}
|
|
12
16
|
|
|
@@ -91,10 +95,33 @@ class VSphereUtils {
|
|
|
91
95
|
};
|
|
92
96
|
}
|
|
93
97
|
|
|
98
|
+
/**
|
|
99
|
+
* Check that system is setup to handle vsphere secrets syncing downstream
|
|
100
|
+
*
|
|
101
|
+
* Do this via checking the provider and that the required FF is enabled.
|
|
102
|
+
*/
|
|
103
|
+
private handleVsphereSecret({ $store, provider }: { $store: any, provider: string}): boolean {
|
|
104
|
+
if (provider !== VMWARE_VSPHERE) {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const isPrebootstrapEnabled = $store.getters['features/get'](PROVISIONING_PRE_BOOTSTRAP);
|
|
109
|
+
|
|
110
|
+
if (!isPrebootstrapEnabled) {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
|
|
94
117
|
/**
|
|
95
118
|
* Create upstream vsphere cpi secret to sync downstream
|
|
96
119
|
*/
|
|
97
120
|
async handleVsphereCpiSecret(rke2Component: Rke2Component) {
|
|
121
|
+
if (!this.handleVsphereSecret(rke2Component)) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
98
125
|
const generateName = `${ rootGenerateName }cpi-`;
|
|
99
126
|
const downstreamName = 'rancher-vsphere-cpi-credentials';
|
|
100
127
|
const downstreamNamespace = 'kube-system';
|
|
@@ -168,6 +195,10 @@ class VSphereUtils {
|
|
|
168
195
|
* Create upstream vsphere csi secret to sync downstream
|
|
169
196
|
*/
|
|
170
197
|
async handleVsphereCsiSecret(rke2Component: Rke2Component) {
|
|
198
|
+
if (!this.handleVsphereSecret(rke2Component)) {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
|
|
171
202
|
const generateName = `${ rootGenerateName }csi-`;
|
|
172
203
|
const downstreamName = 'rancher-vsphere-csi-credentials';
|
|
173
204
|
const downstreamNamespace = 'kube-system';
|
|
@@ -2,7 +2,7 @@ import cronstrue from 'cronstrue';
|
|
|
2
2
|
|
|
3
3
|
export function cronSchedule(schedule = '', getters, errors) {
|
|
4
4
|
try {
|
|
5
|
-
cronstrue.toString(schedule);
|
|
5
|
+
cronstrue.toString(schedule, { verbose: true });
|
|
6
6
|
} catch (e) {
|
|
7
7
|
errors.push(getters['i18n/t']('validation.invalidCron'));
|
|
8
8
|
}
|
|
@@ -131,7 +131,7 @@ export default function(t: Translation, { key = 'Value' }: ValidationOptions): {
|
|
|
131
131
|
|
|
132
132
|
const cronSchedule: Validator = (val: string) => {
|
|
133
133
|
try {
|
|
134
|
-
cronstrue.toString(val);
|
|
134
|
+
cronstrue.toString(val, { verbose: true });
|
|
135
135
|
} catch (e) {
|
|
136
136
|
return t('validation.invalidCron');
|
|
137
137
|
}
|
package/utils/version.js
CHANGED
package/vue.config.js
CHANGED
|
@@ -131,11 +131,11 @@ const instrumentCode = () => {
|
|
|
131
131
|
};
|
|
132
132
|
|
|
133
133
|
const getLoaders = (SHELL_ABS) => [
|
|
134
|
-
//
|
|
134
|
+
// no fallback for pre-2013 browsers https://caniuse.com/webworkers
|
|
135
135
|
{
|
|
136
136
|
test: /web-worker.[a-z-]+.js/i,
|
|
137
137
|
loader: 'worker-loader',
|
|
138
|
-
options: { inline: 'fallback' },
|
|
138
|
+
options: { inline: 'no-fallback' },
|
|
139
139
|
},
|
|
140
140
|
// Handler for csv files (e.g. ec2 instance data)
|
|
141
141
|
{
|