// 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 ( "fmt" "io/ioutil" "os" "path" "testing" "github.com/vtolstov/cloudinit/config" ) func TestPlaceUnit(t *testing.T) { tests := []config.Unit{ { Name: "50-eth0.network", Runtime: true, Content: "[Match]\nName=eth47\n\n[Network]\nAddress=10.209.171.177/19\n", }, { Name: "media-state.mount", Content: "[Mount]\nWhat=/dev/sdb1\nWhere=/media/state\n", }, } for _, tt := range tests { dir, err := ioutil.TempDir(os.TempDir(), "coreos-cloudinit-") if err != nil { panic(fmt.Sprintf("Unable to create tempdir: %v", err)) } u := Unit{tt} sd := &systemd{dir} if err := sd.PlaceUnit(u); err != nil { t.Fatalf("PlaceUnit(): bad error (%+v): want nil, got %s", tt, err) } fi, err := os.Stat(u.Destination(dir)) if err != nil { t.Fatalf("Stat(): bad error (%+v): want nil, got %s", tt, err) } if mode := fi.Mode(); mode != os.FileMode(0644) { t.Errorf("bad filemode (%+v): want %v, got %v", tt, os.FileMode(0644), mode) } c, err := ioutil.ReadFile(u.Destination(dir)) if err != nil { t.Fatalf("ReadFile(): bad error (%+v): want nil, got %s", tt, err) } if string(c) != tt.Content { t.Errorf("bad contents (%+v): want %q, got %q", tt, tt.Content, string(c)) } os.RemoveAll(dir) } } func TestPlaceUnitDropIn(t *testing.T) { tests := []config.Unit{ { Name: "false.service", Runtime: true, DropIns: []config.UnitDropIn{ { Name: "00-true.conf", Content: "[Service]\nExecStart=\nExecStart=/usr/bin/true\n", }, }, }, { Name: "true.service", DropIns: []config.UnitDropIn{ { Name: "00-false.conf", Content: "[Service]\nExecStart=\nExecStart=/usr/bin/false\n", }, }, }, } for _, tt := range tests { dir, err := ioutil.TempDir(os.TempDir(), "coreos-cloudinit-") if err != nil { panic(fmt.Sprintf("Unable to create tempdir: %v", err)) } u := Unit{tt} sd := &systemd{dir} if err := sd.PlaceUnitDropIn(u, u.DropIns[0]); err != nil { t.Fatalf("PlaceUnit(): bad error (%+v): want nil, got %s", tt, err) } fi, err := os.Stat(u.DropInDestination(dir, u.DropIns[0])) if err != nil { t.Fatalf("Stat(): bad error (%+v): want nil, got %s", tt, err) } if mode := fi.Mode(); mode != os.FileMode(0644) { t.Errorf("bad filemode (%+v): want %v, got %v", tt, os.FileMode(0644), mode) } c, err := ioutil.ReadFile(u.DropInDestination(dir, u.DropIns[0])) if err != nil { t.Fatalf("ReadFile(): bad error (%+v): want nil, got %s", tt, err) } if string(c) != u.DropIns[0].Content { t.Errorf("bad contents (%+v): want %q, got %q", tt, u.DropIns[0].Content, string(c)) } os.RemoveAll(dir) } } func TestMachineID(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) 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") } } 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) sd := &systemd{dir} // Ensure mask works with units that do not currently exist uf := Unit{config.Unit{Name: "foo.service"}} if err := sd.MaskUnit(uf); err != nil { 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.Fatal("Unable to read link", err) } if fooTgt != "/dev/null" { t.Fatal("unit not masked, got unit target", fooTgt) } // Ensure mask works with unit files that already exist ub := Unit{config.Unit{Name: "bar.service"}} 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) } if err := sd.MaskUnit(ub); err != nil { t.Fatalf("Unable to mask existing unit: %v", err) } barTgt, err := os.Readlink(barPath) if err != nil { t.Fatal("Unable to read link", err) } if barTgt != "/dev/null" { t.Fatal("unit not masked, got unit target", barTgt) } } 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) sd := &systemd{dir} nilUnit := Unit{config.Unit{Name: "null.service"}} if err := sd.UnmaskUnit(nilUnit); err != nil { t.Errorf("unexpected error from unmasking nonexistent unit: %v", err) } uf := Unit{config.Unit{Name: "foo.service", Content: "[Service]\nExecStart=/bin/true"}} 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) } if err := sd.UnmaskUnit(uf); err != nil { 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") } ub := Unit{config.Unit{Name: "bar.service"}} dst = ub.Destination(dir) if err := os.Symlink("/dev/null", dst); err != nil { t.Fatalf("Unable to create masked unit: %v", err) } if err := sd.UnmaskUnit(ub); err != nil { 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", dst, 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) } }