diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b2e1f9d..b9d92cf0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,12 +2,10 @@ ## [0.2.0](https://github.com/vexxhost/magnum-cluster-api/compare/v0.1.2...v0.2.0) (2022-11-16) - ### Bug Fixes * added flux + node labels ([5f04d4e](https://github.com/vexxhost/magnum-cluster-api/commit/5f04d4ed8b00ba0d45cc59edd678bdf72679b00b)) - ### Miscellaneous Chores * release 0.2.0 ([9c8fe82](https://github.com/vexxhost/magnum-cluster-api/commit/9c8fe8252e61b43019a0c45d31284467ec99af15)) diff --git a/hack/stack.sh b/hack/stack.sh index b4b405b9..726f6384 100755 --- a/hack/stack.sh +++ b/hack/stack.sh @@ -79,6 +79,7 @@ kubectl label node kind-control-plane openstack-control-plane=enabled # Initialize the `clusterctl` CLI export EXP_CLUSTER_RESOURCE_SET=true +export EXP_KUBEADM_BOOTSTRAP_FORMAT_IGNITION=true #Used by the kubeadm bootstrap provider export CLUSTER_TOPOLOGY=true clusterctl init \ --core cluster-api:v1.3.0-rc.0 \ diff --git a/magnum_cluster_api/cmd/image_builder.py b/magnum_cluster_api/cmd/image_builder.py index 4828f7f7..48b03c67 100644 --- a/magnum_cluster_api/cmd/image_builder.py +++ b/magnum_cluster_api/cmd/image_builder.py @@ -25,10 +25,9 @@ @click.command() @click.option( "--operating-system", - show_default=True, - default="ubuntu-2004", - type=click.Choice(["ubuntu-2004"]), + type=click.Choice(["ubuntu-2004", "flatcar"]), help="Operating system to build image for", + prompt="Operating system to build image for", ) @click.option( "--version", @@ -96,6 +95,8 @@ def main(operating_system, version, image_builder_version): "kubernetes_deb_version": f"{version.replace('v', '')}-00", "kubernetes_semver": f"{version}", "kubernetes_series": f"{kubernetes_series}", + # https://github.com/flatcar/Flatcar/issues/823 + "ansible_user_vars": "oem_id=openstack", } with tempfile.NamedTemporaryFile(suffix=".json") as fp: fp.write(json.dumps(customization).encode("utf-8")) diff --git a/magnum_cluster_api/driver.py b/magnum_cluster_api/driver.py index 0815a9c2..84e516e2 100644 --- a/magnum_cluster_api/driver.py +++ b/magnum_cluster_api/driver.py @@ -279,3 +279,11 @@ def provides(self): return [ {"server_type": "vm", "os": "ubuntu-focal", "coe": "kubernetes"}, ] + + +class FlatcarDriver(BaseDriver): + @property + def provides(self): + return [ + {"server_type": "vm", "os": "flatcar", "coe": "kubernetes"}, + ] diff --git a/magnum_cluster_api/resources.py b/magnum_cluster_api/resources.py index e70eb126..cc7626a9 100644 --- a/magnum_cluster_api/resources.py +++ b/magnum_cluster_api/resources.py @@ -494,8 +494,8 @@ def get_object(self) -> objects.KubeadmConfigTemplate: }, }, }, - } - } + }, + }, }, }, ) @@ -793,6 +793,30 @@ def get_object(self) -> objects.ClusterClass: }, }, }, + { + "name": "operatingSystem", + "required": True, + "schema": { + "openAPIV3Schema": { + "type": "string", + "enum": utils.AVAILABLE_OPERATING_SYSTEMS, + "default": "ubuntu", + }, + }, + }, + { + "name": "ntpServers", + "required": True, + "schema": { + "openAPIV3Schema": { + "type": "array", + "items": { + "type": "string", + }, + "default": [], + }, + }, + }, ], "patches": [ { @@ -891,6 +915,238 @@ def get_object(self) -> objects.ClusterClass: } ], }, + { + "name": "ntpServers", + "enabledIf": "{{ if gt (len .ntpServers) 0 }}true{{end}}", + "definitions": [ + { + "selector": { + "apiVersion": objects.KubeadmControlPlaneTemplate.version, + "kind": objects.KubeadmControlPlaneTemplate.kind, + "matchResources": { + "controlPlane": True, + }, + }, + "jsonPatches": [ + { + "op": "add", + "path": "/spec/template/spec/kubeadmConfigSpec/ntp/enabled", + "value": True, + }, + { + "op": "add", + "path": "/spec/template/spec/kubeadmConfigSpec/ntp/servers", + "valueFrom": { + "variable": "ntpServers", + }, + }, + ], + }, + { + "selector": { + "apiVersion": objects.KubeadmConfigTemplate.version, + "kind": objects.KubeadmConfigTemplate.kind, + "matchResources": { + "machineDeploymentClass": { + "names": ["default-worker"], + } + }, + }, + "jsonPatches": [ + { + "op": "add", + "path": "/spec/template/spec/ntp/enabled", + "value": True, + }, + { + "op": "add", + "path": "/spec/template/spec/ntp/servers", + "valueFrom": { + "variable": "ntpServers", + }, + }, + ], + }, + ], + }, + { + "name": "flatcar", + "enabledIf": '{{ if eq .operatingSystem "flatcar" }}true{{end}}', + "definitions": [ + { + "selector": { + "apiVersion": objects.KubeadmControlPlaneTemplate.version, + "kind": objects.KubeadmControlPlaneTemplate.kind, + "matchResources": { + "controlPlane": True, + }, + }, + "jsonPatches": [ + { + "op": "add", + "path": "/spec/template/spec/kubeadmConfigSpec/preKubeadmCommands", + "value": [ + textwrap.dedent( + """\ + bash -c "sed -i 's/__REPLACE_NODE_NAME__/$(hostname -s)/g' /etc/kubeadm.yml" + """ # noqa: E501 + ) + ], + }, + { + "op": "add", + "path": "/spec/template/spec/kubeadmConfigSpec/format", + "value": "ignition", + }, + { + "op": "add", + "path": "/spec/template/spec/kubeadmConfigSpec/ignition", + "value": { + "containerLinuxConfig": { + "additionalConfig": textwrap.dedent( + """\ + storage: + links: + # For some reason enabling services via systemd.units doesn't work on Flatcar. + - path: /etc/systemd/system/kubeadm.service.wants/containerd.service + target: /usr/lib/systemd/system/containerd.service + - path: /etc/systemd/system/multi-user.target.wants/coreos-metadata.service + target: /usr/lib/systemd/system/coreos-metadata.service + - path: /etc/systemd/system/multi-user.target.wants/kubeadm.service + target: /etc/systemd/system/kubeadm.service + systemd: + units: + - name: coreos-metadata.service + dropins: + - name: 20-clct-provider-override.conf + contents: | + [Service] + # Set Openstack as coreos-metadata provider + Environment=COREOS_METADATA_OPT_PROVIDER=--provider=openstack-metadata + - name: coreos-metadata-sshkeys@.service + enabled: true + dropins: + - name: 20-clct-provider-override.conf + contents: | + [Service] + # Set Openstack as coreos-metadata provider + Environment=COREOS_METADATA_OPT_PROVIDER=--provider=openstack-metadata + - name: kubeadm.service + dropins: + - name: 10-flatcar.conf + contents: | + [Unit] + # kubeadm must run after coreos-metadata populated /run/metadata directory. + Requires=coreos-metadata.service + After=coreos-metadata.service + [Service] + # Ensure kubeadm service has access to kubeadm binary in /opt/bin on Flatcar. + Environment=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/opt/bin + # To make metadata environment variables available for pre-kubeadm commands. + EnvironmentFile=/run/metadata/* + """ # noqa: E501 + ), + }, + }, + }, + { + "op": "replace", + "path": "/spec/template/spec/kubeadmConfigSpec/initConfiguration/nodeRegistration/name", # noqa: E501 + "value": "__REPLACE_NODE_NAME__", + }, + { + "op": "replace", + "path": "/spec/template/spec/kubeadmConfigSpec/joinConfiguration/nodeRegistration/name", # noqa: E501 + "value": "__REPLACE_NODE_NAME__", + }, + ], + }, + { + "selector": { + "apiVersion": objects.KubeadmConfigTemplate.version, + "kind": objects.KubeadmConfigTemplate.kind, + "matchResources": { + "machineDeploymentClass": { + "names": ["default-worker"], + } + }, + }, + "jsonPatches": [ + { + "op": "add", + "path": "/spec/template/spec/preKubeadmCommands", + "value": [ + textwrap.dedent( + """\ + bash -c "sed -i 's/__REPLACE_NODE_NAME__/$(hostname -s)/g' /etc/kubeadm.yml" + """ # noqa: E501 + ) + ], + }, + { + "op": "add", + "path": "/spec/template/spec/format", + "value": "ignition", + }, + { + "op": "add", + "path": "/spec/template/spec/ignition", + "value": { + "containerLinuxConfig": { + "additionalConfig": textwrap.dedent( + """\ + storage: + links: + # For some reason enabling services via systemd.units doesn't work on Flatcar. + - path: /etc/systemd/system/kubeadm.service.wants/containerd.service + target: /usr/lib/systemd/system/containerd.service + - path: /etc/systemd/system/multi-user.target.wants/coreos-metadata.service + target: /usr/lib/systemd/system/coreos-metadata.service + - path: /etc/systemd/system/multi-user.target.wants/kubeadm.service + target: /etc/systemd/system/kubeadm.service + systemd: + units: + - name: coreos-metadata.service + dropins: + - name: 20-clct-provider-override.conf + contents: | + [Service] + Environment=COREOS_METADATA_OPT_PROVIDER=--provider=openstack-metadata + - name: coreos-metadata-sshkeys@.service + enabled: true + dropins: + - name: 20-clct-provider-override.conf + contents: | + [Service] + Environment=COREOS_METADATA_OPT_PROVIDER=--provider=openstack-metadata + - name: kubeadm.service + dropins: + - name: 10-flatcar.conf + contents: | + [Unit] + # kubeadm must run after coreos-metadata populated /run/metadata directory. + Requires=coreos-metadata.service + After=coreos-metadata.service + [Service] + # In Flatcar /usr is immutable, so image-builder puts the binaries in /opt/bin instead. + # Ensure kubeadm service has access to kubeadm binary in /opt/bin on Flatcar. + Environment=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/opt/bin + # To make metadata environment variables available for pre-kubeadm commands. + EnvironmentFile=/run/metadata/* + """ # noqa: E501 + ), + }, + }, + }, + { + "op": "replace", + "path": "/spec/template/spec/joinConfiguration/nodeRegistration/name", + "value": "__REPLACE_NODE_NAME__", + }, + ], + }, + ], + }, { "name": "clusterConfig", "definitions": [ @@ -1360,6 +1616,14 @@ def get_object(self) -> objects.Cluster: "name": "sshKeyName", "value": self.cluster.keypair or "", }, + { + "name": "operatingSystem", + "value": utils.get_operating_system(self.cluster), + }, + { + "name": "ntpServers", + "value": utils.get_ntp_servers(self.cluster), + }, ], }, }, diff --git a/magnum_cluster_api/utils.py b/magnum_cluster_api/utils.py index 79e0b0a1..cf7a8203 100644 --- a/magnum_cluster_api/utils.py +++ b/magnum_cluster_api/utils.py @@ -12,6 +12,8 @@ from magnum_cluster_api import clients, objects +AVAILABLE_OPERATING_SYSTEMS = ["ubuntu", "flatcar"] + def get_or_generate_cluster_api_cloud_config_secret_name( api: pykube.HTTPClient, cluster: magnum_objects.Cluster @@ -225,3 +227,16 @@ def delete_loadbalancers(ctx, cluster): octavia.wait_for_lb_deleted(octavia_client, candidates) except Exception as e: raise exception.PreDeletionFailed(cluster_uuid=cluster.uuid, msg=str(e)) + + +def get_operating_system(cluster: magnum_objects.Cluster): + cluster_distro = cluster.cluster_template.cluster_distro + for ops in AVAILABLE_OPERATING_SYSTEMS: + if cluster_distro.startswith(ops): + return ops + return None + + +def get_ntp_servers(cluster: magnum_objects.Cluster): + ntp_servers = get_cluster_label(cluster, "ntp_servers", "") + return list(filter(None, ntp_servers.split(","))) diff --git a/pyproject.toml b/pyproject.toml index a951dce8..2ca83979 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,3 +23,4 @@ magnum-cluster-api-image-loader = "magnum_cluster_api.cmd.image_loader:main" [tool.poetry.plugins."magnum.drivers"] "k8s_cluster_api_ubuntu_focal" = "magnum_cluster_api.driver:UbuntuFocalDriver" +"k8s_cluster_api_flatcar" = "magnum_cluster_api.driver:FlatcarDriver"