github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/cloudconfig/containerinit/container_userdata_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Copyright 2015 Cloudbase Solutions SRL 3 // Licensed under the AGPLv3, see LICENCE file for details. 4 5 package containerinit_test 6 7 import ( 8 "path/filepath" 9 "strings" 10 stdtesting "testing" 11 12 jc "github.com/juju/testing/checkers" 13 gc "gopkg.in/check.v1" 14 "gopkg.in/yaml.v1" 15 16 "github.com/juju/juju/cloudconfig/cloudinit" 17 "github.com/juju/juju/cloudconfig/containerinit" 18 "github.com/juju/juju/container" 19 containertesting "github.com/juju/juju/container/testing" 20 "github.com/juju/juju/feature" 21 "github.com/juju/juju/network" 22 "github.com/juju/juju/service" 23 systemdtesting "github.com/juju/juju/service/systemd/testing" 24 "github.com/juju/juju/testing" 25 ) 26 27 func Test(t *stdtesting.T) { 28 gc.TestingT(t) 29 } 30 31 type UserDataSuite struct { 32 testing.BaseSuite 33 34 networkInterfacesFile string 35 fakeInterfaces []network.InterfaceInfo 36 expectedNetConfig string 37 } 38 39 var _ = gc.Suite(&UserDataSuite{}) 40 41 func (s *UserDataSuite) SetUpTest(c *gc.C) { 42 s.BaseSuite.SetUpTest(c) 43 s.networkInterfacesFile = filepath.Join(c.MkDir(), "interfaces") 44 s.fakeInterfaces = []network.InterfaceInfo{{ 45 InterfaceName: "eth0", 46 CIDR: "0.1.2.0/24", 47 ConfigType: network.ConfigStatic, 48 NoAutoStart: false, 49 Address: network.NewAddress("0.1.2.3"), 50 DNSServers: network.NewAddresses("ns1.invalid", "ns2.invalid"), 51 DNSSearch: "foo.bar", 52 GatewayAddress: network.NewAddress("0.1.2.1"), 53 }, { 54 InterfaceName: "eth1", 55 ConfigType: network.ConfigDHCP, 56 NoAutoStart: true, 57 }} 58 s.expectedNetConfig = ` 59 # loopback interface 60 auto lo 61 iface lo inet loopback 62 63 # interface "eth0" 64 auto eth0 65 iface eth0 inet manual 66 dns-nameservers ns1.invalid ns2.invalid 67 dns-search foo.bar 68 pre-up ip address add 0.1.2.3/32 dev eth0 &> /dev/null || true 69 up ip route replace 0.1.2.1 dev eth0 70 up ip route replace default via 0.1.2.1 71 down ip route del default via 0.1.2.1 &> /dev/null || true 72 down ip route del 0.1.2.1 dev eth0 &> /dev/null || true 73 post-down ip address del 0.1.2.3/32 dev eth0 &> /dev/null || true 74 75 # interface "eth1" 76 iface eth1 inet dhcp 77 ` 78 s.PatchValue(containerinit.NetworkInterfacesFile, s.networkInterfacesFile) 79 } 80 81 func (s *UserDataSuite) TestGenerateNetworkConfig(c *gc.C) { 82 // No config or no interfaces - no error, but also noting to generate. 83 data, err := containerinit.GenerateNetworkConfig(nil) 84 c.Assert(err, jc.ErrorIsNil) 85 c.Assert(data, gc.HasLen, 0) 86 netConfig := container.BridgeNetworkConfig("foo", 0, nil) 87 data, err = containerinit.GenerateNetworkConfig(netConfig) 88 c.Assert(err, jc.ErrorIsNil) 89 c.Assert(data, gc.HasLen, 0) 90 91 // Test with all interface types. 92 netConfig = container.BridgeNetworkConfig("foo", 0, s.fakeInterfaces) 93 data, err = containerinit.GenerateNetworkConfig(netConfig) 94 c.Assert(err, jc.ErrorIsNil) 95 c.Assert(data, gc.Equals, s.expectedNetConfig) 96 } 97 98 func (s *UserDataSuite) TestNewCloudInitConfigWithNetworks(c *gc.C) { 99 netConfig := container.BridgeNetworkConfig("foo", 0, s.fakeInterfaces) 100 cloudConf, err := containerinit.NewCloudInitConfigWithNetworks("quantal", netConfig) 101 c.Assert(err, jc.ErrorIsNil) 102 // We need to indent expectNetConfig to make it valid YAML, 103 // dropping the last new line and using unindented blank lines. 104 lines := strings.Split(s.expectedNetConfig, "\n") 105 indentedNetConfig := strings.Join(lines[:len(lines)-1], "\n ") 106 indentedNetConfig = strings.Replace(indentedNetConfig, "\n \n", "\n\n", -1) 107 expected := ` 108 #cloud-config 109 bootcmd: 110 - install -D -m 644 /dev/null '`[1:] + s.networkInterfacesFile + `' 111 - |- 112 printf '%s\n' '` + indentedNetConfig + ` 113 ' > '` + s.networkInterfacesFile + `' 114 ` 115 assertUserData(c, cloudConf, expected) 116 } 117 118 func (s *UserDataSuite) TestNewCloudInitConfigWithNetworksNoConfig(c *gc.C) { 119 netConfig := container.BridgeNetworkConfig("foo", 0, nil) 120 cloudConf, err := containerinit.NewCloudInitConfigWithNetworks("quantal", netConfig) 121 c.Assert(err, jc.ErrorIsNil) 122 expected := "#cloud-config\n{}\n" 123 assertUserData(c, cloudConf, expected) 124 } 125 126 func (s *UserDataSuite) TestCloudInitUserData(c *gc.C) { 127 instanceConfig, err := containertesting.MockMachineConfig("1/lxc/0") 128 c.Assert(err, jc.ErrorIsNil) 129 networkConfig := container.BridgeNetworkConfig("foo", 0, nil) 130 data, err := containerinit.CloudInitUserData(instanceConfig, networkConfig) 131 c.Assert(err, jc.ErrorIsNil) 132 // No need to test the exact contents here, as they are already 133 // tested separately. 134 c.Assert(string(data), jc.HasPrefix, "#cloud-config\n") 135 } 136 137 func assertUserData(c *gc.C, cloudConf cloudinit.CloudConfig, expected string) { 138 data, err := cloudConf.RenderYAML() 139 c.Assert(err, jc.ErrorIsNil) 140 c.Assert(string(data), gc.Equals, expected) 141 // Make sure it's valid YAML as well. 142 out := make(map[string]interface{}) 143 err = yaml.Unmarshal(data, &out) 144 c.Assert(err, jc.ErrorIsNil) 145 if len(cloudConf.BootCmds()) > 0 { 146 outcmds := out["bootcmd"].([]interface{}) 147 confcmds := cloudConf.BootCmds() 148 c.Assert(len(outcmds), gc.Equals, len(confcmds)) 149 for i, _ := range outcmds { 150 c.Assert(outcmds[i].(string), gc.Equals, confcmds[i]) 151 } 152 } else { 153 c.Assert(out["bootcmd"], gc.IsNil) 154 } 155 } 156 157 func (s *UserDataSuite) TestShutdownInitCommandsUpstart(c *gc.C) { 158 s.SetFeatureFlags(feature.AddressAllocation) 159 cmds, err := containerinit.ShutdownInitCommands(service.InitSystemUpstart, "trusty") 160 c.Assert(err, jc.ErrorIsNil) 161 162 filename := "/etc/init/juju-template-restart.conf" 163 script := ` 164 description "juju shutdown job" 165 author "Juju Team <juju@lists.ubuntu.com>" 166 start on stopped cloud-final 167 168 script 169 /bin/cat > /etc/network/interfaces << EOC 170 # loopback interface 171 auto lo 172 iface lo inet loopback 173 174 # primary interface 175 auto eth0 176 iface eth0 inet dhcp 177 EOC 178 /bin/rm -fr /var/lib/dhcp/dhclient* /var/log/cloud-init*.log 179 /sbin/shutdown -h now 180 end script 181 182 post-stop script 183 rm /etc/init/juju-template-restart.conf 184 end script 185 `[1:] 186 c.Check(cmds, gc.HasLen, 1) 187 testing.CheckWriteFileCommand(c, cmds[0], filename, script, nil) 188 } 189 190 func (s *UserDataSuite) TestShutdownInitCommandsSystemd(c *gc.C) { 191 s.SetFeatureFlags(feature.AddressAllocation) 192 commands, err := containerinit.ShutdownInitCommands(service.InitSystemSystemd, "vivid") 193 c.Assert(err, jc.ErrorIsNil) 194 195 test := systemdtesting.WriteConfTest{ 196 Service: "juju-template-restart", 197 DataDir: "/var/lib/juju", 198 Expected: ` 199 [Unit] 200 Description=juju shutdown job 201 After=syslog.target 202 After=network.target 203 After=systemd-user-sessions.service 204 After=cloud-config.target 205 206 [Service] 207 ExecStart=/var/lib/juju/init/juju-template-restart/exec-start.sh 208 ExecStopPost=/bin/systemctl disable juju-template-restart.service 209 210 [Install] 211 WantedBy=multi-user.target 212 `[1:], 213 Script: ` 214 /bin/cat > /etc/network/interfaces << EOC 215 # loopback interface 216 auto lo 217 iface lo inet loopback 218 219 # primary interface 220 auto eth0 221 iface eth0 inet dhcp 222 EOC 223 /bin/rm -fr /var/lib/dhcp/dhclient* /var/log/cloud-init*.log 224 /sbin/shutdown -h now`[1:], 225 } 226 test.CheckInstallAndStartCommands(c, commands) 227 }