diff --git a/build b/build index cb755cc..51481fc 100755 --- a/build +++ b/build @@ -1,18 +1,18 @@ -#!/bin/bash -e +#!/bin/bash -ex ORG_PATH="github.com/vtolstov" REPO_PATH="${ORG_PATH}/cloudinit" -if [ ! -h gopath/src/${REPO_PATH} ]; then - mkdir -p gopath/src/${ORG_PATH} - ln -s ../../../.. gopath/src/${REPO_PATH} || echo "exit 255" -fi - export GOBIN=${PWD}/bin export GOPATH=${PWD}/third_party export CGO_ENABLED=0 +if [ ! -h $GOPATH/src/${REPO_PATH} ]; then + mkdir -p $GOPATH/src/${ORG_PATH} + ln -s ../../../.. $GOPATH/src/${REPO_PATH} || echo "exit 255" +fi + for os in linux freebsd; do - GOOS=${os} go build -a -installsuffix cgo -o bin/cloudinit-linux-x86_64 ${REPO_PATH} - GOOS=${os} GOARCH=386 go build -a -installsuffix cgo -o bin/cloudinit-linux-x86_32 ${REPO_PATH} + GOOS=${os} go build -x -a -installsuffix cgo -o bin/cloudinit-linux-x86_64 ${REPO_PATH} + GOOS=${os} GOARCH=386 go build -x -a -installsuffix cgo -o bin/cloudinit-linux-x86_32 ${REPO_PATH} done diff --git a/system/systemd.go b/system/systemd.go new file mode 100644 index 0000000..cc5e224 --- /dev/null +++ b/system/systemd.go @@ -0,0 +1,229 @@ +// Copyright 2015 CoreOS, Inc. +// +// 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 system + +import ( + "io/ioutil" + "log" + "os" + "os/exec" + "path" + "strings" + + "github.com/coreos/coreos-cloudinit/config" +) + +func NewUnitManager(root string) UnitManager { + return &systemd{root} +} + +type systemd struct { + root string +} + +// fakeMachineID is placed on non-usr CoreOS images and should +// never be used as a true MachineID +const fakeMachineID = "42000000000000000000000000000042" + +// PlaceUnit writes a unit file at its desired destination, creating parent +// directories as necessary. +func (s *systemd) PlaceUnit(u Unit) error { + file := File{config.File{ + Path: u.Destination(s.root), + Content: u.Content, + RawFilePermissions: "0644", + }} + + _, err := WriteFile(&file, "/") + return err +} + +// PlaceUnitDropIn writes a unit drop-in file at its desired destination, +// creating parent directories as necessary. +func (s *systemd) PlaceUnitDropIn(u Unit, d config.UnitDropIn) error { + file := File{config.File{ + Path: u.DropInDestination(s.root, d), + Content: d.Content, + RawFilePermissions: "0644", + }} + + _, err := WriteFile(&file, "/") + return err +} + +func (s *systemd) EnableUnitFile(u Unit) error { + /* + conn, err := dbus.New() + if err != nil { + return err + } + + units := []string{u.Name} + _, _, err = conn.EnableUnitFiles(units, u.Runtime, true) + return err + */ + return nil +} + +func (s *systemd) RunUnitCommand(u Unit, c string) (string, error) { + /* + conn, err := dbus.New() + if err != nil { + return "", err + } + + var fn func(string, string) (string, error) + switch c { + case "start": + fn = conn.StartUnit + case "stop": + fn = conn.StopUnit + case "restart": + fn = conn.RestartUnit + case "reload": + fn = conn.ReloadUnit + case "try-restart": + fn = conn.TryRestartUnit + case "reload-or-restart": + fn = conn.ReloadOrRestartUnit + case "reload-or-try-restart": + fn = conn.ReloadOrTryRestartUnit + default: + return "", fmt.Errorf("Unsupported systemd command %q", c) + } + + return fn(u.Name, "replace") + */ + return "", nil +} + +func (s *systemd) DaemonReload() error { + /* + conn, err := dbus.New() + if err != nil { + return err + } + + return conn.Reload() + */ + return nil +} + +// MaskUnit masks the given Unit by symlinking its unit file to +// /dev/null, analogous to `systemctl mask`. +// N.B.: Unlike `systemctl mask`, this function will *remove any existing unit +// file at the location*, to ensure that the mask will succeed. +func (s *systemd) MaskUnit(u Unit) error { + masked := u.Destination(s.root) + if _, err := os.Stat(masked); os.IsNotExist(err) { + if err := os.MkdirAll(path.Dir(masked), os.FileMode(0755)); err != nil { + return err + } + } else if err := os.Remove(masked); err != nil { + return err + } + return os.Symlink("/dev/null", masked) +} + +// UnmaskUnit is analogous to systemd's unit_file_unmask. If the file +// associated with the given Unit is empty or appears to be a symlink to +// /dev/null, it is removed. +func (s *systemd) UnmaskUnit(u Unit) error { + masked := u.Destination(s.root) + ne, err := nullOrEmpty(masked) + if os.IsNotExist(err) { + return nil + } else if err != nil { + return err + } + if !ne { + log.Printf("%s is not null or empty, refusing to unmask", masked) + return nil + } + return os.Remove(masked) +} + +// nullOrEmpty checks whether a given path appears to be an empty regular file +// or a symlink to /dev/null +func nullOrEmpty(path string) (bool, error) { + fi, err := os.Stat(path) + if err != nil { + return false, err + } + m := fi.Mode() + if m.IsRegular() && fi.Size() <= 0 { + return true, nil + } + if m&os.ModeCharDevice > 0 { + return true, nil + } + return false, nil +} + +func ExecuteScript(scriptPath string) (string, error) { + /* + props := []dbus.Property{ + dbus.PropDescription("Unit generated and executed by coreos-cloudinit on behalf of user"), + dbus.PropExecStart([]string{"/bin/bash", scriptPath}, false), + } + + base := path.Base(scriptPath) + name := fmt.Sprintf("coreos-cloudinit-%s.service", base) + + log.Printf("Creating transient systemd unit '%s'", name) + + conn, err := dbus.New() + if err != nil { + return "", err + } + + _, err = conn.StartTransientUnit(name, "replace", props...) + return name, err + */ + return "", nil +} + +func SetHostname(hostname string) (err error) { + for _, name := range []string{"hostnamectl", "hostname"} { + if _, err = exec.LookPath(name); err != nil { + continue + } + switch name { + case "hostname": + err = exec.Command(name, hostname).Run() + case "hostnamectl": + err = exec.Command(name, "set-hostname", hostname).Run() + } + } + if err != nil { + return + } + return ioutil.WriteFile("/etc/hostname", []byte(hostname+"\n"), 0644) +} + +func Hostname() (string, error) { + return os.Hostname() +} + +func MachineID(root string) string { + contents, _ := ioutil.ReadFile(path.Join(root, "etc", "machine-id")) + id := strings.TrimSpace(string(contents)) + + if id == fakeMachineID { + id = "" + } + + return id +} diff --git a/system/user.go b/system/user.go index b14faf5..6510dba 100644 --- a/system/user.go +++ b/system/user.go @@ -28,7 +28,7 @@ func UserHome(name string) (string, error) { if err != nil { return "", err } - passwd := strings.Split(output, ":") + passwd := strings.Split(string(output), ":") return passwd[5], nil }