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

Sign up to get free protection for your applications and to get access to all the features.
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