@rancher/shell 0.1.2 → 0.1.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 +27 -769
- package/assets/translations/zh-hans.yaml +8 -769
- package/components/ActionMenu.vue +3 -3
- package/components/CodeMirror.vue +6 -8
- package/components/CommunityLinks.vue +1 -1
- package/components/ContainerResourceLimit.vue +14 -0
- package/components/ExplorerMembers.vue +123 -0
- package/components/ExplorerProjectsNamespaces.vue +405 -0
- package/components/GrafanaDashboard.vue +17 -2
- package/components/LocaleSelector.vue +81 -0
- package/components/PromptModal.vue +2 -3
- package/components/ResourceList/index.vue +1 -1
- package/components/ResourceTable.vue +3 -6
- package/components/SingleClusterInfo.vue +1 -1
- package/components/SortableTable/index.vue +23 -20
- package/components/SortableTable/selection.js +1 -0
- package/components/auth/AzureWarning.vue +5 -1
- package/components/auth/Principal.vue +1 -1
- package/components/auth/RoleDetailEdit.vue +18 -11
- package/components/fleet/FleetRepos.vue +0 -2
- package/components/form/NameNsDescription.vue +4 -6
- package/components/form/NodeScheduling.vue +1 -1
- package/components/form/WorkloadPorts.vue +1 -1
- package/components/formatter/WorkloadHealthScale.vue +1 -1
- package/components/nav/Header.vue +9 -9
- package/components/nav/NamespaceFilter.vue +7 -4
- package/components/nav/TopLevelMenu.vue +6 -43
- package/components/nav/WindowManager/ContainerLogs.vue +1 -1
- package/config/product/harvester-manager.js +64 -2
- package/config/product/manager.js +9 -0
- package/config/settings.js +17 -71
- package/config/table-headers.js +0 -1
- package/config/types.js +5 -25
- package/core/plugin-routes.ts +34 -22
- package/core/plugin.ts +15 -3
- package/core/plugins-loader.js +2 -0
- package/core/plugins.js +79 -36
- package/core/types.ts +7 -1
- package/detail/provisioning.cattle.io.cluster.vue +13 -0
- package/detail/workload/index.vue +11 -5
- package/{components/dialog → dialog}/AddClusterMemberDialog.vue +0 -0
- package/{components/dialog → dialog}/AddCustomBadgeDialog.vue +0 -0
- package/{components/dialog → dialog}/AddProjectMemberDialog.vue +0 -0
- package/{components/dialog → dialog}/AddonConfigConfirmationDialog.vue +0 -0
- package/{components/dialog → dialog}/DrainNode.vue +0 -0
- package/{components/dialog → dialog}/ForceMachineRemoveDialog.vue +0 -0
- package/{components/dialog → dialog}/GenericPrompt.vue +0 -0
- package/{components/dialog → dialog}/RollbackWorkloadDialog.vue +0 -0
- package/{components/dialog → dialog}/RotateCertificatesDialog.vue +0 -0
- package/{components/dialog → dialog}/RotateEncryptionKeyDialog.vue +0 -0
- package/{components/dialog → dialog}/SaveAsRKETemplateDialog.vue +0 -0
- package/{components/dialog → dialog}/ScaleMachineDownDialog.vue +0 -0
- package/edit/auth/azuread.vue +20 -1
- package/edit/management.cattle.io.project.vue +2 -2
- package/edit/namespace.vue +17 -10
- package/edit/persistentvolumeclaim.vue +1 -0
- package/edit/provisioning.cattle.io.cluster/CustomCommand.vue +1 -1
- package/edit/provisioning.cattle.io.cluster/MachinePool.vue +33 -5
- package/edit/service.vue +1 -1
- package/edit/workload/index.vue +363 -15
- package/edit/workload/mixins/workload.js +62 -7
- package/edit/workload/storage/persistentVolumeClaim/persistentvolumeclaim.vue +1 -0
- package/layouts/default.vue +52 -27
- package/layouts/error.vue +5 -1
- package/layouts/home.vue +6 -2
- package/list/harvesterhci.io.management.cluster.vue +74 -33
- package/list/namespace.vue +3 -5
- package/machine-config/amazonec2.vue +2 -0
- package/machine-config/harvester.vue +96 -49
- package/middleware/authenticated.js +56 -52
- package/mixins/form-validation.js +1 -1
- package/mixins/resource-fetch.js +3 -1
- package/models/fleet.cattle.io.bundle.js +26 -19
- package/models/harvesterhci.io.management.cluster.js +194 -5
- package/models/management.cattle.io.cluster.js +1 -1
- package/models/management.cattle.io.clusterroletemplatebinding.js +9 -0
- package/models/management.cattle.io.project.js +23 -2
- package/models/namespace.js +19 -3
- package/models/pod.js +19 -2
- package/models/provisioning.cattle.io.cluster.js +4 -0
- package/models/workload.js +4 -243
- package/models/workload.service.js +314 -0
- package/nuxt.config.js +11 -9
- package/package.json +3 -3
- package/pages/auth/login.vue +11 -2
- package/pages/auth/setup.vue +1 -1
- package/pages/c/_cluster/_product/members/index.vue +3 -93
- package/pages/c/_cluster/_product/projectsnamespaces.vue +6 -403
- package/pages/c/_cluster/settings/performance.vue +19 -16
- package/pages/fail-whale.vue +1 -10
- package/pages/index.vue +18 -4
- package/pages/plugins.vue +2 -2
- package/pages/prefs.vue +8 -6
- package/pkg/auto-import.js +44 -7
- package/pkg/dynamic-plugin-loader.js +28 -0
- package/pkg/import.js +2 -2
- package/pkg/model-loader-require.lib.js +3 -0
- package/pkg/vue.config.js +9 -6
- package/plugins/dashboard-store/model-loader-require.js +12 -0
- package/plugins/dashboard-store/model-loader.js +4 -1
- package/plugins/dashboard-store/resource-class.js +10 -3
- package/plugins/steve/actions.js +1 -1
- package/plugins/steve/index.js +6 -4
- package/plugins/steve/subscribe.js +34 -23
- package/rancher-components/Form/Checkbox/Checkbox.test.ts +77 -0
- package/rancher-components/Form/Checkbox/Checkbox.vue +12 -2
- package/scripts/build-pkg.sh +48 -2
- package/scripts/drone-build-pkg.sh +31 -0
- package/scripts/publish-shell.sh +10 -11
- package/scripts/serve-pkgs +17 -10
- package/store/catalog.js +3 -1
- package/store/i18n.js +16 -11
- package/store/index.js +4 -181
- package/store/prefs.js +30 -2
- package/store/type-map.js +16 -29
- package/utils/cluster.js +1 -1
- package/utils/custom-validators.js +1 -12
- package/utils/dynamic-importer.js +1 -1
- package/utils/validators/setting.js +0 -35
- package/components/FilterLabel.vue +0 -254
- package/components/HarvesterUpgradeProgressBarList.vue +0 -109
- package/components/VMConsoleBar.vue +0 -87
- package/components/dialog/harvester/AddHotplugModal.vue +0 -159
- package/components/dialog/harvester/BackupModal.vue +0 -117
- package/components/dialog/harvester/CloneTemplate.vue +0 -125
- package/components/dialog/harvester/EjectCDROMDialog.vue +0 -157
- package/components/dialog/harvester/ExportImageDialog.vue +0 -152
- package/components/dialog/harvester/MaintenanceDialog.vue +0 -94
- package/components/dialog/harvester/MigrationDialog.vue +0 -154
- package/components/dialog/harvester/RestoreDialog.vue +0 -153
- package/components/dialog/harvester/SupportBundle.vue +0 -217
- package/components/dialog/harvester/UnplugVolume.vue +0 -108
- package/components/form/SerialConsole/index.vue +0 -267
- package/components/formatter/AttachVMWithName.vue +0 -46
- package/components/formatter/CloudInitType.vue +0 -27
- package/components/formatter/HarvesterBackupTargetValidation.vue +0 -43
- package/components/formatter/HarvesterCPUUsed.vue +0 -122
- package/components/formatter/HarvesterDiskState.vue +0 -66
- package/components/formatter/HarvesterHostName.vue +0 -66
- package/components/formatter/HarvesterIpAddress.vue +0 -90
- package/components/formatter/HarvesterMemoryUsed.vue +0 -140
- package/components/formatter/HarvesterMigrationState.vue +0 -85
- package/components/formatter/HarvesterNodeName.vue +0 -49
- package/components/formatter/HarvesterStorageUsed.vue +0 -194
- package/components/formatter/HarvesterVmState.vue +0 -123
- package/components/nav/HarvesterUpgrade.vue +0 -232
- package/components/novnc/NovncConsole.vue +0 -93
- package/components/novnc/NovncConsoleItem.vue +0 -89
- package/components/novnc/NovncConsoleWrapper.vue +0 -243
- package/config/harvester-map.js +0 -44
- package/config/harvester-table-headers.js +0 -27
- package/config/product/harvester.js +0 -305
- package/detail/harvesterhci.io.host/HarvesterHostBasic.vue +0 -364
- package/detail/harvesterhci.io.host/HarvesterHostDisk.vue +0 -200
- package/detail/harvesterhci.io.host/HarvesterHostNetwork.vue +0 -89
- package/detail/harvesterhci.io.host/VirtualMachineInstance.vue +0 -134
- package/detail/harvesterhci.io.host/index.vue +0 -243
- package/detail/harvesterhci.io.virtualmachinebackup/index.vue +0 -221
- package/detail/harvesterhci.io.virtualmachineimage.vue +0 -118
- package/detail/kubevirt.io.virtualmachine/VirtualMachineTabs/VirtualMachineBasics.vue +0 -279
- package/detail/kubevirt.io.virtualmachine/VirtualMachineTabs/VirtualMachineEvents.vue +0 -75
- package/detail/kubevirt.io.virtualmachine/VirtualMachineTabs/VirtualMachineKeypairs.vue +0 -114
- package/detail/kubevirt.io.virtualmachine/VirtualMachineTabs/VirtualMachineMigration.vue +0 -79
- package/detail/kubevirt.io.virtualmachine/index.vue +0 -213
- package/edit/harvesterhci.io.cloudtemplate.vue +0 -123
- package/edit/harvesterhci.io.host/HarvesterDisk.vue +0 -262
- package/edit/harvesterhci.io.host/index.vue +0 -533
- package/edit/harvesterhci.io.keypair.vue +0 -112
- package/edit/harvesterhci.io.managedchart/index.vue +0 -25
- package/edit/harvesterhci.io.managedchart/rancher-monitoring.vue +0 -172
- package/edit/harvesterhci.io.networkattachmentdefinition.vue +0 -210
- package/edit/harvesterhci.io.setting/additional-ca.vue +0 -36
- package/edit/harvesterhci.io.setting/backup-target.vue +0 -182
- package/edit/harvesterhci.io.setting/http-proxy.vue +0 -79
- package/edit/harvesterhci.io.setting/index.vue +0 -201
- package/edit/harvesterhci.io.setting/overcommit-config.vue +0 -94
- package/edit/harvesterhci.io.setting/ssl-certificates.vue +0 -117
- package/edit/harvesterhci.io.setting/ssl-parameters.vue +0 -161
- package/edit/harvesterhci.io.setting/support-bundle-image.vue +0 -134
- package/edit/harvesterhci.io.setting/support-bundle-namespaces.vue +0 -73
- package/edit/harvesterhci.io.setting/vip-pools.vue +0 -244
- package/edit/harvesterhci.io.setting/vm-force-reset-policy.vue +0 -81
- package/edit/harvesterhci.io.virtualmachinebackup.vue +0 -256
- package/edit/harvesterhci.io.virtualmachineimage.vue +0 -364
- package/edit/harvesterhci.io.virtualmachinetemplateversion.vue +0 -340
- package/edit/harvesterhci.io.volume.vue +0 -195
- package/edit/kubevirt.io.virtualmachine/VirtualMachineAccessCredentials/AccessCredentialsUsers.vue +0 -190
- package/edit/kubevirt.io.virtualmachine/VirtualMachineAccessCredentials/index.vue +0 -212
- package/edit/kubevirt.io.virtualmachine/VirtualMachineAccessCredentials/type/basicAuth.vue +0 -94
- package/edit/kubevirt.io.virtualmachine/VirtualMachineAccessCredentials/type/sshkey.vue +0 -85
- package/edit/kubevirt.io.virtualmachine/VirtualMachineCloudConfig/DataTemplate.vue +0 -153
- package/edit/kubevirt.io.virtualmachine/VirtualMachineCloudConfig/index.vue +0 -279
- package/edit/kubevirt.io.virtualmachine/VirtualMachineCpuMemory.vue +0 -113
- package/edit/kubevirt.io.virtualmachine/VirtualMachineNetwork/__tests__/HarvesterEditNetwork.test.ts +0 -41
- package/edit/kubevirt.io.virtualmachine/VirtualMachineNetwork/base.vue +0 -281
- package/edit/kubevirt.io.virtualmachine/VirtualMachineNetwork/index.vue +0 -142
- package/edit/kubevirt.io.virtualmachine/VirtualMachineReserved.vue +0 -54
- package/edit/kubevirt.io.virtualmachine/VirtualMachineSSHKey.vue +0 -256
- package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/index.vue +0 -391
- package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/__tests__/HarvesterEditContainer.test.ts +0 -40
- package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/__tests__/HarvesterEditExisting.test.ts +0 -102
- package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/__tests__/HarvesterEditVMImage.test.ts +0 -117
- package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/__tests__/HarvesterEditVolume.test.ts +0 -74
- package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/container.vue +0 -132
- package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/existing.vue +0 -303
- package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/vmImage.vue +0 -285
- package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/volume.vue +0 -188
- package/edit/kubevirt.io.virtualmachine/index.vue +0 -642
- package/edit/network.harvesterhci.io.clusternetwork/index.vue +0 -19
- package/edit/network.harvesterhci.io.clusternetwork/vlan.vue +0 -134
- package/edit/workload/types/Deployment.vue +0 -377
- package/edit/workload/types/Generic.vue +0 -295
- package/list/harvesterhci.io.cloudtemplate.vue +0 -78
- package/list/harvesterhci.io.dashboard/HarvesterUpgrade.vue +0 -211
- package/list/harvesterhci.io.dashboard/UpgradeInfo.vue +0 -40
- package/list/harvesterhci.io.dashboard/index.vue +0 -752
- package/list/harvesterhci.io.host/index.vue +0 -186
- package/list/harvesterhci.io.networkattachmentdefinition.vue +0 -167
- package/list/harvesterhci.io.setting.vue +0 -241
- package/list/harvesterhci.io.virtualmachinebackup.vue +0 -172
- package/list/harvesterhci.io.virtualmachineimage.vue +0 -80
- package/list/harvesterhci.io.virtualmachinetemplateversion.vue +0 -173
- package/list/harvesterhci.io.volume.vue +0 -122
- package/list/kubevirt.io.virtualmachine.vue +0 -193
- package/mixins/harvester-vm/impl.js +0 -267
- package/mixins/harvester-vm/index.js +0 -1357
- package/models/harvester/configmap.js +0 -32
- package/models/harvester/harvesterhci.io.blockdevice.js +0 -55
- package/models/harvester/harvesterhci.io.keypair.js +0 -12
- package/models/harvester/harvesterhci.io.setting.js +0 -127
- package/models/harvester/harvesterhci.io.supportbundle.js +0 -35
- package/models/harvester/harvesterhci.io.upgrade.js +0 -226
- package/models/harvester/harvesterhci.io.virtualmachinebackup.js +0 -116
- package/models/harvester/harvesterhci.io.virtualmachineimage.js +0 -255
- package/models/harvester/harvesterhci.io.virtualmachinerestore.js +0 -43
- package/models/harvester/harvesterhci.io.virtualmachinetemplate.js +0 -69
- package/models/harvester/harvesterhci.io.virtualmachinetemplateversion.js +0 -227
- package/models/harvester/k8s.cni.cncf.io.networkattachmentdefinition.js +0 -32
- package/models/harvester/kubevirt.io.virtualmachine.js +0 -850
- package/models/harvester/kubevirt.io.virtualmachineinstance.js +0 -142
- package/models/harvester/management.cattle.io.managedchart.js +0 -191
- package/models/harvester/management.cattle.io.setting.js +0 -40
- package/models/harvester/network.harvesterhci.io.clusternetwork.js +0 -100
- package/models/harvester/network.harvesterhci.io.nodenetwork.js +0 -34
- package/models/harvester/node.js +0 -255
- package/models/harvester/persistentvolumeclaim.js +0 -166
- package/models/harvester/pod.js +0 -185
- package/pages/c/_cluster/harvester/airgapupgrade/index.vue +0 -309
- package/pages/c/_cluster/harvester/console/_uid/serial.vue +0 -51
- package/pages/c/_cluster/harvester/console/_uid/vnc.vue +0 -52
- package/pages/c/_cluster/harvester/index.vue +0 -24
- package/pages/c/_cluster/harvester/support/index.vue +0 -154
- package/pkg/model-loader.lib.js +0 -3
- package/promptRemove/kubevirt.io.virtualmachine.vue +0 -164
- package/store/harvester-common.js +0 -126
- package/utils/validators/vm-datavolumes.js +0 -38
- package/utils/validators/vm-image.js +0 -32
- package/utils/validators/vm.js +0 -221
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import Vue from 'vue';
|
|
2
2
|
import ProvCluster from '@shell/models/provisioning.cattle.io.cluster';
|
|
3
|
-
import { DEFAULT_WORKSPACE } from '@shell/config/types';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
return this._availableActions;
|
|
7
|
-
}
|
|
3
|
+
import { DEFAULT_WORKSPACE, HCI, MANAGEMENT } from '@shell/config/types';
|
|
4
|
+
import { HARVESTER_NAME, HARVESTER_NAME as VIRTUAL } from '@shell/config/product/harvester-manager';
|
|
5
|
+
import { SETTING } from '@shell/config/settings';
|
|
8
6
|
|
|
7
|
+
export default class HciCluster extends ProvCluster {
|
|
9
8
|
get stateObj() {
|
|
10
9
|
return this._stateObj;
|
|
11
10
|
}
|
|
@@ -30,4 +29,194 @@ export default class HciCluster extends ProvCluster {
|
|
|
30
29
|
get canEdit() {
|
|
31
30
|
return false;
|
|
32
31
|
}
|
|
32
|
+
|
|
33
|
+
cachedHarvesterClusterVersion = '';
|
|
34
|
+
|
|
35
|
+
_uiInfo = undefined;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Fetch and cache the response for /ui-info
|
|
39
|
+
*
|
|
40
|
+
* Storing this in a cache means any changes to `ui-info` require a dashboard refresh... but it cuts out a http request every time we
|
|
41
|
+
* go to a cluster
|
|
42
|
+
*
|
|
43
|
+
* @param {string} clusterId
|
|
44
|
+
*/
|
|
45
|
+
async _getUiInfo(clusterId) {
|
|
46
|
+
if (!this._uiInfo) {
|
|
47
|
+
try {
|
|
48
|
+
const infoUrl = `/k8s/clusters/${ clusterId }/v1/harvester/ui-info`;
|
|
49
|
+
|
|
50
|
+
this._uiInfo = await this.$dispatch('request', { url: infoUrl });
|
|
51
|
+
} catch (e) {
|
|
52
|
+
console.info(`Failed to fetch harvester ui-info from ${ this.nameDisplay }, this may be an older cluster that cannot provide one`); // eslint-disable-line no-console
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return this._uiInfo;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Determine the harvester plugin's package name and url for legacy clusters that don't provide the package (i.e. it's coming from
|
|
61
|
+
* outside the cluster)
|
|
62
|
+
*/
|
|
63
|
+
_legacyClusterPkgDetails() {
|
|
64
|
+
let uiOfflinePreferred = this.$rootGetters['management/byId'](MANAGEMENT.SETTING, SETTING.UI_OFFLINE_PREFERRED)?.value;
|
|
65
|
+
// options: ['dynamic', 'true', 'false']
|
|
66
|
+
|
|
67
|
+
if (uiOfflinePreferred === 'dynamic') {
|
|
68
|
+
// We shouldn't need to worry about the version of the dashboard when embedded in harvester (aka in isSingleProduct)
|
|
69
|
+
const version = this.$rootGetters['management/byId'](MANAGEMENT.SETTING, 'server-version')?.value;
|
|
70
|
+
|
|
71
|
+
if (version.endsWith('-head')) {
|
|
72
|
+
uiOfflinePreferred = 'false';
|
|
73
|
+
} else {
|
|
74
|
+
uiOfflinePreferred = 'true';
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// This is the version that's embedded in the dashboard
|
|
79
|
+
const pkgName = `${ HARVESTER_NAME }-1.0.3`;
|
|
80
|
+
|
|
81
|
+
if (uiOfflinePreferred === 'true') {
|
|
82
|
+
// Embedded (aka give me the version of the embedded plugin that was in the last release)
|
|
83
|
+
const embeddedPath = `dashboard/${ pkgName }/${ pkgName }.umd.min.js`;
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
pkgUrl: process.env.dev ? `${ process.env.api }/${ embeddedPath }` : embeddedPath,
|
|
87
|
+
pkgName
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (uiOfflinePreferred === 'false') {
|
|
92
|
+
// Remote (aka give me the latest version of the embedded plugin that might not have been released yet)
|
|
93
|
+
const uiDashboardHarvesterRemotePlugin = this.$rootGetters['management/byId'](MANAGEMENT.SETTING, SETTING.UI_DASHBOARD_HARVESTER_LEGACY_PLUGIN)?.value;
|
|
94
|
+
const parts = uiDashboardHarvesterRemotePlugin?.replace('.umd.min.js', '').split('/');
|
|
95
|
+
const pkgNameFromUrl = parts?.length > 1 ? parts[parts.length - 1] : null;
|
|
96
|
+
|
|
97
|
+
if (!pkgNameFromUrl) {
|
|
98
|
+
throw new Error(`Unable to determine harvester plugin name from '${ uiDashboardHarvesterRemotePlugin }'`);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return {
|
|
102
|
+
pkgUrl: uiDashboardHarvesterRemotePlugin,
|
|
103
|
+
pkgName: pkgNameFromUrl
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
throw new Error(`Unsupported value for ${ SETTING.UI_OFFLINE_PREFERRED }: 'uiOfflinePreferred'`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Determine the harvester plugin's package name and url for clusters that provide the plugin
|
|
112
|
+
*/
|
|
113
|
+
_supportedClusterPkgDetails(uiInfo, clusterId) {
|
|
114
|
+
const pkgName = `${ HARVESTER_NAME }-${ uiInfo['ui-plugin-bundled-version'] }`;
|
|
115
|
+
const fileName = `${ pkgName }.umd.min.js`;
|
|
116
|
+
let pkgUrl;
|
|
117
|
+
|
|
118
|
+
if (uiInfo['ui-source'] === 'bundled' ) { // offline bundled
|
|
119
|
+
pkgUrl = `k8s/clusters/${ clusterId }/v1/harvester/plugin-assets/${ fileName }`;
|
|
120
|
+
} else if (uiInfo['ui-source'] === 'external') {
|
|
121
|
+
if (uiInfo['ui-plugin-index']) {
|
|
122
|
+
pkgUrl = uiInfo['ui-plugin-index'];
|
|
123
|
+
} else {
|
|
124
|
+
throw new Error('Harvester cluster requested the plugin at `ui-plugin-index` is used, however did not provide a value for it');
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return {
|
|
129
|
+
pkgUrl,
|
|
130
|
+
pkgName
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
_overridePkgDetails() {
|
|
135
|
+
// Support loading the pkg from a locally, or other, address
|
|
136
|
+
// This helps testing of the harvester plugin when packaged up, instead of directly imported
|
|
137
|
+
const harvesterPkgUrl = process.env.harvesterPkgUrl;
|
|
138
|
+
|
|
139
|
+
if (!harvesterPkgUrl) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
const parts = harvesterPkgUrl.replace('.umd.min.js', '').split('/');
|
|
143
|
+
const pkgNameFromUrl = parts.length > 1 ? parts[parts.length - 1] : null;
|
|
144
|
+
|
|
145
|
+
if (pkgNameFromUrl) {
|
|
146
|
+
return {
|
|
147
|
+
pkgUrl: harvesterPkgUrl,
|
|
148
|
+
pkgName: pkgNameFromUrl
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async _pkgDetails() {
|
|
154
|
+
const overridePkgDetails = this._overridePkgDetails();
|
|
155
|
+
|
|
156
|
+
if (overridePkgDetails) {
|
|
157
|
+
return overridePkgDetails;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const clusterId = this.mgmt.id;
|
|
161
|
+
const uiInfo = await this._getUiInfo(clusterId);
|
|
162
|
+
|
|
163
|
+
return uiInfo ? this._supportedClusterPkgDetails(uiInfo, clusterId) : this._legacyClusterPkgDetails();
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async loadClusterPlugin() {
|
|
167
|
+
// Skip loading if it's built in
|
|
168
|
+
const plugins = this.$rootState.$plugin.getPlugins();
|
|
169
|
+
const loadedPkgs = Object.keys(plugins);
|
|
170
|
+
|
|
171
|
+
if (loadedPkgs.find(pkg => pkg === HARVESTER_NAME)) {
|
|
172
|
+
console.info('Harvester plugin built is built in, skipping load from external sources'); // eslint-disable-line no-console
|
|
173
|
+
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Determine the plugin name and the url it can be fetched from
|
|
178
|
+
const { pkgUrl, pkgName } = await this._pkgDetails();
|
|
179
|
+
|
|
180
|
+
console.info('Harvester plugin details: ', pkgName, pkgUrl); // eslint-disable-line no-console
|
|
181
|
+
|
|
182
|
+
// Skip loading if we've previously loaded the correct one
|
|
183
|
+
if (!!plugins[pkgName]) {
|
|
184
|
+
console.info('Harvester plugin already loaded, no need to load', pkgName); // eslint-disable-line no-console
|
|
185
|
+
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
console.info('Attempting to load Harvester plugin', pkgName); // eslint-disable-line no-console
|
|
190
|
+
|
|
191
|
+
const res = await this.$rootState.$plugin.loadAsync(pkgName, pkgUrl);
|
|
192
|
+
|
|
193
|
+
console.info('Loaded Harvester plugin', pkgName); // eslint-disable-line no-console
|
|
194
|
+
|
|
195
|
+
return res;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
goToCluster() {
|
|
199
|
+
this.loadClusterPlugin()
|
|
200
|
+
.then(() => {
|
|
201
|
+
this.currentRouter().push({
|
|
202
|
+
name: `${ VIRTUAL }-c-cluster-resource`,
|
|
203
|
+
params: {
|
|
204
|
+
cluster: this.status.clusterName,
|
|
205
|
+
product: VIRTUAL,
|
|
206
|
+
resource: HCI.DASHBOARD // Go directly to dashboard to avoid blip of components on screen
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
})
|
|
210
|
+
.catch((err) => {
|
|
211
|
+
const message = typeof error === 'object' ? JSON.stringify(err) : err;
|
|
212
|
+
|
|
213
|
+
console.error('Failed to load harvester package: ', message); // eslint-disable-line no-console
|
|
214
|
+
|
|
215
|
+
this.$dispatch('growl/error', {
|
|
216
|
+
title: this.t('harvesterManager.plugins.loadError'),
|
|
217
|
+
message,
|
|
218
|
+
timeout: 5000
|
|
219
|
+
}, { root: true });
|
|
220
|
+
});
|
|
221
|
+
}
|
|
33
222
|
}
|
|
@@ -9,7 +9,7 @@ import jsyaml from 'js-yaml';
|
|
|
9
9
|
import { eachLimit } from '@shell/utils/promise';
|
|
10
10
|
import { addParams } from '@shell/utils/url';
|
|
11
11
|
import { isEmpty } from '@shell/utils/object';
|
|
12
|
-
import {
|
|
12
|
+
import { HARVESTER_NAME as HARVESTER } from '@shell/config/product/harvester-manager';
|
|
13
13
|
import { isHarvesterCluster } from '@shell/utils/cluster';
|
|
14
14
|
import HybridModel from '@shell/plugins/steve/hybrid-class';
|
|
15
15
|
import { LINUX, WINDOWS } from '@shell/store/catalog';
|
|
@@ -2,6 +2,7 @@ import { CREATOR_ID } from '@shell/config/labels-annotations';
|
|
|
2
2
|
import { _CREATE } from '@shell/config/query-params';
|
|
3
3
|
import { MANAGEMENT, NORMAN } from '@shell/config/types';
|
|
4
4
|
import HybridModel from '@shell/plugins/steve/hybrid-class';
|
|
5
|
+
import { HARVESTER_NAME } from '@shell/config/product/harvester-manager';
|
|
5
6
|
|
|
6
7
|
export default class CRTB extends HybridModel {
|
|
7
8
|
detailPageHeaderActionOverride(realMode) {
|
|
@@ -65,6 +66,9 @@ export default class CRTB extends HybridModel {
|
|
|
65
66
|
return this.cluster ? this.cluster.nameDisplay : this.clusterName;
|
|
66
67
|
}
|
|
67
68
|
|
|
69
|
+
/**
|
|
70
|
+
* This is used in a table formatter on the management.cattle.io.user detail view which exists outside harvester so no override on this route as there is with listLocation
|
|
71
|
+
*/
|
|
68
72
|
get clusterDetailLocation() {
|
|
69
73
|
if (this.cluster) {
|
|
70
74
|
return this.cluster.detailLocation;
|
|
@@ -82,6 +86,11 @@ export default class CRTB extends HybridModel {
|
|
|
82
86
|
}
|
|
83
87
|
|
|
84
88
|
get listLocation() {
|
|
89
|
+
// Harvester uses these resource directly... but has different routes
|
|
90
|
+
if (this.$rootGetters['currentProduct'].inStore === HARVESTER_NAME) {
|
|
91
|
+
return { name: `${ HARVESTER_NAME }-c-cluster-members` };
|
|
92
|
+
}
|
|
93
|
+
|
|
85
94
|
return { name: 'c-cluster-product-members' };
|
|
86
95
|
}
|
|
87
96
|
|
|
@@ -2,6 +2,7 @@ import { DEFAULT_PROJECT, SYSTEM_PROJECT } from '@shell/config/labels-annotation
|
|
|
2
2
|
import { MANAGEMENT, NAMESPACE, NORMAN } from '@shell/config/types';
|
|
3
3
|
import HybridModel from '@shell/plugins/steve/hybrid-class';
|
|
4
4
|
import isEmpty from 'lodash/isEmpty';
|
|
5
|
+
import { HARVESTER_NAME as HARVESTER } from '@shell/config/product/harvester-manager';
|
|
5
6
|
|
|
6
7
|
function clearUnusedResourceQuotas(spec, types) {
|
|
7
8
|
types.forEach((type) => {
|
|
@@ -61,10 +62,30 @@ export default class Project extends HybridModel {
|
|
|
61
62
|
});
|
|
62
63
|
}
|
|
63
64
|
|
|
65
|
+
get doneOverride() {
|
|
66
|
+
return this.listLocation;
|
|
67
|
+
}
|
|
68
|
+
|
|
64
69
|
get listLocation() {
|
|
70
|
+
// Harvester uses these resource directly... but has different routes. listLocation covers routes leading back to route
|
|
71
|
+
if (this.$rootGetters['currentProduct'].inStore === HARVESTER) {
|
|
72
|
+
return { name: `${ HARVESTER }-c-cluster-projectsnamespaces` };
|
|
73
|
+
}
|
|
74
|
+
|
|
65
75
|
return { name: 'c-cluster-product-projectsnamespaces' };
|
|
66
76
|
}
|
|
67
77
|
|
|
78
|
+
get _detailLocation() {
|
|
79
|
+
// Harvester uses these resource directly... but has different routes. detailLocation covers routes leading to resource (like edit)
|
|
80
|
+
const _detailLocation = super._detailLocation;
|
|
81
|
+
|
|
82
|
+
if (this.$rootGetters['currentProduct'].inStore === HARVESTER) {
|
|
83
|
+
_detailLocation.name = `${ HARVESTER }-${ _detailLocation.name }`.replace('-product', '');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return _detailLocation;
|
|
87
|
+
}
|
|
88
|
+
|
|
68
89
|
get parentLocationOverride() {
|
|
69
90
|
return this.listLocation;
|
|
70
91
|
}
|
|
@@ -81,9 +102,9 @@ export default class Project extends HybridModel {
|
|
|
81
102
|
try {
|
|
82
103
|
await newValue.doAction('setpodsecuritypolicytemplate', { podSecurityPolicyTemplateId: this.spec.podSecurityPolicyTemplateId || null });
|
|
83
104
|
} catch (err) {
|
|
84
|
-
if (err.status === 409) {
|
|
105
|
+
if ( err.status === 409 || err.status === 403 ) {
|
|
85
106
|
// The backend updates each new project soon after it is created,
|
|
86
|
-
// so there is a chance of a resource conflict error. If that happens,
|
|
107
|
+
// so there is a chance of a resource conflict or forbidden error. If that happens,
|
|
87
108
|
// retry the action.
|
|
88
109
|
await newValue.doAction('setpodsecuritypolicytemplate', { podSecurityPolicyTemplateId: this.spec.podSecurityPolicyTemplateId || null });
|
|
89
110
|
} else {
|
package/models/namespace.js
CHANGED
|
@@ -9,6 +9,7 @@ import { escapeHtml } from '@shell/utils/string';
|
|
|
9
9
|
import { insertAt, isArray } from '@shell/utils/array';
|
|
10
10
|
import SteveModel from '@shell/plugins/steve/steve-class';
|
|
11
11
|
import Vue from 'vue';
|
|
12
|
+
import { HARVESTER_NAME as HARVESTER } from '@shell/config/product/harvester-manager';
|
|
12
13
|
|
|
13
14
|
const OBSCURE_NAMESPACE_PREFIX = [
|
|
14
15
|
'c-', // cluster namespace
|
|
@@ -172,11 +173,26 @@ export default class Namespace extends SteveModel {
|
|
|
172
173
|
}
|
|
173
174
|
|
|
174
175
|
get listLocation() {
|
|
175
|
-
|
|
176
|
-
|
|
176
|
+
const listLocation = { name: this.$rootGetters['isRancher'] ? 'c-cluster-product-projectsnamespaces' : 'c-cluster-product-resource' };
|
|
177
|
+
|
|
178
|
+
// Harvester uses these resource directly... but has different routes. listLocation covers routes leading back to route
|
|
179
|
+
if (this.$rootGetters['currentProduct'].inStore === HARVESTER) {
|
|
180
|
+
listLocation.name = `${ HARVESTER }-${ listLocation.name }`.replace('-product', '');
|
|
181
|
+
listLocation.params = { resource: 'namespace' };
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return listLocation;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
get _detailLocation() {
|
|
188
|
+
const _detailLocation = super._detailLocation;
|
|
189
|
+
|
|
190
|
+
// Harvester uses these resource directly... but has different routes. detailLocation covers routes leading to resource (like edit)
|
|
191
|
+
if (this.$rootGetters['currentProduct'].inStore === HARVESTER) {
|
|
192
|
+
_detailLocation.name = `${ HARVESTER }-${ _detailLocation.name }`.replace('-product', '');
|
|
177
193
|
}
|
|
178
194
|
|
|
179
|
-
return
|
|
195
|
+
return _detailLocation;
|
|
180
196
|
}
|
|
181
197
|
|
|
182
198
|
get parentLocationOverride() {
|
package/models/pod.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { insertAt } from '@shell/utils/array';
|
|
2
2
|
import { colorForState, stateDisplay } from '@shell/plugins/dashboard-store/resource-class';
|
|
3
3
|
import { NODE, WORKLOAD_TYPES } from '@shell/config/types';
|
|
4
|
-
import SteveModel from '@shell/plugins/steve/steve-class';
|
|
5
4
|
import { escapeHtml, shortenedImage } from '@shell/utils/string';
|
|
5
|
+
import WorkloadService from '@shell/models/workload.service';
|
|
6
6
|
|
|
7
7
|
export const WORKLOAD_PRIORITY = {
|
|
8
8
|
[WORKLOAD_TYPES.DEPLOYMENT]: 1,
|
|
@@ -14,7 +14,7 @@ export const WORKLOAD_PRIORITY = {
|
|
|
14
14
|
[WORKLOAD_TYPES.REPLICATION_CONTROLLER]: 7,
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
-
export default class Pod extends
|
|
17
|
+
export default class Pod extends WorkloadService {
|
|
18
18
|
get _availableActions() {
|
|
19
19
|
const out = super._availableActions;
|
|
20
20
|
|
|
@@ -180,4 +180,21 @@ export default class Pod extends SteveModel {
|
|
|
180
180
|
|
|
181
181
|
return 0;
|
|
182
182
|
}
|
|
183
|
+
|
|
184
|
+
save() {
|
|
185
|
+
const { metadata, spec } = this.spec.template;
|
|
186
|
+
|
|
187
|
+
this.spec = {
|
|
188
|
+
...this.spec,
|
|
189
|
+
metadata: {
|
|
190
|
+
...this.metadata,
|
|
191
|
+
...metadata
|
|
192
|
+
},
|
|
193
|
+
...spec
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
delete this.spec.template;
|
|
197
|
+
|
|
198
|
+
return this._save(...arguments);
|
|
199
|
+
}
|
|
183
200
|
}
|
|
@@ -269,6 +269,10 @@ export default class ProvCluster extends SteveModel {
|
|
|
269
269
|
return !!this.mgmt?.isReady;
|
|
270
270
|
}
|
|
271
271
|
|
|
272
|
+
get eksNodeGroups() {
|
|
273
|
+
return this.mgmt?.spec?.eksConfig?.nodeGroups;
|
|
274
|
+
}
|
|
275
|
+
|
|
272
276
|
waitForProvisioner(timeout, interval) {
|
|
273
277
|
return this.waitForTestFn(() => {
|
|
274
278
|
return !!this.provisioner;
|
package/models/workload.js
CHANGED
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
import { findBy, insertAt } from '@shell/utils/array';
|
|
2
|
-
import {
|
|
3
|
-
TARGET_WORKLOADS, TIMESTAMP, UI_MANAGED, HCI as HCI_LABELS_ANNOTATIONS, CATTLE_PUBLIC_ENDPOINTS
|
|
4
|
-
} from '@shell/config/labels-annotations';
|
|
2
|
+
import { TIMESTAMP, CATTLE_PUBLIC_ENDPOINTS } from '@shell/config/labels-annotations';
|
|
5
3
|
import { WORKLOAD_TYPES, SERVICE, POD } from '@shell/config/types';
|
|
6
|
-
import {
|
|
4
|
+
import { get, set } from '@shell/utils/object';
|
|
7
5
|
import day from 'dayjs';
|
|
8
|
-
import SteveModel from '@shell/plugins/steve/steve-class';
|
|
9
|
-
import { shortenedImage } from '@shell/utils/string';
|
|
10
6
|
import { convertSelectorObj, matching, matches } from '@shell/utils/selector';
|
|
11
7
|
import { SEPARATOR } from '@shell/components/DetailTop';
|
|
8
|
+
import WorkloadService from '@shell/models/workload.service';
|
|
12
9
|
|
|
13
|
-
export default class Workload extends
|
|
10
|
+
export default class Workload extends WorkloadService {
|
|
14
11
|
// remove clone as yaml/edit as yaml until API supported
|
|
15
12
|
get _availableActions() {
|
|
16
13
|
let out = super._availableActions;
|
|
@@ -279,30 +276,6 @@ export default class Workload extends SteveModel {
|
|
|
279
276
|
return out;
|
|
280
277
|
}
|
|
281
278
|
|
|
282
|
-
get containers() {
|
|
283
|
-
if (this.type === WORKLOAD_TYPES.CRON_JOB) {
|
|
284
|
-
// cronjob pod template is nested slightly different than other types
|
|
285
|
-
const { spec: { jobTemplate: { spec: { template: { spec: { containers } } } } } } = this;
|
|
286
|
-
|
|
287
|
-
return containers;
|
|
288
|
-
}
|
|
289
|
-
const { spec:{ template:{ spec:{ containers } } } } = this;
|
|
290
|
-
|
|
291
|
-
return containers;
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
get initContainers() {
|
|
295
|
-
if (this.type === WORKLOAD_TYPES.CRON_JOB) {
|
|
296
|
-
// cronjob pod template is nested slightly different than other types
|
|
297
|
-
const { spec: { jobTemplate: { spec: { template: { spec: { initContainers } } } } } } = this;
|
|
298
|
-
|
|
299
|
-
return initContainers;
|
|
300
|
-
}
|
|
301
|
-
const { spec:{ template:{ spec:{ initContainers } } } } = this;
|
|
302
|
-
|
|
303
|
-
return initContainers;
|
|
304
|
-
}
|
|
305
|
-
|
|
306
279
|
get endpoint() {
|
|
307
280
|
return this?.metadata?.annotations[CATTLE_PUBLIC_ENDPOINTS];
|
|
308
281
|
}
|
|
@@ -441,46 +414,6 @@ export default class Workload extends SteveModel {
|
|
|
441
414
|
return out;
|
|
442
415
|
}
|
|
443
416
|
|
|
444
|
-
async getServicesOwned(force = false) {
|
|
445
|
-
const normanTypes = {
|
|
446
|
-
[WORKLOAD_TYPES.REPLICA_SET]: 'replicaSet',
|
|
447
|
-
[WORKLOAD_TYPES.DEPLOYMENT]: 'deployment',
|
|
448
|
-
[WORKLOAD_TYPES.STATEFUL_SET]: 'statefulSet',
|
|
449
|
-
[WORKLOAD_TYPES.DAEMON_SET]: 'daemonSet'
|
|
450
|
-
};
|
|
451
|
-
const selectorKey = Object.keys(this.workloadSelector)[0];
|
|
452
|
-
|
|
453
|
-
const normanSelectorValue =
|
|
454
|
-
`${ normanTypes[this._type ? this._type : this.type] }-${
|
|
455
|
-
this.metadata.namespace
|
|
456
|
-
}-${ this.metadata.name }`;
|
|
457
|
-
|
|
458
|
-
const steveSelectorValue = this.workloadSelector[selectorKey];
|
|
459
|
-
const allSvc = await this.$dispatch('cluster/findAll', { type: SERVICE, opt: { force } }, { root: true });
|
|
460
|
-
|
|
461
|
-
return (allSvc || []).filter(svc => (svc.spec?.selector || {})[selectorKey] === steveSelectorValue || (svc.spec?.selector || {})[selectorKey] === normanSelectorValue );
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
get imageNames() {
|
|
465
|
-
let containers;
|
|
466
|
-
const images = [];
|
|
467
|
-
|
|
468
|
-
if (this.type === WORKLOAD_TYPES.CRON_JOB) {
|
|
469
|
-
containers = get(this, 'spec.jobTemplate.spec.template.spec.containers');
|
|
470
|
-
} else {
|
|
471
|
-
containers = get(this, 'spec.template.spec.containers');
|
|
472
|
-
}
|
|
473
|
-
if (containers) {
|
|
474
|
-
containers.forEach((container) => {
|
|
475
|
-
if (!images.includes(container.image)) {
|
|
476
|
-
images.push(container.image);
|
|
477
|
-
}
|
|
478
|
-
});
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
return images.map(shortenedImage);
|
|
482
|
-
}
|
|
483
|
-
|
|
484
417
|
redeploy() {
|
|
485
418
|
const now = (new Date()).toISOString().replace(/\.\d+Z$/, 'Z');
|
|
486
419
|
|
|
@@ -496,14 +429,6 @@ export default class Workload extends SteveModel {
|
|
|
496
429
|
this.save();
|
|
497
430
|
}
|
|
498
431
|
|
|
499
|
-
get workloadSelector() {
|
|
500
|
-
return {
|
|
501
|
-
'workload.user.cattle.io/workloadselector': `${ this._type ? this._type : this.type }-${
|
|
502
|
-
this.metadata.namespace
|
|
503
|
-
}-${ this.metadata.name }`
|
|
504
|
-
};
|
|
505
|
-
}
|
|
506
|
-
|
|
507
432
|
// match existing container ports with services created for this workload
|
|
508
433
|
async getPortsWithServiceType() {
|
|
509
434
|
const ports = [];
|
|
@@ -574,170 +499,6 @@ export default class Workload extends SteveModel {
|
|
|
574
499
|
return ports;
|
|
575
500
|
}
|
|
576
501
|
|
|
577
|
-
// create clusterip, nodeport, loadbalancer services from container port spec
|
|
578
|
-
async servicesFromContainerPorts(mode, ports) {
|
|
579
|
-
const ownerRef = {
|
|
580
|
-
apiVersion: this.apiVersion,
|
|
581
|
-
controller: true,
|
|
582
|
-
kind: this.kind,
|
|
583
|
-
name: this.metadata.name,
|
|
584
|
-
uid: this.metadata.uid
|
|
585
|
-
};
|
|
586
|
-
|
|
587
|
-
const annotations = { [TARGET_WORKLOADS]: JSON.stringify([`${ this.metadata.namespace }/${ this.metadata.name }`]), [UI_MANAGED]: 'true' };
|
|
588
|
-
|
|
589
|
-
let clusterIP = {
|
|
590
|
-
type: SERVICE,
|
|
591
|
-
spec: {
|
|
592
|
-
ports: [],
|
|
593
|
-
selector: this.workloadSelector,
|
|
594
|
-
type: 'ClusterIP'
|
|
595
|
-
},
|
|
596
|
-
metadata: {
|
|
597
|
-
name: this.metadata.name,
|
|
598
|
-
namespace: this.metadata.namespace,
|
|
599
|
-
annotations,
|
|
600
|
-
ownerReferences: [ownerRef]
|
|
601
|
-
},
|
|
602
|
-
};
|
|
603
|
-
|
|
604
|
-
let nodePort = {
|
|
605
|
-
type: SERVICE,
|
|
606
|
-
spec: {
|
|
607
|
-
ports: [],
|
|
608
|
-
selector: this.workloadSelector,
|
|
609
|
-
type: 'NodePort'
|
|
610
|
-
},
|
|
611
|
-
metadata: {
|
|
612
|
-
name: `${ this.metadata.name }-nodeport`,
|
|
613
|
-
namespace: this.metadata.namespace,
|
|
614
|
-
annotations,
|
|
615
|
-
ownerReferences: [ownerRef]
|
|
616
|
-
},
|
|
617
|
-
};
|
|
618
|
-
|
|
619
|
-
let loadBalancer = {
|
|
620
|
-
type: SERVICE,
|
|
621
|
-
spec: {
|
|
622
|
-
ports: [],
|
|
623
|
-
selector: this.workloadSelector,
|
|
624
|
-
type: 'LoadBalancer',
|
|
625
|
-
externalTrafficPolicy: 'Cluster'
|
|
626
|
-
},
|
|
627
|
-
metadata: {
|
|
628
|
-
name: `${ this.metadata.name }-loadbalancer`,
|
|
629
|
-
namespace: this.metadata.namespace,
|
|
630
|
-
annotations,
|
|
631
|
-
ownerReferences: [ownerRef]
|
|
632
|
-
},
|
|
633
|
-
};
|
|
634
|
-
|
|
635
|
-
const existing = await this.getServicesOwned(this.isFromNorman);
|
|
636
|
-
|
|
637
|
-
if (existing && existing.length) {
|
|
638
|
-
existing.forEach((service) => {
|
|
639
|
-
switch (service.spec.type) {
|
|
640
|
-
case 'ClusterIP':
|
|
641
|
-
clusterIP = service;
|
|
642
|
-
clusterIP.spec.ports = [];
|
|
643
|
-
break;
|
|
644
|
-
case 'NodePort':
|
|
645
|
-
nodePort = service;
|
|
646
|
-
nodePort.spec.ports = [];
|
|
647
|
-
break;
|
|
648
|
-
case 'LoadBalancer':
|
|
649
|
-
loadBalancer = service;
|
|
650
|
-
loadBalancer.spec.ports = [];
|
|
651
|
-
break;
|
|
652
|
-
default:
|
|
653
|
-
break;
|
|
654
|
-
}
|
|
655
|
-
});
|
|
656
|
-
}
|
|
657
|
-
ports.forEach((port) => {
|
|
658
|
-
const portSpec = {
|
|
659
|
-
name: port.name, protocol: port.protocol, port: port.containerPort, targetPort: port.containerPort
|
|
660
|
-
};
|
|
661
|
-
|
|
662
|
-
if (port._serviceType !== '') {
|
|
663
|
-
clusterIP.spec.ports.push(portSpec);
|
|
664
|
-
switch (port._serviceType) {
|
|
665
|
-
case 'NodePort': {
|
|
666
|
-
const npPort = clone(portSpec);
|
|
667
|
-
|
|
668
|
-
if (port._listeningPort) {
|
|
669
|
-
npPort.nodePort = port._listeningPort;
|
|
670
|
-
}
|
|
671
|
-
nodePort.spec.ports.push(npPort);
|
|
672
|
-
break; }
|
|
673
|
-
case 'LoadBalancer': {
|
|
674
|
-
const lbPort = clone(portSpec);
|
|
675
|
-
|
|
676
|
-
if (port._listeningPort) {
|
|
677
|
-
lbPort.port = port._listeningPort;
|
|
678
|
-
}
|
|
679
|
-
loadBalancer.spec.ports.push(lbPort);
|
|
680
|
-
break; }
|
|
681
|
-
default:
|
|
682
|
-
break;
|
|
683
|
-
}
|
|
684
|
-
}
|
|
685
|
-
});
|
|
686
|
-
|
|
687
|
-
const toSave = [];
|
|
688
|
-
const toRemove = [];
|
|
689
|
-
let clusterIPProxy;
|
|
690
|
-
|
|
691
|
-
if (clusterIP.spec.ports.length > 0) {
|
|
692
|
-
if (clusterIP.id) {
|
|
693
|
-
clusterIPProxy = clusterIP;
|
|
694
|
-
} else {
|
|
695
|
-
clusterIPProxy = await this.$dispatch(`cluster/create`, clusterIP, { root: true });
|
|
696
|
-
}
|
|
697
|
-
toSave.push(clusterIPProxy);
|
|
698
|
-
} else if (clusterIP.id) {
|
|
699
|
-
toRemove.push(clusterIP);
|
|
700
|
-
}
|
|
701
|
-
|
|
702
|
-
if (nodePort.spec.ports.length > 0) {
|
|
703
|
-
let nodePortProxy;
|
|
704
|
-
|
|
705
|
-
// if id is defined it's a preexisting service
|
|
706
|
-
if (nodePort.id) {
|
|
707
|
-
nodePortProxy = nodePort;
|
|
708
|
-
} else {
|
|
709
|
-
nodePortProxy = await this.$dispatch(`cluster/create`, nodePort, { root: true });
|
|
710
|
-
}
|
|
711
|
-
toSave.push(nodePortProxy);
|
|
712
|
-
// if id defined but no ports, the service already exists but should be removed (user has removed all container ports mapping to it)
|
|
713
|
-
} else if (nodePort.id) {
|
|
714
|
-
toRemove.push(nodePort);
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
if (loadBalancer.spec.ports.length > 0) {
|
|
718
|
-
let loadBalancerProxy;
|
|
719
|
-
|
|
720
|
-
if (loadBalancer.id) {
|
|
721
|
-
loadBalancerProxy = loadBalancer;
|
|
722
|
-
} else {
|
|
723
|
-
loadBalancer = clone(loadBalancer);
|
|
724
|
-
|
|
725
|
-
const portsWithIpam = ports.filter(p => p._ipam) || [];
|
|
726
|
-
|
|
727
|
-
if (portsWithIpam.length > 0) {
|
|
728
|
-
loadBalancer.metadata.annotations[HCI_LABELS_ANNOTATIONS.CLOUD_PROVIDER_IPAM] = portsWithIpam[0]._ipam;
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
loadBalancerProxy = await this.$dispatch(`cluster/create`, loadBalancer, { root: true });
|
|
732
|
-
}
|
|
733
|
-
toSave.push(loadBalancerProxy);
|
|
734
|
-
} else if (loadBalancer.id) {
|
|
735
|
-
toRemove.push(loadBalancer);
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
return { toSave, toRemove };
|
|
739
|
-
}
|
|
740
|
-
|
|
741
502
|
get showAsWorkload() {
|
|
742
503
|
const types = Object.values(WORKLOAD_TYPES);
|
|
743
504
|
|