diff --git a/cmd/cloudinit/authorize_ssh_keys.go b/cmd/cloudinitexecute/authorize_ssh_keys.go similarity index 94% rename from cmd/cloudinit/authorize_ssh_keys.go rename to cmd/cloudinitexecute/authorize_ssh_keys.go index 52946129..79016135 100644 --- a/cmd/cloudinit/authorize_ssh_keys.go +++ b/cmd/cloudinitexecute/authorize_ssh_keys.go @@ -1,4 +1,4 @@ -package cloudinit +package cloudinitexecute import ( "os" diff --git a/cmd/cloudinitexecute/cloudinitexecute.go b/cmd/cloudinitexecute/cloudinitexecute.go new file mode 100644 index 00000000..05e889c4 --- /dev/null +++ b/cmd/cloudinitexecute/cloudinitexecute.go @@ -0,0 +1,131 @@ +package cloudinitexecute + +import ( + "flag" + "fmt" + "io/ioutil" + "os" + "os/exec" + "path" + "strings" + + "github.com/docker/docker/pkg/mount" + + log "github.com/Sirupsen/logrus" + "github.com/coreos/coreos-cloudinit/system" + "github.com/rancher/os/config" + "github.com/rancher/os/util" +) + +const ( + resizeStamp = "/var/lib/rancher/resizefs.done" + sshKeyName = "rancheros-cloud-config" +) + +var ( + console bool + preConsole bool + flags *flag.FlagSet +) + +func init() { + flags = flag.NewFlagSet(os.Args[0], flag.ContinueOnError) + flags.BoolVar(&console, "console", false, "apply console configuration") + flags.BoolVar(&preConsole, "pre-console", false, "apply pre-console configuration") +} + +func Main() { + flags.Parse(os.Args[1:]) + + log.Infof("Running cloud-init-execute: pre-console=%v, console=%v", preConsole, console) + + cfg := config.LoadConfig() + + if !console && !preConsole { + console = true + preConsole = true + } + + if console { + applyConsole(cfg) + } + if preConsole { + applyPreConsole(cfg) + } +} + +func applyConsole(cfg *config.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) + } + + for _, configMount := range cfg.Mounts { + if len(configMount) != 4 { + log.Errorf("Unable to mount %s: must specify exactly four arguments", configMount[1]) + } + device := util.ResolveDevice(configMount[0]) + if configMount[2] == "swap" { + cmd := exec.Command("swapon", device) + err := cmd.Run() + if err != nil { + log.Errorf("Unable to swapon %s: %v", device, err) + } + continue + } + if err := mount.Mount(device, configMount[1], configMount[2], configMount[3]); err != nil { + log.Errorf("Unable to mount %s: %v", configMount[1], err) + } + } +} + +func applyPreConsole(cfg *config.CloudConfig) { + if _, err := os.Stat(resizeStamp); os.IsNotExist(err) && cfg.Rancher.ResizeDevice != "" { + if err := resizeDevice(cfg); err == nil { + os.Create(resizeStamp) + } else { + log.Errorf("Failed to resize %s: %s", cfg.Rancher.ResizeDevice, err) + } + } + + for k, v := range cfg.Rancher.Sysctl { + elems := []string{"/proc", "sys"} + elems = append(elems, strings.Split(k, ".")...) + path := path.Join(elems...) + if err := ioutil.WriteFile(path, []byte(v), 0644); err != nil { + log.Errorf("Failed to set sysctl key %s: %s", k, err) + } + } +} + +func resizeDevice(cfg *config.CloudConfig) error { + cmd := exec.Command("growpart", cfg.Rancher.ResizeDevice, "1") + err := cmd.Run() + if err != nil { + return err + } + + cmd = exec.Command("partprobe") + err = cmd.Run() + if err != nil { + return err + } + + cmd = exec.Command("resize2fs", fmt.Sprintf("%s1", cfg.Rancher.ResizeDevice)) + err = cmd.Run() + if err != nil { + return err + } + + return nil +} diff --git a/cmd/cloudinit/cloudinit.go b/cmd/cloudinitsave/cloudinitsave.go similarity index 74% rename from cmd/cloudinit/cloudinit.go rename to cmd/cloudinitsave/cloudinitsave.go index 573131fe..dd78d4aa 100644 --- a/cmd/cloudinit/cloudinit.go +++ b/cmd/cloudinitsave/cloudinitsave.go @@ -13,22 +13,17 @@ // See the License for the specific language governing permissions and // limitations under the License. -package cloudinit +package cloudinitsave import ( "errors" "flag" - "fmt" - "io/ioutil" "os" - "os/exec" - "path" "strings" "sync" "time" yaml "github.com/cloudfoundry-incubator/candiedyaml" - "github.com/docker/docker/pkg/mount" log "github.com/Sirupsen/logrus" "github.com/coreos/coreos-cloudinit/config" @@ -41,9 +36,8 @@ import ( "github.com/coreos/coreos-cloudinit/datasource/proc_cmdline" "github.com/coreos/coreos-cloudinit/datasource/url" "github.com/coreos/coreos-cloudinit/pkg" - "github.com/coreos/coreos-cloudinit/system" "github.com/rancher/netconf" - "github.com/rancher/os/cmd/cloudinit/gce" + "github.com/rancher/os/cmd/cloudinitsave/gce" rancherConfig "github.com/rancher/os/config" "github.com/rancher/os/util" ) @@ -52,13 +46,9 @@ const ( datasourceInterval = 100 * time.Millisecond datasourceMaxInterval = 30 * time.Second datasourceTimeout = 5 * time.Minute - sshKeyName = "rancheros-cloud-config" - resizeStamp = "/var/lib/rancher/resizefs.done" ) var ( - save bool - execute bool network bool flags *flag.FlagSet ) @@ -66,8 +56,16 @@ var ( func init() { flags = flag.NewFlagSet(os.Args[0], flag.ContinueOnError) flags.BoolVar(&network, "network", true, "use network based datasources") - flags.BoolVar(&save, "save", false, "save cloud config and exit") - flags.BoolVar(&execute, "execute", false, "execute saved cloud config") +} + +func Main() { + flags.Parse(os.Args[1:]) + + log.Infof("Running cloud-init-save: network=%v", network) + + if err := saveCloudConfig(); err != nil { + log.Errorf("Failed to save cloud-config: %v", err) + } } func saveFiles(cloudConfigBytes, scriptBytes []byte, metadata datasource.Metadata) error { @@ -171,104 +169,6 @@ func fetchUserData() ([]byte, datasource.Metadata, error) { return userDataBytes, metadata, nil } -func resizeDevice(cfg *rancherConfig.CloudConfig) error { - cmd := exec.Command("growpart", cfg.Rancher.ResizeDevice, "1") - err := cmd.Run() - if err != nil { - return err - } - - cmd = exec.Command("partprobe") - err = cmd.Run() - if err != nil { - return err - } - - cmd = exec.Command("resize2fs", fmt.Sprintf("%s1", cfg.Rancher.ResizeDevice)) - err = cmd.Run() - if err != nil { - return err - } - - return nil -} - -func executeCloudConfig() error { - cc := rancherConfig.LoadConfig() - - if len(cc.SSHAuthorizedKeys) > 0 { - authorizeSSHKeys("rancher", cc.SSHAuthorizedKeys, sshKeyName) - authorizeSSHKeys("docker", cc.SSHAuthorizedKeys, sshKeyName) - } - - for _, file := range cc.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) - } - - if _, err := os.Stat(resizeStamp); os.IsNotExist(err) && cc.Rancher.ResizeDevice != "" { - if err := resizeDevice(cc); err == nil { - os.Create(resizeStamp) - } else { - log.Errorf("Failed to resize %s: %s", cc.Rancher.ResizeDevice, err) - } - } - - for _, configMount := range cc.Mounts { - if len(configMount) != 4 { - log.Errorf("Unable to mount %s: must specify exactly four arguments", configMount[1]) - } - device := util.ResolveDevice(configMount[0]) - if configMount[2] == "swap" { - cmd := exec.Command("swapon", device) - err := cmd.Run() - if err != nil { - log.Errorf("Unable to swapon %s: %v", device, err) - } - continue - } - if err := mount.Mount(device, configMount[1], configMount[2], configMount[3]); err != nil { - log.Errorf("Unable to mount %s: %v", configMount[1], err) - } - } - - for k, v := range cc.Rancher.Sysctl { - elems := []string{"/proc", "sys"} - elems = append(elems, strings.Split(k, ".")...) - path := path.Join(elems...) - if err := ioutil.WriteFile(path, []byte(v), 0644); err != nil { - log.Errorf("Failed to set sysctl key %s: %s", k, err) - } - } - - return nil -} - -func Main() { - flags.Parse(os.Args[1:]) - - log.Infof("Running cloud-init: save=%v, execute=%v", save, execute) - - if save { - err := saveCloudConfig() - if err != nil { - log.WithFields(log.Fields{"err": err}).Error("Failed to save cloud-config") - } - } - - if execute { - err := executeCloudConfig() - if err != nil { - log.WithFields(log.Fields{"err": err}).Error("Failed to execute cloud-config") - } - } -} - // getDatasources creates a slice of possible Datasources for cloudinit based // on the different source command-line flags. func getDatasources(cfg *rancherConfig.CloudConfig) []datasource.Datasource { diff --git a/cmd/cloudinit/gce/metadata.go b/cmd/cloudinitsave/gce/metadata.go similarity index 100% rename from cmd/cloudinit/gce/metadata.go rename to cmd/cloudinitsave/gce/metadata.go diff --git a/cmd/cloudinit/packet.go b/cmd/cloudinitsave/packet.go similarity index 99% rename from cmd/cloudinit/packet.go rename to cmd/cloudinitsave/packet.go index ebf54537..23cd2957 100644 --- a/cmd/cloudinit/packet.go +++ b/cmd/cloudinitsave/packet.go @@ -1,4 +1,4 @@ -package cloudinit +package cloudinitsave import ( "fmt" diff --git a/images/02-cloudinit/cloud-init.sh b/images/02-cloudinit/cloud-init.sh index 026452d8..3c6c0c0a 100755 --- a/images/02-cloudinit/cloud-init.sh +++ b/images/02-cloudinit/cloud-init.sh @@ -12,4 +12,4 @@ else mount -t 9p -o trans=virtio,version=9p2000.L config-2 ${MOUNT_POINT} 2>/dev/null || true fi -cloud-init -save -network=${CLOUD_INIT_NETWORK:-true} +cloud-init-save -network=${CLOUD_INIT_NETWORK:-true} diff --git a/images/02-console/console.sh b/images/02-console/console.sh index 9eb12968..c558d777 100755 --- a/images/02-console/console.sh +++ b/images/02-console/console.sh @@ -115,7 +115,7 @@ EOF echo 'RancherOS \n \l' > /etc/issue echo $(/sbin/ifconfig | grep -B1 "inet addr" |awk '{ if ( $1 == "inet" ) { print $2 } else if ( $2 == "Link" ) { printf "%s:" ,$1 } }' |awk -F: '{ print $1 ": " $3}') >> /etc/issue -cloud-init -execute +cloud-init-execute -console if [ -x /var/lib/rancher/conf/cloud-config-script ]; then echo "Running /var/lib/rancher/conf/cloud-config-script" diff --git a/main.go b/main.go index 6230dfd4..4329b559 100644 --- a/main.go +++ b/main.go @@ -7,7 +7,8 @@ import ( "github.com/docker/docker/pkg/reexec" "github.com/rancher/cniglue" "github.com/rancher/docker-from-scratch" - "github.com/rancher/os/cmd/cloudinit" + "github.com/rancher/os/cmd/cloudinitexecute" + "github.com/rancher/os/cmd/cloudinitsave" "github.com/rancher/os/cmd/control" "github.com/rancher/os/cmd/network" "github.com/rancher/os/cmd/power" @@ -21,24 +22,25 @@ import ( ) var entrypoints = map[string]func(){ - "cloud-init": cloudinit.Main, - "docker": docker.Main, - "dockerlaunch": dockerlaunch.Main, - "halt": power.Halt, - "init": osInit.MainInit, - "netconf": network.Main, - "poweroff": power.PowerOff, - "reboot": power.Reboot, - "respawn": respawn.Main, - "ros-sysinit": sysinit.Main, - "shutdown": power.Main, - "switch-console": switchconsole.Main, - "system-docker": systemdocker.Main, - "user-docker": userdocker.Main, - "wait-for-docker": wait.Main, - "cni-glue": glue.Main, - "bridge": bridge.Main, - "host-local": hostlocal.Main, + "cloud-init-execute": cloudinitexecute.Main, + "cloud-init-save": cloudinitsave.Main, + "docker": docker.Main, + "dockerlaunch": dockerlaunch.Main, + "halt": power.Halt, + "init": osInit.MainInit, + "netconf": network.Main, + "poweroff": power.PowerOff, + "reboot": power.Reboot, + "respawn": respawn.Main, + "ros-sysinit": sysinit.Main, + "shutdown": power.Main, + "switch-console": switchconsole.Main, + "system-docker": systemdocker.Main, + "user-docker": userdocker.Main, + "wait-for-docker": wait.Main, + "cni-glue": glue.Main, + "bridge": bridge.Main, + "host-local": hostlocal.Main, } func main() { diff --git a/os-config.tpl.yml b/os-config.tpl.yml index e13b1f84..4a2faeb0 100644 --- a/os-config.tpl.yml +++ b/os-config.tpl.yml @@ -120,6 +120,19 @@ rancher: volumes_from: - command-volumes - system-volumes + cloud-init-execute: + image: {{.OS_REPO}}/os-base:{{.VERSION}}{{.SUFFIX}} + command: cloud-init-execute -pre-console + labels: + io.rancher.os.detach: "false" + io.rancher.os.scope: system + io.rancher.os.after: cloud-init + net: host + uts: host + privileged: true + volumes_from: + - command-volumes + - system-volumes cloud-init-pre: image: {{.OS_REPO}}/os-cloudinit:{{.VERSION}}{{.SUFFIX}} environment: @@ -159,7 +172,8 @@ rancher: - /usr/bin/ros:/sbin/shutdown:ro - /usr/bin/ros:/usr/bin/respawn:ro - /usr/bin/ros:/usr/bin/ros:ro - - /usr/bin/ros:/usr/bin/cloud-init:ro + - /usr/bin/ros:/usr/bin/cloud-init-execute:ro + - /usr/bin/ros:/usr/bin/cloud-init-save:ro - /usr/bin/ros:/usr/sbin/netconf:ro - /usr/bin/ros:/usr/sbin/wait-for-docker:ro - /usr/bin/ros:/usr/bin/switch-console:ro @@ -212,7 +226,7 @@ rancher: command: netconf --stop-network-pre labels: io.rancher.os.scope: system - io.rancher.os.after: cloud-init + io.rancher.os.after: cloud-init-execute net: host uts: host pid: host diff --git a/tests/swap_test.go b/tests/swap_test.go index e712584f..e062833b 100644 --- a/tests/swap_test.go +++ b/tests/swap_test.go @@ -7,6 +7,6 @@ func (s *QemuSuite) TestSwap(c *C) { c.Assert(err, IsNil) s.CheckCall(c, "sudo mkswap /dev/vdb") - s.CheckCall(c, "sudo cloud-init -execute") + s.CheckCall(c, "sudo cloud-init-execute") s.CheckCall(c, "cat /proc/swaps | grep /dev/vdb") }