@rancher/shell 0.1.4 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/brand/suse/favicon.png +0 -0
- package/assets/images/generic-plugin.svg +1 -7
- package/assets/styles/global/_button.scss +1 -0
- package/assets/translations/en-us.yaml +129 -53
- package/assets/translations/zh-hans.yaml +18 -0
- package/components/CommunityLinks.vue +40 -49
- package/components/ExplorerProjectsNamespaces.vue +20 -3
- package/components/HarvesterServiceAddOnConfig.vue +10 -10
- package/components/LazyImage.vue +21 -8
- package/components/PromptRemove.vue +2 -2
- package/components/ResourceList/Masthead.vue +21 -1
- package/components/ResourceList/ResourceLoadingIndicator.vue +0 -8
- package/components/ResourceList/index.vue +42 -36
- package/components/ResourceTable.vue +19 -0
- package/components/SortableTable/THead.vue +311 -70
- package/components/SortableTable/advanced-filtering.js +272 -0
- package/components/SortableTable/filtering.js +90 -29
- package/components/SortableTable/index.vue +486 -280
- package/components/Tabbed/index.vue +25 -7
- package/components/TypeDescription.vue +10 -1
- package/components/fleet/FleetClusters.vue +6 -0
- package/components/fleet/FleetRepos.vue +7 -1
- package/components/form/Command.vue +5 -0
- package/components/form/EnvVars.vue +5 -0
- package/components/form/NameNsDescription.vue +3 -1
- package/components/form/NodeScheduling.vue +6 -1
- package/components/form/PodAffinity.vue +5 -0
- package/components/form/ServiceNameSelect.vue +5 -0
- package/components/form/ValueFromResource.vue +7 -1
- package/components/form/WorkloadPorts.vue +2 -2
- package/components/nav/TopLevelMenu.vue +2 -1
- package/config/home-links.js +155 -0
- package/config/private-label.js +1 -1
- package/config/product/manager.js +0 -2
- package/config/product/settings.js +1 -0
- package/config/product/uiplugins.js +2 -1
- package/config/settings.js +3 -1
- package/config/uiplugins.js +76 -6
- package/config/version.js +17 -0
- package/core/plugin.ts +12 -0
- package/core/plugins.js +29 -5
- package/core/types.ts +6 -0
- package/creators/app/{.eslintignore → files/.eslintignore} +0 -0
- package/creators/app/{.eslintrc.js → files/.eslintrc.js} +0 -0
- package/creators/app/{.vscode → files/.vscode}/settings.json +0 -0
- package/creators/app/{babel.config.js → files/babel.config.js} +0 -0
- package/creators/app/{nuxt.config.js → files/nuxt.config.js} +0 -0
- package/creators/app/{tsconfig.json → files/tsconfig.json} +2 -1
- package/creators/app/init +16 -17
- package/creators/app/package.json +7 -1
- package/creators/pkg/{babel.config.js → files/babel.config.js} +0 -0
- package/creators/pkg/{index.ts → files/index.ts} +0 -0
- package/creators/pkg/{tsconfig.json → files/tsconfig.json} +13 -12
- package/creators/pkg/{vue.config.js → files/vue.config.js} +0 -0
- package/creators/pkg/init +1 -1
- package/creators/pkg/package.json +1 -1
- package/creators/update/init +54 -0
- package/creators/update/package.json +20 -0
- package/creators/update/upgrade +56 -0
- package/creators/update/yarn-error.log +54 -0
- package/detail/provisioning.cattle.io.cluster.vue +1 -1
- package/detail/workload/index.vue +1 -0
- package/edit/persistentvolume/index.vue +48 -13
- package/edit/persistentvolumeclaim.vue +31 -13
- package/edit/provisioning.cattle.io.cluster/ACE.vue +2 -1
- package/edit/provisioning.cattle.io.cluster/DrainOptions.vue +0 -1
- package/edit/provisioning.cattle.io.cluster/rke2.vue +52 -43
- package/edit/service.vue +1 -1
- package/edit/workload/index.vue +19 -9
- package/edit/workload/mixins/workload.js +109 -114
- package/edit/workload/storage/index.vue +11 -17
- package/edit/workload/storage/persistentVolumeClaim/index.vue +5 -0
- package/edit/workload/storage/secret.vue +6 -1
- package/list/catalog.cattle.io.app.vue +10 -9
- package/list/catalog.cattle.io.clusterrepo.vue +6 -61
- package/list/cis.cattle.io.clusterscan.vue +12 -12
- package/list/fleet.cattle.io.bundle.vue +33 -28
- package/list/fleet.cattle.io.cluster.vue +26 -22
- package/list/fleet.cattle.io.clustergroup.vue +6 -0
- package/list/fleet.cattle.io.clusterregistrationtoken.vue +28 -24
- package/list/fleet.cattle.io.gitrepo.vue +25 -14
- package/list/helm.cattle.io.projecthelmchart.vue +52 -33
- package/list/logging.banzaicloud.io.clusterflow.vue +7 -12
- package/list/logging.banzaicloud.io.flow.vue +7 -14
- package/list/management.cattle.io.cluster.vue +26 -15
- package/list/management.cattle.io.feature.vue +13 -8
- package/list/management.cattle.io.user.vue +38 -19
- package/list/monitoring.coreos.com.alertmanagerconfig.vue +8 -15
- package/list/namespace.vue +14 -1
- package/list/node.vue +13 -16
- package/list/persistentvolume.vue +16 -9
- package/list/persistentvolumeclaim.vue +5 -8
- package/list/provisioning.cattle.io.cluster.vue +34 -8
- package/list/service.vue +24 -12
- package/list/ui.cattle.io.navlink.vue +6 -0
- package/list/workload.vue +2 -2
- package/middleware/authenticated.js +6 -0
- package/mixins/resource-fetch.js +12 -18
- package/mixins/resource-manager.js +126 -0
- package/models/catalog.cattle.io.uiplugin.js +4 -0
- package/models/management.cattle.io.cluster.js +9 -1
- package/models/pod.js +15 -5
- package/models/provisioning.cattle.io.cluster.js +4 -0
- package/models/workload.service.js +10 -0
- package/nuxt.config.js +2 -1
- package/package.json +1 -1
- package/pages/auth/login.vue +10 -0
- package/pages/auth/verify.vue +9 -0
- package/pages/c/_cluster/apps/charts/install.vue +119 -31
- package/pages/c/_cluster/settings/DefaultLinksEditor.vue +108 -0
- package/pages/c/_cluster/settings/links.vue +53 -101
- package/pages/c/_cluster/settings/performance.vue +90 -7
- package/pages/c/_cluster/uiplugins/DeveloperInstallDialog.vue +3 -3
- package/pages/c/_cluster/uiplugins/InstallDialog.vue +72 -21
- package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +26 -7
- package/pages/c/_cluster/uiplugins/RemoveUIPlugins.vue +2 -7
- package/pages/c/_cluster/uiplugins/SetupUIPlugins.vue +23 -15
- package/pages/c/_cluster/uiplugins/UninstallDialog.vue +12 -5
- package/pages/c/_cluster/uiplugins/index.vue +223 -72
- package/pages/support/index.vue +31 -142
- package/plugins/dashboard-store/actions.js +19 -0
- package/plugins/dashboard-store/getters.js +20 -3
- package/plugins/dashboard-store/mutations.js +13 -7
- package/plugins/plugin.js +18 -15
- package/plugins/steve/getters.js +12 -0
- package/plugins/version.js +21 -0
- package/promptRemove/mixin/roleDeletionCheck.js +15 -1
- package/rancher-components/Form/TextArea/TextAreaAutoGrow.vue +6 -7
- package/rancher-components/components/BadgeState/BadgeState.spec.ts +12 -0
- package/rancher-components/components/BadgeState/BadgeState.vue +107 -0
- package/rancher-components/components/BadgeState/index.ts +1 -0
- package/rancher-components/components/Banner/Banner.test.ts +13 -0
- package/rancher-components/components/Banner/Banner.vue +163 -0
- package/rancher-components/components/Banner/index.ts +1 -0
- package/rancher-components/components/Card/Card.vue +150 -0
- package/rancher-components/components/Card/index.ts +1 -0
- package/rancher-components/components/Form/Checkbox/Checkbox.test.ts +77 -0
- package/rancher-components/components/Form/Checkbox/Checkbox.vue +395 -0
- package/rancher-components/components/Form/Checkbox/index.ts +1 -0
- package/rancher-components/components/Form/LabeledInput/LabeledInput.test.ts +29 -0
- package/rancher-components/components/Form/LabeledInput/LabeledInput.vue +343 -0
- package/rancher-components/components/Form/LabeledInput/index.ts +1 -0
- package/rancher-components/components/Form/Radio/RadioButton.vue +270 -0
- package/rancher-components/components/Form/Radio/RadioGroup.vue +235 -0
- package/rancher-components/components/Form/Radio/index.ts +2 -0
- package/rancher-components/components/Form/TextArea/TextAreaAutoGrow.vue +168 -0
- package/rancher-components/components/Form/TextArea/index.ts +1 -0
- package/rancher-components/components/Form/ToggleSwitch/ToggleSwitch.test.ts +107 -0
- package/rancher-components/components/Form/ToggleSwitch/ToggleSwitch.vue +137 -0
- package/rancher-components/components/Form/ToggleSwitch/index.ts +1 -0
- package/rancher-components/components/Form/index.ts +5 -0
- package/rancher-components/components/LabeledTooltip/LabeledTooltip.vue +137 -0
- package/rancher-components/components/LabeledTooltip/index.ts +1 -0
- package/scripts/publish-shell.sh +39 -6
- package/scripts/record-deps.js +37 -0
- package/scripts/test-plugins-build.sh +8 -5
- package/scripts/typegen.sh +84 -0
- package/store/auth.js +3 -0
- package/store/index.js +12 -3
- package/store/type-map.js +2 -0
- package/types/shell/index.d.ts +3046 -0
- package/utils/favicon.js +8 -2
- package/utils/gc/gc-interval.ts +40 -0
- package/utils/gc/gc-root-store.js +76 -0
- package/utils/gc/gc-route-changed.ts +44 -0
- package/utils/gc/gc-types.ts +21 -0
- package/utils/gc/gc.ts +282 -0
- package/config/footer.js +0 -18
- package/creators/pkg/nuxt.config.js +0 -6
- package/yarn-error.log +0 -195
package/mixins/resource-fetch.js
CHANGED
|
@@ -1,26 +1,10 @@
|
|
|
1
1
|
import { mapGetters } from 'vuex';
|
|
2
|
-
import {
|
|
3
|
-
COUNT, MANAGEMENT, POD, WORKLOAD_TYPES, WORKLOAD, SECRET
|
|
4
|
-
} from '@shell/config/types';
|
|
2
|
+
import { COUNT, MANAGEMENT } from '@shell/config/types';
|
|
5
3
|
import { SETTING, DEFAULT_PERF_SETTING } from '@shell/config/settings';
|
|
6
4
|
|
|
7
5
|
// Number of pages to fetch when loading incrementally
|
|
8
6
|
const PAGES = 4;
|
|
9
7
|
|
|
10
|
-
// restrict advanced features of manual refresh and incremental loading to these resource types
|
|
11
|
-
export const TYPES_RESTRICTED = [
|
|
12
|
-
SECRET,
|
|
13
|
-
POD,
|
|
14
|
-
WORKLOAD_TYPES.DEPLOYMENT,
|
|
15
|
-
WORKLOAD_TYPES.CRON_JOB,
|
|
16
|
-
WORKLOAD_TYPES.DAEMON_SET,
|
|
17
|
-
WORKLOAD_TYPES.JOB,
|
|
18
|
-
WORKLOAD_TYPES.STATEFUL_SET,
|
|
19
|
-
WORKLOAD_TYPES.REPLICA_SET,
|
|
20
|
-
WORKLOAD_TYPES.REPLICATION_CONTROLLER,
|
|
21
|
-
WORKLOAD
|
|
22
|
-
];
|
|
23
|
-
|
|
24
8
|
export default {
|
|
25
9
|
data() {
|
|
26
10
|
// fetching the settings related to manual refresh from global settings
|
|
@@ -66,7 +50,17 @@ export default {
|
|
|
66
50
|
}
|
|
67
51
|
},
|
|
68
52
|
|
|
69
|
-
computed: {
|
|
53
|
+
computed: {
|
|
54
|
+
...mapGetters({ refreshFlag: 'resource-fetch/refreshFlag' }),
|
|
55
|
+
rows() {
|
|
56
|
+
const inStore = this.$store.getters['currentStore'](this.resource);
|
|
57
|
+
|
|
58
|
+
return this.$store.getters[`${ inStore }/all`](this.resource);
|
|
59
|
+
},
|
|
60
|
+
loading() {
|
|
61
|
+
return this.rows.length ? false : this.$fetchState.pending;
|
|
62
|
+
},
|
|
63
|
+
},
|
|
70
64
|
watch: {
|
|
71
65
|
refreshFlag(neu) {
|
|
72
66
|
// this is where the data assignment will trigger the update of the list view...
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { mapGetters } from 'vuex';
|
|
2
|
+
import { allHashSettled } from '@shell/utils/promise';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
computed: { ...mapGetters(['currentCluster']) },
|
|
6
|
+
data() {
|
|
7
|
+
return { isLoadingSecondaryResources: false };
|
|
8
|
+
},
|
|
9
|
+
methods: {
|
|
10
|
+
/**
|
|
11
|
+
*
|
|
12
|
+
* Function resourceManagerFetchSecondaryResources
|
|
13
|
+
* This method is used to fetch what is called "secondary resources", which can be defined as resources that are needed to populate
|
|
14
|
+
* the page/component itself (ex: used as options on a Select) but don't need to be put into Vuex store or watched to get constant updates.
|
|
15
|
+
* This method allows to fetch resources for a given namespace to reduce the amount of results instead of needing to fetch all and filtering afterwards.
|
|
16
|
+
*
|
|
17
|
+
*
|
|
18
|
+
* @param {String} resourceData.namespace - Namespace identifier
|
|
19
|
+
* @param {Object} resourceData.data - Object containing info about the data needed to be fetched and how it should be parsed. Note: The KEY NEEDS to be the resource TYPE!
|
|
20
|
+
* @param {Array} resourceData.data[TYPE].applyTo - The array of operations needed to be performed for the specific data TYPE
|
|
21
|
+
* @param {String} resourceData.data[TYPE].applyTo[x].var - The 'this' property name that should be populated with the data fetched
|
|
22
|
+
* @param {Boolean} resourceData.data[TYPE].applyTo[x].classify - Whether the data fetched should have a model applied to it
|
|
23
|
+
* @param {Function} resourceData.data[TYPE].applyTo[x].parsingFunc - Optional parsing function if the fetched data needs to be parsed
|
|
24
|
+
* @param {Boolean} onlyNamespaced - Only fetch namespaced resources
|
|
25
|
+
*/
|
|
26
|
+
async resourceManagerFetchSecondaryResources(resourceData, onlyNamespaced = false) {
|
|
27
|
+
const requests = {};
|
|
28
|
+
const namespace = resourceData.namespace;
|
|
29
|
+
|
|
30
|
+
// Only fetch types if the user is allowed to...
|
|
31
|
+
Object.keys(resourceData.data).forEach((type) => {
|
|
32
|
+
const schema = this.$store.getters['cluster/schemaFor'](type);
|
|
33
|
+
|
|
34
|
+
if (schema) {
|
|
35
|
+
let url = schema.links.collection;
|
|
36
|
+
|
|
37
|
+
if (schema?.attributes?.namespaced && namespace) {
|
|
38
|
+
const parts = url.split('/');
|
|
39
|
+
|
|
40
|
+
parts.splice(parts.length - 2, 0, `api`);
|
|
41
|
+
parts.splice(parts.length - 1, 0, `namespaces/${ namespace }`);
|
|
42
|
+
url = parts.join('/');
|
|
43
|
+
} else if (onlyNamespaced) {
|
|
44
|
+
// Type isn't namespaced and we've been requested to only fetch namespaced types
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
requests[type] = this.$store.dispatch('cluster/request', { url });
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
if (Object.keys(requests).length) {
|
|
53
|
+
// this is the flag/variable that we need to apply to all places that rely on this data. Ex: LabeledSelect
|
|
54
|
+
this.isLoadingSecondaryResources = true;
|
|
55
|
+
const hash = await allHashSettled(requests);
|
|
56
|
+
const types = Object.keys(hash);
|
|
57
|
+
|
|
58
|
+
for (let i = 0; i < types.length; i++) {
|
|
59
|
+
const type = types[i];
|
|
60
|
+
const status = hash[type].status;
|
|
61
|
+
// if it's namespaced, we get the data on 'items' prop, for non-namespaced it's 'data' prop...
|
|
62
|
+
const requestData = hash[type].value.items || hash[type].value.data || hash[type].value;
|
|
63
|
+
const schema = this.$store.getters['cluster/schemaFor'](type);
|
|
64
|
+
|
|
65
|
+
if (status === 'fulfilled' && resourceData.data[type] && resourceData.data[type].applyTo?.length) {
|
|
66
|
+
for (let y = 0; y < resourceData.data[type].applyTo.length; y++) {
|
|
67
|
+
const apply = resourceData.data[type].applyTo[y];
|
|
68
|
+
let resources = requestData;
|
|
69
|
+
|
|
70
|
+
if (schema?.attributes?.namespaced) {
|
|
71
|
+
// The resources returned when requesting namespaced types do not contain id, type and links properties.
|
|
72
|
+
// This isn't perfect, or universally applicable, but will work for the current set of use cases
|
|
73
|
+
// To make this more generic
|
|
74
|
+
// - id param = this.$store.getters['cluster/keyFieldForType'](type)
|
|
75
|
+
// - id value = new dashboard-store getter, overwritten by steve store getter
|
|
76
|
+
requestData.forEach((item) => {
|
|
77
|
+
item.type = type;
|
|
78
|
+
item.id = `${ item.metadata.namespace }/${ item.metadata.name }`;
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (apply.classify) {
|
|
83
|
+
resources = await this.$store.dispatch('cluster/createMany', requestData);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (apply.parsingFunc) {
|
|
87
|
+
this[apply.var] = apply.parsingFunc(resources);
|
|
88
|
+
} else {
|
|
89
|
+
this[apply.var] = resources;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
} else if (status === 'rejected') {
|
|
93
|
+
console.error(`Resource Manager - secondary data request for type ${ type } has failed`, status.error); // eslint-disable-line no-console
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
this.isLoadingSecondaryResources = false;
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Clear the cached secondary resources
|
|
103
|
+
*
|
|
104
|
+
* @param {*} resourceData See resourceManagerFetchSecondaryResources
|
|
105
|
+
* @param {*} onlyNamespaced Clear only namespaced resources
|
|
106
|
+
*/
|
|
107
|
+
resourceManagerClearSecondaryResources(resourceData, onlyNamespaced = false) {
|
|
108
|
+
Object.keys(resourceData.data).forEach((type) => {
|
|
109
|
+
const schema = this.$store.getters['cluster/schemaFor'](type);
|
|
110
|
+
|
|
111
|
+
if (schema) {
|
|
112
|
+
if (!schema?.attributes?.namespaced && onlyNamespaced) {
|
|
113
|
+
// resource isn't namespaced and we're only interested in namespaced resources
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
for (let y = 0; y < resourceData.data[type].applyTo.length; y++) {
|
|
118
|
+
const apply = resourceData.data[type].applyTo[y];
|
|
119
|
+
|
|
120
|
+
this[apply.var] = [];
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import Vue from 'vue';
|
|
2
2
|
import { CATALOG, CLUSTER_BADGE } from '@shell/config/labels-annotations';
|
|
3
|
-
import { NODE, FLEET, MANAGEMENT } from '@shell/config/types';
|
|
3
|
+
import { NODE, FLEET, MANAGEMENT, CAPI } from '@shell/config/types';
|
|
4
4
|
import { insertAt } from '@shell/utils/array';
|
|
5
5
|
import { downloadFile } from '@shell/utils/download';
|
|
6
6
|
import { parseSi } from '@shell/utils/units';
|
|
@@ -430,4 +430,12 @@ export default class MgmtCluster extends HybridModel {
|
|
|
430
430
|
get nodes() {
|
|
431
431
|
return this.$getters['all'](MANAGEMENT.NODE).filter(node => node.id.startsWith(this.id));
|
|
432
432
|
}
|
|
433
|
+
|
|
434
|
+
get provClusterId() {
|
|
435
|
+
const verb = this.isLocal ? 'to' : 'from';
|
|
436
|
+
const from = `${ verb }Type`;
|
|
437
|
+
const id = `${ verb }Id`;
|
|
438
|
+
|
|
439
|
+
return this.metadata.relationships.find(r => r[from] === CAPI.RANCHER_CLUSTER)?.[id];
|
|
440
|
+
}
|
|
433
441
|
}
|
package/models/pod.js
CHANGED
|
@@ -182,19 +182,29 @@ export default class Pod extends WorkloadService {
|
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
save() {
|
|
185
|
+
const prev = { ...this };
|
|
186
|
+
|
|
185
187
|
const { metadata, spec } = this.spec.template;
|
|
186
188
|
|
|
187
189
|
this.spec = {
|
|
188
190
|
...this.spec,
|
|
189
|
-
metadata: {
|
|
190
|
-
...this.metadata,
|
|
191
|
-
...metadata
|
|
192
|
-
},
|
|
193
191
|
...spec
|
|
194
192
|
};
|
|
195
193
|
|
|
194
|
+
this.metadata = {
|
|
195
|
+
...this.metadata,
|
|
196
|
+
...metadata
|
|
197
|
+
};
|
|
198
|
+
|
|
196
199
|
delete this.spec.template;
|
|
197
200
|
|
|
198
|
-
|
|
201
|
+
// IF there is an error POD world model get overwritten
|
|
202
|
+
// For the workloads this need be reset back
|
|
203
|
+
return this._save(...arguments).catch((e) => {
|
|
204
|
+
this.spec = prev.spec;
|
|
205
|
+
this.metadata = prev.metadata;
|
|
206
|
+
|
|
207
|
+
return Promise.reject(e);
|
|
208
|
+
});
|
|
199
209
|
}
|
|
200
210
|
}
|
|
@@ -679,6 +679,10 @@ export default class ProvCluster extends SteveModel {
|
|
|
679
679
|
}
|
|
680
680
|
|
|
681
681
|
get supportsWindows() {
|
|
682
|
+
if (this.isK3s || this.isImportedK3s) {
|
|
683
|
+
return false;
|
|
684
|
+
}
|
|
685
|
+
|
|
682
686
|
if ( this.isRke1 ) {
|
|
683
687
|
return this.mgmt?.spec?.windowsPreferedCluster || false;
|
|
684
688
|
}
|
|
@@ -123,6 +123,11 @@ export default class WorkloadService extends SteveModel {
|
|
|
123
123
|
|
|
124
124
|
return containers;
|
|
125
125
|
}
|
|
126
|
+
|
|
127
|
+
if ( this.spec.containers ) {
|
|
128
|
+
return this.spec.containers;
|
|
129
|
+
}
|
|
130
|
+
|
|
126
131
|
const { spec:{ template:{ spec:{ containers } } } } = this;
|
|
127
132
|
|
|
128
133
|
return containers;
|
|
@@ -135,6 +140,11 @@ export default class WorkloadService extends SteveModel {
|
|
|
135
140
|
|
|
136
141
|
return initContainers;
|
|
137
142
|
}
|
|
143
|
+
|
|
144
|
+
if (this.spec.initContainers) {
|
|
145
|
+
return this.spec.initContainers;
|
|
146
|
+
}
|
|
147
|
+
|
|
138
148
|
const { spec:{ template:{ spec:{ initContainers } } } } = this;
|
|
139
149
|
|
|
140
150
|
return initContainers;
|
package/nuxt.config.js
CHANGED
|
@@ -582,6 +582,7 @@ export default function(dir, _appConfig) {
|
|
|
582
582
|
{ src: path.join(NUXT_SHELL, 'plugins/plugin'), ssr: false }, // Load dyanmic plugins
|
|
583
583
|
{ src: path.join(NUXT_SHELL, 'plugins/codemirror-loader'), ssr: false },
|
|
584
584
|
{ src: path.join(NUXT_SHELL, 'plugins/formatters'), ssr: false }, // Populate formatters cache for sorted table
|
|
585
|
+
{ src: path.join(NUXT_SHELL, 'plugins/version'), ssr: false }, // Makes a fetch to the backend to get version metadata
|
|
585
586
|
],
|
|
586
587
|
|
|
587
588
|
// Proxy: https://github.com/nuxt-community/proxy-module#options
|
|
@@ -595,8 +596,8 @@ export default function(dir, _appConfig) {
|
|
|
595
596
|
'/v3-public': proxyOpts(api), // Rancher Unauthed API
|
|
596
597
|
'/api-ui': proxyOpts(api), // Browser API UI
|
|
597
598
|
'/meta': proxyMetaOpts(api), // Browser API UI
|
|
598
|
-
'/rancherversion': proxyPrimeOpts(api), // Rancher version endpoint
|
|
599
599
|
'/v1-*': proxyOpts(api), // SAML, KDM, etc
|
|
600
|
+
'/rancherversion': proxyPrimeOpts(api), // Rancher version endpoint
|
|
600
601
|
// These are for Ember embedding
|
|
601
602
|
'/c/*/edit': proxyOpts('https://127.0.0.1:8000'), // Can't proxy all of /c because that's used by Vue too
|
|
602
603
|
'/k/': proxyOpts('https://127.0.0.1:8000'),
|
package/package.json
CHANGED
package/pages/auth/login.vue
CHANGED
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
setBrand,
|
|
27
27
|
setVendor
|
|
28
28
|
} from '@shell/config/private-label';
|
|
29
|
+
import loadPlugins from '@shell/plugins/plugin';
|
|
29
30
|
|
|
30
31
|
export default {
|
|
31
32
|
name: 'Login',
|
|
@@ -255,6 +256,15 @@ export default {
|
|
|
255
256
|
this.$cookies.remove(USERNAME);
|
|
256
257
|
}
|
|
257
258
|
|
|
259
|
+
// User logged with local login - we don't do any redirect/reload, so the boot-time plugin will not run again to laod the plugins
|
|
260
|
+
// so we manually load them here - other SSO auth providers bounce out and back to the Dashboard, so on the bounce-back
|
|
261
|
+
// the plugins will load via the boot-time plugin
|
|
262
|
+
await loadPlugins({
|
|
263
|
+
app: this.$store.app,
|
|
264
|
+
store: this.$store,
|
|
265
|
+
$plugin: this.$store.$plugin
|
|
266
|
+
});
|
|
267
|
+
|
|
258
268
|
if (this.firstLogin || user[0]?.mustChangePassword) {
|
|
259
269
|
this.$store.dispatch('auth/setInitialPass', this.password);
|
|
260
270
|
this.$router.push({ name: 'auth-setup' });
|
package/pages/auth/verify.vue
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
import { GITHUB_CODE, GITHUB_NONCE, BACK_TO } from '@shell/config/query-params';
|
|
3
3
|
import { get } from '@shell/utils/object';
|
|
4
4
|
import { base64Decode } from '@shell/utils/crypto';
|
|
5
|
+
import loadPlugins from '@shell/plugins/plugin';
|
|
6
|
+
|
|
5
7
|
const samlProviders = ['ping', 'adfs', 'keycloak', 'okta', 'shibboleth'];
|
|
6
8
|
|
|
7
9
|
function reply(err, code) {
|
|
@@ -60,6 +62,13 @@ export default {
|
|
|
60
62
|
if ( res._status === 200) {
|
|
61
63
|
const backTo = route.query[BACK_TO] || '/';
|
|
62
64
|
|
|
65
|
+
// Load plugins
|
|
66
|
+
await loadPlugins({
|
|
67
|
+
app: store.app,
|
|
68
|
+
store,
|
|
69
|
+
$plugin: store.$plugin
|
|
70
|
+
});
|
|
71
|
+
|
|
63
72
|
redirect(backTo);
|
|
64
73
|
} else {
|
|
65
74
|
redirect(`/auth/login?err=${ escape(res) }`);
|
|
@@ -5,13 +5,13 @@ import isEqual from 'lodash/isEqual';
|
|
|
5
5
|
import { mapPref, DIFF } from '@shell/store/prefs';
|
|
6
6
|
import { mapFeature, MULTI_CLUSTER, LEGACY } from '@shell/store/features';
|
|
7
7
|
import { mapGetters } from 'vuex';
|
|
8
|
-
|
|
9
8
|
import { Banner } from '@components/Banner';
|
|
10
9
|
import ButtonGroup from '@shell/components/ButtonGroup';
|
|
11
10
|
import ChartReadme from '@shell/components/ChartReadme';
|
|
12
11
|
import { Checkbox } from '@components/Form/Checkbox';
|
|
13
12
|
import LabeledSelect from '@shell/components/form/LabeledSelect';
|
|
14
13
|
import { LabeledInput } from '@components/Form/LabeledInput';
|
|
14
|
+
import { LabeledTooltip } from '@components/LabeledTooltip';
|
|
15
15
|
import LazyImage from '@shell/components/LazyImage';
|
|
16
16
|
import Loading from '@shell/components/Loading';
|
|
17
17
|
import NameNsDescription from '@shell/components/form/NameNsDescription';
|
|
@@ -24,7 +24,7 @@ import Wizard from '@shell/components/Wizard';
|
|
|
24
24
|
import TypeDescription from '@shell/components/TypeDescription';
|
|
25
25
|
import ChartMixin from '@shell/mixins/chart';
|
|
26
26
|
import ChildHook, { BEFORE_SAVE_HOOKS, AFTER_SAVE_HOOKS } from '@shell/mixins/child-hook';
|
|
27
|
-
import { CATALOG, MANAGEMENT, DEFAULT_WORKSPACE } from '@shell/config/types';
|
|
27
|
+
import { CATALOG, MANAGEMENT, DEFAULT_WORKSPACE, CAPI } from '@shell/config/types';
|
|
28
28
|
import {
|
|
29
29
|
CHART, FROM_CLUSTER, FROM_TOOLS, HIDE_SIDE_NAV, NAMESPACE, REPO, REPO_TYPE, VERSION, _FLAGGED
|
|
30
30
|
} from '@shell/config/query-params';
|
|
@@ -61,6 +61,7 @@ export default {
|
|
|
61
61
|
Checkbox,
|
|
62
62
|
LabeledInput,
|
|
63
63
|
LabeledSelect,
|
|
64
|
+
LabeledTooltip,
|
|
64
65
|
LazyImage,
|
|
65
66
|
Loading,
|
|
66
67
|
NameNsDescription,
|
|
@@ -93,10 +94,12 @@ export default {
|
|
|
93
94
|
|
|
94
95
|
this.errors = [];
|
|
95
96
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
97
|
+
// If the chart doesn't contain system `systemDefaultRegistry` properties there's no point applying them
|
|
98
|
+
if (this.showCustomRegistry) {
|
|
99
|
+
this.clusterRegistry = await this.getClusterRegistry();
|
|
100
|
+
this.globalRegistry = await this.getGlobalRegistry();
|
|
101
|
+
this.defaultRegistrySetting = this.clusterRegistry || this.globalRegistry;
|
|
102
|
+
}
|
|
100
103
|
|
|
101
104
|
this.serverUrlSetting = await this.$store.dispatch('management/find', {
|
|
102
105
|
type: MANAGEMENT.SETTING,
|
|
@@ -281,6 +284,16 @@ export default {
|
|
|
281
284
|
*/
|
|
282
285
|
this.chartValues = merge(merge({}, this.versionInfo?.values || {}), userValues);
|
|
283
286
|
|
|
287
|
+
if (this.showCustomRegistry) {
|
|
288
|
+
const existingRegistry = this.chartValues?.global?.systemDefaultRegistry || this.chartValues?.global?.cattle?.systemDefaultRegistry;
|
|
289
|
+
|
|
290
|
+
delete this.chartValues?.global?.systemDefaultRegistry;
|
|
291
|
+
delete this.chartValues?.global?.cattle?.systemDefaultRegistry;
|
|
292
|
+
|
|
293
|
+
this.customRegistrySetting = existingRegistry || this.defaultRegistrySetting;
|
|
294
|
+
this.showCustomRegistryInput = !!this.customRegistrySetting;
|
|
295
|
+
}
|
|
296
|
+
|
|
284
297
|
/* Serializes an object as a YAML document */
|
|
285
298
|
this.valuesYaml = saferDump(this.chartValues);
|
|
286
299
|
|
|
@@ -292,6 +305,7 @@ export default {
|
|
|
292
305
|
this.loadedVersionValues = this.versionInfo?.values || {};
|
|
293
306
|
this.loadedVersion = this.version?.key;
|
|
294
307
|
}
|
|
308
|
+
|
|
295
309
|
/* Check if chart exists and if required values exist */
|
|
296
310
|
this.updateStepOneReady();
|
|
297
311
|
|
|
@@ -317,13 +331,16 @@ export default {
|
|
|
317
331
|
};
|
|
318
332
|
|
|
319
333
|
return {
|
|
320
|
-
defaultRegistrySetting:
|
|
334
|
+
defaultRegistrySetting: '',
|
|
335
|
+
customRegistrySetting: '',
|
|
321
336
|
serverUrlSetting: null,
|
|
322
337
|
chartValues: null,
|
|
338
|
+
clusterRegistry: '',
|
|
323
339
|
originalYamlValues: null,
|
|
324
340
|
previousYamlValues: null,
|
|
325
341
|
errors: null,
|
|
326
342
|
existing: null,
|
|
343
|
+
globalRegistry: '',
|
|
327
344
|
forceNamespace: null,
|
|
328
345
|
loadedVersion: null,
|
|
329
346
|
loadedVersionValues: null,
|
|
@@ -335,22 +352,22 @@ export default {
|
|
|
335
352
|
valuesYaml: '',
|
|
336
353
|
project: null,
|
|
337
354
|
migratedApp: false,
|
|
338
|
-
|
|
339
355
|
defaultCmdOpts,
|
|
340
|
-
customCmdOpts:
|
|
356
|
+
customCmdOpts: { ...defaultCmdOpts },
|
|
341
357
|
|
|
342
358
|
nameDisabled: false,
|
|
343
359
|
|
|
344
|
-
preFormYamlOption:
|
|
345
|
-
formYamlOption:
|
|
346
|
-
showDiff:
|
|
347
|
-
showValuesComponent:
|
|
348
|
-
showQuestions:
|
|
349
|
-
showSlideIn:
|
|
350
|
-
shownReadmeWindows:
|
|
351
|
-
componentHasTabs:
|
|
352
|
-
showCommandStep:
|
|
353
|
-
|
|
360
|
+
preFormYamlOption: VALUES_STATE.YAML,
|
|
361
|
+
formYamlOption: VALUES_STATE.YAML,
|
|
362
|
+
showDiff: false,
|
|
363
|
+
showValuesComponent: true,
|
|
364
|
+
showQuestions: true,
|
|
365
|
+
showSlideIn: false,
|
|
366
|
+
shownReadmeWindows: [],
|
|
367
|
+
componentHasTabs: false,
|
|
368
|
+
showCommandStep: false,
|
|
369
|
+
showCustomRegistryInput: false,
|
|
370
|
+
isNamespaceNew: false,
|
|
354
371
|
|
|
355
372
|
stepBasic: {
|
|
356
373
|
name: 'basics',
|
|
@@ -645,6 +662,23 @@ export default {
|
|
|
645
662
|
}
|
|
646
663
|
|
|
647
664
|
return null;
|
|
665
|
+
},
|
|
666
|
+
|
|
667
|
+
/**
|
|
668
|
+
* Check if the chart contains `systemDefaultRegistry` properties. If not we shouldn't apply the setting (or show the UI for them)
|
|
669
|
+
*/
|
|
670
|
+
showCustomRegistry() {
|
|
671
|
+
const global = this.versionInfo?.values?.global || {};
|
|
672
|
+
|
|
673
|
+
return global.systemDefaultRegistry !== undefined || global.cattle?.systemDefaultRegistry !== undefined;
|
|
674
|
+
},
|
|
675
|
+
|
|
676
|
+
/**
|
|
677
|
+
* True if we should apply/save the custom registry value. This should be false if matching the global registry
|
|
678
|
+
* (we shouldn't save the global registry to avoid issues on upgrade where we might confused it with a custom one)
|
|
679
|
+
*/
|
|
680
|
+
applyCustomRegistry() {
|
|
681
|
+
return this.customRegistrySetting !== this.globalRegistry;
|
|
648
682
|
}
|
|
649
683
|
},
|
|
650
684
|
|
|
@@ -744,6 +778,42 @@ export default {
|
|
|
744
778
|
},
|
|
745
779
|
|
|
746
780
|
methods: {
|
|
781
|
+
async getClusterRegistry() {
|
|
782
|
+
const hasPermissionToSeeProvCluster = this.$store.getters[`management/schemaFor`](CAPI.RANCHER_CLUSTER);
|
|
783
|
+
|
|
784
|
+
if (hasPermissionToSeeProvCluster) {
|
|
785
|
+
const mgmCluster = this.$store.getters['currentCluster'];
|
|
786
|
+
const provCluster = await this.$store.dispatch('management/find', {
|
|
787
|
+
type: CAPI.RANCHER_CLUSTER,
|
|
788
|
+
id: mgmCluster.provClusterId
|
|
789
|
+
});
|
|
790
|
+
|
|
791
|
+
if (provCluster.isRke2) { // isRke2 returns true for both RKE2 and K3s clusters.
|
|
792
|
+
const agentConfig = provCluster.spec.rkeConfig.machineSelectorConfig.find(x => !x.machineLabelSelector).config;
|
|
793
|
+
|
|
794
|
+
// If a cluster scoped registry exists,
|
|
795
|
+
// it should be used by default.
|
|
796
|
+
const clusterRegistry = agentConfig?.['system-default-registry'] || '';
|
|
797
|
+
|
|
798
|
+
if (clusterRegistry) {
|
|
799
|
+
return clusterRegistry;
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
},
|
|
804
|
+
|
|
805
|
+
async getGlobalRegistry() {
|
|
806
|
+
// Use the global registry as a fallback.
|
|
807
|
+
// If it is an empty string, the container
|
|
808
|
+
// runtime will pull images from docker.io.
|
|
809
|
+
const globalRegistry = await this.$store.dispatch('management/find', {
|
|
810
|
+
type: MANAGEMENT.SETTING,
|
|
811
|
+
id: 'system-default-registry'
|
|
812
|
+
});
|
|
813
|
+
|
|
814
|
+
return globalRegistry.value;
|
|
815
|
+
},
|
|
816
|
+
|
|
747
817
|
updateValue(value) {
|
|
748
818
|
if (this.$refs.yaml) {
|
|
749
819
|
this.$refs.yaml.updateValue(value);
|
|
@@ -905,7 +975,7 @@ export default {
|
|
|
905
975
|
const cluster = this.currentCluster;
|
|
906
976
|
const projects = this.$store.getters['management/all'](MANAGEMENT.PROJECT);
|
|
907
977
|
const systemProjectId = projects.find(p => p.spec?.displayName === 'System')?.id?.split('/')?.[1] || '';
|
|
908
|
-
|
|
978
|
+
|
|
909
979
|
const serverUrl = this.serverUrlSetting?.value || '';
|
|
910
980
|
const isWindows = (cluster.workerOSs || []).includes(WINDOWS);
|
|
911
981
|
const pathPrefix = cluster?.spec?.rancherKubernetesEngineConfig?.prefixPath || '';
|
|
@@ -913,8 +983,15 @@ export default {
|
|
|
913
983
|
|
|
914
984
|
setIfNotSet(cattle, 'clusterId', cluster?.id);
|
|
915
985
|
setIfNotSet(cattle, 'clusterName', cluster?.nameDisplay);
|
|
916
|
-
|
|
917
|
-
|
|
986
|
+
if (this.showCustomRegistry) {
|
|
987
|
+
// If this is the current global registry leave it blank. This avoids the scenario on upgrade where a previous global registry that's
|
|
988
|
+
// been updated is confused with a custom user registry
|
|
989
|
+
const registry = this.applyCustomRegistry ? this.customRegistrySetting : '';
|
|
990
|
+
|
|
991
|
+
set(cattle, 'systemDefaultRegistry', registry);
|
|
992
|
+
set(global, 'systemDefaultRegistry', registry);
|
|
993
|
+
}
|
|
994
|
+
|
|
918
995
|
setIfNotSet(global, 'cattle.systemProjectId', systemProjectId);
|
|
919
996
|
setIfNotSet(cattle, 'url', serverUrl);
|
|
920
997
|
setIfNotSet(cattle, 'rkePathPrefix', pathPrefix);
|
|
@@ -939,7 +1016,6 @@ export default {
|
|
|
939
1016
|
}
|
|
940
1017
|
|
|
941
1018
|
const cluster = this.$store.getters['currentCluster'];
|
|
942
|
-
const defaultRegistry = this.defaultRegistrySetting?.value || '';
|
|
943
1019
|
const serverUrl = this.serverUrlSetting?.value || '';
|
|
944
1020
|
const isWindows = (cluster.workerOSs || []).includes(WINDOWS);
|
|
945
1021
|
const pathPrefix = cluster?.spec?.rancherKubernetesEngineConfig?.prefixPath || '';
|
|
@@ -948,7 +1024,6 @@ export default {
|
|
|
948
1024
|
if ( values.global?.cattle ) {
|
|
949
1025
|
deleteIfEqual(values.global.cattle, 'clusterId', cluster?.id);
|
|
950
1026
|
deleteIfEqual(values.global.cattle, 'clusterName', cluster?.nameDisplay);
|
|
951
|
-
deleteIfEqual(values.global.cattle, 'systemDefaultRegistry', defaultRegistry);
|
|
952
1027
|
deleteIfEqual(values.global.cattle, 'url', serverUrl);
|
|
953
1028
|
deleteIfEqual(values.global.cattle, 'rkePathPrefix', pathPrefix);
|
|
954
1029
|
deleteIfEqual(values.global.cattle, 'rkeWindowsPathPrefix', windowsPathPrefix);
|
|
@@ -966,10 +1041,6 @@ export default {
|
|
|
966
1041
|
delete values.global.cattle;
|
|
967
1042
|
}
|
|
968
1043
|
|
|
969
|
-
if ( values.global ) {
|
|
970
|
-
deleteIfEqual(values.global, 'systemDefaultRegistry', defaultRegistry);
|
|
971
|
-
}
|
|
972
|
-
|
|
973
1044
|
if ( !Object.keys(values.global || {}).length ) {
|
|
974
1045
|
delete values.global;
|
|
975
1046
|
}
|
|
@@ -1289,7 +1360,6 @@ export default {
|
|
|
1289
1360
|
</div>
|
|
1290
1361
|
</div>
|
|
1291
1362
|
<NameNsDescription
|
|
1292
|
-
v-if="chart"
|
|
1293
1363
|
v-model="value"
|
|
1294
1364
|
:description-hidden="true"
|
|
1295
1365
|
:mode="mode"
|
|
@@ -1316,13 +1386,31 @@ export default {
|
|
|
1316
1386
|
/>
|
|
1317
1387
|
</template>
|
|
1318
1388
|
</NameNsDescription>
|
|
1389
|
+
<Checkbox v-model="showCommandStep" class="mb-20" :label="t('catalog.install.steps.helmCli.checkbox', { action, existing: !!existing })" />
|
|
1390
|
+
|
|
1391
|
+
<Checkbox
|
|
1392
|
+
v-if="showCustomRegistry"
|
|
1393
|
+
v-model="showCustomRegistryInput"
|
|
1394
|
+
class="mb-20"
|
|
1395
|
+
:label="t('catalog.chart.registry.custom.checkBoxLabel')"
|
|
1396
|
+
:tooltip="t('catalog.chart.registry.tooltip')"
|
|
1397
|
+
/>
|
|
1398
|
+
<div v-if="showCustomRegistry" class="row">
|
|
1399
|
+
<div class="col span-6">
|
|
1400
|
+
<LabeledInput
|
|
1401
|
+
v-if="showCustomRegistryInput"
|
|
1402
|
+
v-model="customRegistrySetting"
|
|
1403
|
+
label-key="catalog.chart.registry.custom.inputLabel"
|
|
1404
|
+
placeholder-key="catalog.chart.registry.custom.placeholder"
|
|
1405
|
+
:min-height="30"
|
|
1406
|
+
/>
|
|
1407
|
+
</div>
|
|
1408
|
+
</div>
|
|
1319
1409
|
<div class="step__values__controls--spacer" style="flex:1">
|
|
1320
1410
|
|
|
1321
1411
|
</div>
|
|
1322
1412
|
<Banner v-if="isNamespaceNew" color="info" v-html="t('catalog.install.steps.basics.createNamespace', {namespace: value.metadata.namespace}, true) ">
|
|
1323
1413
|
</Banner>
|
|
1324
|
-
|
|
1325
|
-
<Checkbox v-model="showCommandStep" class="mb-20" :label="t('catalog.install.steps.helmCli.checkbox', { action, existing: !!existing })" />
|
|
1326
1414
|
</div>
|
|
1327
1415
|
</template>
|
|
1328
1416
|
<template #clusterTplVersion>
|