diff --git a/CHANGELOG.md b/CHANGELOG.md index 94e8e55..029f44e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added -- … +- Basic ability to configure MachineSets ([#1]) [Unreleased]: https://github.com/appuio/component-openshift4-nodes/compare/v0.1.0...HEAD +[#1]: https://github.com/appuio/component-openshift4-nodes/pull/1 diff --git a/Makefile b/Makefile index d12337e..b98bd2f 100644 --- a/Makefile +++ b/Makefile @@ -19,11 +19,15 @@ YAMLLINT_CONFIG ?= .yamllint.yml YAMLLINT_IMAGE ?= docker.io/cytopia/yamllint:latest YAMLLINT_DOCKER ?= $(DOCKER_CMD) $(DOCKER_ARGS) $(YAMLLINT_IMAGE) +VALE_CMD ?= $(DOCKER_CMD) $(DOCKER_ARGS) --volume "$${PWD}"/docs/modules:/pages vshn/vale:2.1.1 +VALE_ARGS ?= --minAlertLevel=error --config=/pages/ROOT/pages/.vale.ini /pages + + .PHONY: all all: lint .PHONY: lint -lint: lint_jsonnet lint_yaml +lint: lint_jsonnet lint_yaml lint_adoc .PHONY: lint_jsonnet lint_jsonnet: $(JSONNET_FILES) @@ -33,6 +37,10 @@ lint_jsonnet: $(JSONNET_FILES) lint_yaml: $(YAML_FILES) $(YAMLLINT_DOCKER) -f parsable -c $(YAMLLINT_CONFIG) $(YAMLLINT_ARGS) -- $? +.PHONY: lint_adoc +lint_adoc: + $(VALE_CMD) $(VALE_ARGS) + .PHONY: format format: format_jsonnet diff --git a/class/defaults.yml b/class/defaults.yml index e808e7f..9095843 100644 --- a/class/defaults.yml +++ b/class/defaults.yml @@ -1,3 +1,44 @@ parameters: openshift4_nodes: - namespace: syn-openshift4-nodes + namespace: openshift-machine-api + defaultSpecs: + aws: {} + azure: {} + gcp: + deletePolicy: Oldest + template: + spec: + metadata: + labels: {} + providerSpec: + value: + apiVersion: gcpprovider.openshift.io/v1beta1 + canIPForward: false + credentialsSecret: + name: gcp-cloud-credentials + deletionProtection: false + disks: + - autoDelete: true + boot: true + image: ${openshift4_nodes:infrastructureID}-rhcos-image + labels: null + sizeGb: 128 + type: pd-ssd + kind: GCPMachineProviderSpec + machineType: n1-standard-4 + metadata: + creationTimestamp: null + networkInterfaces: + - network: ${openshift4_nodes:infrastructureID}-network + subnetwork: ${openshift4_nodes:infrastructureID}-worker-subnet + projectID: ${openshift4_nodes:projectName} + region: ${cloud:region} + serviceAccounts: + - email: ${openshift4_nodes:infrastructureID}-w@${openshift4_nodes:projectName}.iam.gserviceaccount.com + scopes: + - https://www.googleapis.com/auth/cloud-platform + tags: [] + userDataSecret: + name: worker-user-data + + nodeGroups: {} diff --git a/component/main.jsonnet b/component/main.jsonnet index 9ddd4d6..a03204e 100644 --- a/component/main.jsonnet +++ b/component/main.jsonnet @@ -1,10 +1,103 @@ -// main template for openshift4-nodes +local com = import 'lib/commodore.libjsonnet'; local kap = import 'lib/kapitan.libjsonnet'; local kube = import 'lib/kube.libjsonnet'; local inv = kap.inventory(); -// The hiera parameters for the component + local params = inv.parameters.openshift4_nodes; +local machineSet = function(name, set) + local role = if std.objectHas(set, 'role') then set.role else 'worker'; + kube._Object('machine.openshift.io/v1beta1', 'MachineSet', name) + + { spec+: params.defaultSpecs[inv.parameters.cloud.provider] } + + { + metadata+: { + labels+: { + 'machine.openshift.io/cluster-api-cluster': params.infrastructureID, + }, + namespace: params.namespace, + }, + spec+: { + replicas: com.getValueOrDefault(set, 'replicas', 1), + selector+: { + matchLabels+: { + 'machine.openshift.io/cluster-api-cluster': params.infrastructureID, + 'machine.openshift.io/cluster-api-machineset': name, + }, + }, + template+: { + metadata+: { + labels+: { + 'machine.openshift.io/cluster-api-cluster': params.infrastructureID, + 'machine.openshift.io/cluster-api-machine-role': role, + 'machine.openshift.io/cluster-api-machine-type': role, + 'machine.openshift.io/cluster-api-machineset': name, + }, + }, + spec+: { + metadata+: { + labels+: { + 'machine.openshift.io/cluster-api-machine-role': role, + }, + }, + providerSpec+: { + value+: { + machineType: set.instanceType, + tags: [ + params.infrastructureID + '-' + role, + ], + zone: params.availabilityZones[0], + }, + }, + }, + }, + }, + } + + if std.objectHas(set, 'spec') then { spec+: com.makeMergeable(set.spec) } else {}; + +local isMultiAz = function(name) + com.getValueOrDefault(params.nodeGroups[name], 'multiAz', false); + +local zoneId = function(name) + std.reverse(std.split(name, '-'))[0]; + +local replicasPerZone(replicas) = + std.ceil(replicas / std.length(params.availabilityZones)); + +local machineSpecs = [ + { name: name, spec: params.nodeGroups[name] } + for name in std.objectFields(params.nodeGroups) + if !isMultiAz(name) +] + std.flattenArrays([ + [ + { + name: name + '-' + zoneId(zone), + spec: params.nodeGroups[name] { + replicas: replicasPerZone(com.getValueOrDefault(params.nodeGroups[name], 'replicas', 1)), + spec+: { + template+: { + spec+: { + providerSpec+: { + value+: { + zone: zone, + }, + }, + }, + }, + }, + }, + } + for zone in params.availabilityZones + ] + for name in std.objectFields(params.nodeGroups) + if isMultiAz(name) +]); + +local machineSets = [ + machineSet(m.name, m.spec) + for m in machineSpecs +]; + // Define outputs below { + '01_machinesets': machineSets, } diff --git a/docs/modules/ROOT/pages/references/parameters.adoc b/docs/modules/ROOT/pages/references/parameters.adoc new file mode 100644 index 0000000..1345ce6 --- /dev/null +++ b/docs/modules/ROOT/pages/references/parameters.adoc @@ -0,0 +1,163 @@ += Parameters + +The parent key for all of the following parameters is `openshift4_nodes`. + +[CAUTION] +==== +This component relies on deep merge of values from several parameters and hierarchy layers. +This works pretty straightforward for scalar values and dictionaries. +Values of arrays will be appended to each other. +There is no way to override values which were set on a lower precedence location. +==== + +== `availabilityZones` + +[horizontal] +type:: list of strings +default:: [] + +List of availability zone names. +The list will be used when distributing MachineSets across zones (see <>). +The first item of this list will also be used to place a MachineSet without an explicit zone defined. + +It's suggested to define its values higher up the config hierarchy. +Most probably the one of the cloud region. + +== `defaultSpecs` + +[horizontal] +type:: dictionary +default:: Sensible defaults for a growing number of cloud providers. + +A dictionary holding the default values applied to each `machinesets.machine.openshift.io` object created by this component. + +The top level keys are the names of cloud providers as reported by the `cloud.provider` fact. +The values can be everything that's accepted in the `spec` field of a `machinesets.machine.openshift.io` object. + +== `infrastructureID` + +[horizontal] +type:: string +default:: undefined + +This is the 12 character infrastructure ID given to a cluster by the OpenShift 4 installer. +Use the following command to retrieve this from the cluster: + +[code,bash] +---- +oc get -o jsonpath='{.status.infrastructureName}{"\n"}' infrastructure cluster +---- + +See also https://github.com/appuio/component-openshift4-nodes/issues/2[Get a clusters infrastructure ID as a fact]. + +[TIP] +==== +This is most likely to be configured on cluster level itself. +Configuring this higher up in the hierarchy can result in unexpected behavior. +==== + +== `namespace` + +[horizontal] +type:: string +default:: openshift-machine-api + +The namespace where namespaced objects will be created in. + +== `nodeGroups` + +[horizontal] +type:: dictionary +default:: empty + +A dictionary of node groups to create on the cluster. +It's centered around the MachineSet CRD but also takes care of some additional aspects like zone distribution and auto scaling. + +The top level key is the name of each set of machines. +Each set of machines has the values described below. + +=== `instanceType` + +=== `multiAz` + +[horizontal] +type:: boolean +default:: false + +A machine set will be placed in one single availability zone. +If not specified otherwise, the first entry of `availabilityZones` will be used. +When set to true, a MachineSet will be created for each zone listed in `availabilityZones`. +The replicas of the generated MachineSets will be calculated. +The `replicas` given will be divided by the cont of zones in `availabilityZones` rounded up. + +See also https://github.com/appuio/component-openshift4-nodes/issues/3[Effective replica count of multi zone machines can be higher than the requested one] + +=== `replicas` + +[horizontal] +type:: number +default:: 1 + +The number of machines to create. +When `multiAZ` is set to `true`, the number given here will be divided so that each of the created MachineSets will get a fraction of replicas but the total of created machines will match the one requested here. + +See also <>. + +[NOTE] +==== +This value can also be set in <>. +If done so, the value in <> will win. +==== + +=== `role` + +[horizontal] +type:: string +default:: worker + +The role of the created Nodes. +The value will be added as the `node-role.kubernetes.io/: ""` label to nodes. + +[NOTE] +==== +In order to add additional labels to the resulting Node object, use `spec.template.spec.metadata.labels`. +==== + +=== `spec` + +[horizontal] +type:: dictionary +default:: See <>. + +This gives you the full control over the resulting MachineSet. +Values given here will be merged with precedence with the defaults configured in <>. +The values can be everything that's accepted in the `spec` field of a `machinesets.machine.openshift.io` object. + +== Example + +[source,yaml] +---- +infrastructureID: c-mist-sg7hn + +nodeGroups: + infra: + instanceType: n1-standard-8 + multiAz: true + replicas: 3 + role: infra + worker: + instanceType: n1-standard-8 + replicas: 3 + spec: + deletePolicy: Oldest + template: + spec: + metadata: + labels: + mylabel: myvalue + +availabilityZones: +- europe-west6-a +- europe-west6-b +- europe-west6-c +---- diff --git a/docs/modules/ROOT/partials/nav.adoc b/docs/modules/ROOT/partials/nav.adoc index 5d67faa..08f9283 100644 --- a/docs/modules/ROOT/partials/nav.adoc +++ b/docs/modules/ROOT/partials/nav.adoc @@ -1 +1,2 @@ * xref:index.adoc[Home] +* xref:references/parameters.adoc[Parameters]