@rancher/shell 0.3.21 → 0.3.23
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 +4 -0
- package/assets/translations/zh-hans.yaml +8 -1
- package/babel.config.js +3 -0
- package/cloud-credential/__tests__/azure.test.ts +53 -0
- package/cloud-credential/azure.vue +6 -0
- package/components/GrowlManager.vue +33 -30
- package/components/SortableTable/paging.js +10 -0
- package/components/form/GitPicker.vue +16 -0
- package/components/form/ResourceQuota/ProjectRow.vue +38 -15
- package/components/form/SelectOrCreateAuthSecret.vue +9 -3
- package/components/formatter/ClusterProvider.vue +9 -3
- package/components/formatter/__tests__/ClusterProvider.test.ts +5 -1
- package/components/nav/Header.vue +1 -0
- package/config/settings.ts +59 -2
- package/config/types.js +2 -0
- package/creators/pkg/files/.github/workflows/build-extension-catalog.yml +28 -0
- package/creators/pkg/files/.github/workflows/build-extension-charts.yml +26 -0
- package/creators/pkg/init +63 -4
- package/detail/provisioning.cattle.io.cluster.vue +4 -2
- package/edit/fleet.cattle.io.gitrepo.vue +1 -0
- package/edit/provisioning.cattle.io.cluster/rke2.vue +4 -4
- package/edit/resources.cattle.io.backup.vue +3 -1
- package/edit/resources.cattle.io.restore.vue +3 -1
- package/mixins/__tests__/chart.test.ts +40 -0
- package/mixins/chart.js +5 -0
- package/models/catalog.cattle.io.clusterrepo.js +6 -2
- package/models/fleet.cattle.io.cluster.js +10 -2
- package/package.json +1 -1
- package/pages/c/_cluster/gatekeeper/index.vue +10 -1
- package/plugins/steve/__tests__/header-warnings.spec.ts +238 -0
- package/plugins/steve/actions.js +4 -23
- package/plugins/steve/header-warnings.ts +91 -0
- package/promptRemove/management.cattle.io.project.vue +9 -6
- package/rancher-components/BadgeState/BadgeState.vue +1 -5
- package/rancher-components/Banner/Banner.test.ts +1 -51
- package/rancher-components/Banner/Banner.vue +53 -134
- package/rancher-components/Card/Card.vue +7 -24
- package/rancher-components/Form/Checkbox/Checkbox.test.ts +29 -20
- package/rancher-components/Form/Checkbox/Checkbox.vue +20 -45
- package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +8 -2
- package/rancher-components/Form/LabeledInput/LabeledInput.vue +10 -22
- package/rancher-components/Form/Radio/RadioButton.vue +13 -30
- package/rancher-components/Form/Radio/RadioGroup.vue +7 -26
- package/rancher-components/Form/TextArea/TextAreaAutoGrow.vue +6 -7
- package/rancher-components/Form/ToggleSwitch/ToggleSwitch.test.ts +38 -25
- package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +11 -23
- package/rancher-components/LabeledTooltip/LabeledTooltip.vue +5 -19
- package/rancher-components/StringList/StringList.test.ts +49 -453
- package/rancher-components/StringList/StringList.vue +58 -92
- package/scripts/extension/parse-tag-name +30 -0
- package/types/shell/index.d.ts +16 -9
- package/utils/__tests__/formatter.test.ts +77 -0
- package/utils/formatter.js +11 -0
- package/utils/settings.ts +2 -17
- package/vue-config-helper.js +135 -0
- package/vue.config.js +29 -141
- package/creators/pkg/files/.github/workflows/build-container.yml +0 -64
- package/creators/pkg/files/.github/workflows/build-extension.yml +0 -110
- package/rancher-components/Card/Card.test.ts +0 -37
- package/rancher-components/Form/Radio/RadioButton.test.ts +0 -31
package/creators/pkg/init
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const fs = require('fs-extra');
|
|
4
4
|
const path = require('path');
|
|
5
|
+
const https = require('https');
|
|
5
6
|
|
|
6
7
|
const targets = {
|
|
7
8
|
dev: './node_modules/.bin/nuxt dev',
|
|
@@ -16,9 +17,10 @@ const files = [
|
|
|
16
17
|
];
|
|
17
18
|
|
|
18
19
|
const topLevelScripts = {
|
|
19
|
-
'build-pkg':
|
|
20
|
-
'serve-pkgs':
|
|
21
|
-
'publish-pkgs':
|
|
20
|
+
'build-pkg': './node_modules/@rancher/shell/scripts/build-pkg.sh',
|
|
21
|
+
'serve-pkgs': './node_modules/@rancher/shell/scripts/serve-pkgs',
|
|
22
|
+
'publish-pkgs': './node_modules/@rancher/shell/scripts/extension/publish',
|
|
23
|
+
'parse-tag-name': './node_modules/@rancher/shell/scripts/extension/parse-tag-name'
|
|
22
24
|
};
|
|
23
25
|
|
|
24
26
|
const typeFolders = [
|
|
@@ -88,11 +90,68 @@ Object.keys(targets).forEach((target) => {
|
|
|
88
90
|
}
|
|
89
91
|
});
|
|
90
92
|
|
|
93
|
+
// Add annotation for the latest Rancher version by default
|
|
94
|
+
function fetchLatestVersion() {
|
|
95
|
+
console.log(' Fetching latest Rancher Version');
|
|
96
|
+
const options = { headers: { 'User-Agent': 'nodejs' } };
|
|
97
|
+
|
|
98
|
+
https.get('https://api.github.com/repos/rancher/rancher/releases/latest', options, (res) => {
|
|
99
|
+
const { statusCode } = res;
|
|
100
|
+
const contentType = res.headers['content-type'];
|
|
101
|
+
|
|
102
|
+
let error;
|
|
103
|
+
|
|
104
|
+
if ( statusCode !== 200 ) {
|
|
105
|
+
error = new Error(' Request Failed.\n' +
|
|
106
|
+
` Status Code: ${ statusCode }`);
|
|
107
|
+
} else if ( !/^application\/json/.test(contentType) ) {
|
|
108
|
+
error = new Error(' Invalid content-type.\n' +
|
|
109
|
+
` Expected application/json but received ${ contentType }`);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if ( error ) {
|
|
113
|
+
console.log(error.message);
|
|
114
|
+
|
|
115
|
+
res.resume();
|
|
116
|
+
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
res.setEncoding('utf8');
|
|
121
|
+
let rawData = '';
|
|
122
|
+
|
|
123
|
+
res.on('data', (chunk) => {
|
|
124
|
+
rawData += chunk;
|
|
125
|
+
});
|
|
126
|
+
res.on('end', () => {
|
|
127
|
+
try {
|
|
128
|
+
const release = JSON.parse(rawData);
|
|
129
|
+
|
|
130
|
+
if ( release.tag_name ) {
|
|
131
|
+
console.log(` Adding rancher-version annotation '>= ${ release.tag_name }' to package.json`);
|
|
132
|
+
|
|
133
|
+
pkg.rancher = { annotations: { 'catalog.cattle.io/rancher-version': `>= ${ release.tag_name }` } };
|
|
134
|
+
writePackageJson();
|
|
135
|
+
}
|
|
136
|
+
} catch (e) {
|
|
137
|
+
console.log(' Error parsing release data', e);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
}).on('error', (e) => {
|
|
141
|
+
console.log(' Error fetching latest Rancher Version', e);
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
fetchLatestVersion();
|
|
146
|
+
writePackageJson();
|
|
147
|
+
|
|
91
148
|
// Add dependencies
|
|
92
149
|
// pkg.dependencies['@rancher/shell'] = '^0.6.2';
|
|
93
150
|
// pkg.dependencies['core-js'] = '3.18.3';
|
|
94
151
|
|
|
95
|
-
|
|
152
|
+
function writePackageJson() {
|
|
153
|
+
fs.writeFileSync(path.join(pkgFolder, 'package.json'), JSON.stringify(pkg, null, 2));
|
|
154
|
+
}
|
|
96
155
|
|
|
97
156
|
// Create type folders if needed
|
|
98
157
|
if (addTypeFolders) {
|
|
@@ -250,8 +250,10 @@ export default {
|
|
|
250
250
|
|
|
251
251
|
computed: {
|
|
252
252
|
defaultTab() {
|
|
253
|
-
if (this.showRegistration
|
|
254
|
-
|
|
253
|
+
if (this.showRegistration) {
|
|
254
|
+
if (this.value.isRke2 ? !this.machines?.length : !this.nodes?.length) {
|
|
255
|
+
return 'registration';
|
|
256
|
+
}
|
|
255
257
|
}
|
|
256
258
|
|
|
257
259
|
if (this.showMachines) {
|
|
@@ -792,10 +792,10 @@ export default {
|
|
|
792
792
|
const names = [];
|
|
793
793
|
const cni = this.serverConfig.cni;
|
|
794
794
|
|
|
795
|
-
if ( cni ) {
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
names.push(...
|
|
795
|
+
if (typeof cni === 'string') {
|
|
796
|
+
names.push(...cni.split(',').map((x) => `rke2-${ x }`));
|
|
797
|
+
} else if (Array.isArray(cni)) {
|
|
798
|
+
names.push(...cni.map((x) => `rke2-${ x }`));
|
|
799
799
|
}
|
|
800
800
|
|
|
801
801
|
if (this.showCloudProvider) { // Shouldn't be removed such that changes to it will re-trigger this watch
|
|
@@ -16,6 +16,8 @@ import { allHash } from '@shell/utils/promise';
|
|
|
16
16
|
import { NAMESPACE, _VIEW } from '@shell/config/query-params';
|
|
17
17
|
import { sortBy } from '@shell/utils/sort';
|
|
18
18
|
import { get } from '@shell/utils/object';
|
|
19
|
+
import { formatEncryptionSecretNames } from '@shell/utils/formatter';
|
|
20
|
+
|
|
19
21
|
export default {
|
|
20
22
|
|
|
21
23
|
components: {
|
|
@@ -108,7 +110,7 @@ export default {
|
|
|
108
110
|
},
|
|
109
111
|
|
|
110
112
|
encryptionSecretNames() {
|
|
111
|
-
return this.allSecrets
|
|
113
|
+
return formatEncryptionSecretNames(this.allSecrets, this.chartNamespace);
|
|
112
114
|
},
|
|
113
115
|
|
|
114
116
|
storageOptions() {
|
|
@@ -13,6 +13,8 @@ import { SECRET, BACKUP_RESTORE, CATALOG } from '@shell/config/types';
|
|
|
13
13
|
import { allHash } from '@shell/utils/promise';
|
|
14
14
|
import { get } from '@shell/utils/object';
|
|
15
15
|
import { _CREATE } from '@shell/config/query-params';
|
|
16
|
+
import { formatEncryptionSecretNames } from '@shell/utils/formatter';
|
|
17
|
+
|
|
16
18
|
export default {
|
|
17
19
|
|
|
18
20
|
components: {
|
|
@@ -93,7 +95,7 @@ export default {
|
|
|
93
95
|
},
|
|
94
96
|
|
|
95
97
|
encryptionSecretNames() {
|
|
96
|
-
return this.allSecrets
|
|
98
|
+
return formatEncryptionSecretNames(this.allSecrets, this.chartNamespace);
|
|
97
99
|
},
|
|
98
100
|
|
|
99
101
|
isEncrypted() {
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { createLocalVue } from '@vue/test-utils';
|
|
2
|
+
import Vuex from 'vuex';
|
|
3
|
+
import ChartMixin from '@shell/mixins/chart';
|
|
4
|
+
import { OPA_GATE_KEEPER_ID } from '@shell/pages/c/_cluster/gatekeeper/index.vue';
|
|
5
|
+
|
|
6
|
+
describe('chartMixin', () => {
|
|
7
|
+
const testCases = [[null, 0], [OPA_GATE_KEEPER_ID, 1], ['any_other_id', 0]];
|
|
8
|
+
|
|
9
|
+
it.each(testCases)(
|
|
10
|
+
'should add OPA deprecation warning properly', (chartId, expected) => {
|
|
11
|
+
const localVue = createLocalVue();
|
|
12
|
+
|
|
13
|
+
localVue.use(Vuex);
|
|
14
|
+
localVue.mixin(ChartMixin);
|
|
15
|
+
|
|
16
|
+
const store = new Vuex.Store({
|
|
17
|
+
getters: {
|
|
18
|
+
currentCluster: () => {},
|
|
19
|
+
isRancher: () => true,
|
|
20
|
+
'catalog/repo': () => {
|
|
21
|
+
return () => 'repo';
|
|
22
|
+
},
|
|
23
|
+
'catalog/chart': () => {
|
|
24
|
+
return () => ({ id: chartId });
|
|
25
|
+
},
|
|
26
|
+
'i18n/t': () => jest.fn()
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const vm = localVue.extend({});
|
|
31
|
+
const instance = new vm({ store });
|
|
32
|
+
|
|
33
|
+
instance.$route = { query: { chart: 'chart_name' } };
|
|
34
|
+
|
|
35
|
+
const warnings = instance.warnings;
|
|
36
|
+
|
|
37
|
+
expect(warnings).toHaveLength(expected);
|
|
38
|
+
}
|
|
39
|
+
);
|
|
40
|
+
});
|
package/mixins/chart.js
CHANGED
|
@@ -8,6 +8,7 @@ import { CATALOG as CATALOG_ANNOTATIONS } from '@shell/config/labels-annotations
|
|
|
8
8
|
import { SHOW_PRE_RELEASE, mapPref } from '@shell/store/prefs';
|
|
9
9
|
import { NAME as EXPLORER } from '@shell/config/product/explorer';
|
|
10
10
|
import { NAME as MANAGER } from '@shell/config/product/manager';
|
|
11
|
+
import { OPA_GATE_KEEPER_ID } from '@shell/pages/c/_cluster/gatekeeper/index.vue';
|
|
11
12
|
|
|
12
13
|
import { formatSi, parseSi } from '@shell/utils/units';
|
|
13
14
|
import { CAPI, CATALOG } from '@shell/config/types';
|
|
@@ -185,6 +186,10 @@ export default {
|
|
|
185
186
|
}
|
|
186
187
|
}
|
|
187
188
|
|
|
189
|
+
if (this.chart?.id === OPA_GATE_KEEPER_ID) {
|
|
190
|
+
warnings.unshift(this.t('gatekeeperIndex.deprecated', {}, true));
|
|
191
|
+
}
|
|
192
|
+
|
|
188
193
|
return warnings;
|
|
189
194
|
},
|
|
190
195
|
|
|
@@ -29,11 +29,15 @@ export default class ClusterRepo extends SteveModel {
|
|
|
29
29
|
return out;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
refresh() {
|
|
32
|
+
async refresh() {
|
|
33
33
|
const now = (new Date()).toISOString().replace(/\.\d+Z$/, 'Z');
|
|
34
34
|
|
|
35
35
|
this.spec.forceUpdate = now;
|
|
36
|
-
this.save();
|
|
36
|
+
await this.save();
|
|
37
|
+
|
|
38
|
+
await this.waitForState('active', 10000, 1000);
|
|
39
|
+
|
|
40
|
+
this.$dispatch('catalog/load', { force: true, reset: true }, { root: true });
|
|
37
41
|
}
|
|
38
42
|
|
|
39
43
|
get isGit() {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { MANAGEMENT, NORMAN } from '@shell/config/types';
|
|
1
|
+
import { LOCAL_CLUSTER, MANAGEMENT, NORMAN } from '@shell/config/types';
|
|
2
2
|
import { CAPI, FLEET as FLEET_LABELS } from '@shell/config/labels-annotations';
|
|
3
3
|
import { _RKE2 } from '@shell/store/prefs';
|
|
4
4
|
import SteveModel from '@shell/plugins/steve/steve-class';
|
|
@@ -34,7 +34,7 @@ export default class FleetCluster extends SteveModel {
|
|
|
34
34
|
enabled: !!this.links.update
|
|
35
35
|
});
|
|
36
36
|
|
|
37
|
-
if (
|
|
37
|
+
if (this.canChangeWorkspace) {
|
|
38
38
|
insertAt(out, 3, {
|
|
39
39
|
action: 'assignTo',
|
|
40
40
|
label: 'Change workspace',
|
|
@@ -79,6 +79,14 @@ export default class FleetCluster extends SteveModel {
|
|
|
79
79
|
return false;
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
+
get canChangeWorkspace() {
|
|
83
|
+
return !this.isRke2 && !this.isLocal;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
get isLocal() {
|
|
87
|
+
return this.metadata.name === LOCAL_CLUSTER || this.metadata?.labels?.[FLEET_LABELS.CLUSTER_NAME] === LOCAL_CLUSTER;
|
|
88
|
+
}
|
|
89
|
+
|
|
82
90
|
get isRke2() {
|
|
83
91
|
const provider = this?.metadata?.labels?.[CAPI.PROVIDER] || this?.status?.provider;
|
|
84
92
|
|
package/package.json
CHANGED
|
@@ -3,10 +3,16 @@ import { NAME, CHART_NAME } from '@shell/config/product/gatekeeper';
|
|
|
3
3
|
import InstallRedirect from '@shell/utils/install-redirect';
|
|
4
4
|
import ChartHeading from '@shell/components/ChartHeading';
|
|
5
5
|
import SortableTable from '@shell/components/SortableTable';
|
|
6
|
+
import { Banner } from '@components/Banner';
|
|
6
7
|
import { CONSTRAINT_VIOLATION_CONSTRAINT_LINK, CONSTRAINT_VIOLATION_COUNT, CONSTRAINT_VIOLATION_TEMPLATE_LINK } from '@shell/config/table-headers';
|
|
7
8
|
import { GATEKEEPER } from '@shell/config/types';
|
|
9
|
+
|
|
10
|
+
export const OPA_GATE_KEEPER_ID = 'cluster/rancher-charts/rancher-gatekeeper';
|
|
11
|
+
|
|
8
12
|
export default {
|
|
9
|
-
components: {
|
|
13
|
+
components: {
|
|
14
|
+
ChartHeading, SortableTable, Banner
|
|
15
|
+
},
|
|
10
16
|
middleware: InstallRedirect(NAME, CHART_NAME),
|
|
11
17
|
async fetch() {
|
|
12
18
|
const constraints = this.constraint ? [this.constraint] : await this.$store.dispatch('cluster/findAll', { type: GATEKEEPER.SPOOFED.CONSTRAINT });
|
|
@@ -49,6 +55,9 @@ export default {
|
|
|
49
55
|
:label="t('gatekeeperIndex.poweredBy')"
|
|
50
56
|
url="https://github.com/open-policy-agent/gatekeeper"
|
|
51
57
|
/>
|
|
58
|
+
<Banner color="warning">
|
|
59
|
+
<span v-clean-html="t('gatekeeperIndex.deprecated', {}, true)" />
|
|
60
|
+
</Banner>
|
|
52
61
|
<div class="spacer" />
|
|
53
62
|
<div class="mb-10">
|
|
54
63
|
<h2><t k="gatekeeperIndex.violations" /></h2>
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import { handleKubeApiHeaderWarnings } from '@shell/plugins/steve/header-warnings';
|
|
2
|
+
import { DEFAULT_PERF_SETTING } from '@shell/config/settings';
|
|
3
|
+
|
|
4
|
+
describe('steve: header-warnings', () => {
|
|
5
|
+
// eslint-disable-next-line jest/no-hooks
|
|
6
|
+
|
|
7
|
+
function setupMocks(settings = {
|
|
8
|
+
separator: '299 - ',
|
|
9
|
+
notificationBlockList: ['299 - unknown field']
|
|
10
|
+
}) {
|
|
11
|
+
return {
|
|
12
|
+
dispatch: jest.fn(),
|
|
13
|
+
consoleWarn: jest.spyOn(console, 'warn').mockImplementation(),
|
|
14
|
+
consoleDebug: jest.spyOn(console, 'debug').mockImplementation(),
|
|
15
|
+
rootGetter: {
|
|
16
|
+
'management/byId': (resource: string, id: string): { value: string} => {
|
|
17
|
+
return {
|
|
18
|
+
value: JSON.stringify({
|
|
19
|
+
...DEFAULT_PERF_SETTING,
|
|
20
|
+
kubeAPI: { warningHeader: settings }
|
|
21
|
+
})
|
|
22
|
+
};
|
|
23
|
+
},
|
|
24
|
+
'i18n/t': (key: string, { resourceType }: any) => {
|
|
25
|
+
return `${ key }_${ resourceType }`;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function createMockRes( headers = {}, data = { type: inputResourceType }) {
|
|
32
|
+
return {
|
|
33
|
+
headers, config: { url: 'unit/test' }, data
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function createGrowlResponse(message: string, action = updateKey) {
|
|
38
|
+
return [
|
|
39
|
+
'growl/warning',
|
|
40
|
+
{
|
|
41
|
+
message, timeout: 0, title: `${ action }_${ inputResourceType }`
|
|
42
|
+
},
|
|
43
|
+
{ root: true }
|
|
44
|
+
];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function createConsoleResponse(warnings: string) {
|
|
48
|
+
return `Validation Warnings for unit/test\n\n${ warnings }`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const inputResourceType = 'abc';
|
|
52
|
+
const updateKey = 'growl.kubeApiHeaderWarning.titleUpdate';
|
|
53
|
+
const createKey = 'growl.kubeApiHeaderWarning.titleCreate';
|
|
54
|
+
const podSecurity = '299 - would violate PodSecurity "restricted:latest": unrestricted capabilities (container "container-0" must set securityContext.capabilities.drop=["ALL"]), runAsNonRoot != true (container "container-0" must not set securityContext.runAsNonRoot=false), seccompProfile (pod or container "container-0" must set securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost")';
|
|
55
|
+
const deprecated = "299 - i'm deprecated";
|
|
56
|
+
const validation = '299 - unknown field "spec.containers[0].__active"';
|
|
57
|
+
|
|
58
|
+
describe('no warnings', () => {
|
|
59
|
+
it('put, no header warning', () => {
|
|
60
|
+
const mocks = setupMocks();
|
|
61
|
+
|
|
62
|
+
handleKubeApiHeaderWarnings(createMockRes(),
|
|
63
|
+
mocks.dispatch,
|
|
64
|
+
mocks.rootGetter,
|
|
65
|
+
'put',
|
|
66
|
+
true,
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
expect(mocks.dispatch).not.toHaveBeenCalled();
|
|
70
|
+
expect(mocks.consoleWarn).not.toHaveBeenCalled();
|
|
71
|
+
expect(mocks.consoleDebug).not.toHaveBeenCalled();
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('post, no header warning', () => {
|
|
75
|
+
const mocks = setupMocks();
|
|
76
|
+
|
|
77
|
+
handleKubeApiHeaderWarnings(createMockRes(),
|
|
78
|
+
mocks.dispatch,
|
|
79
|
+
mocks.rootGetter,
|
|
80
|
+
'post',
|
|
81
|
+
true,
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
expect(mocks.dispatch).not.toHaveBeenCalled();
|
|
85
|
+
expect(mocks.consoleWarn).not.toHaveBeenCalled();
|
|
86
|
+
expect(mocks.consoleDebug).not.toHaveBeenCalled();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('patch, no header warning', () => {
|
|
90
|
+
const mocks = setupMocks();
|
|
91
|
+
|
|
92
|
+
handleKubeApiHeaderWarnings(createMockRes(),
|
|
93
|
+
mocks.dispatch,
|
|
94
|
+
mocks.rootGetter,
|
|
95
|
+
'patch',
|
|
96
|
+
true,
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
expect(mocks.dispatch).not.toHaveBeenCalled();
|
|
100
|
+
expect(mocks.consoleWarn).not.toHaveBeenCalled();
|
|
101
|
+
expect(mocks.consoleDebug).not.toHaveBeenCalled();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('get, no header warning', () => {
|
|
105
|
+
const mocks = setupMocks();
|
|
106
|
+
|
|
107
|
+
handleKubeApiHeaderWarnings(createMockRes(),
|
|
108
|
+
mocks.dispatch,
|
|
109
|
+
mocks.rootGetter,
|
|
110
|
+
'get',
|
|
111
|
+
true,
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
expect(mocks.dispatch).not.toHaveBeenCalled();
|
|
115
|
+
expect(mocks.consoleWarn).not.toHaveBeenCalled();
|
|
116
|
+
expect(mocks.consoleDebug).not.toHaveBeenCalled();
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('get, warnings', () => {
|
|
120
|
+
const mocks = setupMocks();
|
|
121
|
+
|
|
122
|
+
handleKubeApiHeaderWarnings(createMockRes( { warnings: ['erg'] }),
|
|
123
|
+
mocks.dispatch,
|
|
124
|
+
mocks.rootGetter,
|
|
125
|
+
'get',
|
|
126
|
+
true,
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
expect(mocks.dispatch).not.toHaveBeenCalled();
|
|
130
|
+
expect(mocks.consoleWarn).not.toHaveBeenCalled();
|
|
131
|
+
expect(mocks.consoleDebug).not.toHaveBeenCalled();
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it('blocked (via default config)', () => {
|
|
135
|
+
const mocks = setupMocks();
|
|
136
|
+
|
|
137
|
+
handleKubeApiHeaderWarnings(
|
|
138
|
+
createMockRes({ warning: validation }),
|
|
139
|
+
mocks.dispatch,
|
|
140
|
+
mocks.rootGetter,
|
|
141
|
+
'put',
|
|
142
|
+
true
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
expect(mocks.dispatch).not.toHaveBeenCalled();
|
|
146
|
+
expect(mocks.consoleWarn).not.toHaveBeenCalled();
|
|
147
|
+
expect(mocks.consoleDebug).toHaveBeenCalledWith(createConsoleResponse(validation));
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it('blocked (via custom config)', () => {
|
|
151
|
+
const mocks = setupMocks({
|
|
152
|
+
separator: '299 - ',
|
|
153
|
+
notificationBlockList: [deprecated]
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
handleKubeApiHeaderWarnings(
|
|
157
|
+
createMockRes({ warning: deprecated }),
|
|
158
|
+
mocks.dispatch,
|
|
159
|
+
mocks.rootGetter,
|
|
160
|
+
'put',
|
|
161
|
+
true
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
expect(mocks.dispatch).not.toHaveBeenCalled();
|
|
165
|
+
expect(mocks.consoleWarn).not.toHaveBeenCalled();
|
|
166
|
+
expect(mocks.consoleDebug).toHaveBeenCalledWith(createConsoleResponse(deprecated));
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it('multi blocked (via custom config)', () => {
|
|
170
|
+
const mocks = setupMocks({
|
|
171
|
+
separator: '299 - ',
|
|
172
|
+
notificationBlockList: [deprecated, podSecurity]
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
handleKubeApiHeaderWarnings(
|
|
176
|
+
createMockRes({ warning: `${ deprecated },${ podSecurity }` }),
|
|
177
|
+
mocks.dispatch,
|
|
178
|
+
mocks.rootGetter,
|
|
179
|
+
'put',
|
|
180
|
+
true
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
expect(mocks.dispatch).not.toHaveBeenCalled();
|
|
184
|
+
expect(mocks.consoleWarn).not.toHaveBeenCalled();
|
|
185
|
+
expect(mocks.consoleDebug).toHaveBeenCalledWith(createConsoleResponse(`${ deprecated }\n${ podSecurity }`));
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
describe('warnings', () => {
|
|
190
|
+
it('deprecated', () => {
|
|
191
|
+
const mocks = setupMocks();
|
|
192
|
+
|
|
193
|
+
handleKubeApiHeaderWarnings(
|
|
194
|
+
createMockRes({ warning: deprecated }),
|
|
195
|
+
mocks.dispatch,
|
|
196
|
+
mocks.rootGetter,
|
|
197
|
+
'put',
|
|
198
|
+
true,
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
expect(mocks.dispatch).toHaveBeenCalledWith(...createGrowlResponse(deprecated));
|
|
202
|
+
expect(mocks.consoleWarn).not.toHaveBeenCalled();
|
|
203
|
+
expect(mocks.consoleDebug).toHaveBeenCalledWith(createConsoleResponse(deprecated));
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
it('pod security', () => {
|
|
207
|
+
const mocks = setupMocks();
|
|
208
|
+
|
|
209
|
+
handleKubeApiHeaderWarnings(
|
|
210
|
+
createMockRes({ warning: podSecurity }),
|
|
211
|
+
mocks.dispatch,
|
|
212
|
+
mocks.rootGetter,
|
|
213
|
+
'post',
|
|
214
|
+
true,
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
expect(mocks.dispatch).toHaveBeenCalledWith(...createGrowlResponse(podSecurity, createKey));
|
|
218
|
+
expect(mocks.consoleWarn).not.toHaveBeenCalled();
|
|
219
|
+
expect(mocks.consoleDebug).toHaveBeenCalledWith(createConsoleResponse(podSecurity));
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it('deprecated & pod security', () => {
|
|
223
|
+
const mocks = setupMocks();
|
|
224
|
+
|
|
225
|
+
handleKubeApiHeaderWarnings(
|
|
226
|
+
createMockRes({ warning: `${ deprecated },${ podSecurity }` }),
|
|
227
|
+
mocks.dispatch,
|
|
228
|
+
mocks.rootGetter,
|
|
229
|
+
'put',
|
|
230
|
+
true,
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
expect(mocks.dispatch).toHaveBeenCalledWith(...createGrowlResponse(`${ deprecated }, ${ podSecurity }` ));
|
|
234
|
+
expect(mocks.consoleWarn).not.toHaveBeenCalled();
|
|
235
|
+
expect(mocks.consoleDebug).toHaveBeenCalledWith(createConsoleResponse(`${ deprecated }\n${ podSecurity }`));
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
});
|
package/plugins/steve/actions.js
CHANGED
|
@@ -8,6 +8,7 @@ import isObject from 'lodash/isObject';
|
|
|
8
8
|
import { classify } from '@shell/plugins/dashboard-store/classify';
|
|
9
9
|
import { NAMESPACE } from '@shell/config/types';
|
|
10
10
|
import jsyaml from 'js-yaml';
|
|
11
|
+
import { handleKubeApiHeaderWarnings } from '@shell/plugins/steve/header-warnings';
|
|
11
12
|
|
|
12
13
|
export default {
|
|
13
14
|
|
|
@@ -85,7 +86,7 @@ export default {
|
|
|
85
86
|
|
|
86
87
|
while (true) {
|
|
87
88
|
try {
|
|
88
|
-
const out = await makeRequest(this, opt);
|
|
89
|
+
const out = await makeRequest(this, opt, rootGetters);
|
|
89
90
|
|
|
90
91
|
if (!opt.depaginate) {
|
|
91
92
|
return out;
|
|
@@ -116,7 +117,7 @@ export default {
|
|
|
116
117
|
}
|
|
117
118
|
}
|
|
118
119
|
|
|
119
|
-
function makeRequest(that, opt) {
|
|
120
|
+
function makeRequest(that, opt, rootGetters) {
|
|
120
121
|
return that.$axios(opt).then((res) => {
|
|
121
122
|
let out;
|
|
122
123
|
|
|
@@ -128,9 +129,7 @@ export default {
|
|
|
128
129
|
|
|
129
130
|
finishDeferred(key, 'resolve', out);
|
|
130
131
|
|
|
131
|
-
|
|
132
|
-
handleValidationWarnings(res);
|
|
133
|
-
}
|
|
132
|
+
handleKubeApiHeaderWarnings(res, dispatch, rootGetters, opt.method);
|
|
134
133
|
|
|
135
134
|
return out;
|
|
136
135
|
});
|
|
@@ -196,24 +195,6 @@ export default {
|
|
|
196
195
|
|
|
197
196
|
return Promise.reject(out);
|
|
198
197
|
}
|
|
199
|
-
|
|
200
|
-
function handleValidationWarnings(res) {
|
|
201
|
-
const warnings = (res.headers?.warning || '').split(',');
|
|
202
|
-
|
|
203
|
-
if (!warnings.length || !warnings[0]) {
|
|
204
|
-
return;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
const message = warnings.reduce((message, warning) => {
|
|
208
|
-
return `${ message }\n${ warning.trim() }`;
|
|
209
|
-
}, `Validation Warnings for ${ opt.url }\n`);
|
|
210
|
-
|
|
211
|
-
if (process.env.dev) {
|
|
212
|
-
console.warn(`${ message }\n\n`, res.data); // eslint-disable-line no-console
|
|
213
|
-
} else {
|
|
214
|
-
console.debug(message); // eslint-disable-line no-console
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
198
|
},
|
|
218
199
|
|
|
219
200
|
promptMove({ commit, state }, resources) {
|