From 0a053c62ab6f3c48a025780ad98a7d193fc8669f Mon Sep 17 00:00:00 2001 From: Josh Curl Date: Sun, 14 Aug 2016 19:17:24 -0700 Subject: [PATCH] Extend write_files to run in all system services --- cmd/cloudinitexecute/cloudinitexecute.go | 55 +++++++++++++----- cmd/cloudinitsave/cloudinitsave.go | 11 ++-- cmd/control/cli.go | 6 ++ cmd/control/entrypoint.go | 74 ++++++++++++++++++++++++ config/types.go | 8 ++- images/01-base/Dockerfile | 3 +- os-config.tpl.yml | 8 ++- scripts/package-rootfs | 16 ++--- tests/assets/test_23/cloud-config.yml | 29 ++++++++++ tests/kernel_headers_test.go | 2 +- tests/write_files_test.go | 13 +++++ 11 files changed, 191 insertions(+), 34 deletions(-) create mode 100644 cmd/control/entrypoint.go create mode 100644 tests/assets/test_23/cloud-config.yml create mode 100644 tests/write_files_test.go diff --git a/cmd/cloudinitexecute/cloudinitexecute.go b/cmd/cloudinitexecute/cloudinitexecute.go index ff2395f8..d172e8b6 100644 --- a/cmd/cloudinitexecute/cloudinitexecute.go +++ b/cmd/cloudinitexecute/cloudinitexecute.go @@ -12,8 +12,10 @@ import ( log "github.com/Sirupsen/logrus" "github.com/coreos/coreos-cloudinit/system" "github.com/docker/docker/pkg/mount" - "github.com/rancher/os/config" + rancherConfig "github.com/rancher/os/config" + "github.com/rancher/os/docker" "github.com/rancher/os/util" + "golang.org/x/net/context" ) const ( @@ -38,7 +40,7 @@ func Main() { log.Infof("Running cloud-init-execute: pre-console=%v, console=%v", preConsole, console) - cfg := config.LoadConfig() + cfg := rancherConfig.LoadConfig() if !console && !preConsole { console = true @@ -53,21 +55,13 @@ func Main() { } } -func ApplyConsole(cfg *config.CloudConfig) { +func ApplyConsole(cfg *rancherConfig.CloudConfig) { if len(cfg.SSHAuthorizedKeys) > 0 { authorizeSSHKeys("rancher", cfg.SSHAuthorizedKeys, sshKeyName) authorizeSSHKeys("docker", cfg.SSHAuthorizedKeys, sshKeyName) } - for _, file := range cfg.WriteFiles { - f := system.File{File: file} - fullPath, err := system.WriteFile(&f, "/") - if err != nil { - log.WithFields(log.Fields{"err": err, "path": fullPath}).Error("Error writing file") - continue - } - log.Printf("Wrote file %s to filesystem", fullPath) - } + WriteFiles(cfg, "console") for _, configMount := range cfg.Mounts { if len(configMount) != 4 { @@ -88,7 +82,29 @@ func ApplyConsole(cfg *config.CloudConfig) { } } -func applyPreConsole(cfg *config.CloudConfig) { +func WriteFiles(cfg *rancherConfig.CloudConfig, container string) { + for _, file := range cfg.WriteFiles { + fileContainer := file.Container + if fileContainer == "" { + fileContainer = "console" + } + if fileContainer != container { + continue + } + + f := system.File{ + File: file.File, + } + fullPath, err := system.WriteFile(&f, "/") + if err != nil { + log.WithFields(log.Fields{"err": err, "path": fullPath}).Error("Error writing file") + continue + } + log.Printf("Wrote file %s to filesystem", fullPath) + } +} + +func applyPreConsole(cfg *rancherConfig.CloudConfig) { if _, err := os.Stat(resizeStamp); os.IsNotExist(err) && cfg.Rancher.ResizeDevice != "" { if err := resizeDevice(cfg); err == nil { os.Create(resizeStamp) @@ -105,9 +121,20 @@ func applyPreConsole(cfg *config.CloudConfig) { log.Errorf("Failed to set sysctl key %s: %s", k, err) } } + + client, err := docker.NewSystemClient() + if err != nil { + log.Error(err) + } + + for _, restart := range cfg.Rancher.RestartServices { + if err = client.ContainerRestart(context.Background(), restart, 10); err != nil { + log.Error(err) + } + } } -func resizeDevice(cfg *config.CloudConfig) error { +func resizeDevice(cfg *rancherConfig.CloudConfig) error { cmd := exec.Command("growpart", cfg.Rancher.ResizeDevice, "1") err := cmd.Run() if err != nil { diff --git a/cmd/cloudinitsave/cloudinitsave.go b/cmd/cloudinitsave/cloudinitsave.go index dd78d4aa..f1b0503a 100644 --- a/cmd/cloudinitsave/cloudinitsave.go +++ b/cmd/cloudinitsave/cloudinitsave.go @@ -70,9 +70,6 @@ func Main() { func saveFiles(cloudConfigBytes, scriptBytes []byte, metadata datasource.Metadata) error { os.MkdirAll(rancherConfig.CloudConfigDir, os.ModeDir|0600) - os.Remove(rancherConfig.CloudConfigScriptFile) - os.Remove(rancherConfig.CloudConfigBootFile) - os.Remove(rancherConfig.MetaDataFile) if len(scriptBytes) > 0 { log.Infof("Writing to %s", rancherConfig.CloudConfigScriptFile) @@ -82,10 +79,12 @@ func saveFiles(cloudConfigBytes, scriptBytes []byte, metadata datasource.Metadat } } - if err := util.WriteFileAtomic(rancherConfig.CloudConfigBootFile, cloudConfigBytes, 400); err != nil { - return err + if len(cloudConfigBytes) > 0 { + if err := util.WriteFileAtomic(rancherConfig.CloudConfigBootFile, cloudConfigBytes, 400); err != nil { + return err + } + log.Infof("Written to %s:\n%s", rancherConfig.CloudConfigBootFile, string(cloudConfigBytes)) } - log.Infof("Written to %s:\n%s", rancherConfig.CloudConfigBootFile, string(cloudConfigBytes)) metaDataBytes, err := yaml.Marshal(metadata) if err != nil { diff --git a/cmd/control/cli.go b/cmd/control/cli.go index f5d7b833..62157730 100644 --- a/cmd/control/cli.go +++ b/cmd/control/cli.go @@ -45,6 +45,12 @@ func Main() { SkipFlagParsing: true, Action: devAction, }, + { + Name: "entrypoint", + HideHelp: true, + SkipFlagParsing: true, + Action: entrypointAction, + }, { Name: "env", ShortName: "e", diff --git a/cmd/control/entrypoint.go b/cmd/control/entrypoint.go new file mode 100644 index 00000000..7af95dfc --- /dev/null +++ b/cmd/control/entrypoint.go @@ -0,0 +1,74 @@ +package control + +import ( + "os" + "os/exec" + "syscall" + + log "github.com/Sirupsen/logrus" + "github.com/codegangsta/cli" + "golang.org/x/net/context" + + "github.com/docker/docker/pkg/mount" + "github.com/rancher/os/cmd/cloudinitexecute" + "github.com/rancher/os/config" + "github.com/rancher/os/docker" + "github.com/rancher/os/util" +) + +const ( + ca = "/etc/ssl/certs/ca-certificates.crt" + caBase = "/etc/ssl/certs/ca-certificates.crt.rancher" +) + +func entrypointAction(c *cli.Context) error { + if err := mount.Mount("/host/dev", "/dev", "", "rbind"); err != nil { + log.Error(err) + } + + if err := util.FileCopy(caBase, ca); err != nil && !os.IsNotExist(err) { + log.Error(err) + } + + cfg := config.LoadConfig() + + shouldWriteFiles := false + for _, file := range cfg.WriteFiles { + if file.Container != "" { + shouldWriteFiles = true + } + } + + if shouldWriteFiles { + writeFiles(cfg) + } + + if len(os.Args) < 3 { + return nil + } + + binary, err := exec.LookPath(os.Args[2]) + if err != nil { + return err + } + + return syscall.Exec(binary, os.Args[2:], os.Environ()) +} + +func writeFiles(cfg *config.CloudConfig) error { + id, err := util.GetCurrentContainerId() + if err != nil { + return err + } + client, err := docker.NewSystemClient() + if err != nil { + return err + } + info, err := client.ContainerInspect(context.Background(), id) + if err != nil { + return err + } + + cloudinitexecute.WriteFiles(cfg, info.Name[1:]) + return nil +} diff --git a/config/types.go b/config/types.go index 04fb7e6f..5c9b8113 100644 --- a/config/types.go +++ b/config/types.go @@ -85,12 +85,17 @@ type Repositories map[string]Repository type CloudConfig struct { SSHAuthorizedKeys []string `yaml:"ssh_authorized_keys"` - WriteFiles []config.File `yaml:"write_files"` + WriteFiles []File `yaml:"write_files"` Hostname string `yaml:"hostname"` Mounts [][]string `yaml:"mounts,omitempty"` Rancher RancherConfig `yaml:"rancher,omitempty"` } +type File struct { + config.File + Container string `yaml:"container,omitempty"` +} + type RancherConfig struct { Console string `yaml:"console,omitempty"` Environment map[string]string `yaml:"environment,omitempty"` @@ -119,6 +124,7 @@ type RancherConfig struct { Defaults Defaults `yaml:"defaults,omitempty"` ResizeDevice string `yaml:"resize_device,omitempty"` Sysctl map[string]string `yaml:"sysctl,omitempty"` + RestartServices []string `yaml:"restart_services,omitempty"` } type UpgradeConfig struct { diff --git a/images/01-base/Dockerfile b/images/01-base/Dockerfile index ede8632e..b328c2d3 100644 --- a/images/01-base/Dockerfile +++ b/images/01-base/Dockerfile @@ -32,8 +32,7 @@ RUN rm /sbin/poweroff /sbin/reboot /sbin/halt && \ adduser docker sudo && \ echo '%sudo ALL=(ALL) ALL' >> /etc/sudoers COPY inputrc /etc/inputrc -COPY entry.sh /usr/sbin/entry.sh COPY growpart /usr/bin/growpart RUN sed -i -e 's/duid/clientid/g' /etc/dhcpcd.conf -ENTRYPOINT ["/usr/sbin/entry.sh"] +ENTRYPOINT ["/usr/bin/ros", "entrypoint"] diff --git a/os-config.tpl.yml b/os-config.tpl.yml index 64fab571..80298129 100644 --- a/os-config.tpl.yml +++ b/os-config.tpl.yml @@ -250,6 +250,9 @@ rancher: uts: host privileged: true restart: always + volumes_from: + - command-volumes + - system-volumes preload-system-images: image: {{.OS_REPO}}/os-preload:{{.VERSION}}{{.SUFFIX}} labels: @@ -289,6 +292,7 @@ rancher: privileged: true restart: always volumes_from: + - command-volumes - system-volumes system-volumes: image: {{.OS_REPO}}/os-base:{{.VERSION}}{{.SUFFIX}} @@ -325,9 +329,8 @@ rancher: uts: host privileged: true volumes_from: + - command-volumes - system-volumes - volumes: - - /usr/bin/ros:/usr/bin/ros:ro udev: image: {{.OS_REPO}}/os-udev:{{.VERSION}}{{.SUFFIX}} environment: @@ -340,6 +343,7 @@ rancher: privileged: true restart: always volumes_from: + - command-volumes - system-volumes user-volumes: image: {{.OS_REPO}}/os-base:{{.VERSION}}{{.SUFFIX}} diff --git a/scripts/package-rootfs b/scripts/package-rootfs index 187975b2..09534fa5 100755 --- a/scripts/package-rootfs +++ b/scripts/package-rootfs @@ -15,19 +15,19 @@ INITRD=${ARTIFACTS}/initrd mkdir -p ${ARTIFACTS} ${PREPOP_DIR} -if [ "$(docker info | grep 'Storage Driver: ' | sed 's/Storage Driver: //')" != "overlay" ]; then - echo Overlay storage driver is require to prepackage exploded images - echo packaging images.tar instead - tar czf ${ARTIFACTS}/rootfs.tar.gz --exclude lib/modules --exclude lib/firmware -C ${INITRD_DIR} . - exit 0 -fi +#if [ "$(docker info | grep 'Storage Driver: ' | sed 's/Storage Driver: //')" != "overlay" ]; then +echo Overlay storage driver is require to prepackage exploded images +echo packaging images.tar instead +tar czf ${ARTIFACTS}/rootfs.tar.gz --exclude lib/modules --exclude lib/firmware -C ${INITRD_DIR} . +exit 0 +#fi DFS=$(docker run -d --privileged -v /lib/modules/$(uname -r):/lib/modules/$(uname -r) ${DFS_IMAGE}${SUFFIX} ${DFS_ARGS}) trap "docker rm -fv ${DFS_ARCH} ${DFS}" EXIT docker exec -i ${DFS} docker load < ${INITRD_DIR}/usr/share/ros/images.tar docker stop ${DFS} -docker run --rm --volumes-from=${DFS} rancher/os-base tar -c -C /var/lib/docker ./image | tar -x -C ${PREPOP_DIR} -docker run --rm --volumes-from=${DFS} rancher/os-base tar -c -C /var/lib/docker ./overlay | tar -x -C ${PREPOP_DIR} +docker run --rm --volumes-from=${DFS} busybox tar -c -C /var/lib/docker ./image | tar -x -C ${PREPOP_DIR} +docker run --rm --volumes-from=${DFS} busybox tar -c -C /var/lib/docker ./overlay | tar -x -C ${PREPOP_DIR} tar -cf ${ARTIFACTS}/rootfs.tar --exclude usr/share/ros/images.tar --exclude lib/modules --exclude lib/firmware -C ${INITRD_DIR} . tar -rf ${ARTIFACTS}/rootfs.tar -C ${IMAGE_CACHE} . diff --git a/tests/assets/test_23/cloud-config.yml b/tests/assets/test_23/cloud-config.yml new file mode 100644 index 00000000..f121e2d0 --- /dev/null +++ b/tests/assets/test_23/cloud-config.yml @@ -0,0 +1,29 @@ +#cloud-config +write_files: +- path: "/test" + permissions: "0644" + owner: "root" + content: | + console content +- path: "/test2" + container: console + permissions: "0644" + owner: "root" + content: | + console content +- path: "/test" + container: ntp + permissions: "0644" + owner: "root" + content: | + ntp content +- path: "/test" + container: syslog + permissions: "0644" + owner: "root" + content: | + syslog content +rancher: + restart_services: [syslog] +ssh_authorized_keys: + - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC85w9stZyiLQp/DkVO6fqwiShYcj1ClKdtCqgHtf+PLpJkFReSFu8y21y+ev09gsSMRRrjF7yt0pUHV6zncQhVeqsZtgc5WbELY2DOYUGmRn/CCvPbXovoBrQjSorqlBmpuPwsStYLr92Xn+VVsMNSUIegHY22DphGbDKG85vrKB8HxUxGIDxFBds/uE8FhSy+xsoyT/jUZDK6pgq2HnGl6D81ViIlKecpOpWlW3B+fea99ADNyZNVvDzbHE5pcI3VRw8u59WmpWOUgT6qacNVACl8GqpBvQk8sw7O/X9DSZHCKafeD9G5k+GYbAUz92fKWrx/lOXfUXPS3+c8dRIF diff --git a/tests/kernel_headers_test.go b/tests/kernel_headers_test.go index 3297b85d..cbba30f3 100644 --- a/tests/kernel_headers_test.go +++ b/tests/kernel_headers_test.go @@ -7,6 +7,6 @@ func (s *QemuSuite) TestKernelHeaders(c *C) { c.Assert(err, IsNil) s.CheckCall(c, ` -sleep 10 +sleep 15 docker inspect kernel-headers`) } diff --git a/tests/write_files_test.go b/tests/write_files_test.go new file mode 100644 index 00000000..206f3341 --- /dev/null +++ b/tests/write_files_test.go @@ -0,0 +1,13 @@ +package integration + +import . "gopkg.in/check.v1" + +func (s *QemuSuite) TestWriteFiles(c *C) { + err := s.RunQemu("--cloud-config", "./tests/assets/test_23/cloud-config.yml") + c.Assert(err, IsNil) + + s.CheckCall(c, "sudo cat /test | grep 'console content'") + s.CheckCall(c, "sudo cat /test2 | grep 'console content'") + s.CheckCall(c, "sudo system-docker exec ntp cat /test | grep 'ntp content'") + s.CheckCall(c, "sudo system-docker exec syslog cat /test | grep 'syslog content'") +}