diff --git a/lib/shared/addon/components/form-affinity-k8s/component.js b/lib/shared/addon/components/form-affinity-k8s/component.js index 642c0e904..11e421737 100644 --- a/lib/shared/addon/components/form-affinity-k8s/component.js +++ b/lib/shared/addon/components/form-affinity-k8s/component.js @@ -154,12 +154,15 @@ export default Component.extend({ } }), - nodeAffinity: computed('value.nodeAffinity.{preferredDuringSchedulingIgnoredDuringExecution,requiredDuringSchedulingIgnoredDuringExecution}', { + nodeAffinity: computed('value.nodeAffinity.preferredDuringSchedulingIgnoredDuringExecution', 'value.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms', { get(){ if (!this.value?.nodeAffinity){ set(this.value, 'nodeAffinity', {}) } - this.initPreferredRequired(this.value.nodeAffinity) + this.initPreferredRequired(this.value.nodeAffinity, true) + if (!this.value.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms){ + set(this.value, 'nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms', []) + } return get(this.value, 'nodeAffinity') }, @@ -170,11 +173,13 @@ export default Component.extend({ return term }), - requiredDuringSchedulingIgnoredDuringExecution: (val.requiredDuringSchedulingIgnoredDuringExecution || []).map((term) => { - delete term._id; + requiredDuringSchedulingIgnoredDuringExecution: { + nodeSelectorTerms: (val?.requiredDuringSchedulingIgnoredDuringExecution?.nodeSelectorTerms || []).map((term) => { + delete term._id; - return term - }) + return term + }) + } } set(this.value, 'nodeAffinity', withoutId) @@ -184,11 +189,13 @@ export default Component.extend({ } }), - initPreferredRequired: (val) => { + initPreferredRequired: (val, isNode) => { if (!val.preferredDuringSchedulingIgnoredDuringExecution){ set(val, 'preferredDuringSchedulingIgnoredDuringExecution', []) } - if (!val.requiredDuringSchedulingIgnoredDuringExecution){ + if (!val.requiredDuringSchedulingIgnoredDuringExecution && isNode){ + set(val, 'requiredDuringSchedulingIgnoredDuringExecution', { nodeSelectorTerms: [] }) + } else { set(val, 'requiredDuringSchedulingIgnoredDuringExecution', []) } } diff --git a/lib/shared/addon/components/form-affinity-k8s/template.hbs b/lib/shared/addon/components/form-affinity-k8s/template.hbs index 537cde67f..4ac83c91a 100644 --- a/lib/shared/addon/components/form-affinity-k8s/template.hbs +++ b/lib/shared/addon/components/form-affinity-k8s/template.hbs @@ -2,7 +2,7 @@
@@ -11,6 +11,7 @@ @value={{podAffinity}} @podAffinity={{podAffinity}} @podAntiAffinity={{podAntiAffinity}} + {{!-- //TODO nb used? --}} @update={{action "affinityChanged"}} />
diff --git a/lib/shared/addon/components/form-node-affinity-k8s/component.js b/lib/shared/addon/components/form-node-affinity-k8s/component.js index 48f81b364..d8c014b2e 100644 --- a/lib/shared/addon/components/form-node-affinity-k8s/component.js +++ b/lib/shared/addon/components/form-node-affinity-k8s/component.js @@ -1,4 +1,137 @@ import Component from '@ember/component'; import layout from './template'; +import { + computed, + get, + set, + observer +} from '@ember/object'; +import { randomStr } from '../../utils/util'; +import { TERM_PRIORITY } from '../form-pod-affinity-k8s/component'; +/** + * nodeAffinity: { + * preferredDuringSchedulingIgnoredDuringExecution: + * - { + * preference: nodeselectorterm, + * weight: int + * } + * requiredDuringSchedulingIgnoredDuringExecution: + * nodeSelectorTerms: + * - nodeselectorterm + * } + * + * + * nodeselectorterm: { + * matchexpressions: + * - { + * key: string, + * operator: string, one of: [In, NotIn, Exists, DoesNotExist Gt, Lt] + * value: string array ... If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. + * } + * matchfields: same as match expressions but matches fields instead of labels + * } + */ -export default Component.extend({ layout }) \ No newline at end of file + +export default Component.extend({ + layout, + + TERM_PRIORITY, + nodeAffinity: null, + mode: 'new', + allTerms: [], + + /** + * this component renders one list for required & preferred arrays of node selector terms + * each nodeaffinitytermk8s component can change between required and perferred + * the overall list shouldn't re-order when a term is moved to a different underlying array so rather than computing this off the arrays in spec + * this list will track which array a term should belong to and the arrays in spec will be computed off this + * + * list of all terms: + * - { + * priority: preferred/required + * term:preferred or required term + * } + * + */ + init(){ + // TODO nb why is required... an array navigating back from view as yaml? + this._super(...arguments); + const allTerms = [] + const addTerms = function(terms = [], priority){ + terms.forEach((term) => { + allTerms.push({ + priority, + term + }) + }) + } + + addTerms(this.nodeAffinity?.preferredDuringSchedulingIgnoredDuringExecution, TERM_PRIORITY.PREFERRED) + addTerms(this.nodeAffinity?.requiredDuringSchedulingIgnoredDuringExecution?.nodeSelectorTerms, TERM_PRIORITY.REQUIRED) + set(this, 'allTerms', allTerms) + }, + + actions: { + addTerm(){ + const neu = { + priority: TERM_PRIORITY.REQUIRED, + term: { _id: randomStr() } + } + + this.allTerms.push(neu) + get(this.nodeAffinity, 'requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms').addObject(neu.term) + this.notifyPropertyChange('allTerms') + this.notifyPropertyChange('nodeAffinity') + }, + + removeTerm(term){ + // TODO nb does removeObject work here? Will it work in typeChanged? + get(this, 'allTerms').removeObject(term) + + if (term.priority === TERM_PRIORITY.REQUIRED){ + const removeFrom = get(this.nodeAffinity, 'requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms') + + removeFrom.removeObject(term.term) + } else { + const removeFrom = get(this.nodeAffinity, 'preferredDuringSchedulingIgnoredDuringExecution') + + removeFrom.removeObject(term.term) + } + this.notifyPropertyChange('nodeAffinity') + }, + + + typeChanged(term, old){ + // TODO nb add weight + if (old === TERM_PRIORITY.REQUIRED){ + const removeFrom = get(this.nodeAffinity, 'requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms') + const addTo = get(this.nodeAffinity, 'preferredDuringSchedulingIgnoredDuringExecution') + + set(this.nodeAffinity, 'requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms', this.removeFromSpec(term.term, removeFrom)) + + addTo.pushObject(term.term) + } else { + // TODO nb remove weight + const removeFrom = get(this.nodeAffinity, 'preferredDuringSchedulingIgnoredDuringExecution') + const addTo = get(this.nodeAffinity, 'requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms') + + set(this.nodeAffinity, 'preferredDuringSchedulingIgnoredDuringExecution', this.removeFromSpec(term.term, removeFrom)) + addTo.pushObject(term.term) + } + this.notifyPropertyChange('nodeAffinity') + }, + + }, + + editing: computed('mode', function() { + const mode = get(this, 'mode') + + return mode === 'new' || mode === 'edit' + }), + + removeFromSpec: (term, array) => { + return array.filter((each) => each._id !== term._id) + }, + +}) \ No newline at end of file diff --git a/lib/shared/addon/components/form-node-affinity-k8s/template.hbs b/lib/shared/addon/components/form-node-affinity-k8s/template.hbs index b02b2a118..aeeb26037 100644 --- a/lib/shared/addon/components/form-node-affinity-k8s/template.hbs +++ b/lib/shared/addon/components/form-node-affinity-k8s/template.hbs @@ -1,3 +1,29 @@ -
- node affinity component +
+
+ +
+
+
+
+ {{#each allTerms as |term|}} + + {{/each}} +
+ {{#if editing}} + + {{/if}} +
+
\ No newline at end of file diff --git a/lib/shared/addon/components/form-node-selector-term-k8s/component.js b/lib/shared/addon/components/form-node-selector-term-k8s/component.js index 48f81b364..5cffd6967 100644 --- a/lib/shared/addon/components/form-node-selector-term-k8s/component.js +++ b/lib/shared/addon/components/form-node-selector-term-k8s/component.js @@ -1,4 +1,21 @@ import Component from '@ember/component'; import layout from './template'; +import { priorityOptions } from '../form-pod-affinity-term-k8s/component'; -export default Component.extend({ layout }) \ No newline at end of file +export default Component.extend({ + layout, + + value: null, + mode: 'new', + + priorityOptions, + + actions: { + removeTerm(){ + if (this.remove){ + this.remove() + } + } + }, + +}) \ No newline at end of file diff --git a/lib/shared/addon/components/form-node-selector-term-k8s/template.hbs b/lib/shared/addon/components/form-node-selector-term-k8s/template.hbs index e69de29bb..9bd151df4 100644 --- a/lib/shared/addon/components/form-node-selector-term-k8s/template.hbs +++ b/lib/shared/addon/components/form-node-selector-term-k8s/template.hbs @@ -0,0 +1,42 @@ +
+ {{#if editing}} +
+ +
+ {{/if }} +
+
+ {{!-- --}} + +
+
+
+ {{#if (eq value.priority TERM_PRIORITY.PREFERRED)}} +
+ + {{#input-or-display + editable=editing + value=toplogyKey + }} + {{input + type="text" + class="form-control input-sm" + value=weight + placeholder=(t "clusterNew.agentConfig.overrideAffinity.podAffinity.weight.placeholder") + }} + {{/input-or-display}} +
+ {{/if}} +
+
\ No newline at end of file diff --git a/lib/shared/addon/components/form-pod-affinity-k8s/component.js b/lib/shared/addon/components/form-pod-affinity-k8s/component.js index f27544f72..279305af6 100644 --- a/lib/shared/addon/components/form-pod-affinity-k8s/component.js +++ b/lib/shared/addon/components/form-pod-affinity-k8s/component.js @@ -33,7 +33,6 @@ export default Component.extend({ podAntiAffinity: null, value: null, mode: 'new', - anti: false, allTerms: [], /** * this component renders one list for required & preferred arrays of terms in affinity & antiAffinity @@ -70,13 +69,6 @@ export default Component.extend({ }, actions: { - addRequired(){ - this.requiredDuringSchedulingIgnoredDuringExecution.pushObject({}) - }, - addPreferred(){ - this.preferredDuringSchedulingIgnoredDuringExecution.pushObject({}) - }, - addTerm(){ const neu = { priority: TERM_PRIORITY.REQUIRED, @@ -92,6 +84,7 @@ export default Component.extend({ removeTerm(term){ // TODO nb update relevent spec array + // TODO nb does removeObject work here? Will it work in typeChanged and antiChanged? get(this, 'allTerms').removeObject(term) if (term.anti){ if (term.priority === TERM_PRIORITY.REQUIRED){ @@ -118,44 +111,48 @@ export default Component.extend({ } }, - affinityChanged(){ - // TODO nb this.update() - // needed? - }, - - - typeChanged(term, old){ if (term.anti){ + // TODO nb add 'weight' if (old === TERM_PRIORITY.REQUIRED){ const removeFrom = get(this.podAntiAffinity, 'requiredDuringSchedulingIgnoredDuringExecution') const addTo = get(this.podAntiAffinity, 'preferredDuringSchedulingIgnoredDuringExecution') set(this.podAntiAffinity, 'requiredDuringSchedulingIgnoredDuringExecution', this.removeFromSpec(term.term, removeFrom)) + // preferred terms are an object with weight and podAffinityTerm fields; required terms are just the contents of podAffinityTerm + set(term, 'term', this.addWeight(term.term)) addTo.pushObject(term.term) } else { + // TODO nb remove weight const removeFrom = get(this.podAntiAffinity, 'preferredDuringSchedulingIgnoredDuringExecution') const addTo = get(this.podAntiAffinity, 'requiredDuringSchedulingIgnoredDuringExecution') set(this.podAntiAffinity, 'preferredDuringSchedulingIgnoredDuringExecution', this.removeFromSpec(term.term, removeFrom)) + set(term, 'term', this.removeWeight(term)) + addTo.pushObject(term.term) } this.notifyPropertyChange('podAntiAffinity') } else { + // TODO nb add 'weight' if (old === TERM_PRIORITY.REQUIRED){ const removeFrom = get(this.podAffinity, 'requiredDuringSchedulingIgnoredDuringExecution') const addTo = get(this.podAffinity, 'preferredDuringSchedulingIgnoredDuringExecution') set(this.podAffinity, 'requiredDuringSchedulingIgnoredDuringExecution', this.removeFromSpec(term.term, removeFrom)) + set(term, 'term', this.addWeight(term.term)) addTo.pushObject(term.term) } else { + // TODO nb remove weight const removeFrom = get(this.podAffinity, 'preferredDuringSchedulingIgnoredDuringExecution') const addTo = get(this.podAffinity, 'requiredDuringSchedulingIgnoredDuringExecution') set(this.podAffinity, 'preferredDuringSchedulingIgnoredDuringExecution', this.removeFromSpec(term.term, removeFrom)) + set(term, 'term', this.removeWeight(term)) + addTo.pushObject(term.term) } this.notifyPropertyChange('podAffinity') @@ -211,4 +208,25 @@ export default Component.extend({ return array.filter((each) => each._id !== term._id) }, + addWeight: (term) => { + const out = { + // weight: null, + podAffinityTerm: term, + _id: term._id + } + + delete out.podAffinityTerm._id + + return out + }, + + removeWeight: (term) => { + const out = { + _id: term._id, + ...term.podAffinityTerm + } + + return out + } + }) \ No newline at end of file diff --git a/lib/shared/addon/components/form-pod-affinity-k8s/template.hbs b/lib/shared/addon/components/form-pod-affinity-k8s/template.hbs index ce0411b03..87fc1fd70 100644 --- a/lib/shared/addon/components/form-pod-affinity-k8s/template.hbs +++ b/lib/shared/addon/components/form-pod-affinity-k8s/template.hbs @@ -1,11 +1,7 @@
diff --git a/lib/shared/addon/components/form-pod-affinity-term-k8s/component.js b/lib/shared/addon/components/form-pod-affinity-term-k8s/component.js index f3756fd1e..4f88bce49 100644 --- a/lib/shared/addon/components/form-pod-affinity-term-k8s/component.js +++ b/lib/shared/addon/components/form-pod-affinity-term-k8s/component.js @@ -42,11 +42,20 @@ const namespaceModes = { IN_LIST: 'inList' } +export const priorityOptions = [{ + value: TERM_PRIORITY.REQUIRED, + label: 'clusterNew.agentConfig.overrideAffinity.podAffinity.typeOptions.required' +}, { + value: TERM_PRIORITY.PREFERRED, + label: 'clusterNew.agentConfig.overrideAffinity.podAffinity.typeOptions.preferred' +}] + export default Component.extend({ layout, namespaceModes, - + priorityOptions, + TERM_PRIORITY, /** * { * priority: preferred or required @@ -64,13 +73,6 @@ export default Component.extend({ typeChanged: null, antiChanged: null, - priorityOptions: [{ - value: TERM_PRIORITY.REQUIRED, - label: 'clusterNew.agentConfig.overrideAffinity.podAffinity.typeOptions.required' - }, { - value: TERM_PRIORITY.PREFERRED, - label: 'clusterNew.agentConfig.overrideAffinity.podAffinity.typeOptions.preferred' - }], affinityOptions: [{ value: 'true', @@ -88,27 +90,44 @@ export default Component.extend({ } }, - // namespaceModeObserver: observer('namespaceMode', () => { - - // }), - editing: computed('mode', function() { const mode = get(this, 'mode') return mode === 'new' || mode === 'edit' }), - term: computed('value.term', function(){ - return get(this.value, 'term') || {} + + // TODO nb acccount for weight if value.priority === 'preferred' + podAffintyTerm: computed('value.term', 'value.priority', function() { + return get(this.value, 'priority') === TERM_PRIORITY.REQUIRED ? get(this.value, 'term') : get(this.value, 'term.podAffinityTerm') }), - topologyKey: computed('value.topologyKey', function(){ - return get(this.value, 'topologyKey') || '' - }), - - namespaces: computed('term.namespaces', 'namespaceMode', { + weight: computed('value.term', 'value.priority', { get(){ - const namespaces = get(this.term, 'namespaces') || []; + return get(this.value, 'priority') === TERM_PRIORITY.REQUIRED ? null : get(this.value, 'term.weight') + }, + set(key, val){ + if (val || val === 0) { + try { + const toInt = parseInt(val, 10) + + set(this.value.term, 'weight', toInt) + } catch (e){ + // TODO nb handle bad weight value better + console.error(e) + } + } else if (this.value?.term?.weight){ + delete this.value.term.weight + this.notifyPropertyChange('value') + } + + return val + } + }), + + namespaces: computed('podAffintyTerm.namespaces', 'namespaceMode', { + get(){ + const namespaces = get(this.podAffintyTerm, 'namespaces') || []; return namespaces.join(', ') }, @@ -117,9 +136,9 @@ export default Component.extend({ // a,b,c or a, b, c const parsed = val.split(/,\s*/g).map((ns) => ns.trim()).filter((ns) => !!ns) - set(this.term, 'namespaces', parsed) - } else if (this.term.namespaces){ - delete this.term.namespaces + set(this.podAffintyTerm, 'namespaces', parsed) + } else if (this.podAffintyTerm.namespaces){ + delete this.podAffintyTerm.namespaces this.notifyPropertyChange('value') } @@ -127,15 +146,15 @@ export default Component.extend({ } }), - namespaceSelector: computed('namespaceMode', 'term.namespaceSelector', { + namespaceSelector: computed('namespaceMode', 'podAffintyTerm.namespaceSelector', { get(){ - return this.term.namespaceSelector || {} + return this.podAffintyTerm.namespaceSelector || {} }, set(key, val){ if (val){ - set(this.term, 'namespaceSelector', val) - } else if (this.term.namespaceSelector){ - delete this.term.namespaceSelector + set(this.podAffintyTerm, 'namespaceSelector', val) + } else if (this.podAffintyTerm.namespaceSelector){ + delete this.podAffintyTerm.namespaceSelector this.notifyPropertyChange('value') } @@ -178,19 +197,17 @@ export default Component.extend({ // null or empty namespaces and null selector = 'this pod's namespace' // null or empty namespaces and empty object selector = 'all namespaces' - namespaceMode: computed('term.namespaceSelector', 'term.namespaces.length', { + namespaceMode: computed('podAffintyTerm.namespaceSelector', 'podAffintyTerm.namespaces.length', { get(){ - if (this.term.namespaceSelector){ + if (this.podAffintyTerm.namespaceSelector){ return namespaceModes.ALL - } else if (this.term.namespaces){ + } else if (this.podAffintyTerm.namespaces){ return namespaceModes.IN_LIST } return namespaceModes.THIS_POD }, set(key, val){ - // const namespaceMode = get(this, 'namespaceMode'); - switch (val){ case namespaceModes.ALL: set(this, 'namespaceSelector', {}) @@ -208,7 +225,6 @@ export default Component.extend({ return val } - }) - + }), }) \ No newline at end of file diff --git a/lib/shared/addon/components/form-pod-affinity-term-k8s/template.hbs b/lib/shared/addon/components/form-pod-affinity-term-k8s/template.hbs index 0b590d640..0d4a25084 100644 --- a/lib/shared/addon/components/form-pod-affinity-term-k8s/template.hbs +++ b/lib/shared/addon/components/form-pod-affinity-term-k8s/template.hbs @@ -36,7 +36,7 @@
-
+
-
+
+
+
{{#input-or-display editable=editing - value=toplogyKey + value=podAffintyTerm.topologyKey }} {{input type="text" class="form-control input-sm" - value=topologyKey + value=podAffintyTerm.topologyKey placeholder=(t "clusterNew.agentConfig.overrideAffinity.podAffinity.topologyKey.placeholder") }} {{/input-or-display}}
+ {{#if (eq value.priority TERM_PRIORITY.PREFERRED)}} +
+ + {{#input-or-display + editable=editing + value=weight + }} + {{input + type="number" + class="form-control input-sm" + value=weight + placeholder=(t "clusterNew.agentConfig.overrideAffinity.podAffinity.weight.placeholder") + }} + {{/input-or-display}} +
+ {{/if}}
\ No newline at end of file diff --git a/translations/en-us.yaml b/translations/en-us.yaml index 1a87ff05c..3592d193a 100644 --- a/translations/en-us.yaml +++ b/translations/en-us.yaml @@ -3374,9 +3374,13 @@ clusterNew: all: All Namespaces thisPod: This pod's namespace inList: 'Namespaces in this list:' + weight: + placeholder: e.g. 1 + label: Weight priority: Priority nodeAffinity: title: Node Affinity + addTerm: Add Node Selector aliyunack: shortLabel: Alibaba ACK amazoneks: