2014-10-17 15:36:22 -07:00
|
|
|
/*
|
|
|
|
Copyright 2014 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.
|
|
|
|
*/
|
|
|
|
|
2014-03-18 09:00:41 -07:00
|
|
|
package system
|
2014-03-12 15:43:51 -07:00
|
|
|
|
|
|
|
import (
|
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
|
|
|
"path"
|
|
|
|
"testing"
|
2014-09-21 19:22:38 -07:00
|
|
|
|
|
|
|
"github.com/coreos/coreos-cloudinit/config"
|
2014-03-12 15:43:51 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestPlaceNetworkUnit(t *testing.T) {
|
2014-09-21 19:22:38 -07:00
|
|
|
u := Unit{config.Unit{
|
2014-05-06 16:11:26 -07:00
|
|
|
Name: "50-eth0.network",
|
|
|
|
Runtime: true,
|
|
|
|
Content: `[Match]
|
2014-03-12 15:43:51 -07:00
|
|
|
Name=eth47
|
|
|
|
|
|
|
|
[Network]
|
|
|
|
Address=10.209.171.177/19
|
|
|
|
`,
|
2014-09-21 19:22:38 -07:00
|
|
|
}}
|
2014-03-12 15:43:51 -07:00
|
|
|
|
|
|
|
dir, err := ioutil.TempDir(os.TempDir(), "coreos-cloudinit-")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Unable to create tempdir: %v", err)
|
|
|
|
}
|
2014-05-06 16:11:26 -07:00
|
|
|
defer os.RemoveAll(dir)
|
2014-03-12 15:43:51 -07:00
|
|
|
|
2014-06-05 17:40:53 -07:00
|
|
|
sd := &systemd{dir}
|
|
|
|
|
2014-06-03 16:49:26 -07:00
|
|
|
dst := u.Destination(dir)
|
2014-04-14 10:10:10 -07:00
|
|
|
expectDst := path.Join(dir, "run", "systemd", "network", "50-eth0.network")
|
|
|
|
if dst != expectDst {
|
2014-06-03 16:49:26 -07:00
|
|
|
t.Fatalf("unit.Destination returned %s, expected %s", dst, expectDst)
|
2014-04-14 10:10:10 -07:00
|
|
|
}
|
|
|
|
|
2014-06-05 17:40:53 -07:00
|
|
|
if err := sd.PlaceUnit(&u, dst); err != nil {
|
2014-03-12 15:43:51 -07:00
|
|
|
t.Fatalf("PlaceUnit failed: %v", err)
|
|
|
|
}
|
|
|
|
|
2014-04-14 10:10:10 -07:00
|
|
|
fi, err := os.Stat(dst)
|
2014-03-12 15:43:51 -07:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Unable to stat file: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if fi.Mode() != os.FileMode(0644) {
|
|
|
|
t.Errorf("File has incorrect mode: %v", fi.Mode())
|
|
|
|
}
|
|
|
|
|
2014-04-14 10:10:10 -07:00
|
|
|
contents, err := ioutil.ReadFile(dst)
|
2014-03-12 15:43:51 -07:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Unable to read expected file: %v", err)
|
|
|
|
}
|
|
|
|
|
2014-04-14 10:10:10 -07:00
|
|
|
expectContents := `[Match]
|
2014-03-12 15:43:51 -07:00
|
|
|
Name=eth47
|
|
|
|
|
|
|
|
[Network]
|
|
|
|
Address=10.209.171.177/19
|
|
|
|
`
|
2014-04-14 10:10:10 -07:00
|
|
|
if string(contents) != expectContents {
|
|
|
|
t.Fatalf("File has incorrect contents '%s'.\nExpected '%s'", string(contents), expectContents)
|
2014-03-12 15:43:51 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-09 20:33:34 -07:00
|
|
|
func TestUnitDestination(t *testing.T) {
|
|
|
|
dir := "/some/dir"
|
|
|
|
name := "foobar.service"
|
|
|
|
|
2014-09-21 19:22:38 -07:00
|
|
|
u := Unit{config.Unit{
|
2014-05-09 20:33:34 -07:00
|
|
|
Name: name,
|
|
|
|
DropIn: false,
|
2014-09-21 19:22:38 -07:00
|
|
|
}}
|
2014-05-09 20:33:34 -07:00
|
|
|
|
2014-06-03 16:49:26 -07:00
|
|
|
dst := u.Destination(dir)
|
2014-05-09 20:33:34 -07:00
|
|
|
expectDst := path.Join(dir, "etc", "systemd", "system", "foobar.service")
|
|
|
|
if dst != expectDst {
|
2014-06-03 16:49:26 -07:00
|
|
|
t.Errorf("unit.Destination returned %s, expected %s", dst, expectDst)
|
2014-05-09 20:33:34 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
u.DropIn = true
|
|
|
|
|
2014-06-03 16:49:26 -07:00
|
|
|
dst = u.Destination(dir)
|
2014-05-09 20:33:34 -07:00
|
|
|
expectDst = path.Join(dir, "etc", "systemd", "system", "foobar.service.d", cloudConfigDropIn)
|
|
|
|
if dst != expectDst {
|
2014-06-03 16:49:26 -07:00
|
|
|
t.Errorf("unit.Destination returned %s, expected %s", dst, expectDst)
|
2014-05-09 20:33:34 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-12 15:43:51 -07:00
|
|
|
func TestPlaceMountUnit(t *testing.T) {
|
2014-09-21 19:22:38 -07:00
|
|
|
u := Unit{config.Unit{
|
2014-05-06 16:11:26 -07:00
|
|
|
Name: "media-state.mount",
|
|
|
|
Runtime: false,
|
|
|
|
Content: `[Mount]
|
2014-03-12 15:43:51 -07:00
|
|
|
What=/dev/sdb1
|
|
|
|
Where=/media/state
|
|
|
|
`,
|
2014-09-21 19:22:38 -07:00
|
|
|
}}
|
2014-03-12 15:43:51 -07:00
|
|
|
|
|
|
|
dir, err := ioutil.TempDir(os.TempDir(), "coreos-cloudinit-")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Unable to create tempdir: %v", err)
|
|
|
|
}
|
2014-05-06 16:11:26 -07:00
|
|
|
defer os.RemoveAll(dir)
|
2014-03-12 15:43:51 -07:00
|
|
|
|
2014-06-05 17:40:53 -07:00
|
|
|
sd := &systemd{dir}
|
|
|
|
|
2014-06-03 16:49:26 -07:00
|
|
|
dst := u.Destination(dir)
|
2014-04-14 10:10:10 -07:00
|
|
|
expectDst := path.Join(dir, "etc", "systemd", "system", "media-state.mount")
|
|
|
|
if dst != expectDst {
|
2014-06-03 16:49:26 -07:00
|
|
|
t.Fatalf("unit.Destination returned %s, expected %s", dst, expectDst)
|
2014-04-14 10:10:10 -07:00
|
|
|
}
|
|
|
|
|
2014-06-05 17:40:53 -07:00
|
|
|
if err := sd.PlaceUnit(&u, dst); err != nil {
|
2014-03-12 15:43:51 -07:00
|
|
|
t.Fatalf("PlaceUnit failed: %v", err)
|
|
|
|
}
|
|
|
|
|
2014-04-14 10:10:10 -07:00
|
|
|
fi, err := os.Stat(dst)
|
2014-03-12 15:43:51 -07:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Unable to stat file: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if fi.Mode() != os.FileMode(0644) {
|
|
|
|
t.Errorf("File has incorrect mode: %v", fi.Mode())
|
|
|
|
}
|
|
|
|
|
2014-04-14 10:10:10 -07:00
|
|
|
contents, err := ioutil.ReadFile(dst)
|
2014-03-12 15:43:51 -07:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Unable to read expected file: %v", err)
|
|
|
|
}
|
|
|
|
|
2014-04-14 10:10:10 -07:00
|
|
|
expectContents := `[Mount]
|
2014-03-12 15:43:51 -07:00
|
|
|
What=/dev/sdb1
|
|
|
|
Where=/media/state
|
|
|
|
`
|
2014-04-14 10:10:10 -07:00
|
|
|
if string(contents) != expectContents {
|
|
|
|
t.Fatalf("File has incorrect contents '%s'.\nExpected '%s'", string(contents), expectContents)
|
2014-03-12 15:43:51 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-18 09:36:31 -07:00
|
|
|
func TestMachineID(t *testing.T) {
|
|
|
|
dir, err := ioutil.TempDir(os.TempDir(), "coreos-cloudinit-")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Unable to create tempdir: %v", err)
|
|
|
|
}
|
2014-05-06 16:11:26 -07:00
|
|
|
defer os.RemoveAll(dir)
|
2014-03-18 09:36:31 -07:00
|
|
|
|
|
|
|
os.Mkdir(path.Join(dir, "etc"), os.FileMode(0755))
|
|
|
|
ioutil.WriteFile(path.Join(dir, "etc", "machine-id"), []byte("node007\n"), os.FileMode(0444))
|
|
|
|
|
|
|
|
if MachineID(dir) != "node007" {
|
|
|
|
t.Fatalf("File has incorrect contents")
|
|
|
|
}
|
|
|
|
}
|
2014-05-09 20:33:34 -07:00
|
|
|
|
2014-05-06 16:18:36 -07:00
|
|
|
func TestMaskUnit(t *testing.T) {
|
|
|
|
dir, err := ioutil.TempDir(os.TempDir(), "coreos-cloudinit-")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Unable to create tempdir: %v", err)
|
|
|
|
}
|
|
|
|
defer os.RemoveAll(dir)
|
2014-05-21 11:03:52 -07:00
|
|
|
|
2014-06-05 17:40:53 -07:00
|
|
|
sd := &systemd{dir}
|
|
|
|
|
2014-05-21 11:03:52 -07:00
|
|
|
// Ensure mask works with units that do not currently exist
|
2014-09-21 19:22:38 -07:00
|
|
|
uf := &Unit{config.Unit{Name: "foo.service"}}
|
2014-06-05 17:40:53 -07:00
|
|
|
if err := sd.MaskUnit(uf); err != nil {
|
2014-05-21 11:03:52 -07:00
|
|
|
t.Fatalf("Unable to mask new unit: %v", err)
|
|
|
|
}
|
|
|
|
fooPath := path.Join(dir, "etc", "systemd", "system", "foo.service")
|
|
|
|
fooTgt, err := os.Readlink(fooPath)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Unable to read link", err)
|
|
|
|
}
|
|
|
|
if fooTgt != "/dev/null" {
|
|
|
|
t.Fatalf("unit not masked, got unit target", fooTgt)
|
2014-05-06 16:18:36 -07:00
|
|
|
}
|
|
|
|
|
2014-05-21 11:03:52 -07:00
|
|
|
// Ensure mask works with unit files that already exist
|
2014-09-21 19:22:38 -07:00
|
|
|
ub := &Unit{config.Unit{Name: "bar.service"}}
|
2014-05-21 11:03:52 -07:00
|
|
|
barPath := path.Join(dir, "etc", "systemd", "system", "bar.service")
|
|
|
|
if _, err := os.Create(barPath); err != nil {
|
|
|
|
t.Fatalf("Error creating new unit file: %v", err)
|
|
|
|
}
|
2014-06-05 17:40:53 -07:00
|
|
|
if err := sd.MaskUnit(ub); err != nil {
|
2014-05-21 11:03:52 -07:00
|
|
|
t.Fatalf("Unable to mask existing unit: %v", err)
|
|
|
|
}
|
|
|
|
barTgt, err := os.Readlink(barPath)
|
2014-05-06 16:18:36 -07:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Unable to read link", err)
|
|
|
|
}
|
2014-05-21 11:03:52 -07:00
|
|
|
if barTgt != "/dev/null" {
|
|
|
|
t.Fatalf("unit not masked, got unit target", barTgt)
|
2014-05-06 16:18:36 -07:00
|
|
|
}
|
|
|
|
}
|
2014-06-03 16:49:26 -07:00
|
|
|
|
|
|
|
func TestUnmaskUnit(t *testing.T) {
|
|
|
|
dir, err := ioutil.TempDir(os.TempDir(), "coreos-cloudinit-")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Unable to create tempdir: %v", err)
|
|
|
|
}
|
|
|
|
defer os.RemoveAll(dir)
|
|
|
|
|
2014-06-05 17:40:53 -07:00
|
|
|
sd := &systemd{dir}
|
|
|
|
|
2014-09-21 19:22:38 -07:00
|
|
|
nilUnit := &Unit{config.Unit{Name: "null.service"}}
|
2014-06-05 17:40:53 -07:00
|
|
|
if err := sd.UnmaskUnit(nilUnit); err != nil {
|
2014-06-03 16:49:26 -07:00
|
|
|
t.Errorf("unexpected error from unmasking nonexistent unit: %v", err)
|
|
|
|
}
|
|
|
|
|
2014-09-21 19:22:38 -07:00
|
|
|
uf := &Unit{config.Unit{Name: "foo.service", Content: "[Service]\nExecStart=/bin/true"}}
|
2014-06-03 16:49:26 -07:00
|
|
|
dst := uf.Destination(dir)
|
|
|
|
if err := os.MkdirAll(path.Dir(dst), os.FileMode(0755)); err != nil {
|
|
|
|
t.Fatalf("Unable to create unit directory: %v", err)
|
|
|
|
}
|
|
|
|
if _, err := os.Create(dst); err != nil {
|
|
|
|
t.Fatalf("Unable to write unit file: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := ioutil.WriteFile(dst, []byte(uf.Content), 700); err != nil {
|
|
|
|
t.Fatalf("Unable to write unit file: %v", err)
|
|
|
|
}
|
2014-06-05 17:40:53 -07:00
|
|
|
if err := sd.UnmaskUnit(uf); err != nil {
|
2014-06-03 16:49:26 -07:00
|
|
|
t.Errorf("unmask of non-empty unit returned unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
got, _ := ioutil.ReadFile(dst)
|
|
|
|
if string(got) != uf.Content {
|
|
|
|
t.Errorf("unmask of non-empty unit mutated unit contents unexpectedly")
|
|
|
|
}
|
|
|
|
|
2014-09-21 19:22:38 -07:00
|
|
|
ub := &Unit{config.Unit{Name: "bar.service"}}
|
2014-06-03 16:49:26 -07:00
|
|
|
dst = ub.Destination(dir)
|
|
|
|
if err := os.Symlink("/dev/null", dst); err != nil {
|
|
|
|
t.Fatalf("Unable to create masked unit: %v", err)
|
|
|
|
}
|
2014-06-05 17:40:53 -07:00
|
|
|
if err := sd.UnmaskUnit(ub); err != nil {
|
2014-06-03 16:49:26 -07:00
|
|
|
t.Errorf("unmask of unit returned unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
if _, err := os.Stat(dst); !os.IsNotExist(err) {
|
|
|
|
t.Errorf("expected %s to not exist after unmask, but got err: %s", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestNullOrEmpty(t *testing.T) {
|
|
|
|
dir, err := ioutil.TempDir(os.TempDir(), "coreos-cloudinit-")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Unable to create tempdir: %v", err)
|
|
|
|
}
|
|
|
|
defer os.RemoveAll(dir)
|
|
|
|
|
|
|
|
non := path.Join(dir, "does_not_exist")
|
|
|
|
ne, err := nullOrEmpty(non)
|
|
|
|
if !os.IsNotExist(err) {
|
|
|
|
t.Errorf("nullOrEmpty on nonexistent file returned bad error: %v", err)
|
|
|
|
}
|
|
|
|
if ne {
|
|
|
|
t.Errorf("nullOrEmpty returned true unxpectedly")
|
|
|
|
}
|
|
|
|
|
|
|
|
regEmpty := path.Join(dir, "regular_empty_file")
|
|
|
|
_, err = os.Create(regEmpty)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Unable to create tempfile: %v", err)
|
|
|
|
}
|
|
|
|
gotNe, gotErr := nullOrEmpty(regEmpty)
|
|
|
|
if !gotNe || gotErr != nil {
|
|
|
|
t.Errorf("nullOrEmpty of regular empty file returned %t, %v - want true, nil", gotNe, gotErr)
|
|
|
|
}
|
|
|
|
|
|
|
|
reg := path.Join(dir, "regular_file")
|
|
|
|
if err := ioutil.WriteFile(reg, []byte("asdf"), 700); err != nil {
|
|
|
|
t.Fatalf("Unable to create tempfile: %v", err)
|
|
|
|
}
|
|
|
|
gotNe, gotErr = nullOrEmpty(reg)
|
|
|
|
if gotNe || gotErr != nil {
|
|
|
|
t.Errorf("nullOrEmpty of regular file returned %t, %v - want false, nil", gotNe, gotErr)
|
|
|
|
}
|
|
|
|
|
|
|
|
null := path.Join(dir, "null")
|
|
|
|
if err := os.Symlink(os.DevNull, null); err != nil {
|
|
|
|
t.Fatalf("Unable to create /dev/null link: %s", err)
|
|
|
|
}
|
|
|
|
gotNe, gotErr = nullOrEmpty(null)
|
|
|
|
if !gotNe || gotErr != nil {
|
|
|
|
t.Errorf("nullOrEmpty of null symlink returned %t, %v - want true, nil", gotNe, gotErr)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|