github.com/handlerbot/terraform@v0.10.0-beta1.0.20180726153736-26b68d98f9cb/builtin/provisioners/chef/resource_provisioner_test.go (about) 1 package chef 2 3 import ( 4 "fmt" 5 "path" 6 "testing" 7 8 "github.com/hashicorp/terraform/communicator" 9 "github.com/hashicorp/terraform/config" 10 "github.com/hashicorp/terraform/helper/schema" 11 "github.com/hashicorp/terraform/terraform" 12 ) 13 14 func TestResourceProvisioner_impl(t *testing.T) { 15 var _ terraform.ResourceProvisioner = Provisioner() 16 } 17 18 func TestProvisioner(t *testing.T) { 19 if err := Provisioner().(*schema.Provisioner).InternalValidate(); err != nil { 20 t.Fatalf("err: %s", err) 21 } 22 } 23 24 func TestResourceProvider_Validate_good(t *testing.T) { 25 c := testConfig(t, map[string]interface{}{ 26 "environment": "_default", 27 "node_name": "nodename1", 28 "run_list": []interface{}{"cookbook::recipe"}, 29 "server_url": "https://chef.local", 30 "user_name": "bob", 31 "user_key": "USER-KEY", 32 }) 33 34 warn, errs := Provisioner().Validate(c) 35 if len(warn) > 0 { 36 t.Fatalf("Warnings: %v", warn) 37 } 38 if len(errs) > 0 { 39 t.Fatalf("Errors: %v", errs) 40 } 41 } 42 43 func TestResourceProvider_Validate_bad(t *testing.T) { 44 c := testConfig(t, map[string]interface{}{ 45 "invalid": "nope", 46 }) 47 48 warn, errs := Provisioner().Validate(c) 49 if len(warn) > 0 { 50 t.Fatalf("Warnings: %v", warn) 51 } 52 if len(errs) == 0 { 53 t.Fatalf("Should have errors") 54 } 55 } 56 57 // Test that the JSON attributes with an unknown value don't 58 // validate. 59 func TestResourceProvider_Validate_computedValues(t *testing.T) { 60 c := testConfig(t, map[string]interface{}{ 61 "environment": "_default", 62 "node_name": "nodename1", 63 "run_list": []interface{}{"cookbook::recipe"}, 64 "server_url": "https://chef.local", 65 "user_name": "bob", 66 "user_key": "USER-KEY", 67 "attributes_json": config.UnknownVariableValue, 68 }) 69 70 warn, errs := Provisioner().Validate(c) 71 if len(warn) > 0 { 72 t.Fatalf("Warnings: %v", warn) 73 } 74 if len(errs) > 0 { 75 t.Fatalf("Errors: %v", errs) 76 } 77 } 78 79 func TestResourceProvider_runChefClient(t *testing.T) { 80 cases := map[string]struct { 81 Config map[string]interface{} 82 ChefCmd string 83 ConfDir string 84 Commands map[string]bool 85 }{ 86 "Sudo": { 87 Config: map[string]interface{}{ 88 "node_name": "nodename1", 89 "run_list": []interface{}{"cookbook::recipe"}, 90 "server_url": "https://chef.local", 91 "user_name": "bob", 92 "user_key": "USER-KEY", 93 }, 94 95 ChefCmd: linuxChefCmd, 96 97 ConfDir: linuxConfDir, 98 99 Commands: map[string]bool{ 100 fmt.Sprintf(`sudo %s -j %q -E "_default"`, 101 linuxChefCmd, 102 path.Join(linuxConfDir, "first-boot.json")): true, 103 }, 104 }, 105 106 "NoSudo": { 107 Config: map[string]interface{}{ 108 "node_name": "nodename1", 109 "prevent_sudo": true, 110 "run_list": []interface{}{"cookbook::recipe"}, 111 "server_url": "https://chef.local", 112 "user_name": "bob", 113 "user_key": "USER-KEY", 114 }, 115 116 ChefCmd: linuxChefCmd, 117 118 ConfDir: linuxConfDir, 119 120 Commands: map[string]bool{ 121 fmt.Sprintf(`%s -j %q -E "_default"`, 122 linuxChefCmd, 123 path.Join(linuxConfDir, "first-boot.json")): true, 124 }, 125 }, 126 127 "Environment": { 128 Config: map[string]interface{}{ 129 "environment": "production", 130 "node_name": "nodename1", 131 "prevent_sudo": true, 132 "run_list": []interface{}{"cookbook::recipe"}, 133 "server_url": "https://chef.local", 134 "user_name": "bob", 135 "user_key": "USER-KEY", 136 }, 137 138 ChefCmd: windowsChefCmd, 139 140 ConfDir: windowsConfDir, 141 142 Commands: map[string]bool{ 143 fmt.Sprintf(`%s -j %q -E "production"`, 144 windowsChefCmd, 145 path.Join(windowsConfDir, "first-boot.json")): true, 146 }, 147 }, 148 } 149 150 o := new(terraform.MockUIOutput) 151 c := new(communicator.MockCommunicator) 152 153 for k, tc := range cases { 154 c.Commands = tc.Commands 155 156 p, err := decodeConfig( 157 schema.TestResourceDataRaw(t, Provisioner().(*schema.Provisioner).Schema, tc.Config), 158 ) 159 if err != nil { 160 t.Fatalf("Error: %v", err) 161 } 162 163 p.runChefClient = p.runChefClientFunc(tc.ChefCmd, tc.ConfDir) 164 p.useSudo = !p.PreventSudo 165 166 err = p.runChefClient(o, c) 167 if err != nil { 168 t.Fatalf("Test %q failed: %v", k, err) 169 } 170 } 171 } 172 173 func TestResourceProvider_fetchChefCertificates(t *testing.T) { 174 cases := map[string]struct { 175 Config map[string]interface{} 176 KnifeCmd string 177 ConfDir string 178 Commands map[string]bool 179 }{ 180 "Sudo": { 181 Config: map[string]interface{}{ 182 "fetch_chef_certificates": true, 183 "node_name": "nodename1", 184 "run_list": []interface{}{"cookbook::recipe"}, 185 "server_url": "https://chef.local", 186 "user_name": "bob", 187 "user_key": "USER-KEY", 188 }, 189 190 KnifeCmd: linuxKnifeCmd, 191 192 ConfDir: linuxConfDir, 193 194 Commands: map[string]bool{ 195 fmt.Sprintf(`sudo %s ssl fetch -c %s`, 196 linuxKnifeCmd, 197 path.Join(linuxConfDir, "client.rb")): true, 198 }, 199 }, 200 201 "NoSudo": { 202 Config: map[string]interface{}{ 203 "fetch_chef_certificates": true, 204 "node_name": "nodename1", 205 "prevent_sudo": true, 206 "run_list": []interface{}{"cookbook::recipe"}, 207 "server_url": "https://chef.local", 208 "user_name": "bob", 209 "user_key": "USER-KEY", 210 }, 211 212 KnifeCmd: windowsKnifeCmd, 213 214 ConfDir: windowsConfDir, 215 216 Commands: map[string]bool{ 217 fmt.Sprintf(`%s ssl fetch -c %s`, 218 windowsKnifeCmd, 219 path.Join(windowsConfDir, "client.rb")): true, 220 }, 221 }, 222 } 223 224 o := new(terraform.MockUIOutput) 225 c := new(communicator.MockCommunicator) 226 227 for k, tc := range cases { 228 c.Commands = tc.Commands 229 230 p, err := decodeConfig( 231 schema.TestResourceDataRaw(t, Provisioner().(*schema.Provisioner).Schema, tc.Config), 232 ) 233 if err != nil { 234 t.Fatalf("Error: %v", err) 235 } 236 237 p.fetchChefCertificates = p.fetchChefCertificatesFunc(tc.KnifeCmd, tc.ConfDir) 238 p.useSudo = !p.PreventSudo 239 240 err = p.fetchChefCertificates(o, c) 241 if err != nil { 242 t.Fatalf("Test %q failed: %v", k, err) 243 } 244 } 245 } 246 247 func TestResourceProvider_configureVaults(t *testing.T) { 248 cases := map[string]struct { 249 Config map[string]interface{} 250 GemCmd string 251 KnifeCmd string 252 ConfDir string 253 Commands map[string]bool 254 }{ 255 "Linux Vault string": { 256 Config: map[string]interface{}{ 257 "node_name": "nodename1", 258 "prevent_sudo": true, 259 "run_list": []interface{}{"cookbook::recipe"}, 260 "server_url": "https://chef.local", 261 "user_name": "bob", 262 "user_key": "USER-KEY", 263 "vault_json": `{"vault1": "item1"}`, 264 }, 265 266 GemCmd: linuxGemCmd, 267 KnifeCmd: linuxKnifeCmd, 268 ConfDir: linuxConfDir, 269 270 Commands: map[string]bool{ 271 fmt.Sprintf("%s install chef-vault", linuxGemCmd): true, 272 fmt.Sprintf("%s vault update vault1 item1 -C nodename1 -M client -c %s/client.rb "+ 273 "-u bob --key %s/bob.pem", linuxKnifeCmd, linuxConfDir, linuxConfDir): true, 274 }, 275 }, 276 277 "Linux Vault []string": { 278 Config: map[string]interface{}{ 279 "fetch_chef_certificates": true, 280 "node_name": "nodename1", 281 "prevent_sudo": true, 282 "run_list": []interface{}{"cookbook::recipe"}, 283 "server_url": "https://chef.local", 284 "user_name": "bob", 285 "user_key": "USER-KEY", 286 "vault_json": `{"vault1": ["item1", "item2"]}`, 287 }, 288 289 GemCmd: linuxGemCmd, 290 KnifeCmd: linuxKnifeCmd, 291 ConfDir: linuxConfDir, 292 293 Commands: map[string]bool{ 294 fmt.Sprintf("%s install chef-vault", linuxGemCmd): true, 295 fmt.Sprintf("%s vault update vault1 item1 -C nodename1 -M client -c %s/client.rb "+ 296 "-u bob --key %s/bob.pem", linuxKnifeCmd, linuxConfDir, linuxConfDir): true, 297 fmt.Sprintf("%s vault update vault1 item2 -C nodename1 -M client -c %s/client.rb "+ 298 "-u bob --key %s/bob.pem", linuxKnifeCmd, linuxConfDir, linuxConfDir): true, 299 }, 300 }, 301 302 "Linux Vault []string (recreate-client for vault)": { 303 Config: map[string]interface{}{ 304 "fetch_chef_certificates": true, 305 "node_name": "nodename1", 306 "prevent_sudo": true, 307 "run_list": []interface{}{"cookbook::recipe"}, 308 "server_url": "https://chef.local", 309 "user_name": "bob", 310 "user_key": "USER-KEY", 311 "vault_json": `{"vault1": ["item1", "item2"]}`, 312 "recreate_client": true, 313 }, 314 315 GemCmd: linuxGemCmd, 316 KnifeCmd: linuxKnifeCmd, 317 ConfDir: linuxConfDir, 318 319 Commands: map[string]bool{ 320 fmt.Sprintf("%s install chef-vault", linuxGemCmd): true, 321 fmt.Sprintf("%s vault remove vault1 item1 -C \"nodename1\" -M client -c %s/client.rb "+ 322 "-u bob --key %s/bob.pem", linuxKnifeCmd, linuxConfDir, linuxConfDir): true, 323 fmt.Sprintf("%s vault remove vault1 item2 -C \"nodename1\" -M client -c %s/client.rb "+ 324 "-u bob --key %s/bob.pem", linuxKnifeCmd, linuxConfDir, linuxConfDir): true, 325 fmt.Sprintf("%s vault update vault1 item1 -C nodename1 -M client -c %s/client.rb "+ 326 "-u bob --key %s/bob.pem", linuxKnifeCmd, linuxConfDir, linuxConfDir): true, 327 fmt.Sprintf("%s vault update vault1 item2 -C nodename1 -M client -c %s/client.rb "+ 328 "-u bob --key %s/bob.pem", linuxKnifeCmd, linuxConfDir, linuxConfDir): true, 329 }, 330 }, 331 332 "Windows Vault string": { 333 Config: map[string]interface{}{ 334 "node_name": "nodename1", 335 "prevent_sudo": true, 336 "run_list": []interface{}{"cookbook::recipe"}, 337 "server_url": "https://chef.local", 338 "user_name": "bob", 339 "user_key": "USER-KEY", 340 "vault_json": `{"vault1": "item1"}`, 341 }, 342 343 GemCmd: windowsGemCmd, 344 KnifeCmd: windowsKnifeCmd, 345 ConfDir: windowsConfDir, 346 347 Commands: map[string]bool{ 348 fmt.Sprintf("%s install chef-vault", windowsGemCmd): true, 349 fmt.Sprintf("%s vault update vault1 item1 -C nodename1 -M client -c %s/client.rb "+ 350 "-u bob --key %s/bob.pem", windowsKnifeCmd, windowsConfDir, windowsConfDir): true, 351 }, 352 }, 353 354 "Windows Vault []string": { 355 Config: map[string]interface{}{ 356 "fetch_chef_certificates": true, 357 "node_name": "nodename1", 358 "prevent_sudo": true, 359 "run_list": []interface{}{"cookbook::recipe"}, 360 "server_url": "https://chef.local", 361 "user_name": "bob", 362 "user_key": "USER-KEY", 363 "vault_json": `{"vault1": ["item1", "item2"]}`, 364 }, 365 366 GemCmd: windowsGemCmd, 367 KnifeCmd: windowsKnifeCmd, 368 ConfDir: windowsConfDir, 369 370 Commands: map[string]bool{ 371 fmt.Sprintf("%s install chef-vault", windowsGemCmd): true, 372 fmt.Sprintf("%s vault update vault1 item1 -C nodename1 -M client -c %s/client.rb "+ 373 "-u bob --key %s/bob.pem", windowsKnifeCmd, windowsConfDir, windowsConfDir): true, 374 fmt.Sprintf("%s vault update vault1 item2 -C nodename1 -M client -c %s/client.rb "+ 375 "-u bob --key %s/bob.pem", windowsKnifeCmd, windowsConfDir, windowsConfDir): true, 376 }, 377 }, 378 379 "Windows Vault [] string (recreate-client for vault)": { 380 Config: map[string]interface{}{ 381 "fetch_chef_certificates": true, 382 "node_name": "nodename1", 383 "prevent_sudo": true, 384 "run_list": []interface{}{"cookbook::recipe"}, 385 "server_url": "https://chef.local", 386 "user_name": "bob", 387 "user_key": "USER-KEY", 388 "vault_json": `{"vault1": ["item1", "item2"]}`, 389 "recreate_client": true, 390 }, 391 392 GemCmd: windowsGemCmd, 393 KnifeCmd: windowsKnifeCmd, 394 ConfDir: windowsConfDir, 395 396 Commands: map[string]bool{ 397 fmt.Sprintf("%s install chef-vault", windowsGemCmd): true, 398 fmt.Sprintf("%s vault remove vault1 item1 -C \"nodename1\" -M client -c %s/client.rb "+ 399 "-u bob --key %s/bob.pem", windowsKnifeCmd, windowsConfDir, windowsConfDir): true, 400 fmt.Sprintf("%s vault remove vault1 item2 -C \"nodename1\" -M client -c %s/client.rb "+ 401 "-u bob --key %s/bob.pem", windowsKnifeCmd, windowsConfDir, windowsConfDir): true, 402 fmt.Sprintf("%s vault update vault1 item1 -C nodename1 -M client -c %s/client.rb "+ 403 "-u bob --key %s/bob.pem", windowsKnifeCmd, windowsConfDir, windowsConfDir): true, 404 fmt.Sprintf("%s vault update vault1 item2 -C nodename1 -M client -c %s/client.rb "+ 405 "-u bob --key %s/bob.pem", windowsKnifeCmd, windowsConfDir, windowsConfDir): true, 406 }, 407 }, 408 } 409 410 o := new(terraform.MockUIOutput) 411 c := new(communicator.MockCommunicator) 412 413 for k, tc := range cases { 414 c.Commands = tc.Commands 415 416 p, err := decodeConfig( 417 schema.TestResourceDataRaw(t, Provisioner().(*schema.Provisioner).Schema, tc.Config), 418 ) 419 if err != nil { 420 t.Fatalf("Error: %v", err) 421 } 422 423 p.configureVaults = p.configureVaultsFunc(tc.GemCmd, tc.KnifeCmd, tc.ConfDir) 424 p.useSudo = !p.PreventSudo 425 426 err = p.configureVaults(o, c) 427 if err != nil { 428 t.Fatalf("Test %q failed: %v", k, err) 429 } 430 } 431 } 432 433 func testConfig(t *testing.T, c map[string]interface{}) *terraform.ResourceConfig { 434 r, err := config.NewRawConfig(c) 435 if err != nil { 436 t.Fatalf("bad: %s", err) 437 } 438 439 return terraform.NewResourceConfig(r) 440 }