github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/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 "--target-release", "precise-updates/cloud-tools", "cloud-image-utils", 256 // Other regular packages. 257 "ubuntu", 258 }}, 259 func(cfg cloudinit.CloudConfig) { 260 cfg.AddPackage("juju") 261 cfg.AddPackage("curl") 262 // cloud-tools packages need to appear in the list of packages 263 // after the "--target-release" and 264 // "precise-updates/cloud-tools" lines to work around the 265 // broken 0.6.3 cloud-init on precise. cloud-init 0.6.3 266 // concatenates all space-separated arguments for each entry 267 // in the packages list, and then escapes the result in single 268 // quotes, which in turn leads to incorrectly rendered apt-get 269 // command (e.g. instead of "apt-get install --target-release 270 // foo/bar package" 0.6.3 will try to execute "apt-get install 271 // '--target-release foo/bar package'".). See bug #1424777 for 272 // more info. 273 cfg.AddPackage("--target-release") 274 cfg.AddPackage("precise-updates/cloud-tools") 275 cfg.AddPackage("cloud-utils") 276 277 cfg.AddPackage("--target-release") 278 cfg.AddPackage("precise-updates/cloud-tools") 279 cfg.AddPackage("cloud-image-utils") 280 281 cfg.AddPackage("ubuntu") 282 }, 283 }, { 284 "BootCmd", 285 map[string]interface{}{"bootcmd": []string{ 286 "ls > /dev", 287 "ls >with space", 288 }}, 289 func(cfg cloudinit.CloudConfig) { 290 cfg.AddBootCmd("ls > /dev") 291 cfg.AddBootCmd("ls >with space") 292 }, 293 }, { 294 "Mounts", 295 map[string]interface{}{"mounts": [][]string{ 296 {"x", "y"}, 297 {"z", "w"}, 298 }}, 299 func(cfg cloudinit.CloudConfig) { 300 cfg.AddMount("x", "y") 301 cfg.AddMount("z", "w") 302 }, 303 }, { 304 "Attr", 305 map[string]interface{}{"arbitraryAttr": "someValue"}, 306 func(cfg cloudinit.CloudConfig) { 307 cfg.SetAttr("arbitraryAttr", "someValue") 308 }, 309 }, { 310 "RunCmd", 311 map[string]interface{}{"runcmd": []string{ 312 "ifconfig", 313 }}, 314 func(cfg cloudinit.CloudConfig) { 315 cfg.AddRunCmd("ifconfig") 316 }, 317 }, { 318 "AddScripts", 319 map[string]interface{}{"runcmd": []string{ 320 "echo 'Hello World'", 321 "ifconfig", 322 }}, 323 func(cfg cloudinit.CloudConfig) { 324 cfg.AddScripts( 325 "echo 'Hello World'", 326 "ifconfig", 327 ) 328 }, 329 }, { 330 "AddTextFile", 331 map[string]interface{}{"runcmd": []string{ 332 "install -D -m 644 /dev/null '/etc/apt/apt.conf.d/99proxy'", 333 "printf '%s\\n' '\"Acquire::http::Proxy \"http://10.0.3.1:3142\";' > '/etc/apt/apt.conf.d/99proxy'", 334 }}, 335 func(cfg cloudinit.CloudConfig) { 336 cfg.AddRunTextFile( 337 "/etc/apt/apt.conf.d/99proxy", 338 `"Acquire::http::Proxy "http://10.0.3.1:3142";`, 339 0644, 340 ) 341 }, 342 }, { 343 "AddBinaryFile", 344 map[string]interface{}{"runcmd": []string{ 345 "install -D -m 644 /dev/null '/dev/nonsense'", 346 "printf %s AAECAw== | base64 -d > '/dev/nonsense'", 347 }}, 348 func(cfg cloudinit.CloudConfig) { 349 cfg.AddRunBinaryFile( 350 "/dev/nonsense", 351 []byte{0, 1, 2, 3}, 352 0644, 353 ) 354 }, 355 }, { 356 "AddBootTextFile", 357 map[string]interface{}{"bootcmd": []string{ 358 "install -D -m 644 /dev/null '/etc/apt/apt.conf.d/99proxy'", 359 "printf '%s\\n' '\"Acquire::http::Proxy \"http://10.0.3.1:3142\";' > '/etc/apt/apt.conf.d/99proxy'", 360 }}, 361 func(cfg cloudinit.CloudConfig) { 362 cfg.AddBootTextFile( 363 "/etc/apt/apt.conf.d/99proxy", 364 `"Acquire::http::Proxy "http://10.0.3.1:3142";`, 365 0644, 366 ) 367 }, 368 }, 369 } 370 371 func (S) TestOutput(c *gc.C) { 372 for i, t := range ctests { 373 c.Logf("test %d: %s", i, t.name) 374 cfg, err := cloudinit.New("precise") 375 c.Assert(err, jc.ErrorIsNil) 376 t.setOption(cfg) 377 data, err := cfg.RenderYAML() 378 c.Assert(err, jc.ErrorIsNil) 379 c.Assert(data, gc.NotNil) 380 c.Assert(string(data), jc.YAMLEquals, t.expect) 381 data, err = cfg.RenderYAML() 382 c.Assert(err, jc.ErrorIsNil) 383 c.Assert(data, gc.NotNil) 384 c.Assert(string(data), jc.YAMLEquals, t.expect) 385 } 386 } 387 388 func (S) TestRunCmds(c *gc.C) { 389 cfg, err := cloudinit.New("precise") 390 c.Assert(err, jc.ErrorIsNil) 391 c.Assert(cfg.RunCmds(), gc.HasLen, 0) 392 cfg.AddScripts("a", "b") 393 cfg.AddRunCmd("e") 394 c.Assert(cfg.RunCmds(), gc.DeepEquals, []string{ 395 "a", "b", "e", 396 }) 397 } 398 399 func (S) TestPackages(c *gc.C) { 400 cfg, err := cloudinit.New("precise") 401 c.Assert(err, jc.ErrorIsNil) 402 c.Assert(cfg.Packages(), gc.HasLen, 0) 403 cfg.AddPackage("a b c") 404 cfg.AddPackage("d!") 405 expectedPackages := []string{"a b c", "d!"} 406 c.Assert(cfg.Packages(), gc.DeepEquals, expectedPackages) 407 } 408 409 func (S) TestSetOutput(c *gc.C) { 410 type test struct { 411 kind cloudinit.OutputKind 412 stdout string 413 stderr string 414 } 415 tests := []test{{ 416 cloudinit.OutAll, "a", "", 417 }, { 418 cloudinit.OutAll, "", "b", 419 }, { 420 cloudinit.OutInit, "a", "b", 421 }, { 422 cloudinit.OutAll, "a", "b", 423 }, { 424 cloudinit.OutAll, "", "", 425 }} 426 427 cfg, err := cloudinit.New("trusty") 428 c.Assert(err, jc.ErrorIsNil) 429 stdout, stderr := cfg.Output(cloudinit.OutAll) 430 c.Assert(stdout, gc.Equals, "") 431 c.Assert(stderr, gc.Equals, "") 432 for i, t := range tests { 433 c.Logf("test %d: %+v", i, t) 434 cfg.SetOutput(t.kind, t.stdout, t.stderr) 435 stdout, stderr = cfg.Output(t.kind) 436 c.Assert(stdout, gc.Equals, t.stdout) 437 c.Assert(stderr, gc.Equals, t.stderr) 438 } 439 } 440 441 func (S) TestWindowsRender(c *gc.C) { 442 compareOutput := "#ps1_sysnative\r\n\r\npowershell" 443 cfg, err := cloudinit.New("win8") 444 c.Assert(err, jc.ErrorIsNil) 445 cfg.AddRunCmd("powershell") 446 data, err := cfg.RenderYAML() 447 c.Assert(err, jc.ErrorIsNil) 448 c.Assert(data, gc.NotNil) 449 c.Assert(string(data), gc.Equals, compareOutput, gc.Commentf("test %q output differs", "windows renderer")) 450 }