Skip to content

Commit f9c8620

Browse files
create cluster refactor (#164)
* clusterclass variables enhancements: add machine-scoped variable overrides, sections, labels, toggle, highlight * style fixes, move workers and hide remove worker button if its the last worker add info annotation delete assets from testing chart script * fix bad merges in clusterclass-variables util; disable editing capi clusters; add documentation for docs annotation * delete duplicate util * pr feedback; fix required validation * remove console logs and some commented code * pr feedback * pr feedback: style issues, validation issue, dead code, page reload issue * pr feedback on example class dialog; remove throttle from cc variable watcher; hide the config button in the capi cluster detail view * bang bang that awful sound * tweak addPath to match removePath
1 parent 5cd982b commit f9c8620

File tree

18 files changed

+2146
-445
lines changed

18 files changed

+2146
-445
lines changed

pkg/capi/README.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,20 @@
33

44
### **The CAPI UI extension is in tech preview.**
55

6-
Create clusters using the Cluster API and automatically import them into Rancher. The Turtles chart must be installed in the local Rancher cluster for the CAPI UI extension to work. Read more about the Rancher Turtles project [here](https://turtles.docs.rancher.com/turtles/next/en/index.html).
6+
Create clusters using the Cluster API and automatically import them into Rancher. The Turtles chart must be installed in the local Rancher cluster for the CAPI UI extension to work. Read more about the Rancher Turtles project [here](https://turtles.docs.rancher.com/turtles/next/en/index.html).
7+
8+
9+
10+
#### Clusterclass Annotations
11+
The capi UI supports a small collection of annotations that may be applied to clusterclass variables to enhance the cluster creation UI.
12+
13+
14+
| Name | Description|
15+
| --- | --- |
16+
| `turtles-capi.cattle.io/section` | Add variables to an expandable section. You can add variables to existing sections in the cluster form using one of the following values: `general`, `controlplane`, `networking`, or `workers`|
17+
| `turtles-capi.cattle.io/group` | Group variables within a section. Groups within groups are not supported.|
18+
| `turtles-capi.cattle.io/highlight` | Call extra attention to a variable, giving it a larger label and expanded description. Optionally, use a value of `warning` or `error` to add an icon and coloration (yellow for warning, red for error)|
19+
| `turtles-capi.cattle.io/label` | Add a label to your variable. Alternatively, name your variable one of the keys listed under `capi.variables` in ./pkg/capi/en-us.yaml|
20+
| `turtles-capi.cattle.io/docs` | Add documentation link to your variable description. Requires highlight|
21+
| `turtles-capi.cattle.io/toggled-by` | Tell the UI that this variable should only be shown when other variables are truthy. This is a comma-separated list of variable names. Boolean type variables that appear in another variable's toggled-by annotation will be rendered as toggle switches instead of checkboxes. It is the responsibility of the clusterclass author to group toggled variables near their toggle.|
22+
| `turtles-capi.cattle.io/type` | The value of this annotation should be a kubernetes resource type eg `infrastructure.cluster.x-k8s.io.azureclusteridentity` Tell the UI that this variable should be a reference to some kubernetes resource in the local cluster. The UI will automatically search for all instances of this resource type and provide the user a dropdown to select one, or manually enter a name if they do not have permission to view the resource but know its there. This annotation may only be used with object type variables that specify a name key and, if the resource is namespaced, a namespace key.|
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
<script>
2+
import { mapGetters } from 'vuex';
3+
import LabeledSelect from '@shell/components/form/LabeledSelect';
4+
import { _CREATE } from '@shell/config/query-params';
5+
import { NAMESPACE } from '@shell/config/types';
6+
7+
export default {
8+
name: 'ResourceVariableInput',
9+
10+
props: {
11+
// resource type to search for
12+
resourceType: {
13+
type: String,
14+
required: true
15+
},
16+
17+
label: {
18+
type: String,
19+
default: null
20+
},
21+
value: {
22+
type: Object,
23+
default: () => {
24+
return { name: '' };
25+
}
26+
},
27+
// validation rules
28+
// will be passed directly to a labeledselect w/ resource ID as value
29+
rules: {
30+
type: Array,
31+
default: () => {
32+
return [];
33+
}
34+
},
35+
36+
mode: {
37+
type: String,
38+
default: _CREATE
39+
},
40+
41+
// if it exists already, default to the cluster's namespace in the namespace dropdown
42+
clusterNamespace: {
43+
type: String,
44+
default: ''
45+
},
46+
},
47+
48+
emits: ['update:value', 'validationPassed'],
49+
50+
components: { LabeledSelect },
51+
52+
created() {
53+
this.fetchResource(this.clusterNamespace);
54+
},
55+
56+
data() {
57+
return {
58+
// spinner on resource input when querying by ns
59+
loading: false,
60+
resource: []
61+
};
62+
},
63+
64+
methods: {
65+
async fetchResource(ns) {
66+
this.loading = true;
67+
const opt = {};
68+
69+
if (this.namespaced) {
70+
opt.namespaced = ns;
71+
}
72+
try {
73+
this.resource = await this.$store.dispatch('management/findAll', { type: this.resourceType, opt });
74+
} catch (err) {
75+
console.error(err);
76+
}
77+
this.loading = false;
78+
},
79+
80+
update(name = '') {
81+
const out = { name };
82+
83+
if (this.namespaced) {
84+
out.namespace = this.namespace;
85+
}
86+
87+
this.$emit('update:value', out);
88+
},
89+
},
90+
91+
computed: {
92+
...mapGetters({ all: 'management/all', schemaFor: 'management/schemaFor' }),
93+
94+
namespaced() {
95+
const schema = this.schemaFor(this.resourceType);
96+
97+
return !!schema && schema?.attributes?.namespaced;
98+
},
99+
100+
namespaces() {
101+
return this.all(NAMESPACE);
102+
},
103+
104+
resourceNames() {
105+
return this.resource.map((r) => r?.metadata?.name || r.id);
106+
},
107+
108+
name: {
109+
get() {
110+
return this.value?.name || '';
111+
},
112+
set(neu) {
113+
const out = { name: neu };
114+
115+
if (this.namespaced) {
116+
out.namespace = this.namespace;
117+
}
118+
119+
this.$emit('update:value', out);
120+
}
121+
},
122+
123+
namespace: {
124+
get() {
125+
return this.value?.namespace || this.clusterNamespace || '';
126+
},
127+
set(neu) {
128+
const out = { namespace: neu, name: this.name };
129+
130+
this.$emit('update:value', out);
131+
// check if ns from list or user entered value
132+
if (this.namespaces.find((n) => n.id === neu)) {
133+
this.fetchResource(neu);
134+
}
135+
}
136+
},
137+
}
138+
};
139+
</script>
140+
141+
<template>
142+
<div class="row">
143+
<div
144+
v-if="namespaced"
145+
class="col span-6"
146+
>
147+
<LabeledSelect
148+
label-key="tableHeaders.namespace"
149+
:mode="mode"
150+
:value="namespace"
151+
option-label="id"
152+
:options="namespaces || []"
153+
searchable
154+
taggable
155+
:rules="rules"
156+
@selecting="e=>namespace=e?.id"
157+
/>
158+
</div>
159+
<div class="col span-6">
160+
<LabeledSelect
161+
:value="name"
162+
:loading="loading"
163+
label-key="tableHeaders.name"
164+
:options="resourceNames || []"
165+
:mode="mode"
166+
taggable
167+
searchable
168+
:rules="rules"
169+
@selecting="e=>name=e"
170+
/>
171+
</div>
172+
</div>
173+
</template>

0 commit comments

Comments
 (0)