cloud-mu 1.9.0.pre.beta → 2.0.0.pre.alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. checksums.yaml +4 -4
  2. data/Berksfile +16 -54
  3. data/Berksfile.lock +14 -62
  4. data/bin/mu-aws-setup +131 -108
  5. data/bin/mu-configure +311 -74
  6. data/bin/mu-gcp-setup +84 -62
  7. data/bin/mu-load-config.rb +46 -2
  8. data/bin/mu-self-update +11 -9
  9. data/bin/mu-upload-chef-artifacts +4 -4
  10. data/{mu.gemspec → cloud-mu.gemspec} +2 -2
  11. data/cookbooks/awscli/Berksfile +8 -0
  12. data/cookbooks/mu-activedirectory/Berksfile +11 -0
  13. data/cookbooks/mu-firewall/Berksfile +9 -0
  14. data/cookbooks/mu-firewall/metadata.rb +1 -1
  15. data/cookbooks/mu-glusterfs/Berksfile +10 -0
  16. data/cookbooks/mu-jenkins/Berksfile +14 -0
  17. data/cookbooks/mu-master/Berksfile +23 -0
  18. data/cookbooks/mu-master/attributes/default.rb +1 -1
  19. data/cookbooks/mu-master/metadata.rb +2 -2
  20. data/cookbooks/mu-master/recipes/default.rb +1 -1
  21. data/cookbooks/mu-master/recipes/init.rb +7 -3
  22. data/cookbooks/mu-master/recipes/ssl-certs.rb +1 -0
  23. data/cookbooks/mu-mongo/Berksfile +10 -0
  24. data/cookbooks/mu-openvpn/Berksfile +11 -0
  25. data/cookbooks/mu-php54/Berksfile +13 -0
  26. data/cookbooks/mu-splunk/Berksfile +10 -0
  27. data/cookbooks/mu-tools/Berksfile +21 -0
  28. data/cookbooks/mu-tools/files/default/Mu_CA.pem +15 -15
  29. data/cookbooks/mu-utility/Berksfile +9 -0
  30. data/cookbooks/mu-utility/metadata.rb +2 -1
  31. data/cookbooks/nagios/Berksfile +7 -4
  32. data/cookbooks/s3fs/Berksfile +9 -0
  33. data/environments/dev.json +6 -6
  34. data/environments/prod.json +6 -6
  35. data/modules/mu.rb +20 -42
  36. data/modules/mu/cleanup.rb +102 -100
  37. data/modules/mu/cloud.rb +90 -28
  38. data/modules/mu/clouds/aws.rb +449 -218
  39. data/modules/mu/clouds/aws/alarm.rb +29 -17
  40. data/modules/mu/clouds/aws/cache_cluster.rb +78 -64
  41. data/modules/mu/clouds/aws/collection.rb +25 -18
  42. data/modules/mu/clouds/aws/container_cluster.rb +73 -66
  43. data/modules/mu/clouds/aws/database.rb +124 -116
  44. data/modules/mu/clouds/aws/dnszone.rb +27 -20
  45. data/modules/mu/clouds/aws/firewall_rule.rb +30 -22
  46. data/modules/mu/clouds/aws/folder.rb +18 -3
  47. data/modules/mu/clouds/aws/function.rb +77 -23
  48. data/modules/mu/clouds/aws/group.rb +19 -12
  49. data/modules/mu/clouds/aws/habitat.rb +153 -0
  50. data/modules/mu/clouds/aws/loadbalancer.rb +59 -52
  51. data/modules/mu/clouds/aws/log.rb +30 -23
  52. data/modules/mu/clouds/aws/msg_queue.rb +29 -20
  53. data/modules/mu/clouds/aws/notifier.rb +222 -0
  54. data/modules/mu/clouds/aws/role.rb +178 -90
  55. data/modules/mu/clouds/aws/search_domain.rb +40 -24
  56. data/modules/mu/clouds/aws/server.rb +169 -137
  57. data/modules/mu/clouds/aws/server_pool.rb +60 -83
  58. data/modules/mu/clouds/aws/storage_pool.rb +59 -31
  59. data/modules/mu/clouds/aws/user.rb +36 -27
  60. data/modules/mu/clouds/aws/userdata/linux.erb +101 -93
  61. data/modules/mu/clouds/aws/vpc.rb +250 -189
  62. data/modules/mu/clouds/azure.rb +132 -0
  63. data/modules/mu/clouds/cloudformation.rb +65 -1
  64. data/modules/mu/clouds/cloudformation/alarm.rb +8 -0
  65. data/modules/mu/clouds/cloudformation/cache_cluster.rb +7 -0
  66. data/modules/mu/clouds/cloudformation/collection.rb +7 -0
  67. data/modules/mu/clouds/cloudformation/database.rb +7 -0
  68. data/modules/mu/clouds/cloudformation/dnszone.rb +7 -0
  69. data/modules/mu/clouds/cloudformation/firewall_rule.rb +9 -2
  70. data/modules/mu/clouds/cloudformation/loadbalancer.rb +7 -0
  71. data/modules/mu/clouds/cloudformation/log.rb +7 -0
  72. data/modules/mu/clouds/cloudformation/server.rb +7 -0
  73. data/modules/mu/clouds/cloudformation/server_pool.rb +7 -0
  74. data/modules/mu/clouds/cloudformation/vpc.rb +7 -0
  75. data/modules/mu/clouds/google.rb +214 -110
  76. data/modules/mu/clouds/google/container_cluster.rb +42 -24
  77. data/modules/mu/clouds/google/database.rb +15 -6
  78. data/modules/mu/clouds/google/firewall_rule.rb +17 -25
  79. data/modules/mu/clouds/google/group.rb +13 -5
  80. data/modules/mu/clouds/google/habitat.rb +105 -0
  81. data/modules/mu/clouds/google/loadbalancer.rb +28 -20
  82. data/modules/mu/clouds/google/server.rb +93 -354
  83. data/modules/mu/clouds/google/server_pool.rb +18 -10
  84. data/modules/mu/clouds/google/user.rb +22 -14
  85. data/modules/mu/clouds/google/vpc.rb +97 -69
  86. data/modules/mu/config.rb +133 -38
  87. data/modules/mu/config/alarm.rb +25 -0
  88. data/modules/mu/config/cache_cluster.rb +5 -3
  89. data/modules/mu/config/cache_cluster.yml +23 -0
  90. data/modules/mu/config/database.rb +25 -16
  91. data/modules/mu/config/database.yml +3 -3
  92. data/modules/mu/config/function.rb +1 -2
  93. data/modules/mu/config/{project.rb → habitat.rb} +10 -10
  94. data/modules/mu/config/notifier.rb +85 -0
  95. data/modules/mu/config/notifier.yml +9 -0
  96. data/modules/mu/config/role.rb +1 -1
  97. data/modules/mu/config/search_domain.yml +2 -2
  98. data/modules/mu/config/server.rb +13 -1
  99. data/modules/mu/config/server.yml +3 -3
  100. data/modules/mu/config/server_pool.rb +3 -1
  101. data/modules/mu/config/storage_pool.rb +3 -1
  102. data/modules/mu/config/storage_pool.yml +19 -0
  103. data/modules/mu/config/vpc.rb +70 -8
  104. data/modules/mu/groomers/chef.rb +2 -3
  105. data/modules/mu/kittens.rb +500 -122
  106. data/modules/mu/master.rb +5 -5
  107. data/modules/mu/mommacat.rb +151 -91
  108. data/modules/tests/super_complex_bok.yml +12 -0
  109. data/modules/tests/super_simple_bok.yml +12 -0
  110. data/spec/mu/clouds/azure_spec.rb +82 -0
  111. data/spec/spec_helper.rb +105 -0
  112. metadata +26 -5
  113. data/modules/mu/clouds/aws/notification.rb +0 -139
  114. data/modules/mu/config/notification.rb +0 -44
