Merge pull request #4467 from codyrancher/agent-env-vars

Adding the agent env vars to rke drivers.
This commit is contained in:
Westly Wright 2021-02-23 13:14:43 -07:00 committed by GitHub
commit 17c508d6b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 554 additions and 1 deletions

View File

@ -9,6 +9,7 @@ import { scheduleOnce } from '@ember/runloop';
export default Route.extend({
access: service(),
globalStore: service(),
clusterStore: service(),
releaseVersions: service(),
clusterTemplateService: service('clusterTemplates'),
roleTemplateService: service('roleTemplate'),
@ -21,11 +22,13 @@ export default Route.extend({
originalCluster: cluster,
cluster: cluster.clone(),
cloudCredentials: globalStore.findAll('cloudcredential'),
configMaps: this.configMaps(),
kontainerDrivers: globalStore.findAll('kontainerDriver'),
nodeTemplates: globalStore.findAll('nodeTemplate'),
nodeDrivers: globalStore.findAll('nodeDriver'),
psps: globalStore.findAll('podSecurityPolicyTemplate'),
roleTemplates: get(this, 'roleTemplateService').get('allFilteredRoleTemplates'),
secrets: this.secrets(),
users: globalStore.findAll('user'),
clusterRoleTemplateBinding: globalStore.findAll('clusterRoleTemplateBinding'),
me: get(this, 'access.principal'),
@ -157,6 +160,28 @@ export default Route.extend({
}
},
async configMaps() {
const projects = await this.projects();
const configMapPromises = projects.map((project) => project.hasLink('configMaps') ? project.followLink('configMaps') : Promise.resolve([]));
const nestedConfigMaps = await Promise.all(configMapPromises) || [];
return nestedConfigMaps.flatMap((maps) => maps.content);
},
async secrets() {
const projects = await this.projects();
const secretPromises = projects.map((project) => project.hasLink('secrets') ? project.followLink('secrets') : Promise.resolve([]));
const nestedSecrets = await Promise.all(secretPromises) || [];
return nestedSecrets.flatMap((maps) => maps.content);
},
async projects() {
const cluster = this.modelFor('authenticated.cluster');
return (await cluster.followLink('projects')).content;
},
queryParams: {
provider: { refreshModel: true },
clusterTemplateRevision: { refreshModel: true }

View File

@ -140,6 +140,8 @@ export default InputTextFile.extend(ManageLabels, ClusterDriver, {
scheduledClusterScan: { enabled: false },
})
this.initAgentEnvVars();
this.initNodeCounts();
if (!this.useClusterTemplate && this.model.cluster.clusterTemplateRevisionId) {
@ -875,6 +877,10 @@ export default InputTextFile.extend(ManageLabels, ClusterDriver, {
return options;
}),
showCustomConfigMapsAndSecrets: computed('model.provider', function() {
return get(this, 'model.provider') === 'custom';
}),
initScheduledClusterScan() {
// We need to wait for benchmarks to be available before we can actually create the profiles
if (this.cisHelpers.cisScanBenchmarks.length === 0) {
@ -1428,6 +1434,10 @@ export default InputTextFile.extend(ManageLabels, ClusterDriver, {
})
},
initAgentEnvVars() {
setProperties(this.cluster, { agentEnvVars: get(this, 'cluster.agentEnvVars') || [] });
},
initPrivateRegistries() {
const config = get(this, 'config');

View File

@ -1253,6 +1253,21 @@
{{drain-node selection=upgradeStrategy.nodeDrainInput clusterTemplateCreate=clusterTemplateCreate editable=notView applyClusterTemplate=applyClusterTemplate clusterTemplateRevision=model.clusterTemplateRevision.clusterConfig questions=model.clusterTemplateRevision.questions addOverride=(action "addOverride")}}
</div>
{{/if}}
{{#if (not clusterTemplateCreate)}}
<div class="row mt-10">
<label class="acc-label">
{{t "clusterNew.rke.agentEnvVars.label"}}
</label>
<FormAgentEnvVar
@editable={{notView}}
@value={{cluster.agentEnvVars}}
@showCustomConfigMaps={{showCustomConfigMapsAndSecrets}}
@showCustomSecrets={{showCustomConfigMapsAndSecrets}}
@configMaps={{model.configMaps}}
@secrets={{model.secrets}}
/>
</div>
{{/if}}
{{/accordion-list-item}}
{{#accordion-list-item

View File

@ -0,0 +1,254 @@
import Component from '@ember/component';
import { inject as service } from '@ember/service';
import layout from './template';
import { computed, get, set } from '@ember/object';
export default Component.extend({
globalStore: service(),
intl: service(),
layout,
model: null,
editable: true,
statusClass: null,
status: null,
editing: true,
showCustomConfigMaps: false,
showCustomSecrets: false,
typeChoices: [],
configMaps: [],
secrets: [],
value: [],
resourceKeyChoices: [],
init() {
this._super(...arguments);
const configMapsEnabled = this.showCustomConfigMaps || this.configMaps?.length > 0;
const secretsEnabled = this.showCustomSecrets || this.secrets?.length > 0;
const typeChoices = [
{
label: this.intl.t('formAgentEnvVar.typeChoices.keyValue'),
value: 'keyValue'
},
{
label: this.intl.t('formAgentEnvVar.typeChoices.resource'),
value: 'resource'
},
{
label: configMapsEnabled ? this.intl.t('formAgentEnvVar.typeChoices.configMap') : this.intl.t('formAgentEnvVar.typeChoices.configMapNone'),
disabled: !configMapsEnabled,
value: 'configMap'
},
{
label: secretsEnabled ? this.intl.t('formAgentEnvVar.typeChoices.secret') : this.intl.t('formAgentEnvVar.typeChoices.secretNone'),
disabled: !secretsEnabled,
value: 'secret'
},
{
label: this.intl.t('formAgentEnvVar.typeChoices.podField'),
value: 'podfield'
}
];
this.set('typeChoices', typeChoices);
this.set('resourcekeyChoices', [
{
label: 'limits.cpu',
value: 'limits.cpu'
},
{
label: 'limits.ephemeral-storage',
value: 'limits.ephemeral-storage'
},
{
label: 'limits.memory',
value: 'limits.memory'
},
{
label: 'requests.cpu',
value: 'requests.cpu'
},
{
label: 'requests.ephemeral-storage',
value: 'requests.ephemeral-storage'
},
{
label: 'requests.memory',
value: 'requests.memory'
},
]);
this.set('value', this.value || []);
this.value.forEach((envVar) => this.inferTypeAndSetHelpers(envVar));
},
actions: {
add() {
this.value.pushObject(this.createEnvVar('keyValue'));
},
updateType(index, event) {
const type = event.target.value;
this.value.replace(index, 1, [this.createEnvVar(type)]);
},
updateSecret(index, event) {
const secretName = event.target.value;
set(this.value[index], 'secretKeyChoices', this.keyChoices('secrets', secretName));
set(this.value[index], 'valueFrom.secretKeyRef.name', secretName);
set(this.value[index], 'valueFrom.secretKeyRef.key', this.value[index].secretKeyChoices[0].value);
},
updateConfigMap(index, event) {
const configMapName = event.target.value;
set(this.value[index], 'configMapKeyChoices', this.keyChoices('configMaps', configMapName));
set(this.value[index], 'valueFrom.configMapKeyRef.name', configMapName);
set(this.value[index], 'valueFrom.configMapKeyRef.key', this.value[index].configMapKeyChoices[0].value);
},
remove(index) {
this.value.removeAt(index, 1);
},
},
configMapChoices: computed('configMaps', function() {
const configMaps = get(this, 'configMaps') || [];
const choices = configMaps.map((configMap) => ({
label: configMap.displayName,
value: configMap.name
}));
return choices
.uniqBy('label')
.sortBy('label');
}),
secretChoices: computed('secrets', function() {
const secrets = get(this, 'secrets') || [];
const choices = secrets.map((secret) => ({
label: secret.displayName,
value: secret.name
}));
return choices
.uniqBy('label')
.sortBy('label');
}),
inferTypeAndSetHelpers(envVar) {
if (this.isValueFromSet(envVar, 'resourceFieldRef', ['resource', 'containerName', 'divisor'])) {
return this.setEnvVarHelpers(envVar, 'resource');
}
if (this.isValueFromSet(envVar, 'configMapKeyRef', ['name', 'key'])) {
return this.setEnvVarHelpers(envVar, 'configMap');
}
if (this.isValueFromSet(envVar, 'secretKeyRef', ['name', 'key'])) {
return this.setEnvVarHelpers(envVar, 'secret');
}
if (this.isValueFromSet(envVar, 'fieldRef', ['fieldPath'])) {
return this.setEnvVarHelpers(envVar, 'podfield');
}
return this.setEnvVarHelpers(envVar, 'keyValue');
},
isValueFromSet(envVar, refKey, fields) {
return fields.some((field) => get(envVar, `valueFrom.${ refKey }.${ field }`));
},
keyChoices(resource, selectedName) {
const resources = get(this, resource) || [];
const data = resources.find((r) => r.name === selectedName)?.data || {};
return Object.keys(data).map((key) => ({
label: key,
value: key
}))
},
showContainer(type) {
return ['resource'].includes(type);
},
showKey(type) {
return ['resource', 'configMap', 'secret', 'podfield'].includes(type);
},
showValue(type) {
return ['keyValue'].includes(type);
},
showConfigMap(type) {
return ['configMap'].includes(type);
},
showSecret(type) {
return ['secret'].includes(type);
},
showPodField(type) {
return ['podfield'].includes(type);
},
createEnvVar(type) {
const envVar = {};
this.setEnvVarHelpers(envVar, type);
this.setDefaults(envVar, type);
return envVar;
},
setEnvVarHelpers(envVar, type) {
Object.assign(envVar, {
type,
showContainer: this.showContainer(type),
showKey: this.showKey(type),
showValue: this.showValue(type),
showConfigMap: this.showConfigMap(type),
showSecret: this.showSecret(type),
showPodField: this.showPodField(type),
secretKeyChoices: envVar.valueFrom?.secretKeyRef ? this.keyChoices('secrets', envVar.valueFrom.secretKeyRef.name) : null,
configMapKeyChoices: envVar.valueFrom?.configMapKeyRef ? this.keyChoices('configMaps', envVar.valueFrom.configMapKeyRef.name) : null,
});
},
setDefaults(envVar, type) {
if (type !== 'keyValue') {
set(envVar, 'valueFrom', envVar.valueFrom || {});
}
if (type === 'configMap') {
set(envVar, 'valueFrom.configMapKeyRef', envVar.valueFrom.configMapKeyRef || {});
const configMapName = this.configMapChoices[0]?.value;
set(envVar, 'configMapKeyChoices', this.keyChoices('configMaps', configMapName));
set(envVar, 'valueFrom.configMapKeyRef', envVar.valueFrom.configMapKeyRef || {
name: configMapName,
key: envVar.configMapKeyChoices[0]?.value
});
}
if (type === 'resource') {
set(envVar, 'valueFrom.resourceFieldRef', envVar.valueFrom.resourceFieldRef || {});
}
if (type === 'podfield') {
set(envVar, 'valueFrom.fieldRef', envVar.valueFrom.fieldRef || {});
}
if (type === 'secret') {
const secretName = this.secretChoices[0]?.value;
set(envVar, 'secretKeyChoices', this.keyChoices('secrets', secretName));
set(envVar, 'valueFrom.secretKeyRef', envVar.valueFrom.secretKeyRef || {
name: secretName,
key: envVar.secretKeyChoices[0]?.value
});
}
}
});

View File

@ -0,0 +1,212 @@
<div>
<table style="width: 100%;">
<tbody>
{{#each value as |envVar index|}}
<tr>
<td>
<label class="text-small">{{t 'formAgentEnvVar.headers.type'}}</label>
{{#input-or-display
editable=editable
value=envVar.type
}}
{{new-select
class="form-control"
content=typeChoices
value=envVar.type
onChange=(action 'updateType' index)
}}
{{/input-or-display}}
</td>
<td class="pl-10">
<label class="text-small">{{t 'formAgentEnvVar.headers.variableName'}}</label>
{{#input-or-display
editable=editable
value=envVar.name
}}
{{input
class="form-control"
type="text"
value=envVar.name
placeholder=(t 'formAgentEnvVar.placeholders.foo')
}}
{{/input-or-display}}
</td>
{{#if envVar.showValue}}
<td colspan="2" class="pl-10">
<label class="text-small">{{t 'formAgentEnvVar.headers.value'}}</label>
{{#input-or-display
editable=editable
value=envVar.value
}}
{{input
class="form-control"
type="text"
value=envVar.value
placeholder=(t 'formAgentEnvVar.placeholders.bar')
}}
{{/input-or-display}}
</td>
{{/if}}
{{#if envVar.showContainer}}
<td class="pl-10">
<label class="text-small">{{t 'formAgentEnvVar.headers.containerName'}}</label>
{{#input-or-display
editable=editable
value=envVar.valueFrom.resourceFieldRef.containerName
}}
{{input
class="form-control"
type="text"
value=envVar.valueFrom.resourceFieldRef.containerName
placeholder=(t 'formAgentEnvVar.placeholders.container')
}}
{{/input-or-display}}
</td>
<td class="pl-10">
<label class="text-small">{{t 'formAgentEnvVar.headers.key'}}</label>
{{#input-or-display
editable=editable
value=envVar.valueFrom.resourceFieldRef.resource
}}
{{new-select
class="form-control"
content=resourcekeyChoices
value=envVar.valueFrom.resourceFieldRef.resource
}}
{{/input-or-display}}
</td>
{{/if}}
{{#if envVar.showConfigMap}}
<td class="pl-10">
<label class="text-small">{{t 'formAgentEnvVar.headers.configMap'}}</label>
{{#input-or-display
editable=editable
value=envVar.valueFrom.configMapKeyRef.name
}}
{{#if showCustomConfigMaps}}
{{input
class="form-control"
type="text"
value=envVar.valueFrom.configMapKeyRef.name
}}
{{else}}
{{new-select
class="form-control"
content=configMapChoices
value=envVar.valueFrom.configMapKeyRef.name
onChange=(action 'updateConfigMap' index)
}}
{{/if}}
{{/input-or-display}}
</td>
<td class="pl-10">
<label class="text-small">{{t 'formAgentEnvVar.headers.key'}}</label>
{{#input-or-display
editable=editable
value=envVar.valueFrom.configMapKeyRef.key
}}
{{#if showCustomConfigMaps}}
{{input
class="form-control"
type="text"
value=envVar.valueFrom.configMapKeyRef.key
}}
{{else}}
{{new-select
class="form-control"
content=envVar.configMapKeyChoices
value=envVar.valueFrom.configMapKeyRef.key
disabled=(not envVar.configMapKeyChoices.length)
}}
{{/if}}
{{/input-or-display}}
</td>
{{/if}}
{{#if envVar.showSecret}}
<td class="pl-10">
<label class="text-small">{{t 'formAgentEnvVar.headers.secret'}}</label>
{{#input-or-display
editable=editable
value=envVar.valueFrom.secretKeyRef.name
}}
{{#if showCustomSecrets}}
{{input
class="form-control"
type="text"
value=envVar.valueFrom.secretKeyRef.name
}}
{{else}}
{{new-select
class="form-control"
content=secretChoices
value=envVar.valueFrom.secretKeyRef.name
onChange=(action 'updateSecret' index)
}}
{{/if}}
{{/input-or-display}}
</td>
<td class="pl-10">
<label class="text-small">{{t 'formAgentEnvVar.headers.key'}}</label>
{{#input-or-display
editable=editable
value=envVar.valueFrom.secretKeyRef.key
}}
{{#if showCustomSecrets}}
{{input
class="form-control"
type="text"
value=envVar.valueFrom.secretKeyRef.key
}}
{{else}}
{{new-select
class="form-control"
content=envVar.secretKeyChoices
value=envVar.valueFrom.secretKeyRef.key
disabled=(not envVar.secretKeyChoices.length)
}}
{{/if}}
{{/input-or-display}}
</td>
{{/if}}
{{#if envVar.showPodField}}
<td colspan="2" class="pl-10">
<label class="text-small">{{t 'formAgentEnvVar.headers.key'}}</label>
{{#input-or-display
editable=editable
value=envVar.valueFrom.fieldRef.fieldPath
}}
{{input
class="form-control"
type="text"
value=envVar.valueFrom.fieldRef.fieldPath
placeholder=(t 'formAgentEnvVar.placeholders.key')
}}
{{/input-or-display}}
</td>
{{/if}}
<td class="valign-top text-right" style="width: 45px">
<label class="text-small">&nbsp;</label>
{{#if editable}}
<div>
<button
class="btn bg-primary btn-sm" disabled={{eq row.editable false}} type="button" {{action "remove" index}}
>
<i class="icon icon-minus"/>
<span class="sr-only">
{{t "generic.remove"}}
</span>
</button>
</div>
{{/if}}
</td>
</tr>
{{/each}}
</tbody>
</table>
{{#if editable}}
<button class="btn bg-link icon-btn p-0 mt-10" type="button" {{action "add" }}>
<span class="darken"><i class="icon icon-plus text-small" /></span>
<span>{{t 'formAgentEnvVar.addActionLabel'}}</span>
</button>
{{/if}}
</div>

View File

@ -14,6 +14,7 @@ export default Component.extend({
optionLabelPath: 'label',
optionGroupPath: 'group',
optionDisabledPath: 'disabled',
onChange: null,
value: null,
useContentForDefaultValue: false,
@ -49,6 +50,13 @@ export default Component.extend({
this.off('change', this, this._change);
},
actions: {
onChange() {
if (this.onChange) {
this.onChange(...arguments);
}
}
},
setDefaultValueObserver: observer('asyncContent.value', function() {
const content = get(this, 'asyncContent.value');

View File

@ -1,4 +1,4 @@
<select disabled={{or asyncContent.loading disabled}}>
<select disabled={{or asyncContent.loading disabled}} onchange={{action "onChange"}}>
{{#if prompt}}
<option selected={{not selection}}>
{{#if localizedPrompt}}

View File

@ -0,0 +1 @@
export { default } from 'shared/components/form-agent-env-var/component';

View File

@ -4263,6 +4263,8 @@ clusterNew:
rancherd:
shortLabel: RancherD
rke:
agentEnvVars:
label: Agent Environment Variables
secretsEncryption:
label: Secrets Encryption
upgradeStrategy:
@ -6428,6 +6430,32 @@ formEnvVar:
key: Key
value: Value
formAgentEnvVar:
headers:
type: Type
variableName: Variable Name
value: Value
containerName: Container Name
configMap: Config Map
secret: Secret
key: Key
placeholders:
foo: e.g. FOO
bar: e.g. bar
container: e.g. my-container
key: e.g. metadata.labels['KEY']
typeChoices:
keyValue: Key/Value Pair
resource: Resource
configMap: ConfigMap Key
configMapNone: ConfigMap Key (None Available)
secret: Secret Key
secretNone: Secret Key (None Available)
podField: Pod Field
addActionLabel: Add Environment Variable
formGlobalRoles:
title: Global Permissions
description: "Controls what access the {type} has to administer the overall {appName} installation."