github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/cloudconfig/cloudinit/cloudinit_test.go (about) 1 // Copyright 2011, 2012, 2013, 2015 Canonical Ltd. 2 // Copyright 2015 Cloudbase Solutions SRL 3 // Licensed under the AGPLv3, see LICENCE file for details. 4 5 package cloudinit_test 6 7 import ( 8 "fmt" 9 "testing" 10 11 jc "github.com/juju/testing/checkers" 12 "github.com/juju/utils/packaging" 13 sshtesting "github.com/juju/utils/ssh/testing" 14 gc "gopkg.in/check.v1" 15 16 "github.com/juju/juju/cloudconfig/cloudinit" 17 coretesting "github.com/juju/juju/testing" 18 ) 19 20 // TODO integration tests, but how? 21 22 type S struct { 23 coretesting.BaseSuite 24 } 25 26 var _ = gc.Suite(S{}) 27 28 func Test1(t *testing.T) { 29 gc.TestingT(t) 30 } 31 32 var ctests = []struct { 33 name string 34 expect map[string]interface{} 35 setOption func(cfg cloudinit.CloudConfig) 36 }{{ 37 "PackageUpgrade", 38 map[string]interface{}{"package_upgrade": true}, 39 func(cfg cloudinit.CloudConfig) { 40 cfg.SetSystemUpgrade(true) 41 }, 42 }, { 43 "PackageUpdate", 44 map[string]interface{}{"package_update": true}, 45 func(cfg cloudinit.CloudConfig) { 46 cfg.SetSystemUpdate(true) 47 }, 48 }, { 49 "PackageProxy", 50 map[string]interface{}{"apt_proxy": "http://foo.com"}, 51 func(cfg cloudinit.CloudConfig) { 52 cfg.SetPackageProxy("http://foo.com") 53 }, 54 }, { 55 "PackageMirror", 56 map[string]interface{}{"apt_mirror": "http://foo.com"}, 57 func(cfg cloudinit.CloudConfig) { 58 cfg.SetPackageMirror("http://foo.com") 59 }, 60 }, { 61 "DisableEC2Metadata", 62 map[string]interface{}{"disable_ec2_metadata": true}, 63 func(cfg cloudinit.CloudConfig) { 64 cfg.SetDisableEC2Metadata(true) 65 }, 66 }, { 67 "FinalMessage", 68 map[string]interface{}{"final_message": "goodbye"}, 69 func(cfg cloudinit.CloudConfig) { 70 cfg.SetFinalMessage("goodbye") 71 }, 72 }, { 73 "Locale", 74 map[string]interface{}{"locale": "en_us"}, 75 func(cfg cloudinit.CloudConfig) { 76 cfg.SetLocale("en_us") 77 }, 78 }, { 79 "DisableRoot", 80 map[string]interface{}{"disable_root": false}, 81 func(cfg cloudinit.CloudConfig) { 82 cfg.SetDisableRoot(false) 83 }, 84 }, { 85 "SetSSHAuthorizedKeys with two keys", 86 map[string]interface{}{"ssh_authorized_keys": []string{ 87 fmt.Sprintf("%s Juju:user@host", sshtesting.ValidKeyOne.Key), 88 fmt.Sprintf("%s Juju:another@host", sshtesting.ValidKeyTwo.Key), 89 }}, 90 func(cfg cloudinit.CloudConfig) { 91 cfg.SetSSHAuthorizedKeys( 92 sshtesting.ValidKeyOne.Key + " Juju:user@host\n" + 93 sshtesting.ValidKeyTwo.Key + " another@host") 94 }, 95 }, { 96 "SetSSHAuthorizedKeys with comments in keys", 97 map[string]interface{}{"ssh_authorized_keys": []string{ 98 fmt.Sprintf("%s Juju:sshkey", sshtesting.ValidKeyOne.Key), 99 fmt.Sprintf("%s Juju:user@host", sshtesting.ValidKeyTwo.Key), 100 fmt.Sprintf("%s Juju:another@host", sshtesting.ValidKeyThree.Key), 101 }}, 102 func(cfg cloudinit.CloudConfig) { 103 cfg.SetSSHAuthorizedKeys( 104 "#command\n" + sshtesting.ValidKeyOne.Key + "\n" + 105 sshtesting.ValidKeyTwo.Key + " user@host\n" + 106 "# comment\n\n" + 107 sshtesting.ValidKeyThree.Key + " another@host") 108 }, 109 }, { 110 "SetSSHAuthorizedKeys unsets keys", 111 map[string]interface{}{}, 112 func(cfg cloudinit.CloudConfig) { 113 cfg.SetSSHAuthorizedKeys(sshtesting.ValidKeyOne.Key) 114 cfg.SetSSHAuthorizedKeys("") 115 }, 116 }, { 117 "AddUser with keys", 118 map[string]interface{}{"users": []interface{}{map[string]interface{}{ 119 "name": "auser", 120 "lock_passwd": true, 121 "ssh-authorized-keys": []string{ 122 fmt.Sprintf("%s Juju:user@host", sshtesting.ValidKeyOne.Key), 123 fmt.Sprintf("%s Juju:another@host", sshtesting.ValidKeyTwo.Key), 124 }, 125 }}}, 126 func(cfg cloudinit.CloudConfig) { 127 keys := (sshtesting.ValidKeyOne.Key + " Juju:user@host\n" + 128 sshtesting.ValidKeyTwo.Key + " another@host") 129 cfg.AddUser(&cloudinit.User{ 130 Name: "auser", 131 SSHAuthorizedKeys: keys, 132 }) 133 }, 134 }, { 135 "AddUser with groups", 136 map[string]interface{}{"users": []interface{}{map[string]interface{}{ 137 "name": "auser", 138 "lock_passwd": true, 139 "groups": []string{"agroup", "bgroup"}, 140 }}}, 141 func(cfg cloudinit.CloudConfig) { 142 cfg.AddUser(&cloudinit.User{ 143 Name: "auser", 144 Groups: []string{"agroup", "bgroup"}, 145 }) 146 }, 147 }, { 148 "AddUser with everything", 149 map[string]interface{}{"users": []interface{}{map[string]interface{}{ 150 "name": "auser", 151 "lock_passwd": true, 152 "groups": []string{"agroup", "bgroup"}, 153 "shell": "/bin/sh", 154 "ssh-authorized-keys": []string{ 155 sshtesting.ValidKeyOne.Key + " Juju:sshkey", 156 }, 157 "sudo": []string{"ALL=(ALL) ALL"}, 158 }}}, 159 func(cfg cloudinit.CloudConfig) { 160 cfg.AddUser(&cloudinit.User{ 161 Name: "auser", 162 Groups: []string{"agroup", "bgroup"}, 163 Shell: "/bin/sh", 164 SSHAuthorizedKeys: sshtesting.ValidKeyOne.Key + "\n", 165 Sudo: []string{"ALL=(ALL) ALL"}, 166 }) 167 }, 168 }, { 169 "AddUser with only name", 170 map[string]interface{}{"users": []interface{}{map[string]interface{}{ 171 "name": "auser", 172 "lock_passwd": true, 173 }}}, 174 func(cfg cloudinit.CloudConfig) { 175 cfg.AddUser(&cloudinit.User{ 176 Name: "auser", 177 }) 178 }, 179 }, { 180 "Output", 181 map[string]interface{}{"output": map[string]interface{}{ 182 "all": []string{">foo", "|bar"}, 183 }}, 184 func(cfg cloudinit.CloudConfig) { 185 cfg.SetOutput("all", ">foo", "|bar") 186 }, 187 }, { 188 "Output", 189 map[string]interface{}{"output": map[string]interface{}{ 190 "all": ">foo", 191 }}, 192 func(cfg cloudinit.CloudConfig) { 193 cfg.SetOutput(cloudinit.OutAll, ">foo", "") 194 }, 195 }, { 196 "PackageSources", 197 map[string]interface{}{"apt_sources": []map[string]interface{}{ 198 { 199 "source": "keyName", 200 "key": "someKey", 201 }, 202 }}, 203 func(cfg cloudinit.CloudConfig) { 204 cfg.AddPackageSource(packaging.PackageSource{URL: "keyName", Key: "someKey"}) 205 }, 206 }, { 207 "PackageSources with preferences", 208 map[string]interface{}{ 209 "apt_sources": []map[string]interface{}{ 210 { 211 "source": "keyName", 212 "key": "someKey", 213 }, 214 }, 215 "bootcmd": []string{ 216 "install -D -m 644 /dev/null '/some/path'", 217 "printf '%s\\n' 'Explanation: test\n" + 218 "Package: *\n" + 219 "Pin: release n=series\n" + 220 "Pin-Priority: 123\n" + 221 "' > '/some/path'", 222 }, 223 }, 224 func(cfg cloudinit.CloudConfig) { 225 prefs := packaging.PackagePreferences{ 226 Path: "/some/path", 227 Explanation: "test", 228 Package: "*", 229 Pin: "release n=series", 230 Priority: 123, 231 } 232 cfg.AddPackageSource(packaging.PackageSource{URL: "keyName", Key: "someKey"}) 233 cfg.AddPackagePreferences(prefs) 234 }, 235 }, { 236 "Packages", 237 map[string]interface{}{"packages": []string{ 238 "juju", 239 "ubuntu", 240 }}, 241 func(cfg cloudinit.CloudConfig) { 242 cfg.AddPackage("juju") 243 cfg.AddPackage("ubuntu") 244 }, 245 }, { 246 "Packages on precise, needing cloud-tools", 247 map[string]interface{}{"packages": []string{ 248 // Regular packages (not needing the cloud-tools archive) 249 "juju", 250 "curl", 251 // The following need to be among the list of cloud-tools 252 // packages (see cloudArchivePackagesUbuntu in juju/utils 253 // repo). 254 "--target-release", "precise-updates/cloud-tools", "cloud-utils", 255 // Other regular packages. 256 "ubuntu", 257 }}, 258 func(cfg cloudinit.CloudConfig) { 259 cfg.AddPackage("juju") 260 cfg.AddPackage("curl") 261 // cloud-tools packages need to appear in the list of packages 262 // after the "--target-release" and 263 // "precise-updates/cloud-tools" lines to work around the 264 // broken 0.6.3 cloud-init on precise. cloud-init 0.6.3 265 // concatenates all space-separated arguments for each entry 266 // in the packages list, and then escapes the result in single 267 // quotes, which in turn leads to incorrectly rendered apt-get 268 // command (e.g. instead of "apt-get install --target-release 269 // foo/bar package" 0.6.3 will try to execute "apt-get install 270 // '--target-release foo/bar package'".). See bug #1424777 for 271 // more info. 272 cfg.AddPackage("--target-release") 273 cfg.AddPackage("precise-updates/cloud-tools") 274 cfg.AddPackage("cloud-utils") 275 276 cfg.AddPackage("ubuntu") 277 }, 278 }, { 279 "BootCmd", 280 map[string]interface{}{"bootcmd": []string{ 281 "ls > /dev", 282 "ls >with space", 283 }}, 284 func(cfg cloudinit.CloudConfig) { 285 cfg.AddBootCmd("ls > /dev") 286 cfg.AddBootCmd("ls >with space") 287 }, 288 }, { 289 "Mounts", 290 map[string]interface{}{"mounts": [][]string{ 291 {"x", "y"}, 292 {"z", "w"}, 293 }}, 294 func(cfg cloudinit.CloudConfig) { 295 cfg.AddMount("x", "y") 296 cfg.AddMount("z", "w") 297 }, 298 }, { 299 "Attr", 300 map[string]interface{}{"arbitraryAttr": "someValue"}, 301 func(cfg cloudinit.CloudConfig) { 302 cfg.SetAttr("arbitraryAttr", "someValue") 303 }, 304 }, { 305 "RunCmd", 306 map[string]interface{}{"runcmd": []string{ 307 "ifconfig", 308 }}, 309 func(cfg cloudinit.CloudConfig) { 310 cfg.AddRunCmd("ifconfig") 311 }, 312 }, { 313 "AddScripts", 314 map[string]interface{}{"runcmd": []string{ 315 "echo 'Hello World'", 316 "ifconfig", 317 }}, 318 func(cfg cloudinit.CloudConfig) { 319 cfg.AddScripts( 320 "echo 'Hello World'", 321 "ifconfig", 322 ) 323 }, 324 }, { 325 "AddTextFile", 326 map[string]interface{}{"runcmd": []string{ 327 "install -D -m 644 /dev/null '/etc/apt/apt.conf.d/99proxy'", 328 "printf '%s\\n' '\"Acquire::http::Proxy \"http://10.0.3.1:3142\";' > '/etc/apt/apt.conf.d/99proxy'", 329 }}, 330 func(cfg cloudinit.CloudConfig) { 331 cfg.AddRunTextFile( 332 "/etc/apt/apt.conf.d/99proxy", 333 `"Acquire::http::Proxy "http://10.0.3.1:3142";`, 334 0644, 335 ) 336 }, 337 }, { 338 "AddBinaryFile", 339 map[string]interface{}{"runcmd": []string{ 340 "install -D -m 644 /dev/null '/dev/nonsense'", 341 "printf %s AAECAw== | base64 -d > '/dev/nonsense'", 342 }}, 343 func(cfg cloudinit.CloudConfig) { 344 cfg.AddRunBinaryFile( 345 "/dev/nonsense", 346 []byte{0, 1, 2, 3}, 347 0644, 348 ) 349 }, 350 }, { 351 "AddBootTextFile", 352 map[string]interface{}{"bootcmd": []string{ 353 "install -D -m 644 /dev/null '/etc/apt/apt.conf.d/99proxy'", 354 "printf '%s\\n' '\"Acquire::http::Proxy \"http://10.0.3.1:3142\";' > '/etc/apt/apt.conf.d/99proxy'", 355 }}, 356 func(cfg cloudinit.CloudConfig) { 357 cfg.AddBootTextFile( 358 "/etc/apt/apt.conf.d/99proxy", 359 `"Acquire::http::Proxy "http://10.0.3.1:3142";`, 360 0644, 361 ) 362 }, 363 }, 364 } 365 366 func (S) TestOutput(c *gc.C) { 367 for i, t := range ctests { 368 c.Logf("test %d: %s", i, t.name) 369 cfg, err := cloudinit.New("precise") 370 c.Assert(err, jc.ErrorIsNil) 371 t.setOption(cfg) 372 data, err := cfg.RenderYAML() 373 c.Assert(err, jc.ErrorIsNil) 374 c.Assert(data, gc.NotNil) 375 c.Assert(string(data), jc.YAMLEquals, t.expect) 376 data, err = cfg.RenderYAML() 377 c.Assert(err, jc.ErrorIsNil) 378 c.Assert(data, gc.NotNil) 379 c.Assert(string(data), jc.YAMLEquals, t.expect) 380 } 381 } 382 383 func (S) TestRunCmds(c *gc.C) { 384 cfg, err := cloudinit.New("precise") 385 c.Assert(err, jc.ErrorIsNil) 386 c.Assert(cfg.RunCmds(), gc.HasLen, 0) 387 cfg.AddScripts("a", "b") 388 cfg.AddRunCmd("e") 389 c.Assert(cfg.RunCmds(), gc.DeepEquals, []string{ 390 "a", "b", "e", 391 }) 392 } 393 394 func (S) TestPackages(c *gc.C) { 395 cfg, err := cloudinit.New("precise") 396 c.Assert(err, jc.ErrorIsNil) 397 c.Assert(cfg.Packages(), gc.HasLen, 0) 398 cfg.AddPackage("a b c") 399 cfg.AddPackage("d!") 400 expectedPackages := []string{"a b c", "d!"} 401 c.Assert(cfg.Packages(), gc.DeepEquals, expectedPackages) 402 } 403 404 func (S) TestSetOutput(c *gc.C) { 405 type test struct { 406 kind cloudinit.OutputKind 407 stdout string 408 stderr string 409 } 410 tests := []test{{ 411 cloudinit.OutAll, "a", "", 412 }, { 413 cloudinit.OutAll, "", "b", 414 }, { 415 cloudinit.OutInit, "a", "b", 416 }, { 417 cloudinit.OutAll, "a", "b", 418 }, { 419 cloudinit.OutAll, "", "", 420 }} 421 422 cfg, err := cloudinit.New("trusty") 423 c.Assert(err, jc.ErrorIsNil) 424 stdout, stderr := cfg.Output(cloudinit.OutAll) 425 c.Assert(stdout, gc.Equals, "") 426 c.Assert(stderr, gc.Equals, "") 427 for i, t := range tests { 428 c.Logf("test %d: %+v", i, t) 429 cfg.SetOutput(t.kind, t.stdout, t.stderr) 430 stdout, stderr = cfg.Output(t.kind) 431 c.Assert(stdout, gc.Equals, t.stdout) 432 c.Assert(stderr, gc.Equals, t.stderr) 433 } 434 } 435 436 func (S) TestWindowsRender(c *gc.C) { 437 compareOutput := "#ps1_sysnative\r\n\r\npowershell" 438 cfg, err := cloudinit.New("win8") 439 c.Assert(err, jc.ErrorIsNil) 440 cfg.AddRunCmd("powershell") 441 data, err := cfg.RenderYAML() 442 c.Assert(err, jc.ErrorIsNil) 443 c.Assert(data, gc.NotNil) 444 c.Assert(string(data), gc.Equals, compareOutput, gc.Commentf("test %q output differs", "windows renderer")) 445 }