Single + bulk download kubeconfig

This commit is contained in:
Vincent Fiduccia 2021-05-11 12:41:24 -07:00
parent 8f15575514
commit ecfed78021
No known key found for this signature in database
GPG Key ID: 2B29AD6BB2BB2582
4 changed files with 170 additions and 50 deletions

View File

@ -75,9 +75,10 @@ nav:
title: Dashboard title: Dashboard
backToRancher: Cluster Manager backToRancher: Cluster Manager
clusterTools: Cluster Tools clusterTools: Cluster Tools
shell: Kubectl Shell kubeconfig: Download KubeConfig
import: Import YAML import: Import YAML
home: Home home: Home
shell: Kubectl Shell
support: Get Support support: Get Support
group: group:
cluster: Cluster cluster: Cluster

View File

@ -47,11 +47,15 @@ export default {
return this.$store.getters['rancher/byId'](NORMAN.PRINCIPAL, this.$store.getters['auth/principalId']) || {}; return this.$store.getters['rancher/byId'](NORMAN.PRINCIPAL, this.$store.getters['auth/principalId']) || {};
}, },
showShell() { kubeConfigEnabled() {
return true;
},
shellEnabled() {
return !!this.currentCluster?.links?.shell; return !!this.currentCluster?.links?.shell;
}, },
showImport() { importEnabled() {
return !!this.currentCluster?.actions?.apply; return !!this.currentCluster?.actions?.apply;
}, },
@ -147,36 +151,46 @@ export default {
</div> </div>
<div v-if="!simple" class="header-buttons"> <div v-if="!simple" class="header-buttons">
<button <template v-if="currentProduct && currentProduct.showClusterSwitcher">
v-if="currentProduct && currentProduct.showClusterSwitcher" <button
v-tooltip="t('nav.import')" v-tooltip="t('nav.import')"
:disabled="!showImport" :disabled="!importEnabled"
type="button" type="button"
class="btn header-btn role-tertiary" class="btn header-btn role-tertiary"
@click="openImport()" @click="openImport()"
> >
<i class="icon icon-upload icon-lg" /> <i class="icon icon-upload icon-lg" />
</button> </button>
<modal <modal
class="import-modal" class="import-modal"
name="importModal" name="importModal"
width="75%" width="75%"
height="auto" height="auto"
styles="max-height: 90vh;" styles="max-height: 90vh;"
> >
<Import :cluster="currentCluster" @close="closeImport" /> <Import :cluster="currentCluster" @close="closeImport" />
</modal> </modal>
<button <button
v-if="currentProduct && currentProduct.showClusterSwitcher" v-tooltip="t('nav.shell')"
v-tooltip="t('nav.shell')" :disabled="!shellEnabled"
:disabled="!showShell" type="button"
type="button" class="btn header-btn role-tertiary"
class="btn header-btn role-tertiary" @click="currentCluster.openShell()"
@click="currentCluster.openShell()" >
> <i class="icon icon-terminal icon-lg" />
<i class="icon icon-terminal icon-lg" /> </button>
</button>
<button
v-tooltip="t('nav.kubeconfig')"
:disabled="!kubeConfigEnabled"
type="button"
class="btn header-btn role-tertiary"
@click="currentCluster.downloadKubeConfig()"
>
<i class="icon icon-file icon-lg" />
</button>
</template>
<button <button
v-if="showSearch" v-if="showSearch"

View File

@ -1,7 +1,10 @@
import { CATALOG } from '@/config/labels-annotations'; import { CATALOG } from '@/config/labels-annotations';
import { FLEET, MANAGEMENT } from '@/config/types'; import { FLEET, MANAGEMENT } from '@/config/types';
import { insertAt } from '@/utils/array'; import { insertAt } from '@/utils/array';
import { downloadFile } from '@/utils/download';
import { parseSi } from '@/utils/units'; import { parseSi } from '@/utils/units';
import jsyaml from 'js-yaml';
import { eachLimit } from '@/utils/promise';
// See translation file cluster.providers for list of providers // See translation file cluster.providers for list of providers
// If the logo is not named with the provider name, add an override here // If the logo is not named with the provider name, add an override here
@ -37,6 +40,15 @@ export default {
enabled: !!this.links.shell, enabled: !!this.links.shell,
}); });
insertAt(out, 1, {
action: 'downloadKubeConfig',
bulkAction: 'downloadKubeConfigBulk',
label: 'Download KubeConfig',
icon: 'icon icon-download',
bulkable: true,
enabled: this.$rootGetters['isRancher'],
});
return out; return out;
}, },
@ -102,21 +114,6 @@ export default {
return ''; return '';
}, },
openShell() {
return () => {
this.$dispatch('wm/open', {
id: `kubectl-${ this.id }`,
label: this.$rootGetters['i18n/t']('wm.kubectlShell.title', { name: this.nameDisplay }),
icon: 'terminal',
component: 'KubectlShell',
attrs: {
cluster: this,
pod: {}
}
}, { root: true });
};
},
providerOs() { providerOs() {
if ( this.status?.provider === 'rke.windows' ) { if ( this.status?.provider === 'rke.windows' ) {
return 'windows'; return 'windows';
@ -189,5 +186,67 @@ export default {
} else { } else {
return null; return null;
} }
} },
openShell() {
return () => {
this.$dispatch('wm/open', {
id: `kubectl-${ this.id }`,
label: this.$rootGetters['i18n/t']('wm.kubectlShell.title', { name: this.nameDisplay }),
icon: 'terminal',
component: 'KubectlShell',
attrs: {
cluster: this,
pod: {}
}
}, { root: true });
};
},
generateKubeConfig() {
return async() => {
const res = await this.$dispatch('request', {
method: 'post',
url: `/v3/clusters/${ this.id }?action=generateKubeconfig`
});
return res.config;
};
},
downloadKubeConfig() {
return async() => {
const config = await this.generateKubeConfig();
downloadFile(`${ this.nameDisplay }.yaml`, config, 'application/yaml');
};
},
downloadKubeConfigBulk() {
return async(items) => {
let obj = {};
let first = true;
await eachLimit(items, 10, (item, idx) => {
return item.generateKubeConfig().then((config) => {
const entry = jsyaml.safeLoad(config);
if ( first ) {
obj = entry;
first = false;
} else {
obj.clusters.push(...entry.clusters);
obj.users.push(...entry.users);
obj.contexts.push(...entry.contexts);
}
});
});
delete obj['current-context'];
const out = jsyaml.safeDump(obj);
downloadFile('kubeconfig.yaml', out, 'application/yaml');
};
},
}; };