@@ -1,7 +1,7 @@
1
1
  <% if $complexity == "complex" %>
2
2
 
3
3
  name: database-complex
4
- size: <%= db_size %>
4
+ size: db.r4.large
5
5
  engine: postgres
6
6
  engine_version: 9.6.6
7
7
  storage: 5
@@ -20,7 +20,7 @@ region: us-west-2
20
20
 
21
21
  name: database-simple
22
22
  size: <%= db_size %>
23
- engine: postgres
23
+ engine: mariadb
24
24
  storage: 5
25
25
 
26
- <% end %>
26
+ <% end %>
@@ -24,7 +24,7 @@ module MU
24
24
  "type" => "object",
25
25
  "title" => "Function",
26
26
  "description" => "Create a cloud function.",
27
- "required" => ["name", "cloud","runtime","iam_role","handler","code","region"],
27
+ "required" => ["name", "cloud","runtime","handler","code","region"],
28
28
  "additionalProperties" => false,
29
29
  "properties" => {
30
30
  "cloud" => MU::Config.cloud_primitive,
@@ -33,7 +33,6 @@ module MU
33
33
  "type" => "string",
34
34
  "enum" => %w{nodejs nodejs4.3 nodejs6.10 nodejs8.10 java8 python2.7 python3.6 dotnetcore1.0 dotnetcore2.0 dotnetcore2.1 nodejs4.3-edge go1.x}
35
35
  },
