summaryrefslogtreecommitdiff
path: root/actions/filesystem_deploy_action.go
blob: af087f17d9cb1adf81f5f63c175377e879340735 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/*
FilesystemDeploy Action

Deploy prepared root filesystem to output image. This action requires
'image-partition' action to be executed before it.

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
}