View File

@ -1,5 +1,5 @@
import { CAPI, MANAGEMENT, NORMAN } from '@/config/types'; import { CAPI, MANAGEMENT, NORMAN } from '@/config/types';
import { findBy } from '@/utils/array'; import { findBy, insertAt } from '@/utils/array';
import { sortBy } from '@/utils/sort'; import { sortBy } from '@/utils/sort';
import { ucFirst } from '@/utils/string'; import { ucFirst } from '@/utils/string';
@ -25,6 +25,28 @@ export default {
return out; return out;
}, },
_availableActions() {
const out = this._standardActions;
insertAt(out, 0, {
action: 'openShell',
label: 'Kubectl Shell',
icon: 'icon icon-terminal',
enabled: !!this.mgmt?.links.shell,
});
insertAt(out, 1, {
action: 'downloadKubeConfig',
bulkAction: 'downloadKubeConfigBulk',
label: 'Download KubeConfig',
icon: 'icon icon-download',
bulkable: true,
enabled: this.$rootGetters['isRancher'],
});
return out;
},
isImported() { isImported() {
return this.provisioner === 'imported'; return this.provisioner === 'imported';
}, },
@ -208,5 +230,29 @@ export default {
return token.save(); return token.save();
}; };
} },
openShell() {
return () => {
return this.mgmt?.openShell();
};
},
generateKubeConfig() {
return () => {
return this.mgmt?.generateKubeConfig();
};
},
downloadKubeConfig() {
return () => {
return this.mgmt?.downloadKubeConfig();
};
},
downloadKubeConfigBulk() {
return (items) => {
return this.mgmt?.downloadKubeConfigBulk(items);
};
},
}; };