36
- "iam_role" => {"type" => "string"},
37
36
  "region" => MU::Config.region_primitive,
38
37
  "vpc" => MU::Config::VPC.reference(MU::Config::VPC::ONE_SUBNET+MU::Config::VPC::MANY_SUBNETS, MU::Config::VPC::NO_NAT_OPTS, "all_private"),
39
38
  "handler" => {
@@ -15,15 +15,15 @@
15
15
  module MU
16
16
  class Config
17
17
  # Basket of Kittens config schema and parser logic. See modules/mu/clouds/*/project.rb
18
- class Project
18
+ class Habitat
19
19
 
20
- # Base configuration schema for a Project
20
+ # Base configuration schema for a Habitat
21
21
  # @return [Hash]
22
22
  def self.schema
23
23
  {
24
24
  "type" => "object",
25
25
  "additionalProperties" => false,
26
- "description" => "Set up a cloud account (AWS account, Google Cloud project, etc)",
26
+ "description" => "Generate a cloud habitat (AWS account, Google Cloud project, Azure Directory, etc)",
27
27
  "properties" => {
28
28
  "name" => { "type" => "string" },
29
29
  "folder" => MU::Config::Folder.reference
@@ -36,32 +36,32 @@ module MU
36
36
  def self.reference
37
37
  {
38
38
  "type" => "object",
39
- "description" => "Deploy into or connect with resources in a specific account/project",
39
+ "description" => "Deploy into or connect with resources in a specific habitat (AWS account, GCP project, etc)",
40
40
  "minProperties" => 1,
41
41
  "additionalProperties" => false,
42
42
  "properties" => {
43
43
  "id" => {
44
44
  "type" => "string",
45
- "description" => "Discover this account/project by looking for this cloud provider identifier, such as 836541910896 (an AWS account number) or my-project-196124 (a Google Cloud project id)"
45
+ "description" => "Discover this habitat by looking for this cloud provider identifier, such as 836541910896 (an AWS account number) or my-project-196124 (a Google Cloud project id)"
46
46
  },
47
47
  "name" => {
48
48
  "type" => "string",
49
- "description" => "Discover this account/project by Mu-internal name; typically the shorthand 'name' field of an Account object declared elsewhere in the deploy, or in another deploy that's being referenced with 'deploy_id'."
49
+ "description" => "Discover this habitat by Mu-internal name; typically the shorthand 'name' field of a Habitat object declared elsewhere in the deploy, or in another deploy that's being referenced with 'deploy_id'."
50
50
  },
51
51
  "cloud" => MU::Config.cloud_primitive,
52
52
  "deploy_id" => {
53
53
  "type" => "string",
54
- "description" => "Search for this account/project in an existing Mu deploy; specify a Mu deploy id (e.g. DEMO-DEV-2014111400-NG)."
54
+ "description" => "Search for this Habitat in an existing Mu deploy by Mu deploy id (e.g. DEMO-DEV-2014111400-NG)."
55
55
  }
56
56
  }
57
57
  }
58
58
  end
59
59
 
60
- # Generic pre-processing of {MU::Config::BasketofKittens::project}, bare and unvalidated.
61
- # @param project [Hash]: The resource to process and validate
60
+ # Generic pre-processing of {MU::Config::BasketofKittens::habitat}, bare and unvalidated.
61
+ # @param habitat [Hash]: The resource to process and validate
62
62
  # @param configurator [MU::Config]: The overall deployment configurator of which this resource is a member
63
63
  # @return [Boolean]: True if validation succeeded, False otherwise
64
- def self.validate(project, configurator)
64
+ def self.validate(habitat, configurator)
65
65
  ok = true
66
66
  ok
67
67
  end
@@ -0,0 +1,85 @@
1
+ # Copyright:: Copyright (c) 2018 eGlobalTech, Inc., all rights reserved
2
+ #
3
+ # Licensed under the BSD-3 license (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License in the root of the project or at
6
+ #
7
+ # http://egt-labs.com/mu/LICENSE.html
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module MU
16
+ class Config
17
+ # Basket of Kittens config schema and parser logic. See modules/mu/clouds/*/notifier.rb
18
+ class Notifier
19
+
20
+ # Base configuration schema for a Notifier
21
+ # @return [Hash]
22
+ def self.schema
23
+ {
24
+ "type" => "object",
25
+ "additionalProperties" => false,
26
+ "description" => "A stub for inline resource that generate SNS notifications in AWS. This should really be expanded.",
27
+ "properties" => {
28
+ "name" => {
29
+ "type" => "string"
30
+ },
31
+ "region" => MU::Config.region_primitive,
32
+ "credentials" => MU::Config.credentials_primitive,
33
+ "subscriptions" => {
34
+ "type" => "array",
35
+ "description" => "A list of people or resources which should receive notifications",
36
+ "items" => {
37
+ "type" => "object",
38
+ "description" => "A list of people or resources which should receive notifications",
39
+ "required" => ["endpoint"],
40
+ "properties" => {
41
+ "endpoint" => {
42
+ "type" => "string",
43
+ "description" => "The endpoint which should be subscribed to this notifier, typically an email address or SMS-enabled phone number."
44
+ }
45
+ }
46
+ }
47
+ }
48
+ }
49
+ }
50
+ end
51
+
52
+ # Generic pre-processing of {MU::Config::BasketofKittens::notifiers}, bare and unvalidated.
53
+ # @param notifier [Hash]: The resource to process and validate
54
+ # @param configurator [MU::Config]: The overall deployment configurator of which this resource is a member
55
+ # @return [Boolean]: True if validation succeeded, False otherwise
56
+ def self.validate(notifier, configurator)
57
+ ok = true
58
+
59
+ if notifier['subscriptions']
60
+ notifier['subscriptions'].each { |sub|
61
+ if !sub["type"]
62
+ if sub["endpoint"].match(/^http:/i)
63
+ sub["type"] = "http"
64
+ elsif sub["endpoint"].match(/^https:/i)
65
+ sub["type"] = "https"
66
+ elsif sub["endpoint"].match(/^sqs:/i)
67
+ sub["type"] = "sqs"
68
+ elsif sub["endpoint"].match(/^\+?[\d\-]+$/)
69
+ sub["type"] = "sms"
70
+ elsif sub["endpoint"].match(/\A[\w+\-.]+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i)
71
+ sub["type"] = "email"
72
+ else
73
+ MU.log "Notifier #{notifier['name']} subscription #{sub['endpoint']} did not specify a type, and I'm unable to guess one", MU::ERR
74
+ ok = false
75
+ end
76
+ end
77
+ }
78
+ end
79
+
80
+ ok
81
+ end
82
+
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,9 @@
1
+ <% if $complexity == 'complex' %>
2
+ name: notifier
3
+ <% else %>
4
+ name: notifier
5
+ subscriptions:
6
+ - endpoint: admin@example.com
7
+ type: email-json
8
+ - endpoint: 703-555-5555
9
+ <% end %>
@@ -28,7 +28,7 @@ module MU
28
28
  "name" => {
29
29
  "type" => "string",
30
30
  "description" => "The name of a cloud provider role to create",
31
- "pattern" => '^[a-zA-Z0-9]+$'
31
+ "pattern" => '^[a-zA-Z0-9_\-]+$'
32
32
  },
33
33
  "import" => {
34
34
  "type" => "array",
@@ -1,6 +1,6 @@
1
1
  <% if $complexity == "complex" %>
2
2
 
3
- name: search_domain-complex
3
+ name: searchdomain-complex
4
4
  instance_type: t2.small.elasticsearch
5
5
  instance_count: 4
6
6
  dedicated_masters: 1
@@ -20,6 +20,6 @@ vpc:
20
20
 
21
21
  <% else %> # IF NOT COMPLEX THEN ASSUME SIMPLE
22
22
 
23
- name: search_domain-simple
23
+ name: searchdomain-simple
24
24
  instance_type: t2.small.elasticsearch
25
25
  <% end %>
@@ -136,6 +136,16 @@ module MU
136
136
  "default" => MU::Config.defaultGroomer,
137
137
  "enum" => MU.supportedGroomers
138
138
  },
139
+ "groom" => {
140
+ "type" => "boolean",
141
+ "default" => true,
142
+ "description" => "Whether to run a host configuration agent, e.g. Chef, when bootstrapping"
143
+ },
144
+ "groomer_timeout" => {
145
+ "type" => "integer",
146
+ "default" => 1800,
147
+ "description" => "Maximum execution time for a groomer run"
148
+ },
139
149
  "scrub_groomer" => {
140
150
  "type" => "boolean",
141
151
  "default" => false,
@@ -555,7 +565,9 @@ module MU
555
565
  server['vault_access'] << {"vault" => "splunk", "item" => "admin_user"}
556
566
  ok = false if !MU::Config.check_vault_refs(server)
557
567
 
558
- server['dependencies'] << configurator.adminFirewallRuleset(vpc: server['vpc'], region: server['region'], cloud: server['cloud']) if !server['scrub_mu_isms']
568
+ if !server['scrub_mu_isms']
569
+ server['dependencies'] << configurator.adminFirewallRuleset(vpc: server['vpc'], region: server['region'], cloud: server['cloud'], credentials: server['credentials'])
570
+ end
559
571
 
560
572
  if !server["vpc"].nil?
561
573
  # Common mistake- using all_public or all_private subnet_pref for
@@ -1,8 +1,8 @@
1
1
  <% if $complexity == 'complex' %>
2
- name: server-complex
2
+ name: servercomplex
3
3
  size: <%= instance_type %>
4
4
  # TODO: BUILD OUT COMPLEX EXAMPLE
5
5
  <% else %>
6
- name: server-simple
6
+ name: serversimple
7
7
  size: <%= instance_type %>
8
- <% end %>
8
+ <% end %>
@@ -180,7 +180,9 @@ module MU
180
180
  pool['vault_access'] << {"vault" => "splunk", "item" => "admin_user"}
181
181
  ok = false if !MU::Config.check_vault_refs(pool)
182
182
 
183
- pool['dependencies'] << configurator.adminFirewallRuleset(vpc: pool['vpc'], region: pool['region'], cloud: pool['cloud']) if !pool['scrub_mu_isms']
183
+ if !pool['scrub_mu_isms']
184
+ pool['dependencies'] << configurator.adminFirewallRuleset(vpc: pool['vpc'], region: pool['region'], cloud: pool['cloud'], credentials: pool['credentials'])
185
+ end
184
186
 
185
187
  if !pool["vpc"].nil?
186
188
  if !pool["vpc"]["subnet_name"].nil? and configurator.nat_routes.has_key?(pool["vpc"]["subnet_name"])
@@ -96,6 +96,7 @@ module MU
96
96
  "storagepool '#{pool['name']}'",
97
97
  configurator,
98
98
  dflt_region: pool['region'],
99
+ credentials: pool['credentials'],
99
100
  is_sibling: true,
100
101
  sibling_vpcs: [siblingvpc])
101
102
  ok = false
@@ -105,7 +106,8 @@ module MU
105
106
  "storage_pools",
106
107
  "storagepool #{pool['name']}",
107
108
  configurator,
108
- dflt_region: pool['region'])
109
+ dflt_region: pool['region'],
110
+ credentials: pool['credentials'])
109
111
  ok = false
110
112
  end
111
113
  end
@@ -0,0 +1,19 @@
1
+ <% if $complexity == "complex" %>
2
+ # XXX glue to other resources in test BoKs, if you want to test complexity
3
+ name: efs
4
+ mount_points:
5
+ - name: mountpoint
6
+ directory: /efs
7
+ ingress_rules:
8
+ - port: 2049
9
+ hosts:
10
+ - 0.0.0.0/0
11
+ <% else %> # IF NOT COMPLEX THEN ASSUME SIMPLE
12
+ name: efs
13
+ mount_points:
14
+ - name: mountpoint
15
+ directory: /efs
16
+ ingress_rules:
17
+ - port: 2049
18
+ hosts:
19
+ <% end %>
@@ -102,8 +102,8 @@ module MU
102
102
  "description" => "One or more other VPCs with which to attempt to create a peering connection.",
103
103
  "properties" => {
104
104
  "account" => {
105
- "type" => "string",
106
- "description" => "The AWS account which owns the target VPC."
105
+ "type" => "string",
106
+ "description" => "The AWS account which owns the target VPC."
107
107
  },
108
108
  "vpc" => reference(MANY_SUBNETS, NO_NAT_OPTS, "all")
109
109
  # "route_tables" => {
@@ -233,6 +233,7 @@ module MU
233
233
  "type" => "string",
234
234
  "description" => "Discover this VPC by looking for this cloud provider identifier."
235
235
  },
236
+ "credentials" => MU::Config.credentials_primitive,
236
237
  "vpc_name" => {
237
238
  "type" => "string",
238
239
  "description" => "Discover this VPC by Mu-internal name; typically the shorthand 'name' field of a VPC declared elsewhere in the deploy, or in another deploy that's being referenced with 'deploy_id'."
@@ -400,16 +401,39 @@ module MU
400
401
  def self.resolvePeers(vpc, configurator)
401
402
  ok = true
402
403
  if !vpc["peers"].nil?
404
+ append = []
405
+ delete = []
403
406
  vpc["peers"].each { |peer|
404
407
  peer["#MU_CLOUDCLASS"] = Object.const_get("MU").const_get("Cloud").const_get("VPC")
408
+ # We check for multiple siblings because some implementations
409
+ # (Google) can split declared VPCs into parts to get the mimic the
410
+ # routing behaviors we expect.
411
+ siblings = configurator.haveLitterMate?(peer['vpc']["vpc_name"], "vpcs", has_multiple: true)
412
+
405
413
  # If we're peering with a VPC in this deploy, set it as a dependency
406
- if !peer['vpc']["vpc_name"].nil? and
407
- configurator.haveLitterMate?(peer['vpc']["vpc_name"], "vpcs") and
414
+ if !peer['vpc']["vpc_name"].nil? and siblings.size > 0 and
408
415
  peer["vpc"]['deploy_id'].nil? and peer["vpc"]['vpc_id'].nil?
416
+
409
417
  peer['vpc']['cloud'] = vpc['cloud'] if peer['vpc']['cloud'].nil?
410
- vpc["dependencies"] << {
411
- "type" => "vpc",
412
- "name" => peer['vpc']["vpc_name"]
418
+ siblings.each { |sib|
419
+ if sib['name'] != peer['vpc']["vpc_name"]
420
+ if sib['name'] != vpc['name']
421
+ append_me = { "vpc" => peer["vpc"].dup }
422
+ append_me['vpc']['vpc_name'] = sib['name']
423
+ append << append_me
424
+ vpc["dependencies"] << {
425
+ "type" => "vpc",
426
+ "name" => sib['name']
427
+ }
428
+ end
429
+ delete << peer
430
+ else
431
+ vpc["dependencies"] << {
432
+ "type" => "vpc",
433
+ "name" => peer['vpc']["vpc_name"]
434
+ }
435
+ end
436
+ delete << peer if sib['name'] == vpc['name']
413
437
  }
414
438
  # If we're using a VPC from somewhere else, make sure the flippin'
415
439
  # thing exists, and also fetch its id now so later search routines
@@ -426,6 +450,12 @@ module MU
426
450
  end
427
451
  end
428
452
  }
453
+ append.each { |append_me|
454
+ vpc["peers"] << append_me
455
+ }
456
+ delete.each { |delete_me|
457
+ vpc["peers"].delete(delete_me)
458
+ }
429
459
  end
430
460
  ok
431
461
  end
@@ -439,7 +469,7 @@ module MU
439
469
  # @param is_sibling [Boolean]:
440
470
  # @param sibling_vpcs [Array]:
441
471
  # @param dflt_region [String]:
442
- def self.processReference(vpc_block, parent_type, parent_name, configurator, is_sibling: false, sibling_vpcs: [], dflt_region: MU.curRegion)
472
+ def self.processReference(vpc_block, parent_type, parent_name, configurator, is_sibling: false, sibling_vpcs: [], dflt_region: MU.curRegion, credentials: nil)
443
473
  puts vpc_block.ancestors if !vpc_block.is_a?(Hash)
444
474
  if !vpc_block.is_a?(Hash) and vpc_block.kind_of?(MU::Cloud::VPC)
445
475
  return true
@@ -450,6 +480,19 @@ module MU
450
480
  vpc_block['region'] = dflt_region.to_s
451
481
  end
452
482
 
483
+ vpc_block['credentials'] ||= credentials if credentials
484
+
485
+ # Sometimes people set subnet_pref to "private" or "public" when they
486
+ # mean "all_private" or "all_public." Help them out.
487
+ if parent_type and
488
+ MU::Config.schema["properties"][parent_type] and
489
+ MU::Config.schema["properties"][parent_type]["items"]["properties"]["vpc"] and
490
+ MU::Config.schema["properties"][parent_type]["items"]["properties"]["vpc"]["properties"].has_key?("subnets") and
491
+ !MU::Config.schema["properties"][parent_type]["items"]["properties"]["vpc"]["properties"].has_key?("subnet_id")
492
+ vpc_block["subnet_pref"] = "all_public" if vpc_block["subnet_pref"] == "public"
493
+ vpc_block["subnet_pref"] = "all_private" if vpc_block["subnet_pref"] == "private"
494
+ end
495
+
453
496
  flags = {}
454
497
  flags["subnet_pref"] = vpc_block["subnet_pref"] if !vpc_block["subnet_pref"].nil?
455
498
 
@@ -464,6 +507,7 @@ module MU
464
507
  deploy_id: vpc_block["deploy_id"],
465
508
  cloud_id: vpc_block["vpc_id"],
466
509
  name: vpc_block["vpc_name"],
510
+ credentials: vpc_block["credentials"],
467
511
  tag_key: tag_key,
468
512
  tag_value: tag_value,
469
513
  region: vpc_block["region"],
@@ -472,6 +516,24 @@ module MU
472
516
  )
473
517
 
474
518
  ext_vpc = found.first if found.size == 1
519
+
520
+ # Make sure we don't have a weird mismatch between requested
521
+ # credential sets and the VPC we actually found
522
+ if ext_vpc and ext_vpc.cloudobj and ext_vpc.cloudobj.config and
523
+ ext_vpc.cloudobj.config["credentials"]
524
+ if vpc_block['credentials'] and # probably can't happen
525
+ vpc_block['credentials'] != ext_vpc.cloudobj.config["credentials"]
526
+ ok = false
527
+ MU.log "#{parent_type} #{parent_name} requested a VPC on credentials '#{vpc_block['credentials']}' but matched VPC is under credentials '#{ext_vpc.cloudobj.config["credentials"]}'", MU::ERR, details: vpc_block
528
+ end
529
+ if credentials and
530
+ credentials != ext_vpc.cloudobj.config["credentials"]
531
+ ok = false
532
+ MU.log "#{parent_type} #{parent_name} is using credentials '#{credentials}' but matched VPC is under credentials '#{ext_vpc.cloudobj.config["credentials"]}'", MU::ERR, details: vpc_block
533
+ end
534
+ vpc_block['credentials'] ||= ext_vpc.cloudobj.config["credentials"]
535
+ end
536
+
475
537
  end
476
538
  rescue Exception => e
477
539
  raise MuError, e.inspect, e.backtrace
@@ -253,18 +253,17 @@ module MU
253
253
  # @param max_retries [Integer]: The maximum number of attempts at a successful run to make before giving up.
254
254
  # @param output [Boolean]: Display Chef's regular (non-error) output to the console
255
255
  # @param override_runlist [String]: Use the specified run list instead of the node's configured list
256
- def run(purpose: "Chef run", update_runlist: true, max_retries: 5, output: true, override_runlist: nil, reboot_first_fail: false)
256
+ def run(purpose: "Chef run", update_runlist: true, max_retries: 5, output: true, override_runlist: nil, reboot_first_fail: false, timeout: 1800)
257
257
  self.class.loadChefLib
258
258
  if update_runlist and !@config['run_list'].nil?
259
259
  knifeAddToRunList(multiple: @config['run_list'])
260
260
  end
261
261
 
262
- timeout = @server.windows? ? 1800 : 600
263
262
  pending_reboot_count = 0
264
263
  chef_node = ::Chef::Node.load(@server.mu_name)
265
264
  if !@config['application_attributes'].nil?
266
265
  MU.log "Setting node:#{@server.mu_name} application_attributes", MU::DEBUG, details: @config['application_attributes']
267
- chef_node.normal.application_attributes = @config['application_attributes']
266
+ chef_node.normal['application_attributes'] = @config['application_attributes']
268
267
  chef_node.save
269
268
  end
270
269
  if @server.deploy.original_config.has_key?('parameters')