/* FilesystemDeploy Action Deploy prepared root filesystem to output image by copying the files from the temporary scratch directory to the mounted image and optionally creates various configuration files for the image: '/etc/fstab' and '/etc/kernel/cmdline'. This action requires 'image-partition' action to be executed before it. After this action has ran, subsequent actions are executed on the mounted output image. Yaml syntax: - action: filesystem-deploy setup-fstab: bool setup-kernel-cmdline: bool append-kernel-cmdline: arguments Optional properties: - setup-fstab -- generate '/etc/fstab' file according to information provided by 'image-partition' action. By default is 'true'. - setup-kernel-cmdline -- add location of root partition to '/etc/kernel/cmdline' file on target image. By default is 'true'. - append-kernel-cmdline -- additional kernel command line arguments passed to kernel. */ package actions import ( "errors" "fmt" "io" "io/ioutil" "log" "os" "path" "strings" "github.com/go-debos/debos" ) type FilesystemDeployAction struct { debos.BaseAction `yaml:",inline"` SetupFSTab bool `yaml:"setup-fstab"` SetupKernelCmdline bool `yaml:"setup-kernel-cmdline"` AppendKernelCmdline string `yaml:"append-kernel-cmdline"` } func NewFilesystemDeployAction() *FilesystemDeployAction { fd := &FilesystemDeployAction{SetupFSTab: true, SetupKernelCmdline: true} fd.Description = "Deploying filesystem" return fd } func (fd *FilesystemDeployAction) setupFSTab(context *debos.DebosContext) error { if context.ImageFSTab.Len() == 0 { return errors.New("Fstab not generated, missing image-partition action?") } log.Print("Setting up fstab") err := os.MkdirAll(path.Join(context.Rootdir, "etc"), 0755) if err != nil { return fmt.Errorf("Couldn't create etc in image: %v", err) } fstab := path.Join(context.Rootdir, "etc/fstab") f, err := os.OpenFile(fstab, os.O_RDWR|os.O_CREATE, 0755) if err != nil { return fmt.Errorf("Couldn't open fstab: %v", err) } _, err = io.Copy(f, &context.ImageFSTab) if err != nil { return fmt.Errorf("Couldn't write fstab: %v", err) } f.Close() return nil } func (fd *FilesystemDeployAction) setupKernelCmdline(context *debos.DebosContext) error { var cmdline []string log.Print("Setting up /etc/kernel/cmdline") err := os.MkdirAll(path.Join(context.Rootdir, "etc", "kernel"), 0755) if err != nil { return fmt.Errorf("Couldn't create etc/kernel in image: %v", err) } path := path.Join(context.Rootdir, "etc/kernel/cmdline") current, _ := ioutil.ReadFile(path) f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0755) if err != nil { log.Fatalf("Couldn't open kernel cmdline: %v", err) } cmdline = append(cmdline, strings.TrimSpace(string(current))) cmdline = append(cmdline, context.ImageKernelRoot) if fd.AppendKernelCmdline != "" { cmdline = append(cmdline, fd.AppendKernelCmdline) } _, err = f.WriteString(strings.Join(cmdline, " ") + "\n") if err != nil { return fmt.Errorf("Couldn't write kernel/cmdline: %v", err) } f.Close() return nil } func (fd *FilesystemDeployAction) Run(context *debos.DebosContext) error { fd.LogStart() /* Copying files is actually silly hafd, one has to keep permissions, ACL's * extended attribute, misc, other. Leave it to cp... */ err := debos.Command{}.Run("Deploy to image", "cp", "-a", context.Rootdir+"/.", context.ImageMntDir) if err != nil { return fmt.Errorf("rootfs deploy failed: %v", err) } context.Rootdir = context.ImageMntDir context.Origins["filesystem"] = context.ImageMntDir if fd.SetupFSTab { err = fd.setupFSTab(context) if err != nil { return err } } if fd.SetupKernelCmdline { err = fd.setupKernelCmdline(context) if err != nil { return err } } return nil }