-
Notifications
You must be signed in to change notification settings - Fork 45
Added Fedora OS support #791
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -25,24 +25,22 @@ import ( | |
| "github.com/ppc64le-cloud/pvsadm/pkg/utils" | ||
| ) | ||
|
|
||
| var ( | ||
| hostPartitions = []string{"/proc", "/dev", "/sys", "/var/run/", "/etc/machine-id"} | ||
| ) | ||
| var hostPartitions = []string{"/proc", "/dev", "/sys", "/run", "/etc/machine-id"} | ||
|
|
||
| // prepare is a function prepares the CentOS or RHEL image for capturing, this includes | ||
| // - Installs the cloud-init | ||
| // - Install and configure multipath for rootfs | ||
| // - Install all the required modules for PowerVM | ||
| // - Sets the root password | ||
| func prepare(mnt, volume, dist, rhnuser, rhnpasswd, rootpasswd string) error { | ||
| // Setup loop device and cleanup on exit | ||
| lo, err := setupLoop(volume) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| defer removeLoop(lo) | ||
|
|
||
| err = partprobe(lo) | ||
| if err != nil { | ||
| if err = partprobe(lo); err != nil { | ||
| return err | ||
| } | ||
|
|
||
|
|
@@ -51,63 +49,73 @@ func prepare(mnt, volume, dist, rhnuser, rhnpasswd, rootpasswd string) error { | |
| return err | ||
| } | ||
|
|
||
| partDev := lo + "p" + partition | ||
|
|
||
| err = mount("nouuid", partDev, mnt) | ||
| partDev := fmt.Sprintf("%sp%s", lo, partition) | ||
| fsType, err := getFSType(partDev) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| defer Umount(mnt) | ||
|
|
||
| err = growpart(lo, partition) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| switch fsType { | ||
| case "btrfs": | ||
| if err = mount("defaults,subvol=root", partDev, filepath.Join(mnt)); err != nil { | ||
| return err | ||
| } | ||
| defer Umount(mnt) | ||
| case "ext2", "ext3", "ext4", "xfs": | ||
| if err = mount("nouuid", partDev, mnt); err != nil { | ||
| return err | ||
| } | ||
| defer Umount(mnt) | ||
| } | ||
|
|
||
| fsType, err := getFSType(partDev) | ||
| if err != nil { | ||
| // Resize partition | ||
| if err = growpart(lo, partition); err != nil { | ||
| return err | ||
| } | ||
|
|
||
| switch fsType { | ||
| case "xfs": | ||
| err = xfsGrow(partDev) | ||
| if err != nil { | ||
| if err = xfsGrow(partDev); err != nil { | ||
| return err | ||
| } | ||
| case "ext2", "ext3", "ext4": | ||
| err = resize2fs(partDev) | ||
| if err != nil { | ||
| if err = resize2fs(partDev); err != nil { | ||
| return err | ||
| } | ||
| case "btrfs": | ||
| if err = growBtrfs(filepath.Join(mnt, "root"), "max"); err != nil { | ||
| return err | ||
| } | ||
| default: | ||
| return fmt.Errorf("unable to handle the %s filesystem for %s", fsType, partDev) | ||
| } | ||
|
|
||
| // Get the boot partition name and Mount boot partition | ||
| fstabPath := filepath.Join(mnt, "etc", "fstab") | ||
|
|
||
| //get the boot partition name | ||
| deviceuuid, err := bootDeviceuuid(fstabPath) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| if deviceuuid != "" { | ||
| bootDev, err := findDevice(deviceuuid) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| err = mount("nouuid", bootDev, filepath.Join(mnt, "boot")) | ||
| if err != nil { | ||
| bootMount := filepath.Join(mnt, "boot") | ||
| if deviceuuid, err := bootDeviceuuid(fstabPath); err == nil && deviceuuid != "" { | ||
| if bootDev, err := findDevice(deviceuuid); err == nil { | ||
| if fsType == "btrfs" { | ||
| if err = mount("defaults", bootDev, bootMount); err != nil { | ||
| return err | ||
| } | ||
| } else { | ||
| if err = mount("defaults,nouuid", bootDev, bootMount); err != nil { | ||
| return err | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. could you please check if "defaults" work for other filesystem types as well ? |
||
| } | ||
| } | ||
| defer Umount(bootMount) | ||
| } else { | ||
| return err | ||
| } | ||
| defer Umount(filepath.Join(mnt, "boot")) | ||
| } else if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| // Verify /boot is mounted properly and files are present. | ||
| bootDirFiles := []string{"config-*.ppc64le", "efi", "grub2", "initramfs-*.ppc64le.img", "loader", "symvers-*.ppc64le.*", "System.map-*.ppc64le", "vmlinuz-*.ppc64le"} | ||
| for _, file := range bootDirFiles { | ||
| exist, err := checkFileExists(filepath.Join(mnt, "boot", file)) | ||
| exist, err := checkFileExists(filepath.Join(bootMount, file)) | ||
| if err != nil { | ||
| return fmt.Errorf("error while validating contents of /boot directory. %v", err) | ||
| } | ||
|
|
@@ -123,35 +131,32 @@ func prepare(mnt, volume, dist, rhnuser, rhnpasswd, rootpasswd string) error { | |
| return err | ||
| } | ||
| } | ||
| defer UmountHostPartitions(mnt) | ||
| defer UmountHostPartitions(mnt, dist) | ||
|
|
||
| setupStr, err := Render(dist, rhnuser, rhnpasswd, rootpasswd) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| err = os.WriteFile(filepath.Join(mnt, "setup.sh"), []byte(setupStr), 0744) | ||
| if err != nil { | ||
| if setupStr, err := Render(dist, rhnuser, rhnpasswd, rootpasswd); err == nil { | ||
| if err = os.WriteFile(filepath.Join(mnt, "setup.sh"), []byte(setupStr), 0744); err != nil { | ||
| return err | ||
| } | ||
| } else { | ||
| return err | ||
| } | ||
|
|
||
| err = os.WriteFile(filepath.Join(mnt, "/etc/cloud/cloud.cfg"), []byte(CloudConfig), 0644) | ||
| if err != nil { | ||
| return err | ||
| files := map[string]string{ | ||
| "/etc/cloud/cloud.cfg": CloudConfig, | ||
| "/etc/cloud/ds-identify.cfg": dsIdentify, | ||
| } | ||
|
|
||
| err = os.WriteFile(filepath.Join(mnt, "/etc/cloud/ds-identify.cfg"), []byte(dsIdentify), 0644) | ||
| if err != nil { | ||
| return err | ||
| for path, content := range files { | ||
| if err := os.WriteFile(filepath.Join(mnt, path), []byte(content), 0644); err != nil { | ||
| return err | ||
| } | ||
| } | ||
|
|
||
| err = Chroot(mnt) | ||
| if err != nil { | ||
| if err = Chroot(mnt); err != nil { | ||
| return err | ||
| } | ||
| defer ExitChroot() | ||
|
|
||
| err = os.Chdir("/") | ||
| if err != nil { | ||
| if err = os.Chdir("/"); err != nil { | ||
| return err | ||
| } | ||
|
|
||
|
|
@@ -163,7 +168,7 @@ func prepare(mnt, volume, dist, rhnuser, rhnpasswd, rootpasswd string) error { | |
| return nil | ||
| } | ||
|
|
||
| func UmountHostPartitions(mnt string) { | ||
| func UmountHostPartitions(mnt, dist string) { | ||
| for _, p := range hostPartitions { | ||
| Umount(filepath.Join(mnt, p)) | ||
| } | ||
|
|
@@ -176,7 +181,7 @@ func Prepare4capture(mnt, volume, dist, rhnuser, rhnpasswd, rootpasswd string) e | |
| //} | ||
| //defer os.Chdir(cwd) | ||
| switch dist := strings.ToLower(dist); dist { | ||
| case "rhel", "centos": | ||
| case "rhel", "centos", "fedora": | ||
| return prepare(mnt, volume, dist, rhnuser, rhnpasswd, rootpasswd) | ||
| case "coreos": | ||
| klog.Info("No image preparation required for the coreos.") | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -39,8 +39,6 @@ yum install -y cloud-init | |
| yum reinstall grub2-common -y | ||
| rm -rf /etc/systemd/system/multi-user.target.wants/firewalld.service | ||
| rpm -vih --nodeps https://public.dhe.ibm.com/software/server/POWER/Linux/yum/download/ibm-power-repo-latest.noarch.rpm | ||
| sed -i 's/^more \/opt\/ibm\/lop\/notice/#more \/opt\/ibm\/lop\/notice/g' /opt/ibm/lop/configure | ||
| echo 'y' | /opt/ibm/lop/configure | ||
| {{if eq .Dist "rhel"}} | ||
| # Disable the AT repository due to slowness in nature | ||
| yum-config-manager --disable Advance_Toolchain | ||
|
|
@@ -49,6 +47,14 @@ yum-config-manager --disable Advance_Toolchain | |
| yum-config-manager --add-repo=https://public.dhe.ibm.com/software/server/POWER/Linux/yum/IBM/RHEL/$(rpm -E %{rhel})/ppc64le/ | ||
| rpm --import https://public.dhe.ibm.com/software/server/POWER/Linux/yum/IBM/RHEL/$(rpm -E %{rhel})/ppc64le/repodata/repomd.xml.key | ||
| {{end}} | ||
| {{if eq .Dist "fedora"}} | ||
| yum-config-manager --add-repo=https://public.dhe.ibm.com/software/server/POWER/Linux/yum/IBM/$(rpm -E %{dist_vendor})/ppc64le/ | ||
| rpm --import https://public.dhe.ibm.com/software/server/POWER/Linux/yum/IBM/$(rpm -E %{dist_vendor})/ppc64le/repodata/repomd.xml.key | ||
| {{end}} | ||
| sed -i -E 's/^(more \/opt\/ibm\/lop\/notice|less \/opt\/ibm\/lop\/notice)/#\1/' /opt/ibm/lop/configure | ||
|
|
||
| echo 'y' | /opt/ibm/lop/configure | ||
|
|
||
|
bkhadars marked this conversation as resolved.
|
||
| yum install powerpc-utils librtas DynamicRM devices.chrp.base.ServiceRM rsct.opt.storagerm rsct.core rsct.basic rsct.core src -y | ||
| yum install -y device-mapper-multipath | ||
| cat <<EOF > /etc/multipath.conf | ||
|
|
@@ -66,10 +72,15 @@ defaults { | |
| } | ||
| EOF | ||
| sed -i 's/GRUB_TIMEOUT=.*$/GRUB_TIMEOUT=60/g' /etc/default/grub | ||
| sed -i 's/GRUB_CMDLINE_LINUX=.*$/GRUB_CMDLINE_LINUX="console=tty0 console=hvc0,115200n8 biosdevname=0 crashkernel=auto rd.shell rd.debug rd.driver.pre=dm_multipath log_buf_len=1M "/g' /etc/default/grub | ||
| sed -i 's/^\(GRUB_CMDLINE_LINUX_DEFAULT\|GRUB_CMDLINE_LINUX\)=.*$/GRUB_CMDLINE_LINUX="console=tty0 console=hvc0,115200n8 biosdevname=0 crashkernel=auto rd.shell rd.debug rd.driver.pre=dm_multipath log_buf_len=1M autorelabel=1 "/g' /etc/default/grub | ||
| echo 'force_drivers+=" dm-multipath "' >/etc/dracut.conf.d/10-mp.conf | ||
| dracut --regenerate-all --force | ||
| for kernel in $(rpm -q kernel | sort -V | sed 's/kernel-//') | ||
| {{if eq .Dist "fedora"}} | ||
| kernel_pkg="kernel-core" | ||
| {{else}} | ||
| kernel_pkg="kernel" | ||
| {{end}} | ||
| for kernel in $(rpm -q $kernel_pkg | sort -V | sed "s/$kernel_pkg-//") | ||
| do | ||
| echo "Generating initramfs for kernel version: ${kernel}" | ||
| dracut --kver ${kernel} --force --add multipath --include /etc/multipath /etc/multipath --include /etc/multipath.conf /etc/multipath.conf | ||
|
|
@@ -85,7 +96,7 @@ subscription-manager clean | |
| rpm -e ibm-power-repo-*.noarch | ||
|
|
||
| mv /etc/resolv.conf.orig /etc/resolv.conf || true | ||
| touch /.autorelabel | ||
| setfiles -F /etc/selinux/targeted/contexts/files/file_contexts / | ||
| ` | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is already part of the code |
||
|
|
||
| var CloudConfig = `# latest file from cloud-init-22.1-1.el8.noarch | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -45,15 +45,24 @@ Examples: | |
| # Converts the CentOS image from the local filesystem with size 50GB | ||
| pvsadm image qcow2ova --image-name centos-82 --image-dist centos --image-size 50 --image-url /root/CentOS-8-GenericCloud-8.2.2004-20200611.2.ppc64le.qcow2 | ||
|
|
||
| # Converts the Fedora image from the local filesystem with size 50GB | ||
| pvsadm image qcow2ova --image-name fedora-41 --image-dist fedora --image-size 50 --image-url /root/Fedora-Cloud-Base-Generic-41-1.4.ppc64le.qcow2 | ||
|
|
||
| # Converts the RHEL image from local filesystem | ||
| pvsadm image qcow2ova --image-name rhel-82-29oct --image-dist rhel --rhn-user joesmith@example.com --rhn-password someValidPassword --image-url ./rhel-8.2-update-2-ppc64le-kvm.qcow2 | ||
|
|
||
| # Converts the CentOS image from the local filesystem with OS password set | ||
| pvsadm image qcow2ova --image-name centos-82 --image-dist centos --os-password s0meC0mplexPassword --image-url /root/CentOS-8-GenericCloud-8.2.2004-20200611.2.ppc64le.qcow2 | ||
|
|
||
| ## Converts the Fedora image from the local filesystem with OS password set | ||
| pvsadm image qcow2ova --image-name fedora-41 --image-dist fedora --os-password s0meC0mplexPassword --image-url /root/Fedora-Cloud-Base-Generic-41-1.4.ppc64le.qcow2 | ||
|
|
||
| # Converts the CentOS image from the local filesystem without OS password | ||
| pvsadm image qcow2ova --image-name centos-82 --image-dist centos --image-url /root/CentOS-8-GenericCloud-8.2.2004-20200611.2.ppc64le.qcow2 --skip-os-password | ||
|
|
||
| # Converts the Fedora image from the local filesystem without OS password | ||
| pvsadm image qcow2ova --image-name fedora-41 --image-dist fedora --image-url /root/Fedora-Cloud-Base-Generic-41-1.4.ppc64le.qcow2 --skip-os-password | ||
|
|
||
| # Customize the image preparation script for RHEL/CentOS distro, e.g: add additional yum repository or packages, change name servers etc. | ||
| # Step 1 - Dump the default image preparation template | ||
| pvsadm image qcow2ova --prep-template-default > image-prep.template | ||
|
|
@@ -68,14 +77,13 @@ Examples: | |
| # Step 3 - Run the qcow2ova with the modified cloud config template | ||
| pvsadm image qcow2ova --image-name centos-82 --image-dist centos --image-url /root/CentOS-8-GenericCloud-8.2.2004-20200611.2.ppc64le.qcow2 --cloud-config user_cloud.config | ||
|
|
||
|
|
||
|
|
||
| Qcow2 images location: | ||
|
|
||
| # CentOS 8: https://cloud.centos.org/centos/8-stream/ppc64le/images/ | ||
| # CentOS 9: https://cloud.centos.org/centos/9-stream/ppc64le/images/ | ||
| # Old Centos: https://cloud.centos.org/centos/8/ppc64le/images/ | ||
| # RHEL image: https://access.redhat.com/downloads/content/279/ver=/rhel---8/8.3/ppc64le/product-software | ||
| # Fedora image: https://archive.fedoraproject.org/pub/fedora-secondary/releases/41/Cloud/ppc64le/images | ||
| # RHCOS images: https://mirror.openshift.com/pub/openshift-v4/ppc64le/dependencies/rhcos/ | ||
|
|
||
| `, | ||
|
|
@@ -113,11 +121,22 @@ Qcow2 images location: | |
| prep.CloudConfig = string(content) | ||
|
|
||
| } | ||
| if !utils.Contains([]string{"rhel", "centos", "coreos"}, strings.ToLower(opt.ImageDist)) { | ||
| klog.Errorln("--image-dist is a mandatory flag and one of these [rhel, centos, coreos]") | ||
| if !utils.Contains([]string{"rhel", "centos", "fedora", "coreos"}, strings.ToLower(opt.ImageDist)) { | ||
| klog.Errorln("--image-dist is a mandatory flag and valid --image-dist options are [rhel, centos, fedora, coreos]") | ||
| os.Exit(1) | ||
| } | ||
|
|
||
| if opt.ImageDist == "fedora" { | ||
| supported, err := utils.IsBtrfsSupported() | ||
| if err != nil { | ||
| return err | ||
| } | ||
| if !supported { | ||
| klog.Errorln("to create fedora ova image btrfs support should be available in the kernel]") | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Request to make this little more clear, |
||
| os.Exit(1) | ||
| } | ||
| } | ||
|
|
||
| //Read the RHNUser and RHNPassword if empty | ||
| if opt.ImageDist == "rhel" && (opt.RHNUser == "" || opt.RHNPassword == "") { | ||
| var err error | ||
|
|
@@ -179,6 +198,7 @@ Qcow2 images location: | |
|
|
||
| } | ||
|
|
||
| klog.Info("before perflight check validations") | ||
| // preflight checks validations | ||
| return validate.Validate() | ||
| }, | ||
|
|
@@ -209,7 +229,7 @@ Qcow2 images location: | |
| <-c | ||
| klog.Info("Received an interrupt, exiting.") | ||
| prep.ExitChroot() | ||
| prep.UmountHostPartitions(mnt) | ||
| prep.UmountHostPartitions(mnt, opt.ImageDist) | ||
| _ = prep.Umount(mnt) | ||
| _ = os.RemoveAll(tmpDir) | ||
| os.Exit(1) | ||
|
|
@@ -292,7 +312,7 @@ Qcow2 images location: | |
| func init() { | ||
| Cmd.Flags().StringVar(&pkg.ImageCMDOptions.ImageName, "image-name", "", "Name of the resultant OVA image") | ||
| Cmd.Flags().StringVar(&pkg.ImageCMDOptions.ImageURL, "image-url", "", "URL or absolute local file path to the <QCOW2>.gz image") | ||
| Cmd.Flags().StringVar(&pkg.ImageCMDOptions.ImageDist, "image-dist", "", "Image Distribution(supported: rhel, centos, coreos)") | ||
| Cmd.Flags().StringVar(&pkg.ImageCMDOptions.ImageDist, "image-dist", "", "Image Distribution(supported: rhel, centos, fedora, coreos)") | ||
| Cmd.Flags().Uint64Var(&pkg.ImageCMDOptions.ImageSize, "image-size", 11, "Size (in GB) of the resultant OVA image") | ||
| Cmd.Flags().Int64Var(&pkg.ImageCMDOptions.TargetDiskSize, "target-disk-size", 120, "Size (in GB) of the target disk volume where OVA will be copied") | ||
| Cmd.Flags().StringVar(&pkg.ImageCMDOptions.RHNUser, "rhn-user", "", "RedHat Subscription username. Required when Image distribution is rhel") | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.