diff --git a/slemicro/README.md b/slemicro/README.md index e2cd457..f53d256 100644 --- a/slemicro/README.md +++ b/slemicro/README.md @@ -8,377 +8,50 @@

| :warning: **This is an unofficial and unsupported repository. See the [official documentation](https://www.suse.com/solutions/edge-computing/).** | -| --- | +| ------------------------------------------------------------------------------------------------------------------------------------------------- | -- [create\_vm.sh](#create_vmsh) - - [Prerequisites](#prerequisites) - - [Enviroment variables](#enviroment-variables) - - [Usage](#usage) - - [Multiple VMs](#multiple-vms) - - [Static IPs](#static-ips) -- [delete\_vm.sh](#delete_vmsh) - - [Prerequisites](#prerequisites-1) - - [Enviroment variables](#enviroment-variables-1) - - [Usage](#usage-1) -- [get\_kubeconfig.sh](#get_kubeconfigsh) - - [Prerequisites](#prerequisites-2) - - [Enviroment variables](#enviroment-variables-2) - - [Usage](#usage-2) -- [get\_ip.sh](#get_ipsh) - - [Prerequisites](#prerequisites-3) - - [Enviroment variables](#enviroment-variables-3) - - [Usage](#usage-3) -- [getvmsip.sh](#getvmsipsh) - - [Prerequisites](#prerequisites-4) - - [Usage](#usage-4) -- [make\_unattended.sh](#make_unattendedsh) - - [Prerequisites](#prerequisites-5) - - [Usage](#usage-5) -- [create\_vm\_with\_eib.sh](#create_vm_with_eibsh) - - [Prerequisites](#prerequisites-6) - - [Enviroment variables](#enviroment-variables-4) - - [Usage](#usage-6) -- [create\_vm\_with\_image.sh](#create_vm_with_imagesh) - - [Prerequisites](#prerequisites-7) - - [Enviroment variables](#enviroment-variables-5) - - [Usage](#usage-7) -- [What's next?](#whats-next) - -## create_vm.sh - -This script creates a SLE Micro aarch64 VM on OSX using UTM and it is customized using ignition/combustion. - -The script will output the virtual terminal to connect to (using `screen` if needed) as well as the -IP that it gets from the OSX DHCPD service. - -K3s or RKE2 and Rancher are optionally installed. Rancher access is configured with sslip.io and with a custom bootstrap password. - -### Prerequisites - -* `butane` -* `mkisofs` -* `qemu-img` - -NOTE: They can be installed using `brew`. -* `envsubst` is available via the `gettext` package. -* `mkisofs` is available via the `cdrtools` package. -* `qemu-img` is available via the `qemu` package. - -* [UTM 4.2.2](https://docs.getutm.app/) or higest (required for the scripting part) - -* SLE Micro raw image. - * Download the raw image file from the SUSE website at https://www.suse.com/download/sle-micro/ - * Select ARM or X86_64 architecture (depending on the Operating system of the host) - * Look for the raw file (I.e.- `SLE-Micro.aarch64-5.3.0-Default-GM.raw.xz`) - * Note: SLE Micro RT image (I.e.- `SLE-Micro.aarch64-5.3.0-Default-RT-GM.raw.xz`) can be used as well. - -### Enviroment variables - -It requires a few enviroment variables to be set to customize it, the bare minimum are (see [env-minimal.example](env-minimal.example)): - -``` -# SLE Micro image -SLEMICROFILE="${HOME}/Downloads/SLE-Micro.aarch64-5.3.0-Default-GM.raw" -# Folder where the VM will be hosted -VMFOLDER="${HOME}/VMs" -``` - -They can be stored in the script basedir as `.env` or in any file and use the `-f path/to/the/variables` flag. - -**NOTE**: There is a `vm*` pattern already in the `.gitignore` file so you can conviniently name your VM parameters file as `vm-foobar` and they won't be added to git. - -```bash -cat << EOF > ${BASEDIR}/.env -# If required to register to https://scc.suse.com -REGISTER=true -# Email & regcode for the registration -EMAIL="foo@bar.com" -REGCODE="ASDF-1" -# SLE Micro image -SLEMICROFILE="${HOME}/Downloads/SLE-Micro.aarch64-5.3.0-Default-GM.raw" -# Folder where the VM will be hosted -VMFOLDER="${HOME}/VMs" -# VM & Hostname -VMNAME="SLEMicro" -# Selfexplanatory -CPUS=4 -MEMORY=4096 -DISKSIZE=30 -# Extra disks (only OSX for now) -EXTRADISKS="30,10" -# Location of the ssh key file to be copied to /root/.ssh/authorized_keys -SSHPUB="${HOME}/.ssh/id_rsa.pub" -# Enable KUBEVIP to manage a VIP for K3s API -KUBEVIP=true -# Set the VIP -VIP="192.168.205.10" -# Set it to false if you don't want K3s or rke2 to be deployed ["k3s"|"rke2"|false] -CLUSTER="k3s" -# Specify a k3s or rke2 cluster version ["v1.25.8+k3s1"|"v1.25.9+rke2r1"] -INSTALL_CLUSTER_VERSION="v1.25.8+k3s1" -# For the first node in an HA environment. This INSTALL_CLUSTER_EXEC will be translated to INSTALL_K3S_EXEC or INSTALL_RKE2_EXEC depending on the value of CLUSTER -# INSTALL_CLUSTER_EXEC="server --cluster-init --write-kubeconfig-mode=644 --tls-san=${VIP} --tls-san=${VIP}.sslip.io" -# For a single node. This INSTALL_CLUSTER_EXEC will be translated to INSTALL_K3S_EXEC or INSTALL_RKE2_EXEC depending on the value of CLUSTER -INSTALL_CLUSTER_EXEC="server --cluster-init --write-kubeconfig-mode=644" -# To add control plane nodes. This INSTALL_CLUSTER_EXEC will be translated to INSTALL_K3S_EXEC or INSTALL_RKE2_EXEC depending on the value of CLUSTER: -# INSTALL_CLUSTER_EXEC="server --server https://${VIP}:6443 --write-kubeconfig-mode=644" -# To add worker nodes. This INSTALL_CLUSTER_EXEC will be translated to INSTALL_K3S_EXEC or INSTALL_RKE2_EXEC depending on the value of CLUSTER: -# INSTALL_CLUSTER_EXEC="agent --server https://${VIP}:6443" -# Cluster token to be used to add more hosts and it will be translated to K3S_TOKEN or RKE2_TOKEN depending on the value of CLUSTER -CLUSTER_TOKEN="foobar" -# Set it to the Rancher flavor you want to install "stable", "latest", "alpha", "prime" or just false to disable it -RANCHERFLAVOR="latest" -# Use latest cert-manager version or a custom one (as prerequisite for Rancher) -# https://ranchermanager.docs.rancher.com/getting-started/quick-start-guides/deploy-rancher-manager/helm-cli#install-rancher-with-helm -CERTMANAGERVERSION="latest" -# Initial Rancher bootstrap password -RANCHERBOOTSTRAPPASSWORD="admin" -# Enable to skip the rancher bootstrap phase -RANCHERBOOTSTRAPSKIP="true" -# Final Rancher password -RANCHERFINALPASSWORD="adminadminadmin" -# Set it to sync the VM clock. -QEMUGUESTAGENT=true -# Enable cockpit -COCKPIT=true -# Enable podman -PODMAN=true -# Update to latest packages and reboot if needed (zypper needs-reboot) -UPDATEANDREBOOT=true -# Disable IPv6 -DISABLEIPV6=true -# Disable the rebootmgr service -REBOOTMGR=false -# Disable the transactional-updates timers -TRANSACTIONALUPDATES=false -# To test registration with elemental -# Requires latest elemental which includes [this change](https://github.com/rancher/elemental-operator/pull/516) -ELEMENTAL_REGISTER=true -# Configuration file downloaded from elemental MachineRegistration -# Contains the registration URL and cert to connect to elemental -ELEMENTAL_CONFIG="$HOME/Downloads/test_registrationURL.yaml" -EOF -``` - -NOTE: -1. EMAIL and REGCODE must be valid so do not forget to replace them with the real ones. -2. See the [env.example](env.example) file for an always up-to-date list of variables. - -### Usage - -```bash -$ ./create_vm.sh -VM started. You can connect to the serial terminal as: screen /dev/ttys001 -Waiting for IP: ................ -VM IP: 192.168.206.60 -After Rancher is installed, you can access the Web UI as https://rancher-192.168.206.60.sslip.io -``` - -You could also use the `-f` parameter to specify a path where the variables are stored or `-n` to override the name of the VM to be used: - -```bash -$ ./create_vm.sh -h -Usage: ./create_vm.sh [-f ] [-n ] -``` - -### Multiple VMs - -Using the `-f` flag, you can have multiple VM parameter files and create a cluster easily: - -```bash -$ grep ^INSTALL_CLUSTER_EXEC vm-* -vm-master-0:INSTALL_CLUSTER_EXEC="server --cluster-init --write-kubeconfig-mode=644 --tls-san=${VIP} --tls-san=${VIP}.sslip.io" -vm-master-1:INSTALL_CLUSTER_EXEC="server --server https://192.168.205.10:6443 --write-kubeconfig-mode=644" -vm-master-2:INSTALL_CLUSTER_EXEC="server --server https://192.168.205.10:6443 --write-kubeconfig-mode=644" -vm-worker-0:INSTALL_CLUSTER_EXEC="agent --server https://192.168.205.10:6443" -vm-worker-1:INSTALL_CLUSTER_EXEC="agent --server https://192.168.205.10:6443" - -for file in vm-*; do ./create_vm.sh -f ${file}; done - -# after a while - -master-0:~ # kubectl get nodes -NAME STATUS ROLES AGE VERSION -master-0 Ready control-plane,etcd,master 99s v1.25.9+k3s1 -master-1 Ready control-plane,etcd,master 51s v1.25.9+k3s1 -master-2 Ready control-plane,etcd,master 37s v1.25.9+k3s1 -worker-0 Ready 25s v1.25.9+k3s1 -worker-1 Ready 15s v1.25.9+k3s1 -``` - -**TIP:** To run the VM creation in parallel you can use `for file in vm-*; do ./create_vm.sh -f ${file} &; done; wait` (the output will be a little bit messy however) - -### Static IPs - -It is possible to deploy a VM with a static IP by setting the `VM_STATIC_IP` variable. - -Optionally additional configuration may be specified: -* `VM_STATIC_GATEWAY` (defaults to `192.168.122.1`). -* `VM_STATIC_PREFIX` (defaults to `24`). -* `VM_STATIC_DNS` (defaults to the value of `VM_STATIC_GATEWAY`). - -Note that in this configuration you must first disable DHCP for your libvirt network, which can be achieved via `virsh net-edit` to remove the `` stanza, then `virsh net-destroy` followed by `virsh net-start` - -## delete_vm.sh - -This script is intended to easily delete the previously SLE Micro VM created with the `create_vm.sh` script. - -You can use the same `-f` or `-n` parameters as well. - -:warning: There is no confirmation whatsoever! - -### Prerequisites - -* [UTM 4.2.2](https://docs.getutm.app/) or higest (required for the scripting part) - -### Enviroment variables - -The previous environment variables can be used but it requires a few less. - -### Usage - -```bash -$ ./delete_vm.sh -``` - -```bash -$ ./delete_vm.sh -h -Usage: ./delete_vm.sh [-f ] [-n ] -``` - -For multiple VMs: - -```bash -for file in vm-*; do ./delete_vm.sh -f ${file}; done -``` - -For multiple VMs in parallel: - -```bash -for file in vm-*; do ./delete_vm.sh -f ${file} &; done; wait -``` - -## get_kubeconfig.sh - -This script is intended to easily get the Kubeconfig file of the K3s/RKE2 cluster created with the `create_vm.sh` script. - -If Rancher is not deployed, it tries to get the Kubeconfig file via ssh, otherwise it leverages the Rancher API. - -You can use the same `-f` or `-n` parameters as well, an extra `-i` parameter to specify the IP manually or the `-w` flag that will wait until the kubeconfig is available. - -By default the kubeconfig is output on stdout, or you can use `-o` to specify an output filename. - -### Prerequisites - -* A VM already deployed via the `create_vm.sh` - -### Enviroment variables - -The previous environment variables can be used but it requires a few less. - -### Usage - -```bash -$ ./get_kubeconfig.sh - - -$ ./get_kubeconfig.sh -o $KUBECONFIG -# Will write/overwrite the KUBECONFIG file -``` - -```bash -$ ./get_kubeconfig.sh -h -Usage: ./get_kubeconfig.sh [-f ] [-n ] [-i ] [-o ] -``` - -You can use the script in combination with the `create_vm.sh` one as: - -```bash -$ ./create_vm.sh -f vm-foobar -$ ./get_kubeconfig.sh -w -f vm-foobar -o $KUBECONFIG -``` - -## get_ip.sh - -This script is intended to easily get the VM IP created with the `create_vm.sh` script. - -You can use the same `-f` or `-n` parameters as well. - -### Prerequisites - -* A VM already deployed via the `create_vm.sh` - -### Enviroment variables - -The previous environment variables can be used but it requires a few less. - -### Usage - -```bash -$ ./get_ip.sh -192.168.205.2 -``` - -```bash -$ ./get_ip.sh -h -Usage: ./get_ip.sh [-f ] [-n ] - -Options: - -f (Optional) Path to the variables file - -n (Optional) Virtual machine name -``` - -## getvmsip.sh - -This script is intended to easily show all the VMs IP on the host. - -It doesn't require any parameter - -### Prerequisites - -* A VM already deployed - -### Usage - -```bash -$ ./getvmsip.sh -bootstraper 192.168.122.2 -host1rke2 192.168.122.128 -host2rke2 192.168.122.77 -host3rke2 192.168.122.31 -host1k3s 192.168.122.180 -host2k3s 192.168.122.136 -host3k3s 192.168.122.215 -``` - -## make_unattended.sh - -This script is intended to generate a completely unattended SLE Micro SelfInstall ISO. - -It requires the path to the SLE Micro SelfInstall ISO and it will generate a `tweaked.iso` file in the current folder. - -### Prerequisites - -* A SLE Micro SelfInstall ISO (SLE-Micro.x86_64-5.5.0-Default-SelfInstall-GM.install.iso) -* xorriso installed -* Be executed as root - -### Usage - -```bash -$ ./make_unattended.sh -h -Usage: ./make_unattended.sh -i SLE-Micro-SelfInstall.iso [-o tweaked-SLE-Micro-SelfInstall.iso] [-d /dev/sda] - -Options: - -i Path to the original SLE Micro iso file - -o (Optional) Path to the tweaked-SLE-Micro-SelfInstall.iso file (./tweaked.iso by default) - -d (Optional) Disk device where SLE Micro will be installed (if not provided, the first one that the installer finds) -``` -## create_vm_with_eib.sh - -This script creates a SLE Micro VM on OSX/Linux using UTM (or Libvirt) based on EIB. + + +- [create_vm_with_eib.sh](#create_vm_with_eib.sh) + - [Prerequisites](#Prerequisites) + - [Enviroment variables](#Enviromentvariables) + - [Usage](#Usage) +- [create_vm_with_image.sh](#create_vm_with_image.sh) + - [Prerequisites](#Prerequisites-1) + - [Enviroment variables](#Enviromentvariables-1) + - [Usage](#Usage-1) +- [create_eib.sh](#create_eib.sh) + - [Prerequisites](#Prerequisites-1) + - [Enviroment variables](#Enviromentvariables-1) + - [Usage](#Usage-1) +- [delete_vm.sh](#delete_vm.sh) + - [Prerequisites](#Prerequisites-1) + - [Enviroment variables](#Enviromentvariables-1) + - [Usage](#Usage-1) +- [get_kubeconfig.sh](#get_kubeconfig.sh) + - [Prerequisites](#Prerequisites-1) + - [Enviroment variables](#Enviromentvariables-1) + - [Usage](#Usage-1) +- [get_ip.sh](#get_ip.sh) + - [Prerequisites](#Prerequisites-1) + - [Enviroment variables](#Enviromentvariables-1) + - [Usage](#Usage-1) +- [getvmsip.sh](#getvmsip.sh) + - [Prerequisites](#Prerequisites-1) + - [Usage](#Usage-1) +- [What's next?](#Whatsnext) + + + + +## create_vm_with_eib.sh + +This script creates a SLE Micro VM on OSX/Linux using UTM/Libvirt based on EIB. The script will output the virtual terminal to connect to (using `screen` if needed) as well as the IP that it gets from the OSX DHCPD service. @@ -386,24 +59,25 @@ IP that it gets from the OSX DHCPD service. WARNING: Read the [EIB documentation](https://github.com/suse-edge/edge-image-builder/blob/main/docs/building-images.md) carefully to understand the folders and files needed as well as the EIB configuration file. -### Prerequisites +### Prerequisites -* `podman` -* `yq` -* `qemu-img` +- `podman` +- `yq` +- `qemu-img` NOTE: They can be installed using `brew`. -* `qemu-img` is available via the `qemu` package. -* [UTM 4.2.2](https://docs.getutm.app/) or higest (required for the scripting part) +- `qemu-img` is available via the `qemu` package. -* EIB configuration file and folder already created, including the SL Micro raw image. - * Download the raw image file from the SUSE website at https://www.suse.com/download/sle-micro/ - * Select ARM or X86_64 architecture (depending on the Operating system of the host) - * Look for the raw file (I.e.- `SL-Micro.aarch64-6.0-Default-GM2.raw`) - * Note: SLE Micro RT image can be used as well. +- [UTM 4.2.2](https://docs.getutm.app/) or highest (required for the scripting part) -### Enviroment variables +- EIB configuration file and folder already created, including the SL Micro raw image. + - Download the raw image file from the SUSE website at https://www.suse.com/download/sle-micro/ + - Select ARM or X86_64 architecture (depending on the Operating system of the host) + - Look for the raw file (I.e.- `SL-Micro.aarch64-6.0-Default-GM2.raw`) + - Note: SLE Micro RT image can be used as well. + +### Enviroment variables It requires a few enviroment variables to be set to customize it, the bare minimum is just: @@ -411,25 +85,28 @@ It requires a few enviroment variables to be set to customize it, the bare minim # Folder where the VM will be hosted VMFOLDER="${HOME}/VMs" MACADDRESS="00:00:00:00:00:00" +# On libvirt VMs you can influence the disk settings like: +# LIBVIRT_DISK_SETTINGS="bus=virtio,cache=unsafe" ``` The rest of them can be observed in the script itself. The variables can be stored in the script basedir as `.env` or in any file and use the `-f path/to/the/variables` flag. -**NOTE**: There is a `vm*` pattern already in the `.gitignore` file so you can conviniently name your VM parameters file as `vm-foobar` and they won't be added to git. +**NOTE**: There is a `vm*` pattern already in the `.gitignore` file so you can conviniently name your VM parameters file as `vm-foobar` and they won't be added to git. NOTE: + 1. EIB vars and settings are not verified, EIB will complain by itself if needed. 2. The EIB config file is currently hardcoded as `eib.yaml` 3. The EIB folders and files need to be precreated by the user -### Usage +### Usage For a simple example like: ```bash -$ tree --noreport eib +$ tree --noreport eib eib └── smolvm ├── base-images @@ -505,26 +182,31 @@ Usage: ./create_vm_with_eib.sh [-f ] [-e create_vm_with_image.sh -This script creates a SLE Micro VM on OSX/Linux using UTM (or Libvirt) based on a precreated EIB image (via [create\_vm\_with\_eib.sh](#create_vm_with_eibsh)). -The intention is to use EIB to create an image for any number of nodes + the first node via [create\_vm\_with\_eib.sh](#create_vm_with_eibsh) and then create the rest of the nodes with this script. +This script creates a SLE Micro VM on OSX/Linux using UTM/Libvirt based on a precreated EIB image (via [create_vm_with_eib.sh](#create_vm_with_eibsh)). +The intention is to use EIB to create an image for any number of nodes + the first node via [create_vm_with_eib.sh](#create_vm_with_eibsh) and then create the rest of the nodes with this script like: + +```bash +./create_vm_with_eib.sh -e eib/edge-32-mgmt-cluster/ -f vm1 && for i in 2 3; do ./create_vm_with_image.sh -i eib/edge-32-mgmt-cluster/32-mgmt-cluster.raw -f vm${i};done +``` The script will output the virtual terminal to connect to (using `screen` if needed) as well as the IP that it gets from the OSX DHCPD service. -### Prerequisites +### Prerequisites -* `qemu-img` +- `qemu-img` NOTE: They can be installed using `brew`. -* `qemu-img` is available via the `qemu` package. -* [UTM 4.2.2](https://docs.getutm.app/) or higest (required for the scripting part) +- `qemu-img` is available via the `qemu` package. -* EIB raw image already created. +- [UTM 4.2.2](https://docs.getutm.app/) or higest (required for the scripting part) -### Enviroment variables +- EIB raw image already created. + +### Enviroment variables It requires a few enviroment variables to be set to customize it, the bare minimum is just: @@ -538,9 +220,9 @@ The rest of them can be observed in the script itself. The variables can be stored in the script basedir as `.env` or in any file and use the `-f path/to/the/variables` flag. -**NOTE**: There is a `vm*` pattern already in the `.gitignore` file so you can conviniently name your VM parameters file as `vm-foobar` and they won't be added to git. +**NOTE**: There is a `vm*` pattern already in the `.gitignore` file so you can conviniently name your VM parameters file as `vm-foobar` and they won't be added to git. -### Usage +### Usage For a simple example like: @@ -558,6 +240,186 @@ $ ./create_vm_with_eib.sh -h Usage: ./create_vm_with_image.sh [-f ] [-i ] [-n ] ``` -## What's next? +**TIP:** To run the VM creation in parallel you can use `for file in vm-*; do ./create_vm_with_image.sh -f ${file} &; done; wait` (the output will be a little bit messy however) + +## create_eib.sh + +This script uses EIB to create an image. Then it can be. used with [create_vm_with_image.sh](#create_vm_with_imagesh) like: + +```bash +./create_eib.sh -e eib/edge-32-mgmt-cluster/ -f vm1 && for i in 1 2 3; do ./create_vm_with_image.sh -i eib/edge-32-mgmt-cluster/32-mgmt-cluster.raw -f vm${i};done +``` + +### Prerequisites + +- `podman` +- `yq` + +NOTE: They can be installed using `brew`. + +### Enviroment variables + +It requires a few enviroment variables to be set to customize it, the bare minimum is just: + +``` +# Folder where the VM will be hosted +VMFOLDER="${HOME}/VMs" +MACADDRESS="00:00:00:00:00:00" +``` + +The rest of them can be observed in the script itself. + +The variables can be stored in the script basedir as `.env` or in any file and use the `-f path/to/the/variables` flag. + +**NOTE**: There is a `vm*` pattern already in the `.gitignore` file so you can conviniently name your VM parameters file as `vm-foobar` and they won't be added to git. + +### Usage + +For a simple example like: + +```bash +$ ./create_eib.sh -f vm-slmicro62-eib -e eib/smolvm +SELinux is enabled in the Kubernetes configuration. The necessary RPM packages will be downloaded. +Downloading file: rancher-public.key... +Kubernetes ................... [SUCCESS] +Certificates ................. [SKIPPED] +Cleanup ...................... [SUCCESS] +Building RAW image... +Kernel Params ................ [SKIPPED] +Build complete, the image can be found at: 32-mgmt-cluster.raw +``` + +## delete_vm.sh + +This script is intended to easily delete the previously SLE Micro VM created with the `create_vm.sh` script. + +You can use the same `-f` or `-n` parameters as well. + +:warning: There is no confirmation whatsoever! + +### Prerequisites + +- [UTM 4.2.2](https://docs.getutm.app/) or higest (required for the scripting part) + +### Enviroment variables + +The previous environment variables can be used but it requires a few less. + +### Usage + +```bash +$ ./delete_vm.sh +``` + +```bash +$ ./delete_vm.sh -h +Usage: ./delete_vm.sh [-f ] [-n ] +``` + +For multiple VMs: + +```bash +for file in vm-*; do ./delete_vm.sh -f ${file}; done +``` + +For multiple VMs in parallel: + +```bash +for file in vm-*; do ./delete_vm.sh -f ${file} &; done; wait +``` + +## get_kubeconfig.sh + +This script is intended to easily get the Kubeconfig file of the K3s/RKE2 cluster created with the `create_vm.sh` script. + +If Rancher is not deployed, it tries to get the Kubeconfig file via ssh, otherwise it leverages the Rancher API. + +You can use the same `-f` or `-n` parameters as well, an extra `-i` parameter to specify the IP manually or the `-w` flag that will wait until the kubeconfig is available. + +By default the kubeconfig is output on stdout, or you can use `-o` to specify an output filename. + +### Prerequisites + +- A VM already deployed via the `create_vm.sh` + +### Enviroment variables + +The previous environment variables can be used but it requires a few less. + +### Usage + +```bash +$ ./get_kubeconfig.sh + + +$ ./get_kubeconfig.sh -o $KUBECONFIG +# Will write/overwrite the KUBECONFIG file +``` + +```bash +$ ./get_kubeconfig.sh -h +Usage: ./get_kubeconfig.sh [-f ] [-n ] [-i ] [-o ] +``` + +You can use the script in combination with the `create_vm_*.sh` scripts as: + +```bash +$ ./create_vm_with_eib.sh -f vm-foobar -e eib/foobar +$ ./get_kubeconfig.sh -w -f vm-foobar -o $KUBECONFIG +``` + +## get_ip.sh + +This script is intended to easily get the VM IP created with the `create_vm_*.sh` scripts. + +You can use the same `-f` or `-n` parameters as well. + +### Prerequisites + +- A VM already deployed via the `create_vm_*.sh` scripts. + +### Enviroment variables + +The previous environment variables can be used but it requires a few less. + +### Usage + +```bash +$ ./get_ip.sh -f vm-foobar +192.168.205.2 +``` + +```bash +$ ./get_ip.sh -h +Usage: ./get_ip.sh [-f ] [-n ] + +Options: + -f Path to the variables file + -n (Optional) Virtual machine name +``` + +## getvmsip.sh + +This script is intended to easily show all the VMs IP on the host. + +It doesn't require any parameter + +### Prerequisites + +- A VM already deployed + +### Usage + +```bash +$ ./getvmsip.sh +host1rke2 192.168.122.128 +host2rke2 192.168.122.77 +host3rke2 192.168.122.31 +host1k3s 192.168.122.180 +host2k3s 192.168.122.136 +host3k3s 192.168.122.215 +``` + +## What's next? See the [fleet-examples](../fleet-examples/) folder for some workloads you can deploy on top of your new shiny cluster. diff --git a/slemicro/butane/config.fcc b/slemicro/butane/config.fcc deleted file mode 100644 index 512ee6e..0000000 --- a/slemicro/butane/config.fcc +++ /dev/null @@ -1,6 +0,0 @@ -variant: fcos -version: 1.4.0 -passwd: - users: - - name: root - password_hash: "$y$j9T$/t4THH10B7esLiIVBROsE.$G1lyxfy/MoFVOrfXSnWAUq70Tf3mjfZBIe18koGOuXB" diff --git a/slemicro/combustion/00_disable_ipv6.sh b/slemicro/combustion/00_disable_ipv6.sh deleted file mode 100755 index bf4fe13..0000000 --- a/slemicro/combustion/00_disable_ipv6.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash -set -euo pipefail - -if [ "${DISABLEIPV6}" = true ]; then - # https://www.suse.com/support/kb/doc/?id=000016980 - cat <<- EOF > /etc/sysctl.d/disable-ipv6.conf - net.ipv6.conf.all.disable_ipv6 = 1 - net.ipv6.conf.default.disable_ipv6 = 1 - net.ipv6.conf.lo.disable_ipv6 = 1 - EOF - - echo 1 > /proc/sys/net/ipv6/conf/all/disable_ipv6 -fi diff --git a/slemicro/combustion/00_disable_rebootmgr.sh b/slemicro/combustion/00_disable_rebootmgr.sh deleted file mode 100644 index 60333bc..0000000 --- a/slemicro/combustion/00_disable_rebootmgr.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash -set -euo pipefail - -if [ "${REBOOTMGR}" = false ]; then - sed -ie 's/strategy=best-effort/strategy=off/g' /etc/rebootmgr.conf - systemctl disable rebootmgr - systemctl mask rebootmgr -fi \ No newline at end of file diff --git a/slemicro/combustion/00_disable_updates.sh b/slemicro/combustion/00_disable_updates.sh deleted file mode 100644 index 6f263a4..0000000 --- a/slemicro/combustion/00_disable_updates.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash -set -euo pipefail - -if [ "${TRANSACTIONALUPDATES}" = false ]; then - systemctl disable transactional-update.timer transactional-update-cleanup.timer - systemctl mask transactional-update.timer transactional-update-cleanup.timer -fi \ No newline at end of file diff --git a/slemicro/combustion/00_static_ip.sh b/slemicro/combustion/00_static_ip.sh deleted file mode 100755 index b9797a3..0000000 --- a/slemicro/combustion/00_static_ip.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash -set -euxo pipefail - -if [ ! -z "${VM_STATIC_IP}" ]; then - # The NM configuration isn't activated so we have to bring the NIC up manually - # otherwise subsequent steps e.g registration will fail - ip addr add ${VM_STATIC_IP}/24 dev eth0 - ip route add default via ${VM_GATEWAY_IP} - echo "nameserver ${VM_GATEWAY_IP}" > /etc/resolv.conf - - umask 077 # Required for NM config - mkdir -p /etc/NetworkManager/system-connections/ - cat >/etc/NetworkManager/system-connections/eth0.nmconnection <<-EOF -[connection] -id=eth0 -type=ethernet -interface-name=eth0 -autoconnect=true - -[ipv4] -method=manual -dns=${VM_STATIC_DNS} -address1=${VM_STATIC_IP}/${VM_STATIC_PREFIX},${VM_STATIC_GATEWAY} -may-fail=false -EOF -fi diff --git a/slemicro/combustion/01_extra_disks.sh b/slemicro/combustion/01_extra_disks.sh deleted file mode 100644 index 8426d00..0000000 --- a/slemicro/combustion/01_extra_disks.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash -set -euo pipefail - -# Undocumented variable for now :) -ALLTOLONGHORN=${ALLTOLONGHORN:-false} - -if [ "${EXTRADISKS}" != false ]; then - if [ "${ALLTOLONGHORN}" == true ]; then - VGNAME="vg_longhorn" - LVNAME="storage" - MOUNTPOINT="/var/lib/longhorn" - # This is need to create the previous mountpoint - mount /var || true - for disk in $(lsblk -l -o NAME,TYPE -n | awk '/disk/ { print $1 }' | grep -v vda); do - # Create a single partition for the whole disk - # The double (!) dollar sign is because envsubst _removes_ the first one, then the extra one is for the 'EOF' - sfdisk /dev/$${q}{disk} <<- EOF - label: gpt - type=linux - EOF - PARTITION="/dev/$${q}{disk}1" - # Remove all the previous content (probably not needed) - wipefs --all $${q}{PARTITION} - # Create a PV on top of the partition - lvm pvcreate $${q}{PARTITION} - # Add it to the list of PVs so vgcreate can be easily executed - PVS+=" $${q}{PARTITION}" - done - # Create a VG with all the PVs - lvm vgcreate $${q}{VGNAME} $${q}{PVS} - # A LV with all the free space, -Z is needed because there is no udev it seems - # https://serverfault.com/questions/827251/cannot-do-lvcreate-not-found-device-not-cleared-on-centos - lvm lvcreate -Zn -l 100%FREE -n $${q}{LVNAME} $${q}{VGNAME} - mkfs.ext4 /dev/mapper/$${q}{VGNAME}-$${q}{LVNAME} - mkdir -p $${q}{MOUNTPOINT} - echo "/dev/mapper/$${q}{VGNAME}-$${q}{LVNAME} $${q}{MOUNTPOINT} ext4 noatime 0 0" >> /etc/fstab - mount $${q}{MOUNTPOINT} - else - echo "TBD" - fi -fi diff --git a/slemicro/combustion/01_kubevip.sh b/slemicro/combustion/01_kubevip.sh deleted file mode 100755 index 30a3156..0000000 --- a/slemicro/combustion/01_kubevip.sh +++ /dev/null @@ -1,151 +0,0 @@ -#!/bin/bash -set -euo pipefail - -# If Kubevip is enabled to have a VIP for the K3s API -# The official way would be: -# export VIP=192.168.205.68 -# export INTERFACE=eth0 -# export KVVERSION="v0.5.12" -# podman run --rm --network=host ghcr.io/kube-vip/kube-vip:$KVVERSION manifest daemonset \ -# --interface $INTERFACE \ -# --address $VIP \ -# --inCluster \ -# --taint \ -# --controlplane \ -# --arp \ -# --leaderElection > foobar.yaml -if [ "${KUBEVIP}" = true ]; then - # lb_enable requires loading the ip_vs modules - # https://kube-vip.io/docs/about/architecture/?query=lb_enable#control-plane-load-balancing - # But at this point that folder is not valid and it won't work - cat <<- EOF > /root/ipvs.conf - ip_vs - ip_vs_rr - ip_vs_wrr - ip_vs_sh - nf_conntrack - EOF - - # The proper path would be /var/lib/rancher/k3s/server/manifests - # but as this is done at combustion time, the folder will be - # overwritten when installing K3s as: - # Apr 27 10:44:30 cp01 k3s_installer.sh[2437]: Warning: The following files were changed in the snapshot, but are shadowed by - # Apr 27 10:44:30 cp01 k3s_installer.sh[2437]: other mounts and will not be visible to the system: - # Apr 27 10:44:30 cp01 k3s_installer.sh[2437]: /.snapshots/3/snapshot/var/lib/rancher/k3s/server/manifests/kube-vip.yaml - # So, instead, just create it somewhere and move it - # as an ExecStartPost in the k3s_installer service. - # I've tried in /tmp and /var/tmp but - # those seem to be ephemeral at combustion time - cat <<- EOF > /root/kube-vip.yaml - apiVersion: v1 - kind: ServiceAccount - metadata: - name: kube-vip - namespace: kube-system - --- - apiVersion: rbac.authorization.k8s.io/v1 - kind: ClusterRole - metadata: - annotations: - rbac.authorization.kubernetes.io/autoupdate: "true" - name: system:kube-vip-role - rules: - - apiGroups: [""] - resources: ["services", "services/status", "nodes", "endpoints"] - verbs: ["list","get","watch", "update"] - - apiGroups: ["coordination.k8s.io"] - resources: ["leases"] - verbs: ["list", "get", "watch", "update", "create"] - --- - kind: ClusterRoleBinding - apiVersion: rbac.authorization.k8s.io/v1 - metadata: - name: system:kube-vip-binding - roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: system:kube-vip-role - subjects: - - kind: ServiceAccount - name: kube-vip - namespace: kube-system - --- - apiVersion: apps/v1 - kind: DaemonSet - metadata: - labels: - app.kubernetes.io/name: kube-vip-ds - app.kubernetes.io/version: v0.5.12 - name: kube-vip-ds - namespace: kube-system - spec: - selector: - matchLabels: - app.kubernetes.io/name: kube-vip-ds - template: - metadata: - labels: - app.kubernetes.io/name: kube-vip-ds - app.kubernetes.io/version: v0.5.12 - spec: - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: node-role.kubernetes.io/master - operator: Exists - - matchExpressions: - - key: node-role.kubernetes.io/control-plane - operator: Exists - containers: - - args: - - manager - env: - - name: vip_arp - value: "true" - - name: port - value: "6443" - - name: vip_interface - value: eth0 - - name: vip_cidr - value: "32" - - name: cp_enable - value: "true" - - name: cp_namespace - value: kube-system - - name: vip_ddns - value: "false" - - name: vip_leaderelection - value: "true" - - name: vip_leaseduration - value: "30" - - name: vip_renewdeadline - value: "20" - - name: vip_retryperiod - value: "4" - - name: address - value: ${VIP} - - name: lb_enable - value: "true" - - name: prometheus_server - value: :2112 - image: ghcr.io/kube-vip/kube-vip:v0.5.12 - imagePullPolicy: Always - name: kube-vip - securityContext: - capabilities: - add: - - NET_ADMIN - - NET_RAW - hostNetwork: true - nodeSelector: - node-role.kubernetes.io/master: "true" - serviceAccountName: kube-vip - tolerations: - - effect: NoSchedule - operator: Exists - - effect: NoExecute - operator: Exists - EOF -fi \ No newline at end of file diff --git a/slemicro/combustion/01_registration.sh b/slemicro/combustion/01_registration.sh deleted file mode 100755 index 9d2c2d6..0000000 --- a/slemicro/combustion/01_registration.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash -set -euo pipefail - -# Registration -if [ "${REGISTER}" = true ]; then - if ! which SUSEConnect > /dev/null 2>&1; then - zypper --non-interactive install suseconnect-ng - fi - - SCC_REGISTRATION_HOST=${SCC_REGISTRATION_HOST:-https://scc.suse.com} - SUSEConnect --email "${EMAIL}" --url "${SCC_REGISTRATION_URL}" --regcode "${REGCODE}" -fi diff --git a/slemicro/combustion/02_k3s.sh b/slemicro/combustion/02_k3s.sh deleted file mode 100755 index f6336c9..0000000 --- a/slemicro/combustion/02_k3s.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/bash -set -euo pipefail - -# K3s -if [ "${CLUSTER}" == "k3s" ]; then - # Mount /usr/local to store the k3s script - mount /usr/local || true - # Stolen from https://code.opensuse.org/adathor/combustion-dotconf/blob/main/f/K3s%20cluster/k3s_master/script - # Download and install the latest k3s installer - curl -L --output k3s_installer.sh https://get.k3s.io && install -m755 k3s_installer.sh /usr/local/bin/ - # Create a systemd unit that installs k3s if not installed yet. The k3s service is started after the installation - cat <<- EOF > /etc/systemd/system/k3s_installer.service - [Unit] - Description=Run K3s installer - Wants=network-online.target - After=network.target network-online.target - ConditionPathExists=/usr/local/bin/k3s_installer.sh - ConditionPathExists=!/usr/local/bin/k3s - - [Service] - User=root - Type=forking - TimeoutStartSec=600 - Environment="INSTALL_K3S_EXEC=${INSTALL_CLUSTER_EXEC}" - Environment="INSTALL_K3S_VERSION=${INSTALL_CLUSTER_VERSION}" - Environment="K3S_TOKEN=${CLUSTER_TOKEN}" - Environment="INSTALL_K3S_SKIP_START=false" - ExecStart=/usr/local/bin/k3s_installer.sh - RemainAfterExit=yes - KillMode=process - # Load the proper modules for kube-vip lb to work - ExecStartPost=/bin/sh -c "[ -f /root/ipvs.conf ] && mv /root/ipvs.conf /etc/modules-load.d/ipvs.conf && restorecon -vR /etc/modules-load.d || true" - ExecStartPost=/bin/sh -c "[ -f /etc/modules-load.d/ipvs.conf ] && systemctl restart systemd-modules-load || true" - # Move the kube-vip file if exists - ExecStartPost=/bin/sh -c "[ -f /root/kube-vip.yaml ] && mkdir -p /var/lib/rancher/k3s/server/manifests || true" - ExecStartPost=/bin/sh -c "[ -f /root/kube-vip.yaml ] && mv /root/kube-vip.yaml /var/lib/rancher/k3s/server/manifests/kube-vip.yaml || true" - ExecStartPost=/bin/sh -c "[ -f /var/lib/rancher/k3s/server/manifests/kube-vip.yaml ] && chcon -t container_var_lib_t /var/lib/rancher/k3s/server/manifests/kube-vip.yaml || true" - # Disable & delete everything - ExecStartPost=rm -f /usr/local/bin/k3s_installer.sh - ExecStartPost=/bin/sh -c "systemctl disable k3s_installer" - ExecStartPost=rm -f /etc/systemd/system/k3s_installer.service - - [Install] - WantedBy=multi-user.target - EOF - - systemctl enable k3s_installer.service -fi diff --git a/slemicro/combustion/02_rke2.sh b/slemicro/combustion/02_rke2.sh deleted file mode 100755 index 125e81b..0000000 --- a/slemicro/combustion/02_rke2.sh +++ /dev/null @@ -1,61 +0,0 @@ -#!/bin/bash -set -euo pipefail - -# RKE2 -if [ "${CLUSTER}" == "rke2" ]; then - # Mount /usr/local to store the RKE2 script - mount /usr/local || true - - curl -L --output rke2_installer.sh https://get.rke2.io && install -m755 rke2_installer.sh /usr/local/bin/ - # Create a systemd unit that installs rke2 if not installed yet. The rke2 service is started after the installation - cat <<- EOF > /etc/systemd/system/rke2_installer.service - [Unit] - Description=Run RKE2 installer - Wants=network-online.target - After=network.target network-online.target - ConditionPathExists=/usr/local/bin/rke2_installer.sh - ConditionPathExists=!/opt/rke2/bin/rke2 - - [Service] - User=root - Type=forking - TimeoutStartSec=600 - Environment="INSTALL_RKE2_VERSION=${INSTALL_CLUSTER_VERSION}" - Environment="RKE2_TOKEN=${CLUSTER_TOKEN}" - ExecStart=/usr/local/bin/rke2_installer.sh - RemainAfterExit=yes - KillMode=process - ExecStartPost=/bin/sh -c "systemctl enable --now rke2-server.service; systemctl start --no-block --now rke2-server.service" - # update path in exec start post to include rke2 bin path - ExecStartPost=/bin/sh -c "echo 'export KUBECONFIG=/etc/rancher/rke2/rke2.yaml' >> ~/.bashrc ; echo 'export PATH=${PATH}:/var/lib/rancher/rke2/bin' >> ~/.bashrc ; source ~/.bashrc" - # Load the proper modules for kube-vip lb to work - ExecStartPost=/bin/sh -c "[ -f /root/ipvs.conf ] && mv /root/ipvs.conf /etc/modules-load.d/ipvs.conf && restorecon -vR /etc/modules-load.d || true" - ExecStartPost=/bin/sh -c "[ -f /etc/modules-load.d/ipvs.conf ] && systemctl restart systemd-modules-load || true" - # Move the kube-vip file if exists - ExecStartPost=/bin/sh -c "mkdir -p /var/lib/rancher/rke2/server/manifests" - ExecStartPost=/bin/sh -c "[ -f /root/kube-vip.yaml ] && mv /root/kube-vip.yaml /var/lib/rancher/rke2/server/manifests/kube-vip.yaml || true" - ExecStartPost=/bin/sh -c "[ -f /var/lib/rancher/rke2/server/manifests/kube-vip.yaml ] && chcon -t container_var_lib_t /var/lib/rancher/rke2/server/manifests/kube-vip.yaml || true" - # Disable & delete everything - ExecStartPost=rm -f /usr/local/bin/rke2_installer.sh - ExecStartPost=/bin/sh -c "systemctl disable rke2_installer" - ExecStartPost=rm -f /etc/systemd/system/rke2_installer.service - - [Install] - WantedBy=multi-user.target - EOF - - # RKE2 doesn't suport INSTALL_RKE2_EXEC it seems... but a systemd override works - if [[ "${INSTALL_CLUSTER_EXEC}" == "server*" ]]; then - TYPE="server" - else - TYPE="agent" - fi - mkdir -p /etc/systemd/system/rke2-${TYPE}.service.d/ - cat <<- EOF > /etc/systemd/system/rke2-${TYPE}.service.d/override.conf - [Service] - ExecStart= - ExecStart=/opt/rke2/bin/rke2 ${INSTALL_CLUSTER_EXEC} - EOF - - systemctl enable rke2_installer.service -fi diff --git a/slemicro/combustion/03_rancher.sh b/slemicro/combustion/03_rancher.sh deleted file mode 100755 index 62c0218..0000000 --- a/slemicro/combustion/03_rancher.sh +++ /dev/null @@ -1,99 +0,0 @@ -#!/bin/bash -set -euo pipefail - -# Rancher -if [ "${RANCHERFLAVOR}" != false ]; then - # Mount /usr/local to store the rancher install script - mount /usr/local || true - - # Download helm as required to install rancher - curl -fsSL https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 |bash - - CMVERSION=${CERTMANAGERVERSION} - if [ "$${q}{CMVERSION}" == "latest" ]; then - # Using this awk & tr thing to avoid installing jq for just this - CMVERSION=$(curl -s "https://api.github.com/repos/cert-manager/cert-manager/releases/latest" | awk '/tag_name/ { print $2 }' | tr -d '",') - fi - - # Create a script to install rancher that will be called via a systemd service - # See https://stackoverflow.com/a/61259844 for the reason about ${q} :) - cat <<- EOF > /usr/local/bin/rancher_installer.sh - #!/bin/bash - set -euo pipefail - # Wait for cluster to be available - until [ -f ${KUBECONFIG} ]; do sleep 2; done - # export the kubeconfig using the right kubeconfig path depending on the cluster (k3s or rke2) - export KUBECONFIG=${KUBECONFIG} - # Wait for the node to be available, meaning the K8s API is available - while ! ${KUBECTL} wait --for condition=ready node $(cat /etc/hostname | tr '[:upper:]' '[:lower:]') --timeout=60s; do sleep 2 ; done - # https://ranchermanager.docs.rancher.com/pages-for-subheaders/install-upgrade-on-a-kubernetes-cluster - case ${RANCHERFLAVOR} in - "latest" | "stable" | "alpha") - helm repo add rancher https://releases.rancher.com/server-charts/${RANCHERFLAVOR} - ;; - "prime") - helm repo add rancher https://charts.rancher.com/server-charts/prime - ;; - *) - echo "Rancher flavor not detected, using latest" - helm repo add rancher https://releases.rancher.com/server-charts/latest - ;; - esac - - helm repo add jetstack https://charts.jetstack.io - helm repo update - - # Install the cert-manager Helm chart - helm install cert-manager jetstack/cert-manager \ - --namespace cert-manager \ - --create-namespace \ - --set installCRDs=true \ - --version $${q}{CMVERSION} - - # https://github.com/rancher/rke2/issues/3958 - if [ "${CLUSTER}" == "rke2" ]; then - # Wait for the rke2-ingress-nginx-controller DS to be available if using RKE2 - while ! ${KUBECTL} rollout status daemonset -n kube-system rke2-ingress-nginx-controller --timeout=60s; do sleep 2 ; done - fi - - # Install rancher using sslip.io as hostname and with just a single replica - helm install rancher rancher/rancher \ - --namespace cattle-system \ - --create-namespace \ - --set hostname=rancher-$(hostname -I | awk '{print $1}').sslip.io \ - --set bootstrapPassword=${RANCHERBOOTSTRAPPASSWORD} \ - --set replicas=1 \ - --set global.cattle.psp.enabled=false - - rm -f /etc/systemd/system/rancher_installer.service - EOF - - chmod a+x /usr/local/bin/rancher_installer.sh - - # Create a systemd unit to install rancher once - # Using "User=root" is required for some environment variables to be present - cat <<- EOF > /etc/systemd/system/rancher_installer.service - [Unit] - Description=Deploy Rancher on K3S/RKE2 - Wants=network-online.target - After=network.target network-online.target ${CLUSTER_INSTALL_SERVICE} - ConditionPathExists=/usr/local/bin/rancher_installer.sh - - [Service] - User=root - Type=forking - TimeoutStartSec=900 - ExecStart=/usr/local/bin/rancher_installer.sh - RemainAfterExit=yes - KillMode=process - # Disable & delete everything - ExecStartPost=rm -f /usr/local/bin/rancher_installer.sh - ExecStartPost=/bin/sh -c "systemctl disable rancher_installer.service" - ExecStartPost=rm -f /etc/systemd/system/rancher_installer.service - - [Install] - WantedBy=multi-user.target - EOF - - systemctl enable rancher_installer.service -fi \ No newline at end of file diff --git a/slemicro/combustion/04_elemental_register.sh b/slemicro/combustion/04_elemental_register.sh deleted file mode 100755 index 94a8d3d..0000000 --- a/slemicro/combustion/04_elemental_register.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/bash -set -euo pipefail - -if [ "${ELEMENTAL_REGISTER}" = true ]; then - # Install elemental-register and elemental-system-agent - # Dev version currently needed for new --no-toolkit option - zypper ar --refresh --no-gpgcheck https://download.opensuse.org/repositories/isv:/Rancher:/Elemental:/Dev/standard/isv:Rancher:Elemental:Dev.repo - zypper -n in elemental-register elemental-system-agent - mkdir -p /etc/elemental - cp ./elemental_config.yaml /etc/elemental/config.yaml - - # Register --no-toolkit disables OS management - elemental-register --config-path /etc/elemental/config.yaml --state-path /etc/elemental/state.yaml --install --no-toolkit --emulate-tpm --emulated-tpm-seed 99 - - # Enable elemental-system-agent - # On SLEMicro /var/lib is not persistent, so we copy elemental_connection.json in ExecStartPre - cp /var/lib/elemental/agent/elemental_connection.json /etc/rancher/elemental/agent - cat <<- EOF > /etc/systemd/system/elemental-system-agent.service -[Unit] -Description=Elemental System Agent -Documentation=https://github.com/rancher/system-agent -Wants=network-online.target -After=network-online.target -After=time-sync.target - -[Install] -WantedBy=multi-user.target -Alias=elemental-system-agent.service - -[Service] -Type=simple -Restart=always -RestartSec=5s -StandardOutput=journal+console -StandardError=journal+console -Environment="CATTLE_AGENT_CONFIG=/etc/rancher/elemental/agent/config.yaml" -Environment="CATTLE_LOGLEVEL=debug" -ExecStartPre=/bin/sh -c "mkdir -p /var/lib/elemental/agent && cp /etc/rancher/elemental/agent/elemental_connection.json /var/lib/elemental/agent" -ExecStart=/usr/sbin/elemental-system-agent sentinel -EOF - systemctl enable elemental-system-agent.service || true -fi diff --git a/slemicro/combustion/04_rancher_bootstrap.sh b/slemicro/combustion/04_rancher_bootstrap.sh deleted file mode 100755 index 9b81ee4..0000000 --- a/slemicro/combustion/04_rancher_bootstrap.sh +++ /dev/null @@ -1,70 +0,0 @@ -#!/bin/bash -set -euo pipefail - -# Bypass rancher bootstrap -if [ "${RANCHERBOOTSTRAPSKIP}" = true ]; then - # Mount /usr/local to store the rancher bootstrap skip script - mount /usr/local || true - - # Install jq - zypper --non-interactive install jq - - # Create a script that will skip all the rancher bootstrap steps - # See https://stackoverflow.com/a/61259844 for the reason about ${q} :) - cat <<- "EOF" > /usr/local/bin/skip-rancher-bootstrap.sh - #!/bin/bash - set -euo pipefail - HOST="https://rancher-$(hostname -I | awk '{print $1}').sslip.io" - # export the kubeconfig using the right kubeconfig path depending on the cluster (k3s or rke2) - export KUBECONFIG=${KUBECONFIG} - while ! ${KUBECTL} wait --for condition=ready -n cattle-system $(${KUBECTL} get pods -n cattle-system -l app=rancher -o name) --timeout=10s; do sleep 2 ; done - - # https://github.com/rancher/rke2/issues/3958 - if [ "${CLUSTER}" == "rke2" ]; then - # Wait for the rke2-ingress-nginx-controller DS to be available if using RKE2 - while ! ${KUBECTL} rollout status daemonset -n kube-system rke2-ingress-nginx-controller --timeout=60s; do sleep 2 ; done - fi - - # Get token - # The double (!) dollar sign is because envsubst _removes_ the first one, then the extra one is for the 'EOF' - TOKEN=$(curl -sk -X POST $${q}{HOST}/v3-public/localProviders/local?action=login -H 'content-type: application/json' -d '{"username":"admin","password":"${RANCHERBOOTSTRAPPASSWORD}"}' | jq -r .token) - - # Set password - curl -sk $${q}{HOST}/v3/users?action=changepassword -H 'content-type: application/json' -H "Authorization: Bearer $${q}TOKEN" -d '{"currentPassword":"${RANCHERBOOTSTRAPPASSWORD}","newPassword":"${RANCHERFINALPASSWORD}"}' - - # Create a temporary API token (ttl=60 minutes) - APITOKEN=$(curl -sk $${q}{HOST}/v3/token -H 'content-type: application/json' -H "Authorization: Bearer $${q}{TOKEN}" -d '{"type":"token","description":"automation","ttl":3600000}' | jq -r .token) - - curl -sk $${q}{HOST}/v3/settings/server-url -H 'content-type: application/json' -H "Authorization: Bearer $${q}{APITOKEN}" -X PUT -d "{\"name\":\"server-url\",\"value\":\"$${q}{HOST}\"}" - curl -sk $${q}{HOST}/v3/settings/telemetry-opt -X PUT -H 'content-type: application/json' -H 'accept: application/json' -H "Authorization: Bearer $${q}{APITOKEN}" -d '{"value":"out"}' - EOF - - chmod a+x /usr/local/bin/skip-rancher-bootstrap.sh - - # Create a systemd unit to run the steps after rancher has been installed - # Using "User=root" is required for some environment variables to be present - cat <<- EOF > /etc/systemd/system/skip-rancher-bootstrap.service - [Unit] - Description=Skip Rancher Bootstrap - Wants=network-online.target - After=network.target network-online.target rancher_installer.service - ConditionPathExists=/usr/local/bin/skip-rancher-bootstrap.sh - - [Service] - User=root - Type=forking - TimeoutStartSec=900 - ExecStart=/usr/local/bin/skip-rancher-bootstrap.sh - RemainAfterExit=yes - KillMode=process - # Disable & delete everything - ExecStartPost=rm -f /usr/local/bin/skip-rancher-bootstrap.sh - ExecStartPost=/bin/sh -c "systemctl disable skip-rancher-bootstrap.service" - ExecStartPost=rm -f /etc/systemd/system/skip-rancher-bootstrap.service - - [Install] - WantedBy=multi-user.target - EOF - - systemctl enable skip-rancher-bootstrap.service -fi \ No newline at end of file diff --git a/slemicro/combustion/05_install_qemu_guest_agent.sh b/slemicro/combustion/05_install_qemu_guest_agent.sh deleted file mode 100644 index f76ab45..0000000 --- a/slemicro/combustion/05_install_qemu_guest_agent.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash -set -euo pipefail - -# Installing qemu-guest-agent service -if [ "${QEMUGUESTAGENT}" = true ]; then - zypper --non-interactive install qemu-guest-agent - systemctl enable qemu-guest-agent -fi diff --git a/slemicro/combustion/09_cockpit.sh b/slemicro/combustion/09_cockpit.sh deleted file mode 100755 index 012d227..0000000 --- a/slemicro/combustion/09_cockpit.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash -set -euo pipefail - -# Cockpit -if [ "${COCKPIT}" = true ]; then - systemctl enable cockpit.socket -fi diff --git a/slemicro/combustion/09_extra_marker.sh b/slemicro/combustion/09_extra_marker.sh deleted file mode 100755 index c2559f7..0000000 --- a/slemicro/combustion/09_extra_marker.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -set -euo pipefail -# Leave a marker -echo "Configured with combustion" >> /etc/issue.d/combustion \ No newline at end of file diff --git a/slemicro/combustion/09_podman.sh b/slemicro/combustion/09_podman.sh deleted file mode 100755 index a06112d..0000000 --- a/slemicro/combustion/09_podman.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash -set -euo pipefail - -# Podman -if [ "${PODMAN}" = true ]; then - systemctl enable podman.service podman.socket -fi diff --git a/slemicro/combustion/09_ssh_key.sh b/slemicro/combustion/09_ssh_key.sh deleted file mode 100755 index a5a01c6..0000000 --- a/slemicro/combustion/09_ssh_key.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash -set -euo pipefail - -# SSH key management -if [ "${SSHCONFIG}" = true ]; then - mkdir -pm700 /root/.ssh/ - echo "${SSHCONTENT}" >> /root/.ssh/authorized_keys -fi \ No newline at end of file diff --git a/slemicro/combustion/99_update_and_reboot.sh b/slemicro/combustion/99_update_and_reboot.sh deleted file mode 100755 index 9d9c86e..0000000 --- a/slemicro/combustion/99_update_and_reboot.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash -set -euo pipefail - -# Update and reboot as required by transactional-update -if [ "${UPDATEANDREBOOT}" = true ]; then - cat <<- EOF > /etc/systemd/system/update-and-reboot.service - [Unit] - Description=Reboot if required once - Wants=network-online.target - # If services doesn't exist is ok - After=network.target network-online.target ${CLUSTER_INSTALL_SERVICE} rancher_installer.service skip-rancher-bootstrap.service elemental_installer.service - [Service] - User=root - # Run this service the last one - Type=oneshot - ExecStart=transactional-update - ExecStartPost=/bin/sh -c "systemctl disable update-and-reboot.service" - ExecStartPost=rm -f /etc/systemd/system/update-and-reboot.service - ExecStartPost=reboot - RemainAfterExit=yes - # Long timeout just in case - TimeoutSec=3600 - [Install] - WantedBy=multi-user.target - EOF - systemctl enable update-and-reboot.service -fi \ No newline at end of file diff --git a/slemicro/combustion/README.md b/slemicro/combustion/README.md deleted file mode 100644 index ce6bc5f..0000000 --- a/slemicro/combustion/README.md +++ /dev/null @@ -1,68 +0,0 @@ -# Using combustion - -The script here runs all the scripts in order where the script name needs to be `??_*.sh` - -The execution of scripts is wrapped via tukit so the usual way doesn't work: - -```bash -for i in ./*.sh; do - ${i} -done -``` - -That's why they are copied and then appended to the `script` file. - -## How to add a new script - -The procedure is really straightforward. You just need to drop the script in this folder and it will be used at combustion phase. The order can be explicitely be set with the script name `??_foobar.sh` - -> Bear in mind that for limitations of the iso9660 filesystem, the filename will be trimmed if > 32 characters long. See https://en.wikipedia.org/wiki/ISO_9660#Directories_and_files for more information. - -### Considerations - -* The combustion procedure happens at initrd timing... and unfortunately there is not much there, so you need to be a little bit creative. A usual _trick_ is to create a script that performs the deployment of the feature itself and then a systemd unit that executes that script. The systemd unit is a regular systemd unit and it will be executed at boot time. Something like: - -``` -cat <<- "EOF" > /usr/local/bin/myawesomefeature-installer.sh -#!/bin/bash -set -euo pipefail -# do whatever is needed -EOF - -chmod a+x /usr/local/bin/myawesomefeature-installer.sh - -cat <<- EOF > /etc/systemd/system/myaweseomefeature-installer.service -[Unit] -Description=Run my awesome feature -Wants=network-online.target -After=network.target network-online.target -ConditionPathExists=/usr/local/bin/myawesomefeature-installer.sh -ConditionPathExists=!/usr/local/bin/myawesomefeature - -[Service] -User=root -Type=forking -TimeoutStartSec=600 -Environment="FOO=bar" -ExecStart=/usr/local/bin/myawesomefeature-installer.sh -RemainAfterExit=yes -KillMode=process -# Disable & delete everything -ExecStartPost=rm -f /usr/local/bin/myawesomefeature-installer.sh -ExecStartPost=/bin/sh -c "systemctl disable myaweseomefeature-installer" -ExecStartPost=rm -f /etc/systemd/system/myaweseomefeature-installer.service - -[Install] -WantedBy=multi-user.target -EOF - -systemctl enable myawesomefeature-installer.service -``` - -* If you want to be able to enable/disable the feature or the script content, you can use an if at the beginning of the script as: - -``` -if [ "${MYAWESOMEFEATURE}" == true ]; then - # Do what was explained above -fi -``` diff --git a/slemicro/combustion/script b/slemicro/combustion/script deleted file mode 100644 index 6458a00..0000000 --- a/slemicro/combustion/script +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash -# combustion: network -set -euo pipefail - -# Redirect output to the console -exec > >(exec tee -a /dev/tty0) 2>&1 - -cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 - -# Set hostname -echo "${VMNAME}" > /etc/hostname -hostname "${VMNAME}" - -# After this, the other scripts will be appended diff --git a/slemicro/common.sh b/slemicro/common.sh index 93c5498..95278a9 100755 --- a/slemicro/common.sh +++ b/slemicro/common.sh @@ -6,6 +6,149 @@ die(){ exit ${2} } +check_os(){ + if [ $(uname -o) == "Darwin" ]; then + # Check if UTM version is 4.2.2 (required for the scripting part) + ver(){ printf "%03d%03d%03d%03d" $(echo "$1" | tr '.' ' '); } + UTMVERSION=$(/usr/libexec/plistbuddy -c Print:CFBundleShortVersionString: /Applications/UTM.app/Contents/info.plist) + if [ $(ver ${UTMVERSION}) -lt $(ver 4.2.2) ]; then + die "UTM version >= 4.2.2 required" 2 + fi + elif [ $(uname -o) == "GNU/Linux" ]; then + command -v virt-install > /dev/null 2>&1 || die "virt-install command not found" 2 + else + die "Unsupported operating system" 2 + fi +} + +create_image_file(){ + # Create the image file + mkdir -p ${VMFOLDER} + qemu-img convert -O qcow2 ${IMAGE} ${VMFOLDER}/${VMNAME}.qcow2 + +} + +create_extra_disks(){ + if [ "${EXTRADISKS}" != false ]; then + DISKARRAY=(${EXTRADISKS//,/ }) + for (( i=0; i<"${#DISKARRAY[@]}"; i++ )); do + qemu-img create -f qcow2 ${VMFOLDER}/${VMNAME}-extra-disk-${i}.qcow2 "${DISKARRAY[$i]}"G > /dev/null + done + fi +} + +create_vm(){ + if [ $(uname -o) == "Darwin" ]; then + # See if there are extra disks to be created + UTMEXTRADISKS="" + UTMEXTRADISKMAPPING="" + if [ "${EXTRADISKS}" != false ]; then + # Probably not needed + DISKARRAY=(${EXTRADISKS//,/ }) + for (( i=0; i<"${#DISKARRAY[@]}"; i++ )); do + UTMEXTRADISKS="${UTMEXTRADISKS} + set extradisk${i} to POSIX file \"${VMFOLDER}/${VMNAME}-extra-disk-${i}.qcow2\"" + UTMEXTRADISKMAPPING="${UTMEXTRADISKMAPPING}, {removable:false, source:extradisk${i}}" + done + fi + + # If there are not extra disks, this works as well + UTMDISKMAPPING="{removable:false, source:rootfs}${UTMEXTRADISKMAPPING}}" + + # Create the VM + OUTPUT=$(osascript <<-END + tell application "UTM" + -- specify the RAW file + set rootfs to POSIX file "${VMFOLDER}/${VMNAME}.qcow2" + -- specify extra disks + ${UTMEXTRADISKS} + --- create a new QEMU VM + set vm to make new virtual machine with properties {backend:qemu, configuration:{cpu cores:${CPUS}, memory: ${MEMORY}, name:"${VMNAME}", network interfaces:{{hardware:"virtio-net-pci", mode:shared, index:0, address:"${MACADDRESS}", port forwards:{}, host interface:""}}, architecture:"aarch64", drives:${UTMDISKMAPPING}} + start vm + repeat + if status of vm is started then exit repeat + end repeat + get address of first serial port of vm + end tell + END + ) + + echo "VM ${VMNAME} started. You can connect to the serial terminal as: screen ${OUTPUT}" + + VMMAC=$(echo ${MACADDRESS} | sed 's/0\([0-9A-Fa-f]\)/\1/g') + timeout=180 + count=0 + echo -n "Waiting for IP: " + until grep -q -i "${VMMAC}" -B1 -m1 /var/db/dhcpd_leases | head -1 | awk -F= '{ print $2 }'; do + count=$((count + 1)) + if [[ ${count} -ge ${timeout} ]]; then + break + fi + sleep 1 + echo -n "." + done + VMIP=$(grep -i "${VMMAC}" -B1 -m1 /var/db/dhcpd_leases | head -1 | awk -F= '{ print $2 }') + elif [ $(uname -o) == "GNU/Linux" ]; then + # By default virt-install powers off the VM when rebooted once. + # As a workaround, create the VM definition, change the on_reboot behaviour + # and start the VM + # See https://bugzilla.redhat.com/show_bug.cgi?id=1792411 for the print-xml 1 reason :) + # The following ones are perhaps useful: + # --rng /dev/urandom + # --tpm backend.type=emulator,backend.version=2.0 + VIRTFILE=$(mktemp) + virt-install --name ${VMNAME} \ + --noautoconsole \ + --memory ${MEMORY} \ + --vcpus ${CPUS} \ + --disk ${LIBVIRT_DISK_SETTINGS},path=${VMFOLDER}/${VMNAME}.qcow2 \ + --import \ + --network network=${VM_NETWORK},model=virtio,mac=${MACADDRESS} \ + --osinfo detect=on,name=sle-unknown \ + --sound none \ + --boot uefi \ + --print-xml 1 > ${VIRTFILE} + sed -i -e 's#destroy#restart#g' ${VIRTFILE} + virsh define ${VIRTFILE} + virsh start ${VMNAME} + rm -f ${VIRTFILE} + echo "VM ${VMNAME} started. You can connect to the serial terminal as: virsh console ${VMNAME}" + echo -n "Waiting for IP..." + timeout=180 + count=0 + VMIP="" + while [ -z "${VMIP}" ]; do + sleep 1 + count=$((count + 1)) + if [[ ${count} -ge ${timeout} ]]; then + break + fi + echo -n "." + VMIP=$(vm_ip ${VMNAME}) + done + else + die "VM not deployed. Unsupported operating system" 2 + fi +} + +generate_mac(){ + # The fixed OUI prefix for QEMU/KVM + MAC_PREFIX="52:54:00" + + # Generate 3 random octets (6 hexadecimal characters) + # We use /dev/urandom for better randomness, convert to hex, and take the first 6 characters + random_suffix=$(head /dev/urandom | tr -dc '0-9a-f' | head -c 6) + + # Format the suffix into colon-separated pairs + MAC_SUFFIX=$(printf '%s:%s:%s' \ + "${random_suffix:0:2}" \ + "${random_suffix:2:2}" \ + "${random_suffix:4:2}") + + # Combine prefix and suffix + echo "${MAC_PREFIX}:${MAC_SUFFIX}" +} + vm_ip(){ if [ $(uname -o) == "Darwin" ]; then # Check if UTM version is 4.2.2 (required for the scripting part) diff --git a/slemicro/create_eib.sh b/slemicro/create_eib.sh new file mode 100755 index 0000000..e54a4d7 --- /dev/null +++ b/slemicro/create_eib.sh @@ -0,0 +1,107 @@ +#!/usr/bin/env bash +set -euo pipefail +BASEDIR="$(dirname "$0")" +source ${BASEDIR}/common.sh + +usage(){ + cat <<-EOF + Usage: ${0} [-f ] [-e ] [-n ] + EOF +} + +ENVFILE="" +EIBFOLDER="" + +while getopts 'f:e:n:h' OPTION; do + case "${OPTION}" in + f) + [ -f "${OPTARG}" ] && ENVFILE="${OPTARG}" || die "Parameters file ${OPTARG} not found" 2 + ;; + e) + [ -d "${OPTARG}" ] && EIBFOLDER="$(readlink -f ${OPTARG})" || die "EIB folder ${OPTARG} not found" 2 + ;; + n) + NAMEOPTION="${OPTARG}" + ;; + h) + usage && exit 0 + ;; + ?) + usage && exit 2 + ;; + esac +done + +[ -z "${ENVFILE}" ] && { usage && die "\"-f \" required" 2;} +[ -z "${EIBFOLDER}" ] && { usage && die "\"-e \" required" 2;} + +set -a +# Get the env file +source ${ENVFILE:-${BASEDIR}/.env} +# Some defaults just in case +CPUS="${CPUS:-2}" +MEMORY="${MEMORY:-2048}" +VMNAME="${NAMEOPTION:-${VMNAME:-slemicro}}" +MACADDRESS="${MACADDRESS:-null}" +VM_STATIC_IP=${VM_STATIC_IP:-} +VM_STATIC_PREFIX=${VM_STATIC_PREFIX:-24} +VM_STATIC_GATEWAY=${VM_STATIC_GATEWAY:-"192.168.122.1"} +VM_STATIC_DNS=${VM_STATIC_DNS:-${VM_STATIC_GATEWAY}} +EXTRADISKS="${EXTRADISKS:-false}" +VM_NETWORK=${VM_NETWORK:-default} +EIB_IMAGE="${EIB_IMAGE:-registry.suse.com/edge/3.3/edge-image-builder:1.2.1}" +LIBVIRT_DISK_SETTINGS="${LIBVIRT_DISK_SETTINGS:-bus=virtio}" +set +a + +check_os + +# Check if the commands required exist +command -v podman > /dev/null 2>&1 || die "podman not found" 2 +command -v qemu-img > /dev/null 2>&1 || die "qemu-img not found" 2 +command -v yq > /dev/null 2>&1 || die "yq not found" 2 + +# Check if the EIB definition file exist +[ -f ${EIBFOLDER}/eib.yaml ] || die "EIB definition file \"${EIBFOLDER}/eib.yaml\" not found" 2 + +# Check if the network config file exist +if ! [[ -f "${EIBFOLDER}/network/${VMNAME}.yaml" || -f "${EIBFOLDER}/network/_all.yaml" ]]; then + # For some scenarios this may not be needed + echo "Warning: Network definition file for ${VMNAME} \"${EIBFOLDER}/network/${VMNAME}.yaml\" nor \"${EIBFOLDER}/network/_all.yaml\" found" +fi + +# Check if it matches the EIB definition +if [ -f ${EIBFOLDER}/network/${VMNAME}.yaml ]; then + EIBMACADDRESS=$(cat ${EIBFOLDER}/network/${VMNAME}.yaml | yq -r ".interfaces[0].mac-address") + if [ ${EIBMACADDRESS} == "null" ]; then + echo "Info: Network definition file for ${VMNAME}, \"${EIBFOLDER}/network/${VMNAME}.yaml\", doesn't contain a mac-address, a random one will be created" + MACADDRESS=$(generate_mac) + fi + if [ ${EIBMACADDRESS} != "${MACADDRESS}" ]; then + echo "Warning: Network definition file for ${VMNAME}, \"${EIBFOLDER}/network/${VMNAME}.yaml\", mac-address ${EIBMACADDRESS} is different than the env var ${MACADDRESS}, using the \"${EIBFOLDER}/network/${VMNAME}.yaml\" one" + MACADDRESS="${EIBMACADDRESS}" + fi +fi + +# Just in case +[ ${MACADDRESS} == "null" ] && MACADDRESS=$(generate_mac) + +# Only check podman machine on non linux OSes +if [ $(uname -o) != "GNU/Linux" ]; then + # Check podman-machine-default specs and warn the user + PODMANMACHINESPECS=$(podman machine inspect podman-machine-default) + PODMANMACHINECPU=$(echo ${PODMANMACHINESPECS} | yq -r ".[0].Resources.CPUs") + PODMANMACHINEMEMORY=$(echo ${PODMANMACHINESPECS} | yq -r ".[0].Resources.Memory") + + [ ${PODMANMACHINECPU} -lt 4 ] && echo "Warning: Podman machine number of CPUs is too low for the EIB RPM resolution process to work, consider increasing them to at least 4 (see podman machine set --help)" + [ ${PODMANMACHINEMEMORY} -lt 4096 ] && echo "Warning: Podman machine memory is too low for the EIB RPM resolution process to work, consider increasing it to at least 4096 MB (see podman machine set --help)" +fi + +# Do the EIB thing +podman run --rm -it --privileged -v ${EIBFOLDER}:/eib \ + ${EIB_IMAGE} \ + build --definition-file eib.yaml + +OUTPUTNAME=$(cat ${EIBFOLDER}/eib.yaml | yq -r .image.outputImageName) +IMAGE="${EIBFOLDER}/${OUTPUTNAME}" + +exit 0 diff --git a/slemicro/create_vm.sh b/slemicro/create_vm.sh deleted file mode 100755 index 26198d7..0000000 --- a/slemicro/create_vm.sh +++ /dev/null @@ -1,297 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -source common.sh - -usage(){ - cat <<-EOF - Usage: ${0} [-f ] [-n ] - EOF -} - -while getopts 'f:n:h' OPTION; do - case "${OPTION}" in - f) - [ -f "${OPTARG}" ] && ENVFILE="${OPTARG}" || die "Parameters file ${OPTARG} not found" 2 - ;; - n) - NAMEOPTION="${OPTARG}" - ;; - h) - usage && exit 0 - ;; - ?) - usage && exit 2 - ;; - esac -done - -set -a -# Get the env file -source ${ENVFILE:-${BASEDIR}/.env} -# Some defaults just in case -CPUS="${CPUS:-2}" -MEMORY="${MEMORY:-2048}" -DISKSIZE="${DISKSIZE:-30}" -SSHPUB="${SSHPUB:-${HOME}/.ssh/id_rsa.pub}" -VMNAME="${NAMEOPTION:-${VMNAME:-slemicro}}" -VM_STATIC_IP=${VM_STATIC_IP:-} -VM_STATIC_PREFIX=${VM_STATIC_PREFIX:-24} -VM_STATIC_GATEWAY=${VM_STATIC_GATEWAY:-"192.168.122.1"} -VM_STATIC_DNS=${VM_STATIC_DNS:-${VM_STATIC_GATEWAY}} -REGISTER="${REGISTER:-false}" -CERTMANAGERVERSION="${CERTMANAGERVERSION:-latest}" -RANCHERBOOTSTRAPSKIP="${RANCHERBOOTSTRAPSKIP:-false}" -CLUSTER="${CLUSTER:-false}" -COCKPIT="${COCKPIT:-false}" -RANCHERFLAVOR="${RANCHERFLAVOR:-false}" -UPDATEANDREBOOT="${UPDATEANDREBOOT:-false}" -QEMUGUESTAGENT="${QEMUGUESTAGENT:-false}" -DISABLEIPV6="${DISABLEIPV6:-true}" -EXTRADISKS="${EXTRADISKS:-false}" -VM_NETWORK=${VM_NETWORK:-default} -REBOOTMGR="${REBOOTMGR:-false}" -TRANSACTIONALUPDATES="${TRANSACTIONALUPDATES:-false}" -ELEMENTAL_REGISTER=${ELEMENTAL_REGISTER:-} -ELEMENTAL_CONFIG=${ELEMENTAL_CONFIG:-} -set +a - -if [ $(uname -o) == "Darwin" ]; then - # Check if UTM version is 4.2.2 (required for the scripting part) - ver(){ printf "%03d%03d%03d%03d" $(echo "$1" | tr '.' ' '); } - UTMVERSION=$(/usr/libexec/plistbuddy -c Print:CFBundleShortVersionString: /Applications/UTM.app/Contents/info.plist) - [ $(ver ${UTMVERSION}) -lt $(ver 4.2.2) ] && die "UTM version >= 4.2.2 required" 2 -elif [ $(uname -o) == "GNU/Linux" ]; then - command -v virt-install > /dev/null 2>&1 || die "virt-install command not found" 2 -else - die "Unsupported operating system" 2 -fi - -# Check if the commands required exist -command -v butane > /dev/null 2>&1 || die "butane not found" 2 -command -v mkisofs > /dev/null 2>&1 || die "mkisofs not found" 2 -command -v qemu-img > /dev/null 2>&1 || die "qemu-img not found" 2 - -# Check if the SLEMicro image exist -[ -f ${SLEMICROFILE} ] || die "SLE Micro image file not found" 2 - -# Check if REGISTER is enabled or not -if [ "${REGISTER}" == true ]; then - # Check if EMAIL and REGCODE variables are empty - [ -z "${EMAIL}" ] && die "EMAIL variable not found" 2 - [ -z "${REGCODE}" ] && die "REGCODE variable not found" 2 -fi - -# Bootstraping rancher requires a few things -if [ "${RANCHERBOOTSTRAPSKIP}" == true ]; then - # Bootstrapskip requires installing jq... hence registering :( - if [ "${REGISTER}" == false ]; then - die "RANCHERBOOTSTRAPSKIP requires REGISTER" 3 - fi - # Check if RANCHERFINALPASSWORD exist - if [[ -n "${RANCHERFINALPASSWORD}" && ${#RANCHERFINALPASSWORD} -lt 12 ]]; then - die "RANCHERFINALPASSWORD variable needs to be >12 characters long" 3 - fi -fi - -# qemu-guest-agent requires register as well -if [ "${REGISTER}" == false ] && [ "${QEMUGUESTAGENT}" == true ]; then - die "QEMUGUESTAGENT requires REGISTER" 3 -fi - -# Check if cluster installation to set correct path to kubeconfig and kubectl -case ${CLUSTER} in - "k3s") - export KUBECONFIG=/etc/rancher/k3s/k3s.yaml - export KUBECTL=/usr/local/bin/kubectl - export CLUSTER_INSTALL_SERVICE=k3s_installer.service - ;; - "rke2") - export KUBECONFIG=/etc/rancher/rke2/rke2.yaml - export KUBECTL=/var/lib/rancher/rke2/bin/kubectl - export CLUSTER_INSTALL_SERVICE=rke2_installer.service - ;; - false) - ;; - *) - die "CLUSTER variable not supported" 2 - ;; -esac - -# Create the image file -mkdir -p ${VMFOLDER} -cp ${SLEMICROFILE} ${VMFOLDER}/${VMNAME}.raw -qemu-img resize -f raw ${VMFOLDER}/${VMNAME}.raw ${DISKSIZE}G > /dev/null - -if [ "${EXTRADISKS}" != false ]; then - DISKARRAY=(${EXTRADISKS//,/ }) - for (( i=0; i<"${#DISKARRAY[@]}"; i++ )); do - qemu-img create -f raw ${VMFOLDER}/${VMNAME}-extra-disk-${i}.raw "${DISKARRAY[$i]}"G > /dev/null - done -fi - -# Create a temp dir to host the assets -TMPDIR=$(mktemp -d) - -# Create required folders -mkdir -p ${TMPDIR}/{combustion,ignition} - -# If the butane file exists -if [ -f ${BASEDIR}/butane/config.fcc ]; then - # Convert the config.fcc yaml file to ignition - butane -p -o ${TMPDIR}/ignition/config.ign ${BASEDIR}/butane/config.fcc -fi - -# If the ignition file exists -if [ -f ${BASEDIR}/ignition/config.ign ]; then - # Copy it to the final iso destination - cp ${BASEDIR}/ignition/config.ign ${TMPDIR}/ignition/config.ign -fi - -# If the combustion script exists -if [ -f ${BASEDIR}/combustion/script ]; then - # If a SSH key has been set, copy it as well - if [ ! -z "${SSHPUB}" ] && [ -f "${SSHPUB}" ]; then - export SSHCONFIG=true - export SSHCONTENT=$(cat ${SSHPUB}) - fi - - # Parse the file and copy it to the final ISO - envsubst < ${BASEDIR}/combustion/script > ${TMPDIR}/combustion/script - - if [ ! -z "${ELEMENTAL_CONFIG}" ]; then - cp ${ELEMENTAL_CONFIG} ${TMPDIR}/combustion/elemental_config.yaml - fi - - # Copy all combustion related files to the final iso destination parsing the vars - if ls ${BASEDIR}/combustion/*.sh >/dev/null 2>&1; then - for file in ${BASEDIR}/combustion/*.sh; do - FILENAME=$(basename ${file}) - envsubst < ${file} > ${TMPDIR}/combustion/${FILENAME} - chmod a+x ${TMPDIR}/combustion/${FILENAME} - echo "./${FILENAME}" >> ${TMPDIR}/combustion/script - done - fi -fi - -# Create an iso -mkisofs -quiet -full-iso9660-filenames -o ${VMFOLDER}/ignition-and-combustion-${VMNAME}.iso -V ignition ${TMPDIR} - -# Remove leftovers -rm -Rf ${TMPDIR} - -# if x86_64, convert the image to qcow2 -if [ $(uname -o) == "Darwin" ]; then - - # See if there are extra disks to be created - UTMEXTRADISKS="" - UTMEXTRADISKMAPPING="" - if [ "${EXTRADISKS}" != false ]; then - # Probably not needed - DISKARRAY=(${EXTRADISKS//,/ }) - for (( i=0; i<"${#DISKARRAY[@]}"; i++ )); do - UTMEXTRADISKS="${UTMEXTRADISKS} - set extradisk${i} to POSIX file \"${VMFOLDER}/${VMNAME}-extra-disk-${i}.raw\"" - UTMEXTRADISKMAPPING="${UTMEXTRADISKMAPPING}, {removable:false, source:extradisk${i}}" - done - fi - - # If there are not extra disks, this works as well - UTMDISKMAPPING="{{removable:true, source:iso}, {removable:false, source:rawfile}${UTMEXTRADISKMAPPING}}" - - # Create and launch the VM using UTM - OUTPUT=$(osascript <<-END - tell application "UTM" - --- specify a boot ISO - set iso to POSIX file "${VMFOLDER}/ignition-and-combustion-${VMNAME}.iso" - -- specify the RAW file - set rawfile to POSIX file "${VMFOLDER}/${VMNAME}.raw" - -- specify extra disks - ${UTMEXTRADISKS} - --- create a new QEMU VM - set vm to make new virtual machine with properties {backend:qemu, configuration:{cpu cores:${CPUS}, memory: ${MEMORY}, name:"${VMNAME}", architecture:"aarch64", drives:${UTMDISKMAPPING}}} - start vm - repeat - if status of vm is started then exit repeat - end repeat - get address of first serial port of vm - end tell - END - ) - - echo "VM ${VMNAME} started. You can connect to the serial terminal as: screen ${OUTPUT}" - - OUTPUT=$(osascript <<-END - tell application "UTM" - set vm to virtual machine named "${VMNAME}" - set config to configuration of vm - get address of item 1 of network interfaces of config - end tell - END - ) - - VMMAC=$(echo $OUTPUT | sed 's/0\([0-9A-Fa-f]\)/\1/g') - - timeout=180 - count=0 - - echo -n "Waiting for IP: " - until grep -q -i "${VMMAC}" -B1 -m1 /var/db/dhcpd_leases | head -1 | awk -F= '{ print $2 }'; do - count=$((count + 1)) - if [[ ${count} -ge ${timeout} ]]; then - break - fi - sleep 1 - echo -n "." - done - VMIP=$(grep -i "${VMMAC}" -B1 -m1 /var/db/dhcpd_leases | head -1 | awk -F= '{ print $2 }') -elif [ $(uname -o) == "GNU/Linux" ]; then - qemu-img convert -O qcow2 ${VMFOLDER}/${VMNAME}.raw ${VMFOLDER}/${VMNAME}.qcow2 - # The raw file is still there doing nothing - rm -f ${VMFOLDER}/${VMNAME}.raw - # Give libvirt group permissions for both the disk an the ISO - chmod 0664 ${VMFOLDER}/${VMNAME}.qcow2 ${VMFOLDER}/ignition-and-combustion-${VMNAME}.iso - chgrp libvirt ${VMFOLDER}/${VMNAME}.qcow2 ${VMFOLDER}/ignition-and-combustion-${VMNAME}.iso - # By default virt-install powers off the VM when rebooted once. - # As a workaround, create the VM definition, change the on_reboot behaviour - # and start the VM - # See https://bugzilla.redhat.com/show_bug.cgi?id=1792411 for the print-xml 1 reason :) - VIRTFILE=$(mktemp) - virt-install --name ${VMNAME} \ - --noautoconsole \ - --memory ${MEMORY} \ - --vcpus ${CPUS} \ - --disk ${VMFOLDER}/${VMNAME}.qcow2 \ - --import \ - --cdrom ${VMFOLDER}/ignition-and-combustion-${VMNAME}.iso \ - --network network=${VM_NETWORK} \ - --osinfo detect=on,name=sle-unknown \ - --print-xml 1 > ${VIRTFILE} - sed -i -e 's#destroy#restart#g' ${VIRTFILE} - virsh define ${VIRTFILE} - virsh start ${VMNAME} - rm -f ${VIRTFILE} - echo "VM ${VMNAME} started. You can connect to the serial terminal as: virsh console ${VMNAME}" - echo -n "Waiting for IP..." - timeout=180 - count=0 - VMIP="" - while [ -z "${VMIP}" ]; do - sleep 1 - count=$((count + 1)) - if [[ ${count} -ge ${timeout} ]]; then - break - fi - echo -n "." - VMIP=$(vm_ip ${VMNAME}) - done -else - die "VM not deployed. Unsupported operating system" 2 -fi - -printf "\nVM IP: ${VMIP}\n" -[ ${COCKPIT} = true ] && echo "Cockpit Web UI available at https://${VMIP}.sslip.io:9090" -[ ${RANCHERFLAVOR} != false ] && echo "After Rancher is installed, you can access the Web UI as https://rancher-${VMIP}.sslip.io" -[ ${UPDATEANDREBOOT} = true ] && echo "The VM will be updated and rebooted if required, it can take a while" - -exit 0 diff --git a/slemicro/create_vm_with_eib.sh b/slemicro/create_vm_with_eib.sh index c5262c7..7aa403e 100755 --- a/slemicro/create_vm_with_eib.sh +++ b/slemicro/create_vm_with_eib.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -euo pipefail - -source common.sh +BASEDIR="$(dirname "$0")" +source ${BASEDIR}/common.sh usage(){ cat <<-EOF @@ -49,19 +49,11 @@ VM_STATIC_GATEWAY=${VM_STATIC_GATEWAY:-"192.168.122.1"} VM_STATIC_DNS=${VM_STATIC_DNS:-${VM_STATIC_GATEWAY}} EXTRADISKS="${EXTRADISKS:-false}" VM_NETWORK=${VM_NETWORK:-default} -EIB_IMAGE="${EIB_IMAGE:-registry.suse.com/edge/3.2/edge-image-builder:1.1.0}" +EIB_IMAGE="${EIB_IMAGE:-registry.suse.com/edge/3.3/edge-image-builder:1.2.1}" +LIBVIRT_DISK_SETTINGS="${LIBVIRT_DISK_SETTINGS:-bus=virtio}" set +a -if [ $(uname -o) == "Darwin" ]; then - # Check if UTM version is 4.2.2 (required for the scripting part) - ver(){ printf "%03d%03d%03d%03d" $(echo "$1" | tr '.' ' '); } - UTMVERSION=$(/usr/libexec/plistbuddy -c Print:CFBundleShortVersionString: /Applications/UTM.app/Contents/info.plist) - [ $(ver ${UTMVERSION}) -lt $(ver 4.2.2) ] && die "UTM version >= 4.2.2 required" 2 -elif [ $(uname -o) == "GNU/Linux" ]; then - command -v virt-install > /dev/null 2>&1 || die "virt-install command not found" 2 -else - die "Unsupported operating system" 2 -fi +check_os # Check if the commands required exist command -v podman > /dev/null 2>&1 || die "podman not found" 2 @@ -80,16 +72,21 @@ fi # Check if the image file exist [ -f ${VMFOLDER}/${VMNAME}.qcow2 ] && die "Image file ${VMFOLDER}/${VMNAME}.qcow2 already exists" 2 -# Check if the MAC address has been set -[ "${MACADDRESS}" != "null" ] || die "MAC Address needs to be specified" 2 - # Check if it matches the EIB definition if [ -f ${EIBFOLDER}/network/${VMNAME}.yaml ]; then EIBMACADDRESS=$(cat ${EIBFOLDER}/network/${VMNAME}.yaml | yq -r ".interfaces[0].mac-address") - [ ${EIBMACADDRESS} == "null" ] && die "Network definition file for ${VMNAME}, \"${EIBFOLDER}/network/${VMNAME}.yaml\", doesn't contain a mac-address" 2 - [ ${EIBMACADDRESS} == "${MACADDRESS}" ] || echo "Warning: Network definition file for ${VMNAME}, \"${EIBFOLDER}/network/${VMNAME}.yaml\", mac-address ${EIBMACADDRESS} is different than the env var ${MACADDRESS}, using the \"${EIBFOLDER}/network/${VMNAME}.yaml\" one" + if [ ${EIBMACADDRESS} == "null" ]; then + echo "Info: Network definition file for ${VMNAME}, \"${EIBFOLDER}/network/${VMNAME}.yaml\", doesn't contain a mac-address, a random one will be created" + MACADDRESS=$(generate_mac) + fi + if [ ${EIBMACADDRESS} != "${MACADDRESS}" ]; then + echo "Warning: Network definition file for ${VMNAME}, \"${EIBFOLDER}/network/${VMNAME}.yaml\", mac-address ${EIBMACADDRESS} is different than the env var ${MACADDRESS}, using the \"${EIBFOLDER}/network/${VMNAME}.yaml\" one" + MACADDRESS="${EIBMACADDRESS}" + fi fi -EIBMACADDRESS="${MACADDRESS}" + +# Just in case +[ ${MACADDRESS} == "null" ] && MACADDRESS=$(generate_mac) # Only check podman machine on non linux OSes if [ $(uname -o) != "GNU/Linux" ]; then @@ -108,105 +105,13 @@ podman run --rm -it --privileged -v ${EIBFOLDER}:/eib \ build --definition-file eib.yaml OUTPUTNAME=$(cat ${EIBFOLDER}/eib.yaml | yq -r .image.outputImageName) -EIBFILE="${EIBFOLDER}/${OUTPUTNAME}" +IMAGE="${EIBFOLDER}/${OUTPUTNAME}" -# Create the image file -mkdir -p ${VMFOLDER} -qemu-img convert -O qcow2 ${EIBFILE} ${VMFOLDER}/${VMNAME}.qcow2 +create_image_file -if [ "${EXTRADISKS}" != false ]; then - DISKARRAY=(${EXTRADISKS//,/ }) - for (( i=0; i<"${#DISKARRAY[@]}"; i++ )); do - qemu-img create -f qcow2 ${VMFOLDER}/${VMNAME}-extra-disk-${i}.qcow2 "${DISKARRAY[$i]}"G > /dev/null - done -fi +create_extra_disks -if [ $(uname -o) == "Darwin" ]; then - # See if there are extra disks to be created - UTMEXTRADISKS="" - UTMEXTRADISKMAPPING="" - if [ "${EXTRADISKS}" != false ]; then - # Probably not needed - DISKARRAY=(${EXTRADISKS//,/ }) - for (( i=0; i<"${#DISKARRAY[@]}"; i++ )); do - UTMEXTRADISKS="${UTMEXTRADISKS} - set extradisk${i} to POSIX file \"${VMFOLDER}/${VMNAME}-extra-disk-${i}.qcow2\"" - UTMEXTRADISKMAPPING="${UTMEXTRADISKMAPPING}, {removable:false, source:extradisk${i}}" - done - fi - - # If there are not extra disks, this works as well - UTMDISKMAPPING="{removable:false, source:rootfs}${UTMEXTRADISKMAPPING}}" - - # Create the VM - OUTPUT=$(osascript <<-END - tell application "UTM" - -- specify the RAW file - set rootfs to POSIX file "${VMFOLDER}/${VMNAME}.qcow2" - -- specify extra disks - ${UTMEXTRADISKS} - --- create a new QEMU VM - set vm to make new virtual machine with properties {backend:qemu, configuration:{cpu cores:${CPUS}, memory: ${MEMORY}, name:"${VMNAME}", network interfaces:{{hardware:"virtio-net-pci", mode:shared, index:0, address:"${MACADDRESS}", port forwards:{}, host interface:""}}, architecture:"aarch64", drives:${UTMDISKMAPPING}} - start vm - repeat - if status of vm is started then exit repeat - end repeat - get address of first serial port of vm - end tell - END - ) - - echo "VM ${VMNAME} started. You can connect to the serial terminal as: screen ${OUTPUT}" - - VMMAC=$(echo ${MACADDRESS} | sed 's/0\([0-9A-Fa-f]\)/\1/g') - timeout=180 - count=0 - echo -n "Waiting for IP: " - until grep -q -i "${VMMAC}" -B1 -m1 /var/db/dhcpd_leases | head -1 | awk -F= '{ print $2 }'; do - count=$((count + 1)) - if [[ ${count} -ge ${timeout} ]]; then - break - fi - sleep 1 - echo -n "." - done - VMIP=$(grep -i "${VMMAC}" -B1 -m1 /var/db/dhcpd_leases | head -1 | awk -F= '{ print $2 }') -elif [ $(uname -o) == "GNU/Linux" ]; then - # By default virt-install powers off the VM when rebooted once. - # As a workaround, create the VM definition, change the on_reboot behaviour - # and start the VM - # See https://bugzilla.redhat.com/show_bug.cgi?id=1792411 for the print-xml 1 reason :) - VIRTFILE=$(mktemp) - virt-install --name ${VMNAME} \ - --noautoconsole \ - --memory ${MEMORY} \ - --vcpus ${CPUS} \ - --disk ${VMFOLDER}/${VMNAME}.qcow2 \ - --import \ - --network network=${VM_NETWORK},model=virtio,mac=${MACADDRESS} \ - --osinfo detect=on,name=sle-unknown \ - --print-xml 1 > ${VIRTFILE} - sed -i -e 's#destroy#restart#g' ${VIRTFILE} - virsh define ${VIRTFILE} - virsh start ${VMNAME} - rm -f ${VIRTFILE} - echo "VM ${VMNAME} started. You can connect to the serial terminal as: virsh console ${VMNAME}" - echo -n "Waiting for IP..." - timeout=180 - count=0 - VMIP="" - while [ -z "${VMIP}" ]; do - sleep 1 - count=$((count + 1)) - if [[ ${count} -ge ${timeout} ]]; then - break - fi - echo -n "." - VMIP=$(vm_ip ${VMNAME}) - done -else - die "VM not deployed. Unsupported operating system" 2 -fi +create_vm printf "\nVM IP: ${VMIP}\n" diff --git a/slemicro/create_vm_with_image.sh b/slemicro/create_vm_with_image.sh index 6a1bf98..181ec90 100755 --- a/slemicro/create_vm_with_image.sh +++ b/slemicro/create_vm_with_image.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -euo pipefail - -source common.sh +BASEDIR="$(dirname "$0")" +source ${BASEDIR}/common.sh usage(){ cat <<-EOF @@ -49,18 +49,10 @@ VM_STATIC_GATEWAY=${VM_STATIC_GATEWAY:-"192.168.122.1"} VM_STATIC_DNS=${VM_STATIC_DNS:-${VM_STATIC_GATEWAY}} EXTRADISKS="${EXTRADISKS:-false}" VM_NETWORK=${VM_NETWORK:-default} +LIBVIRT_DISK_SETTINGS="${LIBVIRT_DISK_SETTINGS:-bus=virtio}" set +a -if [ $(uname -o) == "Darwin" ]; then - # Check if UTM version is 4.2.2 (required for the scripting part) - ver(){ printf "%03d%03d%03d%03d" $(echo "$1" | tr '.' ' '); } - UTMVERSION=$(/usr/libexec/plistbuddy -c Print:CFBundleShortVersionString: /Applications/UTM.app/Contents/info.plist) - [ $(ver ${UTMVERSION}) -lt $(ver 4.2.2) ] && die "UTM version >= 4.2.2 required" 2 -elif [ $(uname -o) == "GNU/Linux" ]; then - command -v virt-install > /dev/null 2>&1 || die "virt-install command not found" 2 -else - die "Unsupported operating system" 2 -fi +check_os # Check if the commands required exist command -v qemu-img > /dev/null 2>&1 || die "qemu-img not found" 2 @@ -71,103 +63,11 @@ command -v qemu-img > /dev/null 2>&1 || die "qemu-img not found" 2 # Check if the MAC address has been set [ "${MACADDRESS}" != "null" ] || die "MAC Address needs to be specified and it should match the one defined on EIB at \"/network/${VMNAME}.yaml\"" 2 -# Create the image file -mkdir -p ${VMFOLDER} -qemu-img convert -O qcow2 ${IMAGE} ${VMFOLDER}/${VMNAME}.qcow2 - -if [ "${EXTRADISKS}" != false ]; then - DISKARRAY=(${EXTRADISKS//,/ }) - for (( i=0; i<"${#DISKARRAY[@]}"; i++ )); do - qemu-img create -f qcow2 ${VMFOLDER}/${VMNAME}-extra-disk-${i}.qcow2 "${DISKARRAY[$i]}"G > /dev/null - done -fi - -if [ $(uname -o) == "Darwin" ]; then - # See if there are extra disks to be created - UTMEXTRADISKS="" - UTMEXTRADISKMAPPING="" - if [ "${EXTRADISKS}" != false ]; then - # Probably not needed - DISKARRAY=(${EXTRADISKS//,/ }) - for (( i=0; i<"${#DISKARRAY[@]}"; i++ )); do - UTMEXTRADISKS="${UTMEXTRADISKS} - set extradisk${i} to POSIX file \"${VMFOLDER}/${VMNAME}-extra-disk-${i}.qcow2\"" - UTMEXTRADISKMAPPING="${UTMEXTRADISKMAPPING}, {removable:false, source:extradisk${i}}" - done - fi - - # If there are not extra disks, this works as well - UTMDISKMAPPING="{removable:false, source:rootfs}${UTMEXTRADISKMAPPING}}" - -# Create the VM - OUTPUT=$(osascript <<-END - tell application "UTM" - -- specify the RAW file - set rootfs to POSIX file "${VMFOLDER}/${VMNAME}.qcow2" - -- specify extra disks - ${UTMEXTRADISKS} - --- create a new QEMU VM - set vm to make new virtual machine with properties {backend:qemu, configuration:{cpu cores:${CPUS}, memory: ${MEMORY}, name:"${VMNAME}", network interfaces:{{hardware:"virtio-net-pci", mode:shared, index:0, address:"${MACADDRESS}", port forwards:{}, host interface:""}}, architecture:"aarch64", drives:${UTMDISKMAPPING}} - start vm - repeat - if status of vm is started then exit repeat - end repeat - get address of first serial port of vm - end tell - END - ) +create_image_file - echo "VM ${VMNAME} started. You can connect to the serial terminal as: screen ${OUTPUT}" +create_extra_disks - VMMAC=$(echo ${MACADDRESS} | sed 's/0\([0-9A-Fa-f]\)/\1/g') - timeout=180 - count=0 - echo -n "Waiting for IP: " - until grep -q -i "${VMMAC}" -B1 -m1 /var/db/dhcpd_leases | head -1 | awk -F= '{ print $2 }'; do - count=$((count + 1)) - if [[ ${count} -ge ${timeout} ]]; then - break - fi - sleep 1 - echo -n "." - done - VMIP=$(grep -i "${VMMAC}" -B1 -m1 /var/db/dhcpd_leases | head -1 | awk -F= '{ print $2 }') -elif [ $(uname -o) == "GNU/Linux" ]; then - # By default virt-install powers off the VM when rebooted once. - # As a workaround, create the VM definition, change the on_reboot behaviour - # and start the VM - # See https://bugzilla.redhat.com/show_bug.cgi?id=1792411 for the print-xml 1 reason :) - VIRTFILE=$(mktemp) - virt-install --name ${VMNAME} \ - --noautoconsole \ - --memory ${MEMORY} \ - --vcpus ${CPUS} \ - --disk ${VMFOLDER}/${VMNAME}.qcow2 \ - --import \ - --network network=${VM_NETWORK},model=virtio,mac=${MACADDRESS} \ - --osinfo detect=on,name=sle-unknown \ - --print-xml 1 > ${VIRTFILE} - sed -i -e 's#destroy#restart#g' ${VIRTFILE} - virsh define ${VIRTFILE} - virsh start ${VMNAME} - rm -f ${VIRTFILE} - echo "VM ${VMNAME} started. You can connect to the serial terminal as: virsh console ${VMNAME}" - echo -n "Waiting for IP..." - timeout=180 - count=0 - VMIP="" - while [ -z "${VMIP}" ]; do - sleep 1 - count=$((count + 1)) - if [[ ${count} -ge ${timeout} ]]; then - break - fi - echo -n "." - VMIP=$(vm_ip ${VMNAME}) - done -else - die "VM not deployed. Unsupported operating system" 2 -fi +create_vm printf "\nVM IP: ${VMIP}\n" diff --git a/slemicro/delete_vm.sh b/slemicro/delete_vm.sh index 4f6f49d..dc0cdc4 100755 --- a/slemicro/delete_vm.sh +++ b/slemicro/delete_vm.sh @@ -1,6 +1,7 @@ #!/usr/bin/env bash set -euo pipefail BASEDIR="$(dirname "$0")" +source ${BASEDIR}/common.sh die(){ echo ${1} 1>&2 @@ -57,7 +58,7 @@ if [ $(uname -o) == "Darwin" ]; then elif [ $(uname -o) == "GNU/Linux" ]; then if virsh list --all --name | grep -q ${VMNAME} ; then [ "$(virsh domstate ${VMNAME} 2>/dev/null)" == "running" ] && virsh destroy ${VMNAME} - virsh undefine ${VMNAME} + virsh undefine ${VMNAME} --nvram --remove-all-storage else die "${VMNAME} not found" 2 fi @@ -67,7 +68,6 @@ fi [ -f ${VMFOLDER}/${VMNAME}.raw ] && rm -f ${VMFOLDER}/${VMNAME}.raw [ -f ${VMFOLDER}/${VMNAME}.qcow2 ] && rm -f ${VMFOLDER}/${VMNAME}.qcow2 -[ -f ${VMFOLDER}/ignition-and-combustion-${VMNAME}.iso ] && rm -f ${VMFOLDER}/ignition-and-combustion-${VMNAME}.iso [ "${EXTRADISKS}" != false ] && rm -f ${VMFOLDER}/${VMNAME}-extra-disk-*.raw exit 0 \ No newline at end of file diff --git a/slemicro/eib-example-slmicro-unsafe-disk b/slemicro/eib-example-slmicro-unsafe-disk new file mode 100644 index 0000000..ec90588 --- /dev/null +++ b/slemicro/eib-example-slmicro-unsafe-disk @@ -0,0 +1,6 @@ +VMFOLDER="${HOME}/VMs" +VMNAME="slmicro" +CPUS="2" +MEMORY="2048" +MACADDRESS="00:00:00:01:01:01" +LIBVIRT_DISK_SETTINGS="bus=virtio,cache=unsafe" \ No newline at end of file diff --git a/slemicro/env-minimal.example b/slemicro/env-minimal.example deleted file mode 100644 index bcd23dd..0000000 --- a/slemicro/env-minimal.example +++ /dev/null @@ -1,3 +0,0 @@ -# This will create a SLE Micro VM with the default values -SLEMICROFILE="${HOME}/Downloads/SLE-Micro.aarch64-5.3.0-Default-GM.raw" -VMFOLDER="${HOME}/VMs" \ No newline at end of file diff --git a/slemicro/env.example b/slemicro/env.example deleted file mode 100644 index 14d2808..0000000 --- a/slemicro/env.example +++ /dev/null @@ -1,40 +0,0 @@ -REGISTER=true -EMAIL="foo@bar.com" -REGCODE="ASDF-1" -SLEMICROFILE="${HOME}/Downloads/SLE-Micro.aarch64-5.3.0-Default-GM.raw" -VMFOLDER="${HOME}/VMs" -VMNAME="SLEMicro" -VM_STATIC_IP="" -VM_GATEWAY_IP="" -CPUS=4 -MEMORY=4096 -DISKSIZE=30 -EXTRADISKS="30,10" -SSHPUB="${HOME}/.ssh/id_rsa.pub" -KUBEVIP=true -VIP="192.168.205.10" -CLUSTER="k3s" -INSTALL_CLUSTER_VERSION="v1.25.8+k3s1" -# For the first node in an HA environment -# INSTALL_CLUSTER_EXEC="server --cluster-init --write-kubeconfig-mode=644 --tls-san=${VIP} --tls-san=${VIP}.sslip.io" -# For a single node -INSTALL_CLUSTER_EXEC="server --cluster-init --write-kubeconfig-mode=644" -# To add control plane nodes: -# INSTALL_CLUSTER_EXEC="server --server https://${VIP}:6443 --write-kubeconfig-mode=644" -# To add worker nodes: -# INSTALL_CLUSTER_EXEC="agent --server https://${VIP}:6443" -CLUSTER_TOKEN="foobar" -RANCHERFLAVOR="latest" -CERTMANAGERVERSION="latest" -RANCHERBOOTSTRAPPASSWORD="admin" -RANCHERBOOTSTRAPSKIP=true -RANCHERFINALPASSWORD="adminadminadmin" -QEMUGUESTAGENT=true -COCKPIT=true -PODMAN=true -UPDATEANDREBOOT=true -DISABLEIPV6=true -REBOOTMGR=false -TRANSACTIONALUPDATES=false -ELEMENTAL_REGISTER="" -ELEMENTAL_CONFIG="" diff --git a/slemicro/get_ip.sh b/slemicro/get_ip.sh index 4e8b385..feab021 100755 --- a/slemicro/get_ip.sh +++ b/slemicro/get_ip.sh @@ -1,14 +1,14 @@ #!/usr/bin/env bash set -euo pipefail - -source common.sh +BASEDIR="$(dirname "$0")" +source ${BASEDIR}/common.sh usage(){ cat <<-EOF Usage: ${0} [-f ] [-n ] Options: - -f (Optional) Path to the variables file + -f Path to the variables file -n (Optional) Virtual machine name EOF } @@ -30,6 +30,8 @@ while getopts 'f:n:h' OPTION; do esac done +[ -z "${ENVFILE}" ] && { usage && die "\"-f \" required" 2;} + set -a # Get the env file source ${ENVFILE:-${BASEDIR}/.env} diff --git a/slemicro/get_kubeconfig.sh b/slemicro/get_kubeconfig.sh index b27f7a6..a5beff5 100755 --- a/slemicro/get_kubeconfig.sh +++ b/slemicro/get_kubeconfig.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -euo pipefail - -source common.sh +BASEDIR="$(dirname "$0")" +source ${BASEDIR}/common.sh usage(){ cat <<-EOF diff --git a/slemicro/getvmsip.sh b/slemicro/getvmsip.sh index 8501f96..63b6acb 100755 --- a/slemicro/getvmsip.sh +++ b/slemicro/getvmsip.sh @@ -1,7 +1,7 @@ -#!/bin/bash +#!/usr/bin/env bash set -euo pipefail - -source common.sh +BASEDIR="$(dirname "$0")" +source ${BASEDIR}/common.sh if [ $(uname -o) == "Darwin" ]; then VMS=$(osascript <<-END @@ -22,6 +22,7 @@ if [ $(uname -o) == "Darwin" ]; then end tell END ) + VMMAC=$(echo ${VMMAC} | sed 's/0\([0-9A-Fa-f]\)/\1/g') VMIP=$(grep -i "${VMMAC}" -B1 -m1 /var/db/dhcpd_leases | head -1 | awk -F= '{ print $2 }') echo "${vm} ${VMIP}" done diff --git a/slemicro/ignition/.gitkeep b/slemicro/ignition/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/slemicro/make_unattended.sh b/slemicro/make_unattended.sh deleted file mode 100755 index c35e085..0000000 --- a/slemicro/make_unattended.sh +++ /dev/null @@ -1,186 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -usage(){ - cat <<-EOF - Usage: ${0} -i SLE-Micro-SelfInstall.iso [-o tweaked-SLE-Micro-SelfInstall.iso] [-d /dev/sda] - - Options: - -i Path to the original SLE Micro iso file - -o (Optional) Path to the tweaked-SLE-Micro-SelfInstall.iso file (./tweaked.iso by default) - -d (Optional) Disk device where SLE Micro will be installed (if not provided, the first one that the installer finds) - EOF -} - -die(){ - echo "${1}" 1>&2 - exit "${2}" -} - -while getopts 'i:o:d:h' OPTION; do - case "${OPTION}" in - i) - if [ -f "${OPTARG}" ]; then - INPUTISO="${OPTARG}" - else - die "Input ISO ${OPTARG} not found" 2 - fi - ;; - o) - if [ -d "$(dirname "${OPTARG}")" ]; then - OUTPUTISO="${OPTARG}" - else - die "Output path $(dirname "${OPTARG}") not found" 2 - fi - ;; - d) - WRITETO="${OPTARG}" - ;; - h) - usage && exit 0 - ;; - ?) - usage && exit 2 - ;; - esac -done - -# INPUTISO is mandatory -if [ -z "${INPUTISO:-}" ]; then - usage && exit 2 -fi - -# OUTPUTISO defaults to ./tweaked.iso -OUTPUTISO="${OUTPUTISO:-./tweaked.iso}" - -# Don't overwrite the destination -if [ -f ${OUTPUTISO} ]; then - usage - die "${OUTPUTISO} already exists" 2 -fi - -# Root needed by mount -[ "$(id -u)" -eq 0 ] || die "This script must be executed by root" 2 - -TMPDIR="$(mktemp -d -t make_unattended.XXXXXX)" -# shellcheck disable=SC2064 -trap "rm -rf '$TMPDIR'" EXIT - -# We mount the ISO and extract the files we need -mkdir -p "${TMPDIR}"/orig -mount "${INPUTISO}" "${TMPDIR}"/orig >/dev/null 2>&1 -cp "${TMPDIR}"/orig/boot/x86_64/loader/initrd "${TMPDIR}"/initrd -cp "${TMPDIR}"/orig/boot/grub2/grub.cfg "${TMPDIR}"/grub.cfg-orig -umount "${TMPDIR}"/orig -rmdir "${TMPDIR}"/orig - -# First step is to extract the .profile from the second cpio -lsinitrd "${TMPDIR}"/initrd .profile > "${TMPDIR}"/.profile - -# Then, append the kiwi_oem flags -echo "kiwi_oemunattended='true'" >> "${TMPDIR}"/.profile - -# Specify the destination disk if present -if [ -n "${WRITETO:-}" ]; then - echo "kiwi_oemunattended_id='${WRITETO}'" >> "${TMPDIR}"/.profile -fi - -# Finally, we append the .profile into the initrd as: -pushd "${TMPDIR}" > /dev/null -echo ./.profile | cpio --quiet -o -H newc >> "${TMPDIR}"/initrd -popd > /dev/null - -#### Old method, keeping this here just for reference -# # We mount the ISO and extract the files we need -# mkdir -p "${TMPDIR}"/{orig,init} -# mount "${INPUTISO}" "${TMPDIR}"/orig >/dev/null 2>&1 -# cp "${TMPDIR}"/orig/boot/x86_64/loader/initrd "${TMPDIR}"/init -# cp "${TMPDIR}"/orig/boot/grub2/grub.cfg "${TMPDIR}"/grub.cfg-orig -# umount "${TMPDIR}"/orig -# rmdir "${TMPDIR}"/orig -# chmod 666 "${TMPDIR}"/init/initrd - -# # The initrd contained in the iso is basically two cpios concatenated -# # The first one contains the microcode essentially (early cpio): - -# # dd if=initrd-orig skip=0 | cpio -it -# # . -# # early_cpio -# # kernel -# # kernel/x86 -# # kernel/x86/microcode -# # kernel/x86/microcode/AuthenticAMD.bin -# # kernel/x86/microcode/GenuineIntel.bin -# # 25782 blocks - -# # And the second one contains the filesystem compressed with zstd: - -# # dd if=./initrd-orig skip=25782 | zstd -dc | cpio -it -# # . -# # .profile -# # bin -# # bin/arping -# # bin/awk -# # bin/basename -# # bin/bash -# # bin/cat -# # bin/chmod -# # bin/chown -# # bin/cp -# # bin/date -# # [... a lot more files ...] - -# # The .profile is the one used by kiwi to perform the installation -# # We need to add the kiwi_oemunattended flag to it. -# # There is also the kiwi_oemunattended_id https://github.com/OSInside/kiwi/blob/master/dracut/modules.d/90kiwi-dump/kiwi-dump-image.sh -# # which we can use to specify the device we want to use to write the image into. - -# # First step is to extract the initrd filesystem content (the second cpio) -# # pushd and popd commands are needed because lsinitrd doesn't have a way to extract the data than to the current folder -# pushd "${TMPDIR}"/init > /dev/null -# lsinitrd --unpack ./initrd -# popd > /dev/null - -# # Then, in order to be able to recreate it, we need to get the first cpio as well -# # We just list the content from it but we need stderr as this is where cpio prints the number of blocks written -# # The usual cat initrd | cpio -it gives a pipefail (because of cat), so use -F instead (which should be better) -# BLOCKS=$(cpio -itF "${TMPDIR}"/init/initrd 2>&1 | awk '/blocks/ { print $1 }') -# dd if="${TMPDIR}"/init/initrd skip=0 count="${BLOCKS}" of="${TMPDIR}"/first >/dev/null 2>&1 - -# # We have everything we need from initrd -# rm -f "${TMPDIR}"/init/initrd - -# # We inject the unattended flag -# echo "kiwi_oemunattended='true'" >> "${TMPDIR}"/init/.profile - -# # Specify the destination disk if present -# if [ -n "${WRITETO:-}" ]; then -# echo "kiwi_oemunattended_id='${WRITETO}'" >> "${TMPDIR}"/init/.profile -# fi - -# # This will generate the "second" cpio -# pushd "${TMPDIR}"/init/ > /dev/null -# find . | cpio -o -H newc -F "${TMPDIR}"/second 2>/dev/null -# popd > /dev/null - -# # We can clean up the extracted one -# rm -Rf "${TMPDIR}"/init - -# # Now we need to compress the filesystem -# zstd -q "${TMPDIR}"/second -# rm -f "${TMPDIR}"/second - -# # And create the proper initrd by concatenating both -# cat "${TMPDIR}"/first "${TMPDIR}"/second.zst > "${TMPDIR}"/initrd -# rm -f "${TMPDIR}"/first "${TMPDIR}"/second.zst - -# This will remove the need to select "install" in grub -echo -e "set timeout=3\nset timeout_style=menu" > "${TMPDIR}"/pre-grub.txt -cat "${TMPDIR}"/pre-grub.txt "${TMPDIR}"/grub.cfg-orig > "${TMPDIR}"/grub.cfg -rm -f "${TMPDIR}"/pre-grub.txt "${TMPDIR}"/grub.cfg-orig - -# Finally we create the iso replacing the initrd and grub.cfg files -xorriso -indev "${INPUTISO}" -outdev "${OUTPUTISO}" \ - -map "${TMPDIR}"/grub.cfg /boot/grub2/grub.cfg \ - -map "${TMPDIR}"/initrd /boot/x86_64/loader/initrd \ - -boot_image any replay > /dev/null 2>&1 \ No newline at end of file