# OpenStack<no value>

<!-- Generated by website/sync-docs.py from docs/install/openstack.md. Edit that file, not this one. -->

A node on an OpenStack cloud, from the published qcow2. Verified on OVH Public
Cloud; nothing below is specific to that provider beyond the network name.

Corium boots UEFI only, so the image has to be registered as such. That is the
one thing worth getting right before anything else.

## What you need

- An OpenStack project and the `openstack` client.
- A flavor whose disk is at least the image's virtual size — 10 GiB. The
  filesystem grows to the flavor's disk on first boot.
- A network that gives the instance an address you can reach.

## 1. Register the image

Download the qcow2 first — see [downloads](/docs/install/downloads/) for where it lives and
how to check it.

```bash
openstack image create corium-0.1.0 \
  --file corium-0.1.0-x86_64.qcow2 --disk-format qcow2 --container-format bare \
  --property hw_firmware_type=uefi \
  --property hw_machine_type=q35 \
  --property hw_disk_bus=virtio \
  --property os_type=linux
```

`hw_firmware_type=uefi` is not optional. Without it the instance is booted with
a BIOS firmware and never finds a bootloader.

Glance can sometimes import straight from a URL, which saves uploading a
gigabyte and a half from your laptop:

```bash
openstack image create corium-0.1.0 --import \
  --import-method web-download --uri https://<the URL from the release notes>
```

Check first — `openstack image import-info` lists what the cloud supports. OVH
offers only `glance-download`, so there the file goes up from your machine.

## 2. Key and firewall

```bash
openstack keypair create --public-key ~/.ssh/id_ed25519.pub corium
openstack security group create corium
openstack security group rule create --proto tcp --dst-port 22 --remote-ip 0.0.0.0/0 corium
openstack security group rule create --proto tcp --dst-port 6443 --remote-ip 0.0.0.0/0 corium
```

The keypair is convenience only. What actually creates the user is the
`users:` block in the configuration below, so the two should carry the same
key.

## 3. Launch it

```bash
openstack server create corium \
  --image corium-0.1.0 --flavor <a flavor with 4 GB or more> \
  --key-name corium --security-group corium \
  --network <your external network> \
  --user-data corium.yaml --wait
```

with `corium.yaml`:

```yaml
#cloud-config
corium:
  role: single
  cluster:
    name: homelab
users:
  - name: core
    sudo: ALL=(ALL) NOPASSWD:ALL
    groups: wheel
    shell: /bin/bash
    ssh_authorized_keys:
      - ssh-ed25519 AAAA... you@example.com
ssh_pwauth: false
```

**The `corium:` block arrives through the OpenStack metadata service**, not
through a config drive. cloud-init reads it from `169.254.169.254`, and Corium
picks it up from cloud-init like any other source. Nothing needs to be baked
into the image.

## 4. Check it

```console
$ sudo cloud-init query --format '{{ v1.platform }} / {{ v1.subplatform }}'
openstack / metadata (http://169.254.169.254)

$ sudo k0s kubectl get nodes -o wide
NAME         STATUS   ROLES           AGE    VERSION       INTERNAL-IP
corium-rc7   Ready    control-plane   7m2s   v1.36.4+k0s   57.130.75.237

$ df -h /sysroot
/dev/vda4   48G  3.3G   43G   8% /sysroot
```

SSH answered about forty seconds after the instance went ACTIVE, and the node
reached `Ready` a few minutes later.

Two things that come from the cloud rather than from Corium. The hostname is
whatever OpenStack gave the instance — the agent logs `keeping the hostname
already set` and leaves it alone, so set `node.name` if you want to choose.
And the filesystem grew from the image's 10 GiB to the flavor's disk on the
first boot, without being asked.

## 5. When you are done

```bash
openstack server delete corium --wait
openstack image delete corium-0.1.0
openstack security group delete corium
openstack keypair delete corium
```

## What to read next

- [Downloads](/docs/install/downloads/) — fetching an artefact and checking it
- [cctl](/docs/reference/cli/) — managing this node without SSH: its state, its journals,
  its upgrades, and a kubeconfig
- [Configuration](/docs/reference/configuration/) — every field of the `corium:` block
