From 9ea892b669df9e48daf121254bcb1712b8db77ce Mon Sep 17 00:00:00 2001 From: Yolanda Robla Date: Wed, 13 Mar 2019 13:39:59 +0100 Subject: [PATCH] Add command to build images Change-Id: I8a01b72c78555d4af899856637e1f49a940e36ad --- Makefile | 16 ++++-- README.md | 15 +++++ cmd/images.go | 175 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 201 insertions(+), 5 deletions(-) create mode 100644 cmd/images.go diff --git a/Makefile b/Makefile index 8998dc9..46095c9 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,7 @@ GONAME="kni-edge-installer" BUILDDIR = $(shell pwd)/build INSTALLER_GIT_REPO = github.com/openshift/installer +RHCOS_VERSION = "maipo" ifndef INSTALLER_PATH override INSTALLER_PATH = https://github.com/openshift/installer/releases/download/v0.14.0/openshift-install-linux-amd64 @@ -25,19 +26,24 @@ build: @echo "Building kni-edge-installer with $(GOPATH) to ./bin" @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go build -o bin/$(GONAME) $(GOFILES) -deploy: - @echo "Launching cluster deployment bin/$(GONAME)" - @./bin/$(GONAME) generate --installer_path $(INSTALLER_PATH) --build_path $(BUILDDIR) --base_repository $(BASE_REPO) --base_path $(BASE_PATH) --secrets_repository $(CREDENTIALS) --site_repository $(SITE_REPO) --settings_path $(SETTINGS_PATH) - clean: @echo "Destroying previous cluster" @./bin/$(GONAME) clean --build_path $(BUILDDIR) +deploy: + @echo "Launching cluster deployment bin/$(GONAME)" + @./bin/$(GONAME) generate --installer_path $(INSTALLER_PATH) --build_path $(BUILDDIR) --base_repository $(BASE_REPO) --base_path $(BASE_PATH) --secrets_repository $(CREDENTIALS) --site_repository $(SITE_REPO) --settings_path $(SETTINGS_PATH) --master_memory_mb $(MASTER_MEMORY_MB) + +images: + @echo "Launching image generation" + @./bin/$(GONAME) images --build_path $(BUILDDIR) --version $(RHCOS_VERSION) + help: @echo "Please use \`make ' where is one of" @echo " binary to generate a new openshift-install binary" @echo " build to produce the installer binary" @echo " clean to destroy a previously created cluster and remove build contents" - @echo " deploy CREDENTIALS= BASE_REPO= BASE_PATH= SITE_REPO= SETTINGS_PATH= + @echo " deploy CREDENTIALS= BASE_REPO= BASE_PATH= SITE_REPO= SETTINGS_PATH=" + @echo " images to download baremetal images" .PHONY: build get install run watch start stop restart clean diff --git a/README.md b/README.md index 98dd723..90a3a9f 100644 --- a/README.md +++ b/README.md @@ -163,3 +163,18 @@ can be modified with the desired values. After that this code can be executed to generate a new cluster based on the modified manifests: /path/to/openshift-install create cluster + +## How to create images (WIP) + +For the installer to work on baremetal, it needs a different type of images: installer image (kernel, ramdisk), and the deployment image (raw). To generate the images please execute: + + make images + +<<<<<<< HEAD +======= +By default it will generate RHCOS Maipo images. But ootpa can be generated by: + + make images RHCOS_VERSION=ootpa + +>>>>>>> 10f8945... Add command to build images +And this will leave the needed images inside your build directory. Those can be used later for a baremetal deploy. diff --git a/cmd/images.go b/cmd/images.go new file mode 100644 index 0000000..f042e66 --- /dev/null +++ b/cmd/images.go @@ -0,0 +1,175 @@ +// Copyright © 2019 Red Hat +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cmd + +import ( + "bytes" + "fmt" + "io" + "io/ioutil" + "log" + "os" + "os/exec" + + "github.com/spf13/cobra" +) + +// UmountDirectory will umount the ISO directory +func UmountDirectory(mountPath string) { + cmd := exec.Command("sudo", "umount", mountPath) + out, err := cmd.CombinedOutput() + if err != nil { + log.Fatal(fmt.Sprintf("Error umounting directory: %s - %s", err, string(out))) + os.Exit(1) + } + + // remove mount directory + os.RemoveAll(mountPath) +} + +// ExtractIsoFiles will extract vmlinuz and initramfs from a given ISO +func ExtractIsoFiles(isoPath string, buildPath string) { + // once there, mount it + mountPath := fmt.Sprintf("%s/iso_mount", buildPath) + os.RemoveAll(mountPath) + os.MkdirAll(mountPath, 0775) + + // mount iso into that directory + log.Println("Extracting image content") + cmd := exec.Command("sudo", "mount", "-o", "loop", isoPath, mountPath) + cmd.Dir = buildPath + out, err := cmd.CombinedOutput() + if err != nil { + log.Fatal(fmt.Sprintf("Error creating manifests: %s - %s", err, string(out))) + os.Exit(1) + } + + // copy the images to the build directory + cmd = exec.Command("cp", fmt.Sprintf("%s/vmlinuz", mountPath), buildPath) + cmd.Dir = buildPath + out, err = cmd.CombinedOutput() + if err != nil { + log.Fatal(fmt.Sprintf("Error copying vmlinuz: %s - %s", err, string(out))) + UmountDirectory(mountPath) + os.Exit(1) + } + + cmd = exec.Command("cp", fmt.Sprintf("%s/initramfs.img", mountPath), buildPath) + cmd.Dir = buildPath + out, err = cmd.CombinedOutput() + if err != nil { + log.Fatal(fmt.Sprintf("Error copying initramfs: %s - %s", err, string(out))) + UmountDirectory(mountPath) + os.Exit(1) + } + os.Chmod(fmt.Sprintf("%s/initramfs.img", buildPath), 0664) + UmountDirectory(mountPath) + + log.Println("Installer images are under: build/vmlinuz, build/initramfs.img") + +} + +// GenerateInstallerImages will extract vmlinuz/ramdisk from modified FCOS iso +func GenerateInstallerImages(buildPath string) { + // Generate build directory for cosa + cosaPath := fmt.Sprintf("%s/cosa_build", buildPath) + os.RemoveAll(cosaPath) + os.MkdirAll(cosaPath, 0775) + + // generate installer file + cosaBuildContent := ` +#! /bin/bash +# init the build and proceed +cd /srv +coreos-assembler init https://github.com/yrobla/fedora-coreos-config --force + +coreos-assembler build +coreos-assembler buildextend-installer +` + builderPath := fmt.Sprintf("%s/cosa_build_image.sh", cosaPath) + f, err := os.Create(builderPath) + if err != nil { + log.Fatal(fmt.Sprintf("Error creating installer script: %s", err)) + os.Exit(1) + } + _, err = f.WriteString(cosaBuildContent) + f.Sync() + f.Close() + os.Chmod(builderPath, 0775) + + log.Println("Installing coreos-assembler and running generation script") + cmd := exec.Command("podman", "run", "--rm", "--net=host", "-ti", "--privileged", "--userns=host", "-v", fmt.Sprintf("%s:/srv", cosaPath), + "--workdir", "/srv", "quay.io/coreos-assembler/coreos-assembler:latest", "shell", "/srv/cosa_build_image.sh") + cmd.Dir = buildPath + + var stdBuffer bytes.Buffer + mw := io.MultiWriter(os.Stdout, &stdBuffer) + cmd.Stdout = mw + cmd.Stderr = mw + + err = cmd.Run() + if err != nil { + log.Fatal(fmt.Sprintf("Error installing coreos-assembler: %s - %s", err, stdBuffer.String())) + os.Exit(1) + } + log.Println(stdBuffer.String()) + + // once the iso has been generated, extract vmlinuz/initramfs.img + isoPath := fmt.Sprintf("%s/builds/latest/fedora-coreos-29.iso", cosaPath) + if _, err := os.Stat(isoPath); os.IsNotExist(err) { + // path/to/whatever does not exist + log.Fatal("Final ISO image does not exist") + os.Exit(1) + } + + ExtractIsoFiles(isoPath, buildPath) + +} + +// imagesCmd represents the images command +var imagesCmd = &cobra.Command{ + Use: "images", + Short: "Command to build the installer and deployment images (to be used on baremetal)", + Long: ``, + TraverseChildren: true, + Run: func(cmd *cobra.Command, args []string) { + // Check if build path exists, create if not + buildPath, _ := cmd.Flags().GetString("build_path") + if len(buildPath) == 0 { + // will generate a temporary directory + buildPath, _ = ioutil.TempDir("/tmp", "kni") + } else { + // remove if exists, recreate + os.RemoveAll(buildPath) + os.MkdirAll(buildPath, 0775) + } + + // check version + version, _ := cmd.Flags().GetString("version") + if len(version) == 0 || (version != "maipo" && version != "ootpa") { + log.Fatal("Version needs to be maipo or ootpa") + os.Exit(1) + } + + GenerateInstallerImages(buildPath) + }, +} + +func init() { + rootCmd.AddCommand(imagesCmd) + + imagesCmd.Flags().StringP("build_path", "", "", "Directory to use as build path. If that not exists, the installer will generate a default directory") + imagesCmd.Flags().StringP("version", "", "", "Version of the images being generated (maipo, ootpa)") +} -- 2.16.6