diff --git a/Dockerfile b/Dockerfile index 02f57c71..bcd30e68 100644 --- a/Dockerfile +++ b/Dockerfile @@ -36,21 +36,26 @@ RUN ["/usr/bin/busybox", "rm", "-rf", "/var", "/etc/ssl", "/usr/bin/busybox"] # Make OS image FROM opensuse/leap:15.3 as os RUN zypper in -y \ + apparmor-parser \ avahi \ bash-completion \ conntrack-tools \ coreutils \ curl \ device-mapper \ + dmidecode \ dosfstools \ dracut \ e2fsprogs \ + ethtool \ findutils \ gawk \ gptfdisk \ grub2-i386-pc \ grub2-x86_64-efi \ haveged \ + hdparm \ + iotop \ iproute2 \ iptables \ iputils \ @@ -58,14 +63,22 @@ RUN zypper in -y \ jq \ kernel-default \ kernel-firmware-bnx2 \ + kernel-firmware-chelsio \ kernel-firmware-i915 \ kernel-firmware-intel \ kernel-firmware-iwlwifi \ + kernel-firmware-liquidio \ + kernel-firmware-marvell \ + kernel-firmware-mediatek \ kernel-firmware-mellanox \ kernel-firmware-network \ kernel-firmware-platform \ + kernel-firmware-qlogic \ kernel-firmware-realtek \ + kernel-firmware-usb-network \ less \ + lshw \ + lsof \ lsscsi \ lvm2 \ mdadm \ @@ -76,23 +89,27 @@ RUN zypper in -y \ open-iscsi \ open-vm-tools \ parted \ + pciutils \ pigz \ policycoreutils \ - psmisc \ procps \ + psmisc \ python-azure-agent \ qemu-guest-agent \ + rng-tools \ rsync \ squashfs \ strace \ SUSEConnect \ + sysstat \ systemd \ systemd-sysvinit \ - tcpdump \ tar \ + tcpdump \ timezone \ vim \ - which + which \ + zstd # Copy in some local OS customizations COPY opensuse/files / @@ -100,7 +117,7 @@ COPY opensuse/files / # Starting from here are the lines needed for RancherOS to work # IMPORTANT: Setup rancheros-release used for versioning/upgrade. The -# values here should reflect the tag of the image building built +# values here should reflect the tag of the image being built ARG IMAGE_REPO=norepo ARG IMAGE_TAG=latest RUN echo "IMAGE_REPO=${IMAGE_REPO}" > /usr/lib/rancheros-release && \ diff --git a/Makefile b/Makefile index f6d940eb..c09adbe0 100644 --- a/Makefile +++ b/Makefile @@ -18,6 +18,14 @@ ci: .dapper clean: rm -rf build +.PHONY: build-framework +build-framework: + docker build \ + --build-arg CACHEBUST=${CACHEBUST} \ + --build-arg IMAGE_TAG=${TAG} \ + --build-arg IMAGE_REPO=${REPO}-framework \ + -t ${REPO}-framework:${TAG} . + .PHONY: build build: docker build \ @@ -27,9 +35,13 @@ build: -t ${IMAGE} . .PHONY: push -push: build +push: docker push ${IMAGE} +.PHONY: push +push-framework: + docker push ${REPO}-framework:${TAG} + .PHONY: iso iso: build ./ros-image-build ${IMAGE} iso diff --git a/framework/files/etc/cos/bootargs.cfg b/framework/files/etc/cos/bootargs.cfg new file mode 100644 index 00000000..f2801b85 --- /dev/null +++ b/framework/files/etc/cos/bootargs.cfg @@ -0,0 +1,8 @@ +set kernel=/boot/vmlinuz +if [ -n "$recoverylabel" ]; then + set kernelcmd="console=tty1 console=ttyS0 root=live:LABEL=$recoverylabel rd.live.dir=/ rd.live.squashimg=$img panic=5" +else + set kernelcmd="console=tty1 console=ttyS0 root=LABEL=$label cos-img/filename=$img panic=5 security=selinux selinux=1" +fi + +set initramfs=/boot/initrd diff --git a/framework/files/etc/cos/config b/framework/files/etc/cos/config new file mode 100644 index 00000000..14617f68 --- /dev/null +++ b/framework/files/etc/cos/config @@ -0,0 +1,26 @@ +# cOS configuration file +# This file allows to tweak cOS configuration such as: default upgrade/recovery image and GRUB menu entry + +# Disable/enable image verification during upgrades ( default: true ) +VERIFY=false + +# Disable/enable upgrades via release channels instead of container images. ( default: true ) +CHANNEL_UPGRADES=false + +# Default container image used for upgrades. ( defaults to system/cos with channel CHANNEL_UPGRADES enabled ) +#UPGRADE_IMAGE="quay.io/mudler/cos-test:cos-standard" + +# Default recovery image to use when upgrading the recovery partition +# ( defaults to recovery/cos in vanilla cOS images with channel CHANNEL_UPGRADES enabled. Otherwise it defaults to UPGRADE_IMAGE ). +#RECOVERY_IMAGE="quay.io/mudler/cos-test:cos-standard" + +# GRUB entry to display on boot. ( defaults: cOS ) +GRUB_ENTRY_NAME="RancherOS" + +# Space separated list of additional paths that are used to +# source cloud-config from. ( defaults paths are: /system/oem /oem/ /usr/local/cloud-config/ ) +#CLOUD_INIT_PATHS="" + +# This is the directory that can be used to store cloud-init files that can be enabled/disabled in runtime +# by cos-features. ( defaults to /system/features ) +#COS_FEATURESDIR="/system/features" diff --git a/framework/files/etc/dracut.conf.d/51-livenet-initrd.conf b/framework/files/etc/dracut.conf.d/51-livenet-initrd.conf new file mode 100644 index 00000000..0b6e573c --- /dev/null +++ b/framework/files/etc/dracut.conf.d/51-livenet-initrd.conf @@ -0,0 +1,2 @@ +# This is required for booting a squashfs from network +add_dracutmodules+=" livenet " diff --git a/framework/files/system/oem/00_ros-rootfs.yaml b/framework/files/system/oem/00_ros-rootfs.yaml deleted file mode 100644 index 7e19fc1b..00000000 --- a/framework/files/system/oem/00_ros-rootfs.yaml +++ /dev/null @@ -1,67 +0,0 @@ -name: "ROS Rootfs Layout Settings" -stages: - initramfs: - - if: '[ ! -f /run/cos/recovery_mode ]' - commands: - - | - target=/usr/local/.ros-state - - # Always want the latest update of systemd conf from the image - mkdir -p ${target}/etc/systemd/ - rsync -av /etc/systemd/ ${target}/etc/systemd/ - - if [ ! -e /usr/local/etc/hostname ]; then - echo rancher-${RANDOM} > /usr/local/etc/hostname - fi - ln -sf /usr/local/etc/hostname /etc/hostname - - # Only populate ssh conf once - if [ ! -e ${target}/etc/ssh ]; then - mkdir -p ${target}/etc/ssh/ - rsync -a /etc/ssh/ ${target}/etc/ssh/ - fi - - sed -i '/overlay \/home /d' /etc/fstab - sed -i '/overlay \/opt /d' /etc/fstab - nsenter -m -t 1 -- umount /sysroot/home - nsenter -m -t 1 -- umount /sysroot/opt - - # setup directories as persistent - for i in root opt home var/lib/rancher var/lib/kubelet etc/systemd etc/rancher etc/ssh usr/libexec var/log var/lib/wicked; do - mkdir -p ${target}/$i /$i - nsenter -m -t 1 -- mount /sysroot${target}/$i /sysroot/$i -t none -o bind - done - - # This is hidden so that if you run some selinux label checking or relabeling the bind - # mount won't screw up things. If you have two files at different paths they will get - # labeled with two different labels. - mkdir -p ${target}/empty - nsenter -m -t 1 -- mount /sysroot${target}/empty /sysroot${target} -o bind,ro - - # ensure /var/log/journal exists so it's labeled correctly - nsenter -m -t 1 -- mkdir -p /sysroot/var/log/journal - initramfs.after: - - if: '[ ! -f /run/cos/recovery_mode ]' - commands: - - restorecon -R -v /etc /home /opt /var /usr/local /tmp /srv /root - fs.before: - - name: "Pull data from provider (local)" - datasource: - providers: ["aws", "gcp", "openstack", "cdrom"] - path: "/oem" - - if: '[ ! -f /run/cos/recovery_mode ]' - commands: - - restorecon -R -v /etc /home /opt /var /usr/local /tmp /srv /root - rootfs.after: - - if: '[ ! -f /run/cos/recovery_mode ] && [ ! -f /run/cos/live_mode ]' - name: "Grow persistent" - layout: - device: - label: COS_PERSISTENT - expand_partition: - size: 0 - fs.before: - - if: '[ ! -f "/run/cos/recovery_mode" ] && [ ! -f /run/cos/live_mode ]' - name: "Grow persistent fs" - commands: - - resize2fs $(blkid -L COS_PERSISTENT) diff --git a/framework/files/system/oem/01_ros-rootfs.yaml b/framework/files/system/oem/01_ros-rootfs.yaml new file mode 100644 index 00000000..cfd299f6 --- /dev/null +++ b/framework/files/system/oem/01_ros-rootfs.yaml @@ -0,0 +1,58 @@ +name: "ROS Rootfs Layout Settings" +stages: + initramfs: + - if: '[ ! -f /run/cos/recovery_mode ]' + commands: + - | + if [ ! -e /usr/local/etc/hostname ]; then + echo rancher-${RANDOM} > /usr/local/etc/hostname + fi + ln -sf /usr/local/etc/hostname /etc/hostname + rootfs: + - if: '[ ! -f "/run/cos/recovery_mode" ]' + name: "Layout configuration" + environment_file: /run/cos/cos-layout.env + environment: + VOLUMES: "LABEL=COS_OEM:/oem LABEL=COS_PERSISTENT:/usr/local" + OVERLAY: "tmpfs:25%" + RW_PATHS: "/var /etc /srv" + PERSISTENT_STATE_PATHS: >- + /etc/systemd + /etc/rancher + /etc/ssh + /etc/iscsi + /etc/cni + /home + /opt + /root + /usr/libexec + /var/log + /var/lib/rancher + /var/lib/kubelet + /var/lib/wicked + /var/lib/longhorn + /var/lib/cni + PERSISTENT_STATE_BIND: "true" + rootfs.before: + - name: "Pull data from provider" + datasource: + providers: ["cdrom"] + path: "/oem" + fs.before: + - name: "Pull data from provider (local)" + datasource: + providers: ["aws", "gcp", "openstack", "cdrom"] + path: "/oem" + rootfs.after: + - if: '[ ! -f /run/cos/recovery_mode ] && [ ! -f /run/cos/live_mode ]' + name: "Grow persistent" + layout: + device: + label: COS_PERSISTENT + expand_partition: + size: 0 + fs.before: + - if: '[ ! -f "/run/cos/recovery_mode" ] && [ ! -f /run/cos/live_mode ]' + name: "Grow persistent fs" + commands: + - resize2fs $(blkid -L COS_PERSISTENT) diff --git a/framework/files/system/oem/05_elemental-installer.yaml b/framework/files/system/oem/05_rancheros-installer.yaml similarity index 95% rename from framework/files/system/oem/05_elemental-installer.yaml rename to framework/files/system/oem/05_rancheros-installer.yaml index 5bbfc5c5..da4894a0 100644 --- a/framework/files/system/oem/05_elemental-installer.yaml +++ b/framework/files/system/oem/05_rancheros-installer.yaml @@ -1,4 +1,4 @@ -name: "Elemental Installer" +name: "RancherOS Installer" stages: initramfs: - if: '[ -f /run/cos/live_mode ]' diff --git a/framework/files/var/log/journal/.placeholder b/framework/files/var/log/journal/.placeholder new file mode 100644 index 00000000..e69de29b diff --git a/opensuse/files/etc/bash.bashrc.local b/opensuse/files/etc/bash.bashrc.local index 16a6b51a..26aa5dba 100644 --- a/opensuse/files/etc/bash.bashrc.local +++ b/opensuse/files/etc/bash.bashrc.local @@ -13,3 +13,8 @@ fi if [ -z "$IMAGE_SERVICE_ENDPOINT" ]; then export IMAGE_SERVICE_ENDPOINT=unix:///var/run/k3s/containerd/containerd.sock fi + +# For ctr +if [ -z "$CONTAINERD_ADDRESS" ]; then + export CONTAINERD_ADDRESS=/run/k3s/containerd/containerd.sock +fi diff --git a/pkg/config/config.go b/pkg/config/config.go index eb5e7431..60bbae87 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -1,6 +1,6 @@ package config -type Elemental struct { +type Rancher struct { Install Install `json:"install,omitempty"` } @@ -21,8 +21,8 @@ type Install struct { } type Config struct { - SSHAuthorizedKeys []string `json:"sshAuthorizedKeys,omitempty"` - Elemental Elemental `json:"elemental,omitempty"` + SSHAuthorizedKeys []string `json:"sshAuthorizedKeys,omitempty"` + Rancher Rancher `json:"rancher,omitempty"` } type YipConfig struct { diff --git a/pkg/config/read.go b/pkg/config/read.go index 78703444..ac60ada1 100644 --- a/pkg/config/read.go +++ b/pkg/config/read.go @@ -40,7 +40,7 @@ func mapToEnv(prefix string, data map[string]interface{}) []string { var result []string for k, v := range data { keyName := strings.ToUpper(prefix + convert.ToYAMLKey(k)) - keyName = strings.ReplaceAll(keyName, "ELEMENTAL_", "COS_") + keyName = strings.ReplaceAll(keyName, "RANCHER_", "COS_") if data, ok := v.(map[string]interface{}); ok { subResult := mapToEnv(keyName+"_", data) result = append(result, subResult...) diff --git a/pkg/config/write.go b/pkg/config/write.go index 303062d7..8adf7944 100644 --- a/pkg/config/write.go +++ b/pkg/config/write.go @@ -6,10 +6,10 @@ import ( ) func PrintInstall(cfg Config) ([]byte, error) { - if cfg.Elemental.Install.Password != "" { - cfg.Elemental.Install.Password = "******" + if cfg.Rancher.Install.Password != "" { + cfg.Rancher.Install.Password = "******" } - data, err := convert.EncodeToMap(cfg.Elemental.Install) + data, err := convert.EncodeToMap(cfg.Rancher.Install) if err != nil { return nil, err } diff --git a/pkg/install/ask.go b/pkg/install/ask.go index c4ccdc23..09b06c17 100644 --- a/pkg/install/ask.go +++ b/pkg/install/ask.go @@ -10,7 +10,7 @@ import ( ) func Ask(cfg *config.Config) error { - if cfg.Elemental.Install.Silent { + if cfg.Rancher.Install.Silent { return nil } @@ -22,7 +22,7 @@ func Ask(cfg *config.Config) error { return err } - if cfg.Elemental.Install.ConfigURL == "" { + if cfg.Rancher.Install.ConfigURL == "" { if err := AskGithub(cfg); err != nil { return err } @@ -40,7 +40,7 @@ func Ask(cfg *config.Config) error { } func AskInstallDevice(cfg *config.Config) error { - if cfg.Elemental.Install.Device != "" { + if cfg.Rancher.Install.Device != "" { return nil } @@ -54,7 +54,7 @@ func AskInstallDevice(cfg *config.Config) error { return err } - cfg.Elemental.Install.Device = "/dev/" + fields[i] + cfg.Rancher.Install.Device = "/dev/" + fields[i] return nil } @@ -64,7 +64,7 @@ func AskToken(cfg *config.Config, server bool) error { err error ) - if cfg.Elemental.Install.Token != "" { + if cfg.Rancher.Install.Token != "" { return nil } @@ -77,7 +77,7 @@ func AskToken(cfg *config.Config, server bool) error { } else { token, err = questions.Prompt(msg+": ", "") } - cfg.Elemental.Install.Token = token + cfg.Rancher.Install.Token = token return err } @@ -93,7 +93,7 @@ func isServer(cfg *config.Config) (bool, error) { } func AskServerAgent(cfg *config.Config) error { - if cfg.Elemental.Install.ServerURL != "" { + if cfg.Rancher.Install.ServerURL != "" { return nil } @@ -110,13 +110,13 @@ func AskServerAgent(cfg *config.Config) error { if err != nil { return err } - cfg.Elemental.Install.ServerURL = url + cfg.Rancher.Install.ServerURL = url return AskToken(cfg, false) } func AskPassword(cfg *config.Config) error { - if cfg.Elemental.Install.Silent || cfg.Elemental.Install.Password != "" { + if cfg.Rancher.Install.Silent || cfg.Rancher.Install.Password != "" { return nil } @@ -140,12 +140,12 @@ func AskPassword(cfg *config.Config) error { } } - cfg.Elemental.Install.Password = pass + cfg.Rancher.Install.Password = pass return nil } func AskGithub(cfg *config.Config) error { - if len(cfg.SSHAuthorizedKeys) > 0 || cfg.Elemental.Install.Password != "" { + if len(cfg.SSHAuthorizedKeys) > 0 || cfg.Rancher.Install.Password != "" { return nil } @@ -167,11 +167,11 @@ func AskGithub(cfg *config.Config) error { } func AskConfigURL(cfg *config.Config) error { - if cfg.Elemental.Install.ConfigURL != "" { + if cfg.Rancher.Install.ConfigURL != "" { return nil } - ok, err := questions.PromptBool("Configure system using an Elemental config file?", false) + ok, err := questions.PromptBool("Configure system using an cloud-config file?", false) if err != nil { return err } @@ -180,11 +180,11 @@ func AskConfigURL(cfg *config.Config) error { return nil } - str, err := questions.Prompt("Elemental config file location (file path or http URL): ", "") + str, err := questions.Prompt("cloud-config file location (file path or http URL): ", "") if err != nil { return err } - cfg.Elemental.Install.ConfigURL = str + cfg.Rancher.Install.ConfigURL = str return nil } diff --git a/pkg/install/install.go b/pkg/install/install.go index 248d44ae..7c5fdccf 100644 --- a/pkg/install/install.go +++ b/pkg/install/install.go @@ -16,10 +16,10 @@ func Run(automatic bool) error { return err } - if automatic && !cfg.Elemental.Install.Automatic { + if automatic && !cfg.Rancher.Install.Automatic { return nil } else if automatic { - cfg.Elemental.Install.Silent = true + cfg.Rancher.Install.Silent = true } err = Ask(&cfg) @@ -27,7 +27,7 @@ func Run(automatic bool) error { return err } - tempFile, err := ioutil.TempFile("", "elemental-install") + tempFile, err := ioutil.TempFile("", "ros-install") if err != nil { return err } @@ -44,7 +44,7 @@ func runInstall(cfg config.Config, output string) error { return err } - if !cfg.Elemental.Install.Silent { + if !cfg.Rancher.Install.Silent { val, err := questions.PromptBool("\nConfiguration\n"+"-------------\n\n"+ string(installBytes)+ "\nYour disk will be formatted and installed with the above configuration.\nContinue?", false) @@ -53,30 +53,30 @@ func runInstall(cfg config.Config, output string) error { } } - if cfg.Elemental.Install.ConfigURL == "" { + if cfg.Rancher.Install.ConfigURL == "" { yip := config.YipConfig{ Rancherd: config.Rancherd{ - Server: cfg.Elemental.Install.ServerURL, - Token: cfg.Elemental.Install.Token, + Server: cfg.Rancher.Install.ServerURL, + Token: cfg.Rancher.Install.Token, }, } - if cfg.Elemental.Install.ServerURL == "" { + if cfg.Rancher.Install.ServerURL == "" { yip.Rancherd.Role = "cluster-init" } else { yip.Rancherd.Role = "agent" } - if cfg.Elemental.Install.Password != "" || len(cfg.SSHAuthorizedKeys) > 0 { + if cfg.Rancher.Install.Password != "" || len(cfg.SSHAuthorizedKeys) > 0 { yip.Stages = map[string][]config.Stage{ - "initramfs": {{ + "network": {{ Users: map[string]config.User{ "root": { Name: "root", - PasswordHash: cfg.Elemental.Install.Password, + PasswordHash: cfg.Rancher.Install.Password, SSHAuthorizedKeys: cfg.SSHAuthorizedKeys, }, }}, }} - cfg.Elemental.Install.Password = "" + cfg.Rancher.Install.Password = "" } data, err := yaml.Marshal(yip) @@ -87,7 +87,7 @@ func runInstall(cfg config.Config, output string) error { if err := ioutil.WriteFile(output+".yip", data, 0600); err != nil { return err } - cfg.Elemental.Install.ConfigURL = output + ".yip" + cfg.Rancher.Install.ConfigURL = output + ".yip" } ev, err := config.ToEnv(cfg)