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
@@ -40,7 +40,7 @@ module MU
40
40
  def create
41
41
 
42
42
  begin
43
- MU::Cloud::AWS.iam.get_user(user_name: @mu_name, path: @config['path'])
43
+ MU::Cloud::AWS.iam(credentials: @config['credentials']).get_user(user_name: @mu_name, path: @config['path'])
44
44
  if !@config['use_if_exists']
45
45
  raise MuError, "IAM user #{@mu_name} already exists and use_if_exists is false"
46
46
  end
@@ -48,7 +48,7 @@ module MU
48
48
  @config['path'] ||= "/"+@deploy.deploy_id+"/"
49
49
  MU.log "Creating IAM user #{@config['path']}/#{@mu_name}"
50
50
  tags = get_tag_params
51
- MU::Cloud::AWS.iam.create_user(
51
+ MU::Cloud::AWS.iam(credentials: @config['credentials']).create_user(
52
52
  user_name: @mu_name,
53
53
  path: @config['path'],
54
54
  tags: tags
@@ -59,7 +59,7 @@ module MU
59
59
 
60
60
  # Called automatically by {MU::Deploy#createResources}
61
61
  def groom
62
- resp = MU::Cloud::AWS.iam.list_user_tags(user_name: @mu_name)
62
+ resp = MU::Cloud::AWS.iam(credentials: @config['credentials']).list_user_tags(user_name: @mu_name)
63
63
 
64
64
  ext_tags = resp.tags.map { |t| t.to_h }
65
65
  tag_param = get_tag_params(true)
@@ -67,7 +67,7 @@ module MU
67
67
 
68
68
  if tag_param.size > 0
69
69
  MU.log "Updating tags on IAM user #{@mu_name}", MU::NOTICE, details: tag_param
70
- MU::Cloud::AWS.iam.tag_user(user_name: @mu_name, tags: tag_param)
70
+ MU::Cloud::AWS.iam(credentials: @config['credentials']).tag_user(user_name: @mu_name, tags: tag_param)
71
71
  end
72
72
  # Note: We don't delete tags, because we often share user accounts
73
73
  # managed outside of Mu. We have no way of know what tags might come
@@ -76,12 +76,12 @@ module MU
76
76
 
77
77
  if @config['create_console_password']
78
78
  begin
79
- MU::Cloud::AWS.iam.get_login_profile(user_name: @mu_name)
79
+ MU::Cloud::AWS.iam(credentials: @config['credentials']).get_login_profile(user_name: @mu_name)
80
80
  rescue Aws::IAM::Errors::NoSuchEntity
81
81
  pw = Password.pronounceable(12..14)
82
82
  retries = 0
83
83
  begin
84
- MU::Cloud::AWS.iam.create_login_profile(
84
+ MU::Cloud::AWS.iam(credentials: @config['credentials']).create_login_profile(
85
85
  user_name: @mu_name,
86
86
  password: pw
87
87
  )
@@ -101,11 +101,11 @@ module MU
101
101
  end
102
102
 
103
103
  if @config['create_api_keys']
104
- resp = MU::Cloud::AWS.iam.list_access_keys(
104
+ resp = MU::Cloud::AWS.iam(credentials: @config['credentials']).list_access_keys(
105
105
  user_name: @mu_name
106
106
  )
107
107
  if resp.access_key_metadata.size == 0
108
- resp = MU::Cloud::AWS.iam.create_access_key(
108
+ resp = MU::Cloud::AWS.iam(credentials: @config['credentials']).create_access_key(
109
109
  user_name: @mu_name
110
110
  )
111
111
  scratchitem = MU::Master.storeScratchPadSecret("AWS Access Key and Secret for user #{@mu_name}:\nKEY: #{resp.access_key.access_key_id}\nSECRET: #{resp.access_key.secret_access_key}")
@@ -124,61 +124,68 @@ module MU
124
124
  # Return the metadata for this user cofiguration
125
125
  # @return [Hash]
126
126
  def notify
127
- descriptor = MU.structToHash(MU::Cloud::AWS.iam.get_user(user_name: @mu_name).user)
127
+ descriptor = MU.structToHash(MU::Cloud::AWS.iam(credentials: @config['credentials']).get_user(user_name: @mu_name).user)
128
128
  descriptor["cloud_id"] = @mu_name
129
129
  descriptor
130
130
  end
131
131
 
132
+ # Does this resource type exist as a global (cloud-wide) artifact, or
133
+ # is it localized to a region/zone?
134
+ # @return [Boolean]
135
+ def self.isGlobal?
136
+ true
137
+ end
138
+
132
139
  # Remove all users associated with the currently loaded deployment.
133
140
  # @param noop [Boolean]: If true, will only print what would be done
134
141
  # @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
135
142
  # @param region [String]: The cloud provider region
136
143
  # @return [void]
137
- def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, flags: {})
144
+ def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
138
145
 
139
146
  # XXX this doesn't belong here; maybe under roles, maybe as its own stupid first-class resource
140
- resp = MU::Cloud::AWS.iam.list_policies(
147
+ resp = MU::Cloud::AWS.iam(credentials: credentials).list_policies(
141
148
  path_prefix: "/"+MU.deploy_id+"/"
142
149
  )
143
150
  if resp and resp.policies
144
151
  resp.policies.each { |policy|
145
152
  MU.log "Deleting policy /#{MU.deploy_id}/#{policy.policy_name}"
146
153
  if !noop
147
- attachments = MU::Cloud::AWS.iam.list_entities_for_policy(
154
+ attachments = MU::Cloud::AWS.iam(credentials: credentials).list_entities_for_policy(
148
155
  policy_arn: policy.arn
149
156
  )
150
157
  attachments.policy_users.each { |u|
151
- MU::Cloud::AWS.iam.detach_user_policy(
158
+ MU::Cloud::AWS.iam(credentials: credentials).detach_user_policy(
152
159
  user_name: u.user_name,
153
160
  policy_arn: policy.arn
154
161
  )
155
162
  }
156
163
  attachments.policy_groups.each { |g|
157
- MU::Cloud::AWS.iam.detach_role_policy(
164
+ MU::Cloud::AWS.iam(credentials: credentials).detach_role_policy(
158
165
  group_name: g.group_name,
159
166
  policy_arn: policy.arn
160
167
  )
161
168
  }
162
169
  attachments.policy_roles.each { |r|
163
- MU::Cloud::AWS.iam.detach_role_policy(
170
+ MU::Cloud::AWS.iam(credentials: credentials).detach_role_policy(
164
171
  role_name: r.role_name,
165
172
  policy_arn: policy.arn
166
173
  )
167
174
  }
168
- MU::Cloud::AWS.iam.delete_policy(
175
+ MU::Cloud::AWS.iam(credentials: credentials).delete_policy(
169
176
  policy_arn: policy.arn
170
177
  )
171
178
  end
172
179
  }
173
180
  end
174
181
 
175
- resp = MU::Cloud::AWS.iam.list_users
182
+ resp = MU::Cloud::AWS.iam(credentials: credentials).list_users
176
183
 
177
184
  # XXX this response includes a tags attribute, but it's always empty,
178
185
  # even when the user is tagged. So we go through the extra call for
179
186
  # each user. Inefficient. Probably Amazon's bug.
180
187
  resp.users.each { |u|
181
- tags = MU::Cloud::AWS.iam.list_user_tags(
188
+ tags = MU::Cloud::AWS.iam(credentials: credentials).list_user_tags(
182
189
  user_name: u.user_name
183
190
  ).tags
184
191
  has_nodelete = false
@@ -194,43 +201,45 @@ module MU
194
201
  MU.log "Deleting IAM user #{u.path}#{u.user_name}"
195
202
  if !@noop
196
203
  begin
197
- groups = MU::Cloud::AWS.iam.list_groups_for_user(
204
+ groups = MU::Cloud::AWS.iam(credentials: credentials).list_groups_for_user(
198
205
  user_name: u.user_name
199
206
  ).groups
200
207
 
201
208
  groups.each { |g|
202
- MU::Cloud::AWS.iam.remove_user_from_group(
209
+ MU::Cloud::AWS.iam(credentials: credentials).remove_user_from_group(
203
210
  user_name: u.user_name,
204
211
  group_name: g.group_name
205
212
  )
206
213
  }
207
- profile = MU::Cloud::AWS.iam.get_login_profile(
214
+ profile = MU::Cloud::AWS.iam(credentials: credentials).get_login_profile(
208
215
  user_name: u.user_name
209
216
  )
210
217
  MU.log "Deleting IAM login profile for #{u.user_name}"
211
- MU::Cloud::AWS.iam.delete_login_profile(
218
+ MU::Cloud::AWS.iam(credentials: credentials).delete_login_profile(
212
219
  user_name: u.user_name
213
220
  )
221
+ rescue Aws::IAM::Errors::EntityTemporarilyUnmodifiable
222
+ sleep 10
223
+ retry
214
224
  rescue Aws::IAM::Errors::NoSuchEntity
215
225
  end
216
- keys = MU::Cloud::AWS.iam.list_access_keys(
226
+ keys = MU::Cloud::AWS.iam(credentials: credentials).list_access_keys(
217
227
  user_name: u.user_name
218
228
  )
219
229
  if keys.access_key_metadata.size > 0
220
230
  keys.access_key_metadata.each { |key|
221
231
  MU.log "Deleting IAM access key #{key.access_key_id} for #{u.user_name}"
222
- keys = MU::Cloud::AWS.iam.delete_access_key(
232
+ keys = MU::Cloud::AWS.iam(credentials: credentials).delete_access_key(
223
233
  user_name: u.user_name,
224
234
  access_key_id: key.access_key_id
225
235
  )
226
236
  }
227
237
  end
228
- MU::Cloud::AWS.iam.delete_user(user_name: u.user_name)
238
+ MU::Cloud::AWS.iam(credentials: credentials).delete_user(user_name: u.user_name)
229
239
  end
230
240
  end
231
241
  }
232
242
 
233
- # MU.log "CLEANUP CALLED ON AWS::USER", MU::WARN, details: resp
234
243
  end
235
244
 
236
245
  # Canonical Amazon Resource Number for this resource
@@ -244,7 +253,7 @@ module MU
244
253
  # @param region [String]: The cloud provider region.
245
254
  # @param flags [Hash]: Optional flags
246
255
  # @return [OpenStruct]: The cloud provider's complete descriptions of matching user group.
247
- def self.find(cloud_id: nil, region: MU.curRegion, flags: {})
256
+ def self.find(cloud_id: nil, region: MU.curRegion, credentials: nil, flags: {})
248
257
  found = nil
249
258
 
250
259
  begin
@@ -20,94 +20,99 @@ region="`curl -s http://169.254.169.254/latest/meta-data/placement/availability-
20
20
 
21
21
  # cleanse inherited ephemeral devices that don't actually exist
22
22
  for d in r s t u ;do
23
- if [ ! -f "/dev/xvd$d" ];then
24
- sed -Ein "s'^(/dev/xvd$d)'#\\1'" /etc/fstab
25
- fi
23
+ if [ ! -f "/dev/xvd$d" ];then
24
+ sed -Ein "s'^(/dev/xvd$d)'#\\1'" /etc/fstab
25
+ fi
26
26
  done
27
27
 
28
- if [ -f /etc/debian_version ];then
29
- if ! grep '^/bin/sh /var/lib/cloud/instance/user-data.txt$' /etc/rc.local > /dev/null;then
30
- echo "/bin/sh /var/lib/cloud/instance/user-data.txt" >> /etc/rc.local
31
- fi
32
- apt-get update -y
33
- if [ ! -f /usr/bin/pip ] ;then /usr/bin/apt-get --fix-missing -y install python-pip;fi
34
- if [ ! -f /usr/bin/curl ] ;then /usr/bin/apt-get --fix-missing -y install curl;fi
35
- AWSCLI=/usr/local/bin/aws
28
+ if ping -c 5 8.8.8.8 > /dev/null; then
29
+ if [ -f /etc/debian_version ];then
30
+ if ! grep '^/bin/sh /var/lib/cloud/instance/user-data.txt$' /etc/rc.local > /dev/null;then
31
+ echo "/bin/sh /var/lib/cloud/instance/user-data.txt" >> /etc/rc.local
32
+ fi
33
+ apt-get update -y
34
+ if [ ! -f /usr/bin/pip ] ;then /usr/bin/apt-get --fix-missing -y install python-pip;fi
35
+ if [ ! -f /usr/bin/curl ] ;then /usr/bin/apt-get --fix-missing -y install curl;fi
36
+ AWSCLI=/usr/local/bin/aws
36
37
  <% if !$mu.skipApplyUpdates %>
37
- if [ ! -f /.mu-installer-ran-updates ];then
38
- service ssh stop
39
- apt-get --fix-missing -y upgrade
40
- if [ $? -eq 0 ]
41
- then
42
- echo "Successfully updated packages"
43
- updates_run=1
44
- else
45
- echo "FAILED PACKAGE UPDATE" >&2
46
- fi
47
- # Proceed regardless
48
- touch /.mu-installer-ran-updates
49
-
50
- # XXX this logic works on Ubuntu, is it Debian-friendly?
51
- latest_kernel="`ls -1 /boot/vmlinuz-* | sed -r 's/^\/boot\/vmlinuz-//' | tail -1`"
52
- running_kernel="`uname -r`"
53
- if [ "$running_kernel" != "$latest_kernel" -a "$latest_kernel" != "" ];then
54
- need_reboot=1
55
- else
56
- service ssh start
57
- fi
58
- fi
38
+ if [ ! -f /.mu-installer-ran-updates ];then
39
+ service ssh stop
40
+ apt-get --fix-missing -y upgrade
41
+ if [ $? -eq 0 ]
42
+ then
43
+ echo "Successfully updated packages"
44
+ updates_run=1
45
+ else
46
+ echo "FAILED PACKAGE UPDATE" >&2
47
+ fi
48
+ # Proceed regardless
49
+ touch /.mu-installer-ran-updates
50
+
51
+ # XXX this logic works on Ubuntu, is it Debian-friendly?
52
+ latest_kernel="`ls -1 /boot/vmlinuz-* | sed -r 's/^\/boot\/vmlinuz-//' | tail -1`"
53
+ running_kernel="`uname -r`"
54
+ if [ "$running_kernel" != "$latest_kernel" -a "$latest_kernel" != "" ];then
55
+ need_reboot=1
56
+ else
57
+ service ssh start
58
+ fi
59
+ fi
59
60
  <% end %>
60
- elif [ -x /usr/bin/yum ];then
61
- version=`/bin/rpm -qa \*-release | grep -Ei "redhat|centos" | cut -d"-" -f3`
62
- if [ -z "$version" ];then
63
- amazon_version=`/bin/rpm -qa \*-release | grep -Ei "system-release"| cut -d"-" -f3 | cut -d"." -f1`
64
- if [ "$amazon_version" == "2014" ] || [ "$amazon_version" == "2015" ] || [ "$amazon_version" == "2016" ];then
65
- version=6
66
- fi
67
- fi
68
- if [ $version -eq 7 ];then
69
- userdata_dir="/var/lib/cloud/instances/$instance_id"
70
- else
71
- userdata_dir="/var/lib/cloud/instance"
72
- fi
73
- if ! grep "^/bin/sh $userdata_dir/user-data.txt$" /etc/rc.d/rc.local > /dev/null;then
74
- cat /etc/rc.d/rc.local | grep -v '^/bin/sh /var/lib/cloud/instances/' >> /tmp/rc.local.$$
75
- echo "/bin/sh $userdata_dir/user-data.txt" >> /tmp/rc.local.$$
76
- mv /tmp/rc.local.$$ /etc/rc.d/rc.local
77
- fi
78
-
79
- sed -i 's/^Defaults.*requiretty$/Defaults !requiretty/' /etc/sudoers
80
-
81
- if [ $version == 7 ];then
82
- chmod 755 /etc/rc.d/rc.local
83
- systemctl reset-failed sshd.service
84
- fi
85
- if [ ! -f /usr/bin/curl ] ;then /usr/bin/yum -y install curl;fi
86
- # Ugh, rando EPEL mirror
87
- if [ ! -f /etc/yum.repos.d/epel.repo ];then
88
- /bin/rpm -ivh http://mirror.metrocast.net/fedora/epel/epel-release-latest-$version.noarch.rpm
89
- fi
61
+ elif [ -x /usr/bin/yum ];then
62
+ version=`/bin/rpm -qa \*-release | grep -Ei "redhat|centos" | cut -d"-" -f3`
63
+ if [ -z "$version" ];then
64
+ amazon_version=`/bin/rpm -qa \*-release | grep -Ei "system-release"| cut -d"-" -f3 | cut -d"." -f1`
65
+ if [ "$amazon_version" == "2014" ] || [ "$amazon_version" == "2015" ] || [ "$amazon_version" == "2016" ];then
66
+ version=6
67
+ fi
68
+ fi
69
+ if [ $version -eq 7 ];then
70
+ userdata_dir="/var/lib/cloud/instances/$instance_id"
71
+ else
72
+ userdata_dir="/var/lib/cloud/instance"
73
+ fi
74
+ if ! grep "^/bin/sh $userdata_dir/user-data.txt$" /etc/rc.d/rc.local > /dev/null;then
75
+ cat /etc/rc.d/rc.local | grep -v '^/bin/sh /var/lib/cloud/instances/' >> /tmp/rc.local.$$
76
+ echo "/bin/sh $userdata_dir/user-data.txt" >> /tmp/rc.local.$$
77
+ mv /tmp/rc.local.$$ /etc/rc.d/rc.local
78
+ fi
79
+
80
+ sed -i 's/^Defaults.*requiretty$/Defaults !requiretty/' /etc/sudoers
81
+
82
+ if [ $version == 7 ];then
83
+ chmod 755 /etc/rc.d/rc.local
84
+ systemctl reset-failed sshd.service
85
+ fi
86
+ if [ ! -f /usr/bin/curl ] ;then /usr/bin/yum -y install curl;fi
87
+ # Ugh, rando EPEL mirror
88
+ if [ ! -f /etc/yum.repos.d/epel.repo ];then
89
+ /bin/rpm -ivh http://mirror.metrocast.net/fedora/epel/epel-release-latest-$version.noarch.rpm
90
+ fi
90
91
  <% if !$mu.skipApplyUpdates %>
91
- if [ ! -f /.mu-installer-ran-updates ];then
92
- service sshd stop
93
- kernel_update=`yum list updates | grep kernel`
94
- yum -y update
95
- if [ $? -eq 0 ]
96
- then
97
- echo "Successfully updated packages"
98
- updates_run=1
99
- else
100
- echo "FAILED PACKAGE UPDATE" >&2
101
- fi
102
- # Proceed regardless
103
- touch /.mu-installer-ran-updates
104
- if [ -n "$kernel_update" ]; then
105
- need_reboot=1
106
- else
107
- service sshd start
108
- fi
109
- fi
92
+ if [ ! -f /.mu-installer-ran-updates ];then
93
+ service sshd stop
94
+ kernel_update=`yum list updates | grep kernel`
95
+ yum -y update
96
+ if [ $? -eq 0 ]
97
+ then
98
+ echo "Successfully updated packages"
99
+ updates_run=1
100
+ else
101
+ echo "FAILED PACKAGE UPDATE" >&2
102
+ fi
103
+ # Proceed regardless
104
+ touch /.mu-installer-ran-updates
105
+ if [ -n "$kernel_update" ]; then
106
+ need_reboot=1
107
+ else
108
+ service sshd start
109
+ fi
110
+ fi
111
+ fi
110
112
  <% end %>
113
+ else
114
+ /bin/logger "***** Unable to verify internet connectivity, skipping package updates from userdata"
115
+ touch /.mu-installer-ran-updates
111
116
  fi
112
117
 
113
118
  AWSCLI='command -v aws'
@@ -140,24 +145,27 @@ umask 0077
140
145
 
141
146
  # Install Chef now, because why not?
142
147
  if [ ! -f /opt/chef/embedded/bin/ruby ];then
143
- curl https://www.chef.io/chef/install.sh > chef-install.sh
144
- set +e
145
- # We may run afoul of a synchronous bootstrap process doing the same thing. So
146
- # wait until we've managed to run successfully.
147
- while ! sh chef-install.sh -v <%= MU.chefVersion %>;do
148
- sleep 10
149
- done
150
- touch /opt/mu_installed_chef
151
- set -e
148
+ curl https://www.chef.io/chef/install.sh > chef-install.sh
149
+ set +e
150
+ # We may run afoul of a synchronous bootstrap process doing the same thing. So
151
+ # wait until we've managed to run successfully.
152
+ while ! sh chef-install.sh -v <%= MU.chefVersion %>;do
153
+ sleep 10
154
+ done
155
+ touch /opt/mu_installed_chef
156
+ set -e
152
157
  fi
153
158
 
154
159
  <% if !$mu.skipApplyUpdates %>
155
160
  if [ "$need_reboot" == "1" ];then
156
- shutdown -r now "Applying new kernel"
161
+ shutdown -r now "Applying new kernel"
157
162
  fi
158
163
  <% end %>
164
+ fi
159
165
 
160
- $AWSCLI --region="$region" s3 cp s3://<%= MU.adminBucketName %>/<%= $mu.muID %>-secret .
166
+ if [ "$AWSCLI" != "" ];then
167
+ $AWSCLI --region="$region" s3 cp s3://<%= MU.adminBucketName %>/<%= $mu.muID %>-secret .
168
+ fi
161
169
 
162
170
  echo '
163
171
  require "openssl"
@@ -46,21 +46,21 @@ module MU
46
46
  # Called automatically by {MU::Deploy#createResources}
47
47
  def create
48
48
  MU.log "Creating VPC #{@mu_name}", details: @config
49
- resp = MU::Cloud::AWS.ec2(@config['region']).create_vpc(cidr_block: @config['ip_block']).vpc
49
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_vpc(cidr_block: @config['ip_block']).vpc
50
50
  vpc_id = @config['vpc_id'] = resp.vpc_id
51
51
 
52
- MU::MommaCat.createStandardTags(vpc_id, region: @config['region'])
53
- MU::MommaCat.createTag(vpc_id, "Name", @mu_name, region: @config['region'])
52
+ MU::MommaCat.createStandardTags(vpc_id, region: @config['region'], credentials: @config['credentials'])
53
+ MU::MommaCat.createTag(vpc_id, "Name", @mu_name, region: @config['region'], credentials: @config['credentials'])
54
54
 
55
55
  if @config['tags']
56
56
  @config['tags'].each { |tag|
57
- MU::MommaCat.createTag(vpc_id, tag['key'], tag['value'], region: @config['region'])
57
+ MU::MommaCat.createTag(vpc_id, tag['key'], tag['value'], region: @config['region'], credentials: @config['credentials'])
58
58
  }
59
59
  end
60
60
 
61
61
  if @config['optional_tags']
62
62
  MU::MommaCat.listOptionalTags.each { |key, value|
63
- MU::MommaCat.createTag(vpc_id, key, value, region: @config['region'])
63
+ MU::MommaCat.createTag(vpc_id, key, value, region: @config['region'], credentials: @config['credentials'])
64
64
  }
65
65
  end
66
66
 
@@ -68,10 +68,10 @@ module MU
68
68
  begin
69
69
  MU.log "Waiting for VPC #{@mu_name} (#{vpc_id}) to be available", MU::NOTICE
70
70
  sleep 5
71
- resp = MU::Cloud::AWS.ec2(@config['region']).describe_vpcs(vpc_ids: [vpc_id]).vpcs.first
71
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_vpcs(vpc_ids: [vpc_id]).vpcs.first
72
72
  end while resp.state != "available"
73
73
  # There's a default route table that comes with. Let's tag it.
74
- resp = MU::Cloud::AWS.ec2(@config['region']).describe_route_tables(
74
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_route_tables(
75
75
  filters: [
76
76
  {
77
77
  name: "vpc-id",
@@ -80,18 +80,18 @@ module MU
80
80
  ]
81
81
  )
82
82
  resp.route_tables.each { |rtb|
83
- MU::MommaCat.createTag(rtb.route_table_id, "Name", @mu_name+"-#DEFAULTPRIV", region: @config['region'])
83
+ MU::MommaCat.createTag(rtb.route_table_id, "Name", @mu_name+"-#DEFAULTPRIV", region: @config['region'], credentials: @config['credentials'])
84
84
  if @config['tags']
85
85
  @config['tags'].each { |tag|
86
- MU::MommaCat.createTag(rtb.route_table_id, tag['key'], tag['value'], region: @config['region'])
86
+ MU::MommaCat.createTag(rtb.route_table_id, tag['key'], tag['value'], region: @config['region'], credentials: @config['credentials'])
87
87
  }
88
88
  end
89
89
 
90
- MU::MommaCat.createStandardTags(rtb.route_table_id, region: @config['region'])
90
+ MU::MommaCat.createStandardTags(rtb.route_table_id, region: @config['region'], credentials: @config['credentials'])
91
91
 
92
92
  if @config['optional_tags']
93
93
  MU::MommaCat.listOptionalTags.each { |key, value|
94
- MU::MommaCat.createTag(rtb.route_table_id, key, value, region: @config['region'])
94
+ MU::MommaCat.createTag(rtb.route_table_id, key, value, region: @config['region'], credentials: @config['credentials'])
95
95
  }
96
96
  end
97
97
  }
@@ -101,24 +101,24 @@ module MU
101
101
 
102
102
  if @config['create_internet_gateway']
103
103
  MU.log "Creating Internet Gateway #{@mu_name}"
104
- resp = MU::Cloud::AWS.ec2(@config['region']).create_internet_gateway
104
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_internet_gateway
105
105
  internet_gateway_id = resp.internet_gateway.internet_gateway_id
106
106
  sleep 5
107
- MU::MommaCat.createStandardTags(internet_gateway_id, region: @config['region'])
108
- MU::MommaCat.createTag(internet_gateway_id, "Name", @mu_name, region: @config['region'])
107
+ MU::MommaCat.createStandardTags(internet_gateway_id, region: @config['region'], credentials: @config['credentials'])
108
+ MU::MommaCat.createTag(internet_gateway_id, "Name", @mu_name, region: @config['region'], credentials: @config['credentials'])
109
109
  if @config['tags']
110
110
  @config['tags'].each { |tag|
111
- MU::MommaCat.createTag(internet_gateway_id, tag['key'], tag['value'], region: @config['region'])
111
+ MU::MommaCat.createTag(internet_gateway_id, tag['key'], tag['value'], region: @config['region'], credentials: @config['credentials'])
112
112
  }
113
113
  end
114
114
 
115
115
  if @config['optional_tags']
116
116
  MU::MommaCat.listOptionalTags.each { |key, value|
117
- MU::MommaCat.createTag(internet_gateway_id, key, value, region: @config['region'])
117
+ MU::MommaCat.createTag(internet_gateway_id, key, value, region: @config['region'], credentials: @config['credentials'])
118
118
  }
119
119
  end
120
120
 
121
- MU::Cloud::AWS.ec2(@config['region']).attach_internet_gateway(vpc_id: vpc_id, internet_gateway_id: internet_gateway_id)
121
+ MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).attach_internet_gateway(vpc_id: vpc_id, internet_gateway_id: internet_gateway_id)
122
122
  @config['internet_gateway_id'] = internet_gateway_id
123
123
  end
124
124
 
@@ -142,7 +142,7 @@ module MU
142
142
  config[:policy_document] = statement.to_json
143
143
  end
144
144
 
145
- resp = MU::Cloud::AWS.ec2(@config['region']).create_vpc_endpoint(config).vpc_endpoint
145
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_vpc_endpoint(config).vpc_endpoint
146
146
  endpoint_id = resp.vpc_endpoint_id
147
147
  MU.log "Creating VPC endpoint #{endpoint_id}"
148
148
  attempts = 0
@@ -151,7 +151,7 @@ module MU
151
151
  MU.log "Waiting for VPC endpoint #{endpoint_id} to become available" if attempts % 5 == 0
152
152
  sleep 10
153
153
  begin
154
- resp = MU::Cloud::AWS.ec2(@config['region']).describe_vpc_endpoints(vpc_endpoint_ids: [endpoint_id]).vpc_endpoints.first
154
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_vpc_endpoints(vpc_endpoint_ids: [endpoint_id]).vpc_endpoints.first
155
155
  rescue Aws::EmptyStructure, NoMethodError
156
156
  sleep 5
157
157
  retry
@@ -168,7 +168,7 @@ module MU
168
168
  logrole = @deploy.findLitterMate(name: @config['name']+"logrole", type: "roles")
169
169
 
170
170
  MU.log "Enabling traffic logging on VPC #{@mu_name} to log group #{loggroup.mu_name}"
171
- MU::Cloud::AWS.ec2(@config['region']).create_flow_logs(
171
+ MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_flow_logs(
172
172
  resource_ids: [@cloud_id],
173
173
  resource_type: "VPC",
174
174
  traffic_type: "ALL",
@@ -187,7 +187,7 @@ module MU
187
187
  @config['subnets'].each { |subnet|
188
188
  subnet_name = @config['name']+"-"+subnet['name']
189
189
  MU.log "Creating Subnet #{subnet_name} (#{subnet['ip_block']})", details: subnet
190
- azs = MU::Cloud::AWS.listAZs if azs.size == 0
190
+ azs = MU::Cloud::AWS.listAZs(region: @config['region'], credentials: @config['credentials']) if azs.size == 0
191
191
  if !subnet['availability_zone'].nil?
192
192
  az = subnet['availability_zone']
193
193
  else
@@ -196,23 +196,23 @@ module MU
196
196
 
197
197
  subnetthreads << Thread.new {
198
198
  MU.dupGlobals(parent_thread_id)
199
- resp = MU::Cloud::AWS.ec2(@config['region']).create_subnet(
199
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_subnet(
200
200
  vpc_id: vpc_id,
201
201
  cidr_block: subnet['ip_block'],
202
202
  availability_zone: az
203
203
  ).subnet
204
204
  subnet_id = subnet['subnet_id'] = resp.subnet_id
205
- MU::MommaCat.createStandardTags(subnet_id, region: @config['region'])
206
- MU::MommaCat.createTag(subnet_id, "Name", @mu_name+"-"+subnet['name'], region: @config['region'])
205
+ MU::MommaCat.createStandardTags(subnet_id, region: @config['region'], credentials: @config['credentials'])
206
+ MU::MommaCat.createTag(subnet_id, "Name", @mu_name+"-"+subnet['name'], region: @config['region'], credentials: @config['credentials'])
207
207
  if @config['tags']
208
208
  @config['tags'].each { |tag|
209
- MU::MommaCat.createTag(subnet_id, tag['key'], tag['value'], region: @config['region'])
209
+ MU::MommaCat.createTag(subnet_id, tag['key'], tag['value'], region: @config['region'], credentials: @config['credentials'])
210
210
  }
211
211
  end
212
212
 
213
213
  if @config['optional_tags']
214
214
  MU::MommaCat.listOptionalTags.each { |key, value|
215
- MU::MommaCat.createTag(subnet_id, key, value, region: @config['region'])
215
+ MU::MommaCat.createTag(subnet_id, key, value, region: @config['region'], credentials: @config['credentials'])
216
216
  }
217
217
  end
218
218
 
@@ -222,7 +222,7 @@ module MU
222
222
  begin
223
223
  MU.log "Waiting for Subnet #{subnet_name} (#{subnet_id}) to be available", MU::NOTICE
224
224
  sleep 5
225
- resp = MU::Cloud::AWS.ec2(@config['region']).describe_subnets(subnet_ids: [subnet_id]).subnets.first
225
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_subnets(subnet_ids: [subnet_id]).subnets.first
226
226
  rescue Aws::EC2::Errors::InvalidSubnetIDNotFound => e
227
227
  sleep 10
228
228
  retry
@@ -233,7 +233,7 @@ module MU
233
233
  MU.log "Got bogus Aws::EmptyResponse error on #{subnet_id} (retries used: #{retries}/3)", MU::WARN
234
234
  retries = retries + 1
235
235
  sleep 5
236
- resp = MU::Cloud::AWS.ec2(@config['region']).describe_subnets(subnet_ids: [subnet_id]).subnets.first
236
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_subnets(subnet_ids: [subnet_id]).subnets.first
237
237
  retry
238
238
  else
239
239
  raise e
@@ -252,7 +252,7 @@ module MU
252
252
  MU.log "Associating Route Table '#{subnet['route_table']}' (#{routes[subnet['route_table']]['route_table_id']}) with #{subnet_name}"
253
253
  retries = 0
254
254
  begin
255
- MU::Cloud::AWS.ec2(@config['region']).associate_route_table(
255
+ MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).associate_route_table(
256
256
  route_table_id: routes[subnet['route_table']]['route_table_id'],
257
257
  subnet_id: subnet_id
258
258
  )
@@ -268,7 +268,7 @@ module MU
268
268
  end
269
269
  retries = 0
270
270
  begin
271
- resp = MU::Cloud::AWS.ec2(@config['region']).describe_subnets(subnet_ids: [subnet_id]).subnets.first
271
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_subnets(subnet_ids: [subnet_id]).subnets.first
272
272
  rescue Aws::EC2::Errors::InvalidSubnetIDNotFound => e
273
273
  if retries < 10
274
274
  MU.log "Got #{e.inspect}, waiting and retrying", MU::WARN
@@ -282,7 +282,7 @@ module MU
282
282
  if subnet['is_public'] && subnet['create_nat_gateway']
283
283
  MU::MommaCat.lock("nat-gateway-eipalloc")
284
284
  filters = [{name: "domain", values: ["vpc"]}]
285
- eips = MU::Cloud::AWS.ec2(@config['region']).describe_addresses(filters: filters).addresses
285
+ eips = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_addresses(filters: filters).addresses
286
286
  allocation_id = nil
287
287
  eips.each { |eip|
288
288
  next if !eip.association_id.nil? and !eip.association_id.empty?
@@ -295,12 +295,12 @@ module MU
295
295
  }
296
296
 
297
297
  if allocation_id.nil?
298
- allocation_id = MU::Cloud::AWS.ec2(@config['region']).allocate_address(domain: "vpc").allocation_id
298
+ allocation_id = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).allocate_address(domain: "vpc").allocation_id
299
299
  MU::MommaCat.lock(allocation_id, false, true)
300
300
  end
301
301
 
302
302
  allocation_ids << allocation_id
303
- resp = MU::Cloud::AWS.ec2(@config['region']).create_nat_gateway(
303
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_nat_gateway(
304
304
  subnet_id: subnet['subnet_id'],
305
305
  allocation_id: allocation_id
306
306
  ).nat_gateway
@@ -312,7 +312,7 @@ module MU
312
312
  MU.log "Waiting for nat gateway #{nat_gateway_id} () to become available (EIP allocation: #{allocation_id})" if attempts % 5 == 0
313
313
  sleep 30
314
314
  begin
315
- resp = MU::Cloud::AWS.ec2(@config['region']).describe_nat_gateways(nat_gateway_ids: [nat_gateway_id]).nat_gateways.first
315
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_nat_gateways(nat_gateway_ids: [nat_gateway_id]).nat_gateways.first
316
316
  rescue Aws::EmptyStructure, NoMethodError
317
317
  sleep 5
318
318
  retry
@@ -332,7 +332,7 @@ module MU
332
332
  if subnet.has_key?("map_public_ips")
333
333
  retries = 0
334
334
  begin
335
- resp = MU::Cloud::AWS.ec2(@config['region']).modify_subnet_attribute(
335
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).modify_subnet_attribute(
336
336
  subnet_id: subnet_id,
337
337
  map_public_ip_on_launch: {
338
338
  value: subnet['map_public_ips'],
@@ -353,7 +353,7 @@ module MU
353
353
  loggroup = @deploy.findLitterMate(name: @config['name']+"loggroup", type: "logs")
354
354
  logrole = @deploy.findLitterMate(name: @config['name']+"logrole", type: "roles")
355
355
  MU.log "Enabling traffic logging on Subnet #{subnet_name} in VPC #{@mu_name} to log group #{loggroup.mu_name}"
356
- MU::Cloud::AWS.ec2(@config['region']).create_flow_logs(
356
+ MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_flow_logs(
357
357
  resource_ids: [subnet_id],
358
358
  resource_type: "Subnet",
359
359
  traffic_type: subnet["traffic_type_to_log"],
@@ -387,7 +387,7 @@ module MU
387
387
 
388
388
  MU.log "Creating route for #{route['destination_network']} through NAT gatway #{gateway['id']}", details: route_config
389
389
  begin
390
- resp = MU::Cloud::AWS.ec2(@config['region']).create_route(route_config)
390
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_route(route_config)
391
391
  rescue Aws::EC2::Errors::RouteAlreadyExists => e
392
392
  MU.log "Attempt to create duplicate route to #{route['destination_network']} for #{gateway['id']} in #{rtb['route_table_id']}", MU::WARN
393
393
  end
@@ -402,14 +402,14 @@ module MU
402
402
 
403
403
  if @config['enable_dns_support']
404
404
  MU.log "Enabling DNS support in #{@mu_name}"
405
- MU::Cloud::AWS.ec2(@config['region']).modify_vpc_attribute(
405
+ MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).modify_vpc_attribute(
406
406
  vpc_id: vpc_id,
407
407
  enable_dns_support: {value: @config['enable_dns_support']}
408
408
  )
409
409
  end
410
410
  if @config['enable_dns_hostnames']
411
411
  MU.log "Enabling DNS hostnames in #{@mu_name}"
412
- MU::Cloud::AWS.ec2(@config['region']).modify_vpc_attribute(
412
+ MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).modify_vpc_attribute(
413
413
  vpc_id: vpc_id,
414
414
  enable_dns_hostnames: {value: @config['enable_dns_hostnames']}
415
415
  )
@@ -435,33 +435,33 @@ module MU
435
435
  dhcpopts << {key: "netbios-name-servers", values: @config['dhcp']['netbios_servers']}
436
436
  end
437
437
 
438
- resp = MU::Cloud::AWS.ec2(@config['region']).create_dhcp_options(
438
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_dhcp_options(
439
439
  dhcp_configurations: dhcpopts
440
440
  )
441
441
  dhcpopt_id = resp.dhcp_options.dhcp_options_id
442
- MU::MommaCat.createStandardTags(dhcpopt_id, region: @config['region'])
443
- MU::MommaCat.createTag(dhcpopt_id, "Name", @mu_name, region: @config['region'])
442
+ MU::MommaCat.createStandardTags(dhcpopt_id, region: @config['region'], credentials: @config['credentials'])
443
+ MU::MommaCat.createTag(dhcpopt_id, "Name", @mu_name, region: @config['region'], credentials: @config['credentials'])
444
444
 
445
445
  if @config['tags']
446
446
  @config['tags'].each { |tag|
447
- MU::MommaCat.createTag(dhcpopt_id, tag['key'], tag['value'], region: @config['region'])
447
+ MU::MommaCat.createTag(dhcpopt_id, tag['key'], tag['value'], region: @config['region'], credentials: @config['credentials'])
448
448
  }
449
449
  end
450
450
 
451
451
  if @config['optional_tags']
452
452
  MU::MommaCat.listOptionalTags.each { |key, value|
453
- MU::MommaCat.createTag(dhcpopt_id, key, value, region: @config['region'])
453
+ MU::MommaCat.createTag(dhcpopt_id, key, value, region: @config['region'], credentials: @config['credentials'])
454
454
  }
455
455
  end
456
456
 
457
- MU::Cloud::AWS.ec2(@config['region']).associate_dhcp_options(dhcp_options_id: dhcpopt_id, vpc_id: vpc_id)
457
+ MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).associate_dhcp_options(dhcp_options_id: dhcpopt_id, vpc_id: vpc_id)
458
458
  end
459
459
  notify
460
460
 
461
461
  if !MU::Cloud::AWS.isGovCloud?(@config['region'])
462
- mu_zone = MU::Cloud::DNSZone.find(cloud_id: "platform-mu").values.first
462
+ mu_zone = MU::Cloud::DNSZone.find(cloud_id: "platform-mu", credentials: @config['credentials']).values.first
463
463
  if !mu_zone.nil?
464
- MU::Cloud::AWS::DNSZone.toggleVPCAccess(id: mu_zone.id, vpc_id: vpc_id, region: @config['region'])
464
+ MU::Cloud::AWS::DNSZone.toggleVPCAccess(id: mu_zone.id, vpc_id: vpc_id, region: @config['region'], credentials: @config['credentials'])
465
465
  end
466
466
  end
467
467
  loadSubnets
@@ -472,7 +472,7 @@ module MU
472
472
  # Canonical Amazon Resource Number for this resource
473
473
  # @return [String]
474
474
  def arn
475
- "arn:"+(MU::Cloud::AWS.isGovCloud?(@config["region"]) ? "aws-us-gov" : "aws")+":ec2:"+@config['region']+":"+MU.account_number+":vpc/"+@cloud_id
475
+ "arn:"+(MU::Cloud::AWS.isGovCloud?(@config["region"]) ? "aws-us-gov" : "aws")+":ec2:"+@config['region']+":"+MU::Cloud::AWS.credToAcct(@config['credentials'])+":vpc/"+@cloud_id
476
476
  end
477
477
 
478
478
  # Describe this VPC
@@ -489,73 +489,99 @@ module MU
489
489
  if !@config['peers'].nil? and @config['peers'].size > 0
490
490
  @config['peers'].each { |peer|
491
491
  peer_obj = nil
492
+ peer_id = nil
493
+
492
494
  begin
493
- if peer['account'].nil? or peer['account'] == MU.account_number
495
+ # If we know this to be a sibling VPC elsewhere in our stack,
496
+ # go fetch it, and fix it if we've been misconfigured with a
497
+ # duplicate peering connection
498
+ if peer['vpc']['vpc_name'] and !peer['account']
499
+ peer_obj = @deploy.findLitterMate(name: peer['vpc']['vpc_name'], type: "vpcs")
500
+ if peer_obj
501
+ if peer_obj.config['peers']
502
+ skipme = false
503
+ peer_obj.config['peers'].each { |peerpeer|
504
+ if peerpeer['vpc']['vpc_name'] == @config['name'] and
505
+ (peer['vpc']['vpc_name'] <=> @config['name']) == -1
506
+ skipme = true
507
+ MU.log "VPCs #{peer['vpc']['vpc_name']} and #{@config['name']} both declare mutual peering connection, ignoring #{@config['name']}'s redundant declaration", MU::DEBUG
508
+ # XXX and if deploy_id matches or is unset
509
+ end
510
+ }
511
+ end
512
+ next if skipme
513
+ peer['account'] = MU::Cloud::AWS.credToAcct(peer_obj.credentials)
514
+ peer['vpc']['vpc_id'] = peer_obj.cloud_id
515
+ end
516
+ end
517
+
518
+ # If we still don't know our peer's vpc identifier, go fishing
519
+ if !peer_obj
494
520
  tag_key, tag_value = peer['vpc']['tag'].split(/=/, 2) if !peer['vpc']['tag'].nil?
495
521
  if peer['vpc']['deploy_id'].nil? and peer['vpc']['vpc_id'].nil? and tag_key.nil?
496
522
  peer['vpc']['deploy_id'] = @deploy.deploy_id
497
523
  end
498
524
  peer_obj = MU::MommaCat.findStray(
499
- "AWS",
500
- "vpcs",
501
- deploy_id: peer['vpc']['deploy_id'],
502
- cloud_id: peer['vpc']['vpc_id'],
503
- name: peer['vpc']['vpc_name'],
504
- tag_key: tag_key,
505
- tag_value: tag_value,
506
- dummy_ok: true,
507
- region: peer['vpc']['region']
525
+ "AWS",
526
+ "vpcs",
527
+ deploy_id: peer['vpc']['deploy_id'],
528
+ cloud_id: peer['vpc']['vpc_id'],
529
+ # XXX we need a credentials argument here... maybe
530
+ name: peer['vpc']['vpc_name'],
531
+ tag_key: tag_key,
532
+ tag_value: tag_value,
533
+ dummy_ok: true,
534
+ region: peer['vpc']['region']
508
535
  )
509
536
  raise MuError, "No result looking for #{@mu_name}'s peer VPCs (#{peer['vpc']})" if peer_obj.nil? or peer_obj.first.nil?
510
537
  peer_obj = peer_obj.first
511
- peer_id = peer_obj.cloud_id
512
-
513
- MU.log "Setting peering connection from VPC #{@config['name']} (#{@cloud_id}) to #{peer_id}"
514
- resp = MU::Cloud::AWS.ec2(@config['region']).create_vpc_peering_connection(
515
- vpc_id: @cloud_id,
516
- peer_vpc_id: peer_id
517
- )
518
- else
519
- peer_id = peer['vpc']['vpc_id']
520
- MU.log "Setting peering connection from VPC #{@config['name']} (#{@cloud_id}) to #{peer_id} in account #{peer['account']}", MU::INFO, details: peer
521
- resp = MU::Cloud::AWS.ec2(@config['region']).create_vpc_peering_connection(
522
- vpc_id: @cloud_id,
523
- peer_vpc_id: peer_id,
524
- peer_owner_id: peer['account']
525
- )
538
+ peer['account'] ||= MU::Cloud::AWS.credToAcct(peer_obj.credentials)
539
+ peer['vpc']['vpc_id'] ||= peer_obj.cloud_id
526
540
  end
541
+
542
+ peer_id = peer['vpc']['vpc_id']
543
+ peer['account'] ||= MU::Cloud::AWS.account_number
544
+
545
+ MU.log "Setting peering connection from VPC #{@config['name']} (#{@cloud_id} in account #{MU::Cloud::AWS.credToAcct(@config['credentials'])}) to #{peer_id} in account #{peer['account']}", MU::INFO, details: peer
546
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_vpc_peering_connection(
547
+ vpc_id: @cloud_id,
548
+ peer_vpc_id: peer_id,
549
+ peer_owner_id: peer['account']
550
+ )
551
+
527
552
  rescue Aws::EC2::Errors::VpcPeeringConnectionAlreadyExists => e
528
553
  MU.log "Attempt to create duplicate peering connection to #{peer_id} from VPC #{@config['name']}", MU::WARN
529
554
  end
530
- peering_name = @deploy.getResourceName(@config['name']+"-PEER-"+peer_id)
555
+ peering_name = @deploy.getResourceName(@config['name']+"-PEER-"+peer['vpc']['vpc_id'])
531
556
 
532
557
  peering_id = resp.vpc_peering_connection.vpc_peering_connection_id
533
- MU::MommaCat.createStandardTags(peering_id, region: @config['region'])
534
- MU::MommaCat.createTag(peering_id, "Name", peering_name, region: @config['region'])
558
+ MU::MommaCat.createStandardTags(peering_id, region: @config['region'], credentials: @config['credentials'])
559
+ MU::MommaCat.createTag(peering_id, "Name", peering_name, region: @config['region'], credentials: @config['credentials'])
535
560
 
536
561
  if @config['optional_tags']
537
562
  MU::MommaCat.listOptionalTags.each { |key, value|
538
- MU::MommaCat.createTag(peering_id, key, value, region: @config['region'])
563
+ MU::MommaCat.createTag(peering_id, key, value, region: @config['region'], credentials: @config['credentials'])
539
564
  }
540
565
  end
541
566
 
542
567
  if @config['tags']
543
568
  @config['tags'].each { |tag|
544
- MU::MommaCat.createTag(peering_id, tag['key'], tag['value'], region: @config['region'])
569
+ MU::MommaCat.createTag(peering_id, tag['key'], tag['value'], region: @config['region'], credentials: @config['credentials'])
545
570
  }
546
571
  end
547
572
 
548
573
  # Create routes to our new friend.
549
- MU::Cloud::AWS::VPC.listAllSubnetRouteTables(@cloud_id, region: @config['region']).each { |rtb_id|
574
+ MU::Cloud::AWS::VPC.listAllSubnetRouteTables(@cloud_id, region: @config['region'], credentials: @config['credentials']).each { |rtb_id|
550
575
  my_route_config = {
551
576
  :route_table_id => rtb_id,
552
577
  :destination_cidr_block => peer_obj.cloud_desc.cidr_block,
553
578
  :vpc_peering_connection_id => peering_id
554
579
  }
555
580
  begin
556
- resp = MU::Cloud::AWS.ec2(@config['region']).create_route(my_route_config)
581
+ MU.log "Creating peering route to #{peer_obj.cloud_desc.cidr_block} from VPC #{@config['name']}"
582
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_route(my_route_config)
557
583
  rescue Aws::EC2::Errors::RouteAlreadyExists => e
558
- rtbdesc = MU::Cloud::AWS.ec2(@config['region']).describe_route_tables(
584
+ rtbdesc = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_route_tables(
559
585
  route_table_ids: [rtb_id]
560
586
  ).route_tables.first
561
587
  rtbdesc.routes.each { |r|
@@ -569,35 +595,51 @@ module MU
569
595
  end
570
596
  }
571
597
  end
572
- }
598
+ } # MU::Cloud::AWS::VPC.listAllSubnetRouteTables
573
599
 
574
600
  begin
575
- cnxn = MU::Cloud::AWS.ec2(@config['region']).describe_vpc_peering_connections(
576
- vpc_peering_connection_ids: [peering_id]
601
+ cnxn = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_vpc_peering_connections(
602
+ vpc_peering_connection_ids: [peering_id]
577
603
  ).vpc_peering_connections.first
578
604
 
579
605
  if cnxn.status.code == "pending-acceptance"
580
606
  if ((!peer_obj.nil? and !peer_obj.deploydata.nil? and peer_obj.deploydata['auto_accept_peers']) or $MU_CFG['allow_invade_foreign_vpcs'])
581
607
  MU.log "Auto-accepting peering connection from VPC #{@config['name']} (#{@cloud_id}) to #{peer_id}", MU::NOTICE
582
608
  begin
583
- MU::Cloud::AWS.ec2(@config['region']).accept_vpc_peering_connection(
584
- vpc_peering_connection_id: peering_id
609
+ MU::Cloud::AWS.ec2(region: @config['region'], credentials: peer['account']).accept_vpc_peering_connection(
610
+ vpc_peering_connection_id: peering_id
585
611
  )
612
+ if peer['account'] != MU::Cloud::AWS.credToAcct(@config['credentials'])
613
+ # this seems to take a while across accounts
614
+ sleep 5
615
+ end
616
+ cnxn = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_vpc_peering_connections(
617
+ vpc_peering_connection_ids: [peering_id]
618
+ ).vpc_peering_connections.first
586
619
  rescue Aws::EC2::Errors::VpcPeeringConnectionAlreadyExists => e
587
620
  MU.log "Attempt to create duplicate peering connection to #{peer_id} from VPC #{@config['name']}", MU::WARN
588
621
  end
589
622
 
590
623
  # Create routes back from our new friend to us.
591
- MU::Cloud::AWS::VPC.listAllSubnetRouteTables(peer_id, region: peer['vpc']['region']).each { |rtb_id|
624
+ MU::Cloud::AWS::VPC.listAllSubnetRouteTables(peer_id, region: peer['vpc']['region'], credentials: peer['account']).uniq.each { |rtb_id|
592
625
  peer_route_config = {
593
- :route_table_id => rtb_id,
594
- :destination_cidr_block => @config['ip_block'],
595
- :vpc_peering_connection_id => peering_id
626
+ :route_table_id => rtb_id,
627
+ :destination_cidr_block => @config['ip_block'],
628
+ :vpc_peering_connection_id => peering_id
596
629
  }
597
630
  begin
598
- resp = MU::Cloud::AWS.ec2(@config['region']).create_route(peer_route_config)
631
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: peer['account']).create_route(peer_route_config)
599
632
  rescue Aws::EC2::Errors::RouteAlreadyExists => e
600
- MU.log "Attempt to create duplicate route to #{@config['ip_block']} from VPC #{peer_id}", MU::WARN
633
+ rtbdesc = MU::Cloud::AWS.ec2(region: @config['region'], credentials: peer['account']).describe_route_tables(
634
+ route_table_ids: [rtb_id]
635
+ ).route_tables.first
636
+ rtbdesc.routes.each { |r|
637
+ if r.destination_cidr_block == @config['ip_block']
638
+ if r.vpc_peering_connection_id != peering_id
639
+ MU.log "Attempt to create duplicate route to VPC #{@config['name']} (#{@config['ip_block']}) from peer VPC #{peer_id}'s route table #{rtb_id}", MU::ERR
640
+ end
641
+ end
642
+ }
601
643
  end
602
644
  }
603
645
  else
@@ -608,15 +650,16 @@ module MU
608
650
  if cnxn.status.code == "failed" or cnxn.status.code == "rejected" or cnxn.status.code == "expired" or cnxn.status.code == "deleted"
609
651
  MU.log "VPC peering connection from VPC #{@config['name']} (#{@cloud_id}) to #{peer_id} #{cnxn.status.code}: #{cnxn.status.message}", MU::ERR
610
652
  begin
611
- MU::Cloud::AWS.ec2(@config['region']).delete_vpc_peering_connection(
612
- vpc_peering_connection_id: peering_id
653
+ MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).delete_vpc_peering_connection(
654
+ vpc_peering_connection_id: peering_id
613
655
  )
614
656
  rescue Aws::EC2::Errors::InvalidStateTransition => e
615
657
  # XXX apparently this is normal?
616
658
  end
617
659
  raise MuError, "VPC peering connection from VPC #{@config['name']} (#{@cloud_id}) to #{peer_id} #{cnxn.status.code}: #{cnxn.status.message}"
618
660
  end
619
- end while cnxn.status.code != "active" and !(cnxn.status.code == "pending-acceptance" and (peer_obj.nil? or peer_obj.deploydata.nil? or !peer_obj.deploydata['auto_accept_peers']))
661
+
662
+ end while cnxn.status.code != "active" and !((peer_obj.nil? or peer_obj.deploydata.nil? or !peer_obj.deploydata['auto_accept_peers']) and cnxn.status.code == "pending-acceptance")
620
663
 
621
664
  }
622
665
  end
@@ -644,7 +687,7 @@ module MU
644
687
  route_config[:instance_id] = nat_instance.cloud_id
645
688
 
646
689
  MU.log "Creating route for #{route['destination_network']} through NAT host #{nat_instance.cloud_id}", details: route_config
647
- resp = MU::Cloud::AWS.ec2(@config['region']).create_route(route_config)
690
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_route(route_config)
648
691
  end
649
692
  }
650
693
 
@@ -659,7 +702,7 @@ module MU
659
702
  # @param tag_key [String]: A tag key to search.
660
703
  # @param tag_value [String]: The value of the tag specified by tag_key to match when searching by tag.
661
704
  # @return [Array<Hash<String,OpenStruct>>]: The cloud provider's complete descriptions of matching VPCs
662
- def self.find(cloud_id: nil, region: MU.curRegion, tag_key: "Name", tag_value: nil, flags: {})
705
+ def self.find(cloud_id: nil, region: MU.curRegion, tag_key: "Name", tag_value: nil, credentials: nil, flags: {})
663
706
 
664
707
  retries = 0
665
708
  map = {}
@@ -668,7 +711,7 @@ module MU
668
711
 
669
712
  if tag_value
670
713
  MU.log "Searching for VPC by tag:#{tag_key}=#{tag_value}", MU::DEBUG
671
- resp = MU::Cloud::AWS.ec2(region).describe_vpcs(
714
+ resp = MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_vpcs(
672
715
  filters: [
673
716
  {name: "tag:#{tag_key}", values: [tag_value]}
674
717
  ]
@@ -686,7 +729,7 @@ module MU
686
729
  if !cloud_id.nil?
687
730
  MU.log "Searching for VPC id '#{cloud_id}' in #{region}", MU::DEBUG
688
731
  begin
689
- resp = MU::Cloud::AWS.ec2(region).describe_vpcs(vpc_ids: [cloud_id.to_s])
732
+ resp = MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_vpcs(vpc_ids: [cloud_id.to_s])
690
733
  resp.vpcs.each { |vpc|
691
734
  map[vpc.vpc_id] = vpc
692
735
  }
@@ -720,7 +763,7 @@ module MU
720
763
  # @return [Array<Hash>]: A list of cloud provider identifiers of subnets associated with this VPC.
721
764
  def loadSubnets
722
765
  if @cloud_id
723
- resp = MU::Cloud::AWS.ec2(@config['region']).describe_subnets(
766
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_subnets(
724
767
  filters: [
725
768
  { name: "vpc-id", values: [@cloud_id] }
726
769
  ]
@@ -741,6 +784,7 @@ module MU
741
784
  @config['subnets'].each { |subnet|
742
785
  subnet['mu_name'] = @mu_name+"-"+subnet['name'] if !subnet.has_key?("mu_name")
743
786
  subnet['region'] = @config['region']
787
+ subnet['credentials'] = @config['credentials']
744
788
  if !resp.nil? and !resp.data.nil? and !resp.data.subnets.nil?
745
789
  resp.data.subnets.each { |desc|
746
790
  if desc.cidr_block == subnet["ip_block"]
@@ -776,6 +820,7 @@ module MU
776
820
  subnet["tags"] = MU.structToHash(desc.tags)
777
821
  subnet["cloud_id"] = desc.subnet_id
778
822
  subnet['region'] = @config['region']
823
+ subnet['credentials'] = @config['credentials']
779
824
  if !ext_ids.include?(desc.subnet_id)
780
825
  @subnets << MU::Cloud::AWS::VPC::Subnet.new(self, subnet)
781
826
  end
@@ -790,16 +835,16 @@ module MU
790
835
  # @param nat_filter_key [String]: A cloud provider filter to help identify the resource, used in conjunction with nat_filter_value.
791
836
  # @param nat_filter_value [String]: A cloud provider filter to help identify the resource, used in conjunction with nat_filter_key.
792
837
  # @param region [String]: The cloud provider region of the target instance.
793
- def findNat(nat_cloud_id: nil, nat_filter_key: nil, nat_filter_value: nil, region: MU.curRegion)
838
+ def findNat(nat_cloud_id: nil, nat_filter_key: nil, nat_filter_value: nil, region: MU.curRegion, credentials: nil)
794
839
  # Discard the nat_cloud_id if it's an AWS instance ID
795
840
  nat_cloud_id = nil if nat_cloud_id && nat_cloud_id.start_with?("i-")
796
841
 
797
842
  if @gateways.nil?
798
843
  @gateways =
799
844
  if nat_cloud_id
800
- MU::Cloud::AWS.ec2(region).describe_nat_gateways(nat_gateway_ids: [nat_cloud_id])
845
+ MU::Cloud::AWS.ec2(region: region, credentials: nil).describe_nat_gateways(nat_gateway_ids: [nat_cloud_id])
801
846
  elsif nat_filter_key && nat_filter_value
802
- MU::Cloud::AWS.ec2(region).describe_nat_gateways(
847
+ MU::Cloud::AWS.ec2(region: region, credentials: nil).describe_nat_gateways(
803
848
  filter: [
804
849
  {
805
850
  name: nat_filter_key,
@@ -893,13 +938,13 @@ module MU
893
938
  # @param instance [String]: A cloud descriptor for the instance, to save us an API call if we already have it
894
939
  # @param region [String]: The cloud provider region of the target instance
895
940
  # @return [Array<String>]
896
- def self.getInstanceSubnets(instance_id: nil, instance: nil, region: MU.curRegion)
941
+ def self.getInstanceSubnets(instance_id: nil, instance: nil, region: MU.curRegion, credentials: nil)
897
942
  return [] if instance_id.nil? and instance.nil?
898
943
  my_subnets = []
899
944
 
900
945
  if instance.nil?
901
946
  begin
902
- instance = MU::Cloud::AWS.ec2(region).describe_instances(instance_ids: [instance_id]).reservations.first.instances.first
947
+ instance = MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_instances(instance_ids: [instance_id]).reservations.first.instances.first
903
948
  rescue NoMethodError, Aws::EC2::Errors::InvalidInstanceIDNotFound => e
904
949
  MU.log "Failed to identify instance #{instance_id} in MU::Cloud::AWS::VPC.getInstanceSubnets", MU::WARN
905
950
  return []
@@ -923,7 +968,7 @@ module MU
923
968
  # @param target_instance [OpenStruct]: The cloud descriptor of the instance to check.
924
969
  # @param region [String]: The cloud provider region of the target subnet.
925
970
  # @return [Boolean]
926
- def self.haveRouteToInstance?(target_instance, region: MU.curRegion)
971
+ def self.haveRouteToInstance?(target_instance, region: MU.curRegion, credentials: nil)
927
972
  return false if target_instance.nil?
928
973
  return false if MU.myCloud != "AWS"
929
974
  instance_id = target_instance.instance_id
@@ -941,21 +986,20 @@ module MU
941
986
 
942
987
  return @route_cache[instance_id] if @route_cache.has_key?(instance_id) && @route_cache[instance_id]
943
988
  my_subnets = MU::Cloud::AWS::VPC.getInstanceSubnets(instance: MU.myCloudDescriptor)
944
- target_subnets = MU::Cloud::AWS::VPC.getInstanceSubnets(instance: target_instance, region: region)
945
- # XXX make sure accounts for being in different regions
989
+ target_subnets = MU::Cloud::AWS::VPC.getInstanceSubnets(instance: target_instance, region: region, credentials: credentials)
946
990
 
947
991
  resp = nil
948
992
  my_subnets_key = my_subnets.join(",")
949
993
  target_subnets_key = target_subnets.join(",")
950
994
  MU::Cloud::AWS::VPC.update_route_tables_cache(my_subnets_key, region: MU.myRegion)
951
- MU::Cloud::AWS::VPC.update_route_tables_cache(target_subnets_key, region: region)
995
+ MU::Cloud::AWS::VPC.update_route_tables_cache(target_subnets_key, region: region, credentials: credentials)
952
996
 
953
997
  if MU::Cloud::AWS::VPC.have_route_peered_vpc?(my_subnets_key, target_subnets_key, instance_id)
954
998
  return true
955
999
  else
956
1000
  # The cache can be out of date at times, check again without it
957
1001
  MU::Cloud::AWS::VPC.update_route_tables_cache(my_subnets_key, use_cache: false, region: MU.myRegion)
958
- MU::Cloud::AWS::VPC.update_route_tables_cache(target_subnets_key, use_cache: false, region: region)
1002
+ MU::Cloud::AWS::VPC.update_route_tables_cache(target_subnets_key, use_cache: false, region: region, credentials: credentials)
959
1003
 
960
1004
  return MU::Cloud::AWS::VPC.have_route_peered_vpc?(my_subnets_key, target_subnets_key, instance_id)
961
1005
  end
@@ -968,7 +1012,7 @@ module MU
968
1012
  # @param subnet_key [String]: The subnet/subnets route tables will be extracted from.
969
1013
  # @param use_cache [Boolean]: If to use the existing cache and add records to cache only if missing, or to also replace exising records in cache.
970
1014
  # @param region [String]: The cloud provider region of the target subnet.
971
- def self.update_route_tables_cache(subnet_key, use_cache: true, region: MU.curRegion)
1015
+ def self.update_route_tables_cache(subnet_key, use_cache: true, region: MU.curRegion, credentials: nil)
972
1016
  @rtb_cache_semaphore.synchronize {
973
1017
  update =
974
1018
  if !use_cache
@@ -980,12 +1024,12 @@ module MU
980
1024
  end
981
1025
 
982
1026
  if update
983
- route_tables = MU::Cloud::AWS::VPC.get_route_tables(subnet_ids: subnet_key.split(","), region: region)
1027
+ route_tables = MU::Cloud::AWS::VPC.get_route_tables(subnet_ids: subnet_key.split(","), region: region, credentials: credentials)
984
1028
 
985
1029
  if route_tables.empty? && !subnet_key.empty?
986
- vpc_id = MU::Cloud::AWS.ec2(region).describe_subnets(subnet_ids: subnet_key.split(",")).subnets.first.vpc_id
1030
+ vpc_id = MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_subnets(subnet_ids: subnet_key.split(",")).subnets.first.vpc_id
987
1031
  MU.log "No route table associations found for #{subnet_key}, falling back to the default table for #{vpc_id}", MU::NOTICE
988
- route_tables = MU::Cloud::AWS::VPC.get_route_tables(vpc_ids: [vpc_id], region: region)
1032
+ route_tables = MU::Cloud::AWS::VPC.get_route_tables(vpc_ids: [vpc_id], region: region, credentials: credentials)
989
1033
  end
990
1034
 
991
1035
  @rtb_cache[subnet_key] = route_tables
@@ -1004,16 +1048,19 @@ module MU
1004
1048
 
1005
1049
  @rtb_cache[source_subnets_key].each { |route_table|
1006
1050
  route_table.routes.each { |route|
1007
- if route.destination_cidr_block != "0.0.0.0/0" and route.state == "active" and !route.destination_cidr_block.nil?
1051
+ if route.destination_cidr_block != "0.0.0.0/0" and !route.destination_cidr_block.nil?
1008
1052
  my_routes << NetAddr::IPv4Net.parse(route.destination_cidr_block)
1009
1053
  if !route.vpc_peering_connection_id.nil?
1054
+ if route.state == "blackhole"
1055
+ MU.log "Ignoring blackhole route to #{route.destination_cidr_block} over #{route.vpc_peering_connection_id}", MU::WARN
1056
+ end
1057
+ next if route.state != "active"
1010
1058
  vpc_peer_mapping[route.vpc_peering_connection_id] = route.destination_cidr_block
1011
1059
  end
1012
1060
  end
1013
1061
  }
1014
1062
  }
1015
1063
  my_routes.uniq!
1016
-
1017
1064
  target_routes = []
1018
1065
  @rtb_cache[target_subnets_key].each { |route_table|
1019
1066
  route_table.routes.each { |route|
@@ -1021,6 +1068,7 @@ module MU
1021
1068
  cidr = NetAddr::IPv4Net.parse(route.destination_cidr_block)
1022
1069
  shared_ip_space = false
1023
1070
  my_routes.each { |my_cidr|
1071
+ target_routes << NetAddr::IPv4Net.parse(route.destination_cidr_block)
1024
1072
  if my_cidr.contains(NetAddr::IPv4Net.parse(route.destination_cidr_block).nth(2)) or my_cidr.cmp(cidr)
1025
1073
  shared_ip_space = true
1026
1074
  break
@@ -1043,10 +1091,10 @@ module MU
1043
1091
  # @param vpc_ids [Array]: The cloud identifier of the VPCs to retrieve route tables for.
1044
1092
  # @param region [String]: The cloud provider region of the target subnet.
1045
1093
  # @return [Array<OpenStruct>]: The cloud provider's complete descriptions of the route tables
1046
- def self.get_route_tables(subnet_ids: [], vpc_ids: [], region: MU.curRegion)
1094
+ def self.get_route_tables(subnet_ids: [], vpc_ids: [], region: MU.curRegion, credentials: nil)
1047
1095
  resp = []
1048
1096
  if !subnet_ids.empty?
1049
- resp = MU::Cloud::AWS.ec2(region).describe_route_tables(
1097
+ resp = MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_route_tables(
1050
1098
  filters: [
1051
1099
  {
1052
1100
  name: "association.subnet-id",
@@ -1055,7 +1103,7 @@ module MU
1055
1103
  ]
1056
1104
  ).route_tables
1057
1105
  elsif !vpc_ids.empty?
1058
- resp = MU::Cloud::AWS.ec2(region).describe_route_tables(
1106
+ resp = MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_route_tables(
1059
1107
  filters: [
1060
1108
  {
1061
1109
  name: "vpc-id",
@@ -1068,21 +1116,28 @@ module MU
1068
1116
  ]
1069
1117
  ).route_tables
1070
1118
  else
1071
- resp = MU::Cloud::AWS.ec2(region).describe_route_tables.route_tables
1119
+ resp = MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_route_tables.route_tables
1072
1120
  end
1073
1121
 
1074
1122
  return resp
1075
1123
  end
1076
1124
 
1125
+ # Does this resource type exist as a global (cloud-wide) artifact, or
1126
+ # is it localized to a region/zone?
1127
+ # @return [Boolean]
1128
+ def self.isGlobal?
1129
+ false
1130
+ end
1131
+
1077
1132
  # Remove all VPC resources associated with the currently loaded deployment.
1078
1133
  # @param noop [Boolean]: If true, will only print what would be done
1079
1134
  # @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
1080
1135
  # @param region [String]: The cloud provider region
1081
1136
  # @return [void]
1082
- def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, flags: {})
1137
+ def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
1083
1138
 
1084
1139
  tagfilters = [
1085
- {name: "tag:MU-ID", values: [MU.deploy_id]}
1140
+ {name: "tag:MU-ID", values: [MU.deploy_id]}
1086
1141
  ]
1087
1142
  if !ignoremaster
1088
1143
  tagfilters << {name: "tag:MU-MASTER-IP", values: [MU.mu_public_ip]}
@@ -1091,7 +1146,7 @@ module MU
1091
1146
  vpcs = []
1092
1147
  retries = 0
1093
1148
  begin
1094
- resp = MU::Cloud::AWS.ec2(region).describe_vpcs(filters: tagfilters).vpcs
1149
+ resp = MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_vpcs(filters: tagfilters).vpcs
1095
1150
  vpcs = resp if !resp.empty?
1096
1151
  rescue Aws::EC2::Errors::InvalidVpcIDNotFound => e
1097
1152
  if retries < 5
@@ -1106,8 +1161,8 @@ module MU
1106
1161
  vpcs.each { |vpc|
1107
1162
  # NAT gateways don't have any tags, and we can't assign them a name. Lets find them based on a VPC ID
1108
1163
  gwthreads << Thread.new {
1109
- purge_nat_gateways(noop, vpc_id: vpc.vpc_id, region: region)
1110
- purge_endpoints(noop, vpc_id: vpc.vpc_id, region: region)
1164
+ purge_nat_gateways(noop, vpc_id: vpc.vpc_id, region: region, credentials: credentials)
1165
+ purge_endpoints(noop, vpc_id: vpc.vpc_id, region: region, credentials: credentials)
1111
1166
  }
1112
1167
  }
1113
1168
  gwthreads.each { |t|
@@ -1115,12 +1170,12 @@ module MU
1115
1170
  }
1116
1171
  end
1117
1172
 
1118
- purge_gateways(noop, tagfilters, region: region)
1119
- purge_routetables(noop, tagfilters, region: region)
1120
- purge_interfaces(noop, tagfilters, region: region)
1121
- purge_subnets(noop, tagfilters, region: region)
1122
- purge_vpcs(noop, tagfilters, region: region)
1123
- purge_dhcpopts(noop, tagfilters, region: region)
1173
+ purge_gateways(noop, tagfilters, region: region, credentials: credentials)
1174
+ purge_routetables(noop, tagfilters, region: region, credentials: credentials)
1175
+ purge_interfaces(noop, tagfilters, region: region, credentials: credentials)
1176
+ purge_subnets(noop, tagfilters, region: region, credentials: credentials)
1177
+ purge_vpcs(noop, tagfilters, region: region, credentials: credentials)
1178
+ purge_dhcpopts(noop, tagfilters, region: region, credentials: credentials)
1124
1179
 
1125
1180
  unless noop
1126
1181
  MU::Cloud::AWS.iam.list_roles.roles.each{ |role|
@@ -1339,7 +1394,7 @@ module MU
1339
1394
 
1340
1395
  if (!vpc['subnets'] or vpc['subnets'].empty?) and vpc['create_standard_subnets']
1341
1396
  if vpc['availability_zones'].nil? or vpc['availability_zones'].empty?
1342
- vpc['availability_zones'] = MU::Cloud::AWS.listAZs(vpc['region'])
1397
+ vpc['availability_zones'] = MU::Cloud::AWS.listAZs(region: vpc['region'])
1343
1398
  else
1344
1399
  # turn into a hash so we can use list parameters easily
1345
1400
  vpc['availability_zones'] = vpc['availability_zones'].map { |val| val['zone'] }
@@ -1390,8 +1445,8 @@ module MU
1390
1445
 
1391
1446
 
1392
1447
  # List the route tables for each subnet in the given VPC
1393
- def self.listAllSubnetRouteTables(vpc_id, region: MU.curRegion)
1394
- resp = MU::Cloud::AWS.ec2(region).describe_subnets(
1448
+ def self.listAllSubnetRouteTables(vpc_id, region: MU.curRegion, credentials: nil)
1449
+ resp = MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_subnets(
1395
1450
  filters: [
1396
1451
  {
1397
1452
  name: "vpc-id",
@@ -1402,7 +1457,7 @@ module MU
1402
1457
 
1403
1458
  subnets = resp.subnets.map { |subnet| subnet.subnet_id }
1404
1459
 
1405
- tables = MU::Cloud::AWS.ec2(region).describe_route_tables(
1460
+ tables = MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_route_tables(
1406
1461
  filters: [
1407
1462
  {
1408
1463
  name: "vpc-id",
@@ -1417,7 +1472,7 @@ module MU
1417
1472
 
1418
1473
  if tables.nil? or tables.route_tables.size == 0
1419
1474
  MU.log "No route table associations found for #{subnets}, falling back to the default table for #{vpc_id}", MU::NOTICE
1420
- tables = MU::Cloud::AWS.ec2(MU.myRegion).describe_route_tables(
1475
+ tables = MU::Cloud::AWS.ec2(region: MU.myRegion).describe_route_tables(
1421
1476
  filters: [
1422
1477
  {name: "vpc-id", values: [vpc_id]},
1423
1478
  {name: "association.main", values: ["true"]},
@@ -1440,24 +1495,24 @@ module MU
1440
1495
  vpc_id = @cloud_id
1441
1496
  vpc_name = @config['name']
1442
1497
  MU.setVar("curRegion", @config['region']) if !@config['region'].nil?
1443
- resp = MU::Cloud::AWS.ec2.create_route_table(vpc_id: vpc_id).route_table
1498
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_route_table(vpc_id: vpc_id).route_table
1444
1499
  route_table_id = rtb['route_table_id'] = resp.route_table_id
1445
1500
  sleep 5
1446
- MU::MommaCat.createTag(route_table_id, "Name", vpc_name+"-"+rtb['name'].upcase)
1501
+ MU::MommaCat.createTag(route_table_id, "Name", vpc_name+"-"+rtb['name'].upcase, credentials: @config['credentials'])
1447
1502
 
1448
1503
  if @config['tags']
1449
1504
  @config['tags'].each { |tag|
1450
- MU::MommaCat.createTag(route_table_id, tag['key'], tag['value'])
1505
+ MU::MommaCat.createTag(route_table_id, tag['key'], tag['value'], credentials: @config['credentials'])
1451
1506
  }
1452
1507
  end
1453
1508
 
1454
1509
  if @config['optional_tags']
1455
1510
  MU::MommaCat.listOptionalTags.each { |key, value|
1456
- MU::MommaCat.createTag(route_table_id, key, value, region: @config['region'])
1511
+ MU::MommaCat.createTag(route_table_id, key, value, region: @config['region'], credentials: @config['credentials'])
1457
1512
  }
1458
1513
  end
1459
1514
 
1460
- MU::MommaCat.createStandardTags(route_table_id)
1515
+ MU::MommaCat.createStandardTags(route_table_id, credentials: @config['credentials'])
1461
1516
  rtb['routes'].each { |route|
1462
1517
  if route['nat_host_id'].nil? and route['nat_host_name'].nil?
1463
1518
  route_config = {
@@ -1473,7 +1528,7 @@ module MU
1473
1528
  unless route['gateway'] == '#NAT'
1474
1529
  # Need to change the order of how things are created to create the route here
1475
1530
  MU.log "Creating route for #{route['destination_network']}", details: route_config
1476
- resp = MU::Cloud::AWS.ec2.create_route(route_config)
1531
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_route(route_config)
1477
1532
  end
1478
1533
  end
1479
1534
  }
@@ -1485,8 +1540,8 @@ module MU
1485
1540
  # @param noop [Boolean]: If true, will only print what would be done
1486
1541
  # @param region [String]: The cloud provider region
1487
1542
  # @return [void]
1488
- def self.purge_gateways(noop = false, tagfilters = [{name: "tag:MU-ID", values: [MU.deploy_id]}], region: MU.curRegion)
1489
- resp = MU::Cloud::AWS.ec2(region).describe_internet_gateways(
1543
+ def self.purge_gateways(noop = false, tagfilters = [{name: "tag:MU-ID", values: [MU.deploy_id]}], region: MU.curRegion, credentials: nil)
1544
+ resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_internet_gateways(
1490
1545
  filters: tagfilters
1491
1546
  )
1492
1547
  gateways = resp.data.internet_gateways
@@ -1495,7 +1550,7 @@ module MU
1495
1550
  gateway.attachments.each { |attachment|
1496
1551
  MU.log "Detaching Internet Gateway #{gateway.internet_gateway_id} from #{attachment.vpc_id}"
1497
1552
  begin
1498
- MU::Cloud::AWS.ec2(region).detach_internet_gateway(
1553
+ MU::Cloud::AWS.ec2(credentials: credentials, region: region).detach_internet_gateway(
1499
1554
  internet_gateway_id: gateway.internet_gateway_id,
1500
1555
  vpc_id: attachment.vpc_id
1501
1556
  ) if !noop
@@ -1505,7 +1560,7 @@ module MU
1505
1560
  }
1506
1561
  MU.log "Deleting Internet Gateway #{gateway.internet_gateway_id}"
1507
1562
  begin
1508
- MU::Cloud::AWS.ec2(region).delete_internet_gateway(internet_gateway_id: gateway.internet_gateway_id) if !noop
1563
+ MU::Cloud::AWS.ec2(credentials: credentials, region: region).delete_internet_gateway(internet_gateway_id: gateway.internet_gateway_id) if !noop
1509
1564
  rescue Aws::EC2::Errors::InvalidInternetGatewayIDNotFound
1510
1565
  MU.log "Gateway #{gateway.internet_gateway_id} was already destroyed by the time I got to it", MU::WARN
1511
1566
  end
@@ -1518,8 +1573,8 @@ module MU
1518
1573
  # @param vpc_id [String]: The cloud provider's unique VPC identifier
1519
1574
  # @param region [String]: The cloud provider region
1520
1575
  # @return [void]
1521
- def self.purge_nat_gateways(noop = false, vpc_id: nil, region: MU.curRegion)
1522
- gateways = MU::Cloud::AWS.ec2(region).describe_nat_gateways(
1576
+ def self.purge_nat_gateways(noop = false, vpc_id: nil, region: MU.curRegion, credentials: nil)
1577
+ gateways = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_nat_gateways(
1523
1578
  filter: [
1524
1579
  {
1525
1580
  name: "vpc-id",
@@ -1537,15 +1592,15 @@ module MU
1537
1592
  MU.log "Deleting NAT Gateway #{gateway.nat_gateway_id}"
1538
1593
  if !noop
1539
1594
  begin
1540
- MU::Cloud::AWS.ec2(region).delete_nat_gateway(nat_gateway_id: gateway.nat_gateway_id)
1541
- resp = MU::Cloud::AWS.ec2(region).describe_nat_gateways(nat_gateway_ids: [gateway.nat_gateway_id]).nat_gateways.first
1595
+ MU::Cloud::AWS.ec2(credentials: credentials, region: region).delete_nat_gateway(nat_gateway_id: gateway.nat_gateway_id)
1596
+ resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_nat_gateways(nat_gateway_ids: [gateway.nat_gateway_id]).nat_gateways.first
1542
1597
 
1543
1598
  attempts = 0
1544
1599
  while resp.state != "deleted" and resp.state != "failed"
1545
1600
  MU.log "Waiting for nat gateway #{gateway.nat_gateway_id} to delete" if attempts % 2 == 0
1546
1601
  sleep 30
1547
1602
  begin
1548
- resp = MU::Cloud::AWS.ec2(region).describe_nat_gateways(nat_gateway_ids: [gateway.nat_gateway_id]).nat_gateways.first
1603
+ resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_nat_gateways(nat_gateway_ids: [gateway.nat_gateway_id]).nat_gateways.first
1549
1604
  rescue Aws::EmptyStructure, NoMethodError
1550
1605
  sleep 5
1551
1606
  retry
@@ -1575,8 +1630,8 @@ module MU
1575
1630
  # @param vpc_id [String]: The cloud provider's unique VPC identifier
1576
1631
  # @param region [String]: The cloud provider region
1577
1632
  # @return [void]
1578
- def self.purge_endpoints(noop = false, vpc_id: nil, region: MU.curRegion)
1579
- vpc_endpoints = MU::Cloud::AWS.ec2(region).describe_vpc_endpoints(
1633
+ def self.purge_endpoints(noop = false, vpc_id: nil, region: MU.curRegion, credentials: nil)
1634
+ vpc_endpoints = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_vpc_endpoints(
1580
1635
  filters: [
1581
1636
  {
1582
1637
  name:"vpc-id",
@@ -1594,15 +1649,15 @@ module MU
1594
1649
  MU.log "Deleting VPC endpoint #{endpoint.vpc_endpoint_id}"
1595
1650
  if !noop
1596
1651
  begin
1597
- MU::Cloud::AWS.ec2(region).delete_vpc_endpoints(vpc_endpoint_ids: [endpoint.vpc_endpoint_id])
1598
- resp = MU::Cloud::AWS.ec2(region).describe_vpc_endpoints(vpc_endpoint_ids: [endpoint.vpc_endpoint_id]).vpc_endpoints.first
1652
+ MU::Cloud::AWS.ec2(credentials: credentials, region: region).delete_vpc_endpoints(vpc_endpoint_ids: [endpoint.vpc_endpoint_id])
1653
+ resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_vpc_endpoints(vpc_endpoint_ids: [endpoint.vpc_endpoint_id]).vpc_endpoints.first
1599
1654
 
1600
1655
  attempts = 0
1601
1656
  while resp.state != "deleted"
1602
1657
  MU.log "Waiting for VPC endpoint #{endpoint.vpc_endpoint_id} to delete" if attempts % 5 == 0
1603
1658
  sleep 30
1604
1659
  begin
1605
- resp = MU::Cloud::AWS.ec2(region).describe_vpc_endpoints(vpc_endpoint_ids: [endpoint.vpc_endpoint_id]).vpc_endpoints.first
1660
+ resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_vpc_endpoints(vpc_endpoint_ids: [endpoint.vpc_endpoint_id]).vpc_endpoints.first
1606
1661
  rescue Aws::EmptyStructure, NoMethodError
1607
1662
  sleep 5
1608
1663
  retry
@@ -1634,8 +1689,8 @@ module MU
1634
1689
  # @param tagfilters [Array<Hash>]: EC2 tags to filter against when search for resources to purge
1635
1690
  # @param region [String]: The cloud provider region
1636
1691
  # @return [void]
1637
- def self.purge_routetables(noop = false, tagfilters = [{name: "tag:MU-ID", values: [MU.deploy_id]}], region: MU.curRegion)
1638
- resp = MU::Cloud::AWS.ec2(region).describe_route_tables(
1692
+ def self.purge_routetables(noop = false, tagfilters = [{name: "tag:MU-ID", values: [MU.deploy_id]}], region: MU.curRegion, credentials: nil)
1693
+ resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_route_tables(
1639
1694
  filters: tagfilters
1640
1695
  )
1641
1696
  route_tables = resp.data.route_tables
@@ -1647,7 +1702,7 @@ module MU
1647
1702
  if !route.network_interface_id.nil?
1648
1703
  MU.log "Deleting Network Interface #{route.network_interface_id}"
1649
1704
  begin
1650
- MU::Cloud::AWS.ec2(region).delete_network_interface(network_interface_id: route.network_interface_id) if !noop
1705
+ MU::Cloud::AWS.ec2(credentials: credentials, region: region).delete_network_interface(network_interface_id: route.network_interface_id) if !noop
1651
1706
  rescue Aws::EC2::Errors::InvalidNetworkInterfaceIDNotFound => e
1652
1707
  MU.log "Network Interface #{route.network_interface_id} has already been deleted", MU::WARN
1653
1708
  end
@@ -1655,7 +1710,7 @@ module MU
1655
1710
  if route.gateway_id != "local"
1656
1711
  MU.log "Deleting #{table.route_table_id}'s route for #{route.destination_cidr_block}"
1657
1712
  begin
1658
- MU::Cloud::AWS.ec2(region).delete_route(
1713
+ MU::Cloud::AWS.ec2(credentials: credentials, region: region).delete_route(
1659
1714
  route_table_id: table.route_table_id,
1660
1715
  destination_cidr_block: route.destination_cidr_block
1661
1716
  ) if !noop
@@ -1667,7 +1722,7 @@ module MU
1667
1722
  can_delete = true
1668
1723
  table.associations.each { |assoc|
1669
1724
  begin
1670
- MU::Cloud::AWS.ec2(region).disassociate_route_table(association_id: assoc.route_table_association_id) if !noop
1725
+ MU::Cloud::AWS.ec2(credentials: credentials, region: region).disassociate_route_table(association_id: assoc.route_table_association_id) if !noop
1671
1726
  rescue Aws::EC2::Errors::InvalidAssociationIDNotFound => e
1672
1727
  MU.log "Route table association #{assoc.route_table_association_id} already removed", MU::WARN
1673
1728
  rescue Aws::EC2::Errors::InvalidParameterValue => e
@@ -1679,7 +1734,7 @@ module MU
1679
1734
  next if !can_delete
1680
1735
  MU.log "Deleting Route Table #{table.route_table_id}"
1681
1736
  begin
1682
- MU::Cloud::AWS.ec2(region).delete_route_table(route_table_id: table.route_table_id) if !noop
1737
+ MU::Cloud::AWS.ec2(credentials: credentials, region: region).delete_route_table(route_table_id: table.route_table_id) if !noop
1683
1738
  rescue Aws::EC2::Errors::InvalidRouteTableIDNotFound
1684
1739
  MU.log "Route table #{table.route_table_id} already removed", MU::WARN
1685
1740
  end
@@ -1693,8 +1748,8 @@ module MU
1693
1748
  # @param tagfilters [Array<Hash>]: EC2 tags to filter against when search for resources to purge
1694
1749
  # @param region [String]: The cloud provider region
1695
1750
  # @return [void]
1696
- def self.purge_interfaces(noop = false, tagfilters = [{name: "tag:MU-ID", values: [MU.deploy_id]}], region: MU.curRegion)
1697
- resp = MU::Cloud::AWS.ec2(region).describe_network_interfaces(
1751
+ def self.purge_interfaces(noop = false, tagfilters = [{name: "tag:MU-ID", values: [MU.deploy_id]}], region: MU.curRegion, credentials: nil)
1752
+ resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_network_interfaces(
1698
1753
  filters: tagfilters
1699
1754
  )
1700
1755
  ifaces = resp.data.network_interfaces
@@ -1703,7 +1758,7 @@ module MU
1703
1758
 
1704
1759
  ifaces.each { |iface|
1705
1760
  MU.log "Deleting Network Interface #{iface.network_interface_id}"
1706
- MU::Cloud::AWS.ec2(region).delete_network_interface(network_interface_id: iface.network_interface_id)
1761
+ MU::Cloud::AWS.ec2(credentials: credentials, region: region).delete_network_interface(network_interface_id: iface.network_interface_id)
1707
1762
  }
1708
1763
  end
1709
1764
 
@@ -1712,8 +1767,8 @@ module MU
1712
1767
  # @param tagfilters [Array<Hash>]: EC2 tags to filter against when search for resources to purge
1713
1768
  # @param region [String]: The cloud provider region
1714
1769
  # @return [void]
1715
- def self.purge_subnets(noop = false, tagfilters = [{name: "tag:MU-ID", values: [MU.deploy_id]}], region: MU.curRegion)
1716
- resp = MU::Cloud::AWS.ec2(region).describe_subnets(
1770
+ def self.purge_subnets(noop = false, tagfilters = [{name: "tag:MU-ID", values: [MU.deploy_id]}], region: MU.curRegion, credentials: nil)
1771
+ resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_subnets(
1717
1772
  filters: tagfilters
1718
1773
  )
1719
1774
  subnets = resp.data.subnets
@@ -1728,7 +1783,7 @@ module MU
1728
1783
  sleep 30
1729
1784
  else
1730
1785
  MU.log "Deleting Subnet #{subnet.subnet_id}"
1731
- MU::Cloud::AWS.ec2(region).delete_subnet(subnet_id: subnet.subnet_id) if !noop
1786
+ MU::Cloud::AWS.ec2(credentials: credentials, region: region).delete_subnet(subnet_id: subnet.subnet_id) if !noop
1732
1787
  end
1733
1788
  rescue Aws::EC2::Errors::DependencyViolation => e
1734
1789
  if retries < 7
@@ -1752,8 +1807,8 @@ module MU
1752
1807
  # @param tagfilters [Array<Hash>]: EC2 tags to filter against when search for resources to purge
1753
1808
  # @param region [String]: The cloud provider region
1754
1809
  # @return [void]
1755
- def self.purge_dhcpopts(noop = false, tagfilters = [{name: "tag:MU-ID", values: [MU.deploy_id]}], region: MU.curRegion)
1756
- resp = MU::Cloud::AWS.ec2(region).describe_dhcp_options(
1810
+ def self.purge_dhcpopts(noop = false, tagfilters = [{name: "tag:MU-ID", values: [MU.deploy_id]}], region: MU.curRegion, credentials: nil)
1811
+ resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_dhcp_options(
1757
1812
  filters: tagfilters
1758
1813
  )
1759
1814
  sets = resp.data.dhcp_options
@@ -1763,7 +1818,7 @@ module MU
1763
1818
  sets.each { |optset|
1764
1819
  begin
1765
1820
  MU.log "Deleting DHCP Option Set #{optset.dhcp_options_id}"
1766
- MU::Cloud::AWS.ec2(region).delete_dhcp_options(dhcp_options_id: optset.dhcp_options_id)
1821
+ MU::Cloud::AWS.ec2(credentials: credentials, region: region).delete_dhcp_options(dhcp_options_id: optset.dhcp_options_id)
1767
1822
  rescue Aws::EC2::Errors::DependencyViolation => e
1768
1823
  MU.log e.inspect, MU::ERR
1769
1824
  # rescue Aws::EC2::Errors::InvalidSubnetIDNotFound
@@ -1778,8 +1833,8 @@ module MU
1778
1833
  # @param tagfilters [Array<Hash>]: EC2 tags to filter against when search for resources to purge
1779
1834
  # @param region [String]: The cloud provider region
1780
1835
  # @return [void]
1781
- def self.purge_vpcs(noop = false, tagfilters = [{name: "tag:MU-ID", values: [MU.deploy_id]}], region: MU.curRegion)
1782
- resp = MU::Cloud::AWS.ec2(region).describe_vpcs(
1836
+ def self.purge_vpcs(noop = false, tagfilters = [{name: "tag:MU-ID", values: [MU.deploy_id]}], region: MU.curRegion, credentials: nil)
1837
+ resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_vpcs(
1783
1838
  filters: tagfilters
1784
1839
  )
1785
1840
 
@@ -1787,7 +1842,7 @@ module MU
1787
1842
  return if vpcs.nil? or vpcs.size == 0
1788
1843
 
1789
1844
  vpcs.each { |vpc|
1790
- my_peer_conns = MU::Cloud::AWS.ec2(region).describe_vpc_peering_connections(
1845
+ my_peer_conns = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_vpc_peering_connections(
1791
1846
  filters: [
1792
1847
  {
1793
1848
  name: "requester-vpc-info.vpc-id",
@@ -1795,7 +1850,7 @@ module MU
1795
1850
  }
1796
1851
  ]
1797
1852
  ).vpc_peering_connections
1798
- my_peer_conns.concat(MU::Cloud::AWS.ec2(region).describe_vpc_peering_connections(
1853
+ my_peer_conns.concat(MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_vpc_peering_connections(
1799
1854
  filters: [
1800
1855
  {
1801
1856
  name: "accepter-vpc-info.vpc-id",
@@ -1806,15 +1861,19 @@ module MU
1806
1861
  my_peer_conns.each { |cnxn|
1807
1862
 
1808
1863
  [cnxn.accepter_vpc_info.vpc_id, cnxn.requester_vpc_info.vpc_id].each { |peer_vpc|
1809
- MU::Cloud::AWS::VPC.listAllSubnetRouteTables(peer_vpc, region: region).each { |rtb_id|
1810
- resp = MU::Cloud::AWS.ec2(region).describe_route_tables(
1864
+ MU::Cloud::AWS::VPC.listAllSubnetRouteTables(peer_vpc, region: region, credentials: credentials).each { |rtb_id|
1865
+ begin
1866
+ resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_route_tables(
1811
1867
  route_table_ids: [rtb_id]
1812
- )
1868
+ )
1869
+ rescue Aws::EC2::Errors::InvalidRouteTableIDNotFound => e
1870
+ next
1871
+ end
1813
1872
  resp.route_tables.each { |rtb|
1814
1873
  rtb.routes.each { |route|
1815
1874
  if route.vpc_peering_connection_id == cnxn.vpc_peering_connection_id
1816
1875
  MU.log "Removing route #{route.destination_cidr_block} from route table #{rtb_id} in VPC #{peer_vpc}"
1817
- MU::Cloud::AWS.ec2(region).delete_route(
1876
+ MU::Cloud::AWS.ec2(credentials: credentials, region: region).delete_route(
1818
1877
  route_table_id: rtb_id,
1819
1878
  destination_cidr_block: route.destination_cidr_block
1820
1879
  ) if !noop
@@ -1825,18 +1884,20 @@ module MU
1825
1884
  }
1826
1885
  MU.log "Deleting VPC peering connection #{cnxn.vpc_peering_connection_id}"
1827
1886
  begin
1828
- MU::Cloud::AWS.ec2(region).delete_vpc_peering_connection(
1887
+ MU::Cloud::AWS.ec2(credentials: credentials, region: region).delete_vpc_peering_connection(
1829
1888
  vpc_peering_connection_id: cnxn.vpc_peering_connection_id
1830
1889
  ) if !noop
1831
1890
  rescue Aws::EC2::Errors::InvalidStateTransition => e
1832
1891
  MU.log "VPC peering connection #{cnxn.vpc_peering_connection_id} not in removable (state #{cnxn.status.code})", MU::WARN
1892
+ rescue Aws::EC2::Errors::OperationNotPermitted => e
1893
+ MU.log "VPC peering connection #{cnxn.vpc_peering_connection_id} refuses to delete: #{e.message}", MU::WARN
1833
1894
  end
1834
1895
  }
1835
1896
 
1836
1897
  MU.log "Deleting VPC #{vpc.vpc_id}"
1837
1898
  retries = 0
1838
1899
  begin
1839
- MU::Cloud::AWS.ec2(region).delete_vpc(vpc_id: vpc.vpc_id) if !noop
1900
+ MU::Cloud::AWS.ec2(credentials: credentials, region: region).delete_vpc(vpc_id: vpc.vpc_id) if !noop
1840
1901
  rescue Aws::EC2::Errors::InvalidVpcIDNotFound
1841
1902
  MU.log "VPC #{vpc.vpc_id} has already been deleted", MU::WARN
1842
1903
  rescue Aws::EC2::Errors::DependencyViolation => e
@@ -1851,9 +1912,9 @@ module MU
1851
1912
  end
1852
1913
 
1853
1914
  if !MU::Cloud::AWS.isGovCloud?(region)
1854
- mu_zone = MU::Cloud::DNSZone.find(cloud_id: "platform-mu", region: region).values.first
1915
+ mu_zone = MU::Cloud::DNSZone.find(cloud_id: "platform-mu", region: region, credentials: credentials).values.first
1855
1916
  if !mu_zone.nil?
1856
- MU::Cloud::AWS::DNSZone.toggleVPCAccess(id: mu_zone.id, vpc_id: vpc.vpc_id, remove: true)
1917
+ MU::Cloud::AWS::DNSZone.toggleVPCAccess(id: mu_zone.id, vpc_id: vpc.vpc_id, remove: true, credentials: credentials)
1857
1918
  end
1858
1919
  end
1859
1920
  }
@@ -1882,20 +1943,20 @@ module MU
1882
1943
  @mu_name = config['mu_name']
1883
1944
  @name = config['name']
1884
1945
  @deploydata = config # This is a dummy for the sake of describe()
1885
- resp = MU::Cloud::AWS.ec2(@config['region']).describe_subnets(subnet_ids: [@cloud_id]).subnets.first
1946
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_subnets(subnet_ids: [@cloud_id]).subnets.first
1886
1947
  @az = resp.availability_zone
1887
1948
  @ip_block = resp.cidr_block
1888
- @cloud_desc = resp
1949
+ @cloud_desc = resp # XXX this really isn't the cloud implementation's business
1889
1950
 
1890
1951
  end
1891
1952
 
1892
1953
  # Return the cloud identifier for the default route of this subnet.
1893
1954
  def defaultRoute
1894
- resp = MU::Cloud::AWS.ec2(@config['region']).describe_route_tables(
1955
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_route_tables(
1895
1956
  filters: [{name: "association.subnet-id", values: [@cloud_id]}]
1896
1957
  )
1897
1958
  if resp.route_tables.size == 0 # use default route table for the VPC
1898
- resp = MU::Cloud::AWS.ec2(@config['region']).describe_route_tables(
1959
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_route_tables(
1899
1960
  filters: [{name: "vpc-id", values: [@parent.cloud_id]}]
1900
1961
  )
1901
1962
  end
@@ -1916,11 +1977,11 @@ module MU
1916
1977
  # @return [Boolean]
1917
1978
  def private?
1918
1979
  return false if @cloud_id.nil?
1919
- resp = MU::Cloud::AWS.ec2(@config['region']).describe_route_tables(
1980
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_route_tables(
1920
1981
  filters: [{name: "association.subnet-id", values: [@cloud_id]}]
1921
1982
  )
1922
1983
  if resp.route_tables.size == 0 # use default route table for the VPC
1923
- resp = MU::Cloud::AWS.ec2(@config['region']).describe_route_tables(
1984
+ resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_route_tables(
1924
1985
  filters: [{name: "vpc-id", values: [@parent.cloud_id]}]
1925
1986
  )
1926
1987
  end