cloud-mu 2.1.0beta → 3.0.0beta

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 (291) hide show
  1. checksums.yaml +5 -5
  2. data/Berksfile +4 -5
  3. data/Berksfile.lock +179 -0
  4. data/README.md +1 -6
  5. data/ansible/roles/geerlingguy.firewall/templates/firewall.bash.j2 +0 -0
  6. data/ansible/roles/mu-installer/README.md +33 -0
  7. data/ansible/roles/mu-installer/defaults/main.yml +2 -0
  8. data/ansible/roles/mu-installer/handlers/main.yml +2 -0
  9. data/ansible/roles/mu-installer/meta/main.yml +60 -0
  10. data/ansible/roles/mu-installer/tasks/main.yml +13 -0
  11. data/ansible/roles/mu-installer/tests/inventory +2 -0
  12. data/ansible/roles/mu-installer/tests/test.yml +5 -0
  13. data/ansible/roles/mu-installer/vars/main.yml +2 -0
  14. data/bin/mu-adopt +125 -0
  15. data/bin/mu-aws-setup +4 -4
  16. data/bin/mu-azure-setup +265 -0
  17. data/bin/mu-azure-tests +43 -0
  18. data/bin/mu-cleanup +20 -8
  19. data/bin/mu-configure +224 -98
  20. data/bin/mu-deploy +8 -3
  21. data/bin/mu-gcp-setup +16 -8
  22. data/bin/mu-gen-docs +92 -8
  23. data/bin/mu-load-config.rb +52 -12
  24. data/bin/mu-momma-cat +36 -0
  25. data/bin/mu-node-manage +34 -27
  26. data/bin/mu-self-update +2 -2
  27. data/bin/mu-ssh +12 -8
  28. data/bin/mu-upload-chef-artifacts +11 -4
  29. data/bin/mu-user-manage +3 -0
  30. data/cloud-mu.gemspec +8 -11
  31. data/cookbooks/firewall/libraries/helpers_iptables.rb +2 -2
  32. data/cookbooks/firewall/metadata.json +1 -1
  33. data/cookbooks/firewall/recipes/default.rb +5 -9
  34. data/cookbooks/mu-firewall/attributes/default.rb +2 -0
  35. data/cookbooks/mu-firewall/metadata.rb +1 -1
  36. data/cookbooks/mu-glusterfs/templates/default/mu-gluster-client.erb +0 -0
  37. data/cookbooks/mu-master/Berksfile +2 -2
  38. data/cookbooks/mu-master/files/default/check_mem.pl +0 -0
  39. data/cookbooks/mu-master/files/default/cloudamatic.png +0 -0
  40. data/cookbooks/mu-master/metadata.rb +5 -4
  41. data/cookbooks/mu-master/recipes/389ds.rb +1 -1
  42. data/cookbooks/mu-master/recipes/basepackages.rb +30 -10
  43. data/cookbooks/mu-master/recipes/default.rb +59 -7
  44. data/cookbooks/mu-master/recipes/firewall-holes.rb +1 -1
  45. data/cookbooks/mu-master/recipes/init.rb +65 -47
  46. data/cookbooks/mu-master/recipes/{eks-kubectl.rb → kubectl.rb} +4 -10
  47. data/cookbooks/mu-master/recipes/sssd.rb +2 -1
  48. data/cookbooks/mu-master/recipes/update_nagios_only.rb +6 -6
  49. data/cookbooks/mu-master/templates/default/web_app.conf.erb +2 -2
  50. data/cookbooks/mu-master/templates/mods/ldap.conf.erb +4 -0
  51. data/cookbooks/mu-php54/Berksfile +1 -2
  52. data/cookbooks/mu-php54/metadata.rb +4 -5
  53. data/cookbooks/mu-php54/recipes/default.rb +1 -1
  54. data/cookbooks/mu-splunk/templates/default/splunk-init.erb +0 -0
  55. data/cookbooks/mu-tools/Berksfile +3 -2
  56. data/cookbooks/mu-tools/files/default/Mu_CA.pem +33 -0
  57. data/cookbooks/mu-tools/libraries/helper.rb +20 -8
  58. data/cookbooks/mu-tools/metadata.rb +5 -2
  59. data/cookbooks/mu-tools/recipes/apply_security.rb +2 -3
  60. data/cookbooks/mu-tools/recipes/eks.rb +1 -1
  61. data/cookbooks/mu-tools/recipes/gcloud.rb +5 -30
  62. data/cookbooks/mu-tools/recipes/nagios.rb +1 -1
  63. data/cookbooks/mu-tools/recipes/rsyslog.rb +1 -0
  64. data/cookbooks/mu-tools/recipes/selinux.rb +19 -0
  65. data/cookbooks/mu-tools/recipes/split_var_partitions.rb +0 -1
  66. data/cookbooks/mu-tools/recipes/windows-client.rb +256 -122
  67. data/cookbooks/mu-tools/resources/disk.rb +3 -1
  68. data/cookbooks/mu-tools/templates/amazon/sshd_config.erb +1 -1
  69. data/cookbooks/mu-tools/templates/default/etc_hosts.erb +1 -1
  70. data/cookbooks/mu-tools/templates/default/{kubeconfig.erb → kubeconfig-eks.erb} +0 -0
  71. data/cookbooks/mu-tools/templates/default/kubeconfig-gke.erb +27 -0
  72. data/cookbooks/mu-tools/templates/windows-10/sshd_config.erb +137 -0
  73. data/cookbooks/mu-utility/recipes/nat.rb +4 -0
  74. data/extras/alpha.png +0 -0
  75. data/extras/beta.png +0 -0
  76. data/extras/clean-stock-amis +2 -2
  77. data/extras/generate-stock-images +131 -0
  78. data/extras/git-fix-permissions-hook +0 -0
  79. data/extras/image-generators/AWS/centos6.yaml +17 -0
  80. data/extras/image-generators/{aws → AWS}/centos7-govcloud.yaml +0 -0
  81. data/extras/image-generators/{aws → AWS}/centos7.yaml +0 -0
  82. data/extras/image-generators/{aws → AWS}/rhel7.yaml +0 -0
  83. data/extras/image-generators/{aws → AWS}/win2k12.yaml +0 -0
  84. data/extras/image-generators/{aws → AWS}/win2k16.yaml +0 -0
  85. data/extras/image-generators/{aws → AWS}/windows.yaml +0 -0
  86. data/extras/image-generators/{gcp → Google}/centos6.yaml +1 -0
  87. data/extras/image-generators/Google/centos7.yaml +18 -0
  88. data/extras/python_rpm/build.sh +0 -0
  89. data/extras/release.png +0 -0
  90. data/extras/ruby_rpm/build.sh +0 -0
  91. data/extras/ruby_rpm/muby.spec +1 -1
  92. data/install/README.md +43 -5
  93. data/install/deprecated-bash-library.sh +0 -0
  94. data/install/installer +1 -1
  95. data/install/jenkinskeys.rb +0 -0
  96. data/install/mu-master.yaml +55 -0
  97. data/modules/mommacat.ru +41 -7
  98. data/modules/mu.rb +444 -149
  99. data/modules/mu/adoption.rb +500 -0
  100. data/modules/mu/cleanup.rb +235 -158
  101. data/modules/mu/cloud.rb +675 -138
  102. data/modules/mu/clouds/aws.rb +156 -24
  103. data/modules/mu/clouds/aws/alarm.rb +4 -14
  104. data/modules/mu/clouds/aws/bucket.rb +60 -18
  105. data/modules/mu/clouds/aws/cache_cluster.rb +8 -20
  106. data/modules/mu/clouds/aws/collection.rb +12 -22
  107. data/modules/mu/clouds/aws/container_cluster.rb +209 -118
  108. data/modules/mu/clouds/aws/database.rb +120 -45
  109. data/modules/mu/clouds/aws/dnszone.rb +7 -18
  110. data/modules/mu/clouds/aws/endpoint.rb +5 -15
  111. data/modules/mu/clouds/aws/firewall_rule.rb +144 -72
  112. data/modules/mu/clouds/aws/folder.rb +4 -11
  113. data/modules/mu/clouds/aws/function.rb +6 -16
  114. data/modules/mu/clouds/aws/group.rb +4 -12
  115. data/modules/mu/clouds/aws/habitat.rb +11 -13
  116. data/modules/mu/clouds/aws/loadbalancer.rb +40 -28
  117. data/modules/mu/clouds/aws/log.rb +5 -13
  118. data/modules/mu/clouds/aws/msg_queue.rb +9 -24
  119. data/modules/mu/clouds/aws/nosqldb.rb +4 -12
  120. data/modules/mu/clouds/aws/notifier.rb +6 -13
  121. data/modules/mu/clouds/aws/role.rb +69 -40
  122. data/modules/mu/clouds/aws/search_domain.rb +17 -20
  123. data/modules/mu/clouds/aws/server.rb +184 -94
  124. data/modules/mu/clouds/aws/server_pool.rb +33 -38
  125. data/modules/mu/clouds/aws/storage_pool.rb +5 -12
  126. data/modules/mu/clouds/aws/user.rb +59 -33
  127. data/modules/mu/clouds/aws/userdata/linux.erb +18 -30
  128. data/modules/mu/clouds/aws/userdata/windows.erb +9 -9
  129. data/modules/mu/clouds/aws/vpc.rb +214 -145
  130. data/modules/mu/clouds/azure.rb +978 -44
  131. data/modules/mu/clouds/azure/container_cluster.rb +413 -0
  132. data/modules/mu/clouds/azure/firewall_rule.rb +500 -0
  133. data/modules/mu/clouds/azure/habitat.rb +167 -0
  134. data/modules/mu/clouds/azure/loadbalancer.rb +205 -0
  135. data/modules/mu/clouds/azure/role.rb +211 -0
  136. data/modules/mu/clouds/azure/server.rb +810 -0
  137. data/modules/mu/clouds/azure/user.rb +257 -0
  138. data/modules/mu/clouds/azure/userdata/README.md +4 -0
  139. data/modules/mu/clouds/azure/userdata/linux.erb +137 -0
  140. data/modules/mu/clouds/azure/userdata/windows.erb +275 -0
  141. data/modules/mu/clouds/azure/vpc.rb +782 -0
  142. data/modules/mu/clouds/cloudformation.rb +12 -9
  143. data/modules/mu/clouds/cloudformation/firewall_rule.rb +5 -13
  144. data/modules/mu/clouds/cloudformation/server.rb +10 -1
  145. data/modules/mu/clouds/cloudformation/server_pool.rb +1 -0
  146. data/modules/mu/clouds/cloudformation/vpc.rb +0 -2
  147. data/modules/mu/clouds/google.rb +554 -117
  148. data/modules/mu/clouds/google/bucket.rb +173 -32
  149. data/modules/mu/clouds/google/container_cluster.rb +1112 -157
  150. data/modules/mu/clouds/google/database.rb +24 -47
  151. data/modules/mu/clouds/google/firewall_rule.rb +344 -89
  152. data/modules/mu/clouds/google/folder.rb +156 -79
  153. data/modules/mu/clouds/google/group.rb +272 -82
  154. data/modules/mu/clouds/google/habitat.rb +177 -52
  155. data/modules/mu/clouds/google/loadbalancer.rb +9 -34
  156. data/modules/mu/clouds/google/role.rb +1211 -0
  157. data/modules/mu/clouds/google/server.rb +491 -227
  158. data/modules/mu/clouds/google/server_pool.rb +233 -48
  159. data/modules/mu/clouds/google/user.rb +479 -125
  160. data/modules/mu/clouds/google/userdata/linux.erb +3 -3
  161. data/modules/mu/clouds/google/userdata/windows.erb +9 -9
  162. data/modules/mu/clouds/google/vpc.rb +381 -223
  163. data/modules/mu/config.rb +689 -214
  164. data/modules/mu/config/bucket.rb +1 -1
  165. data/modules/mu/config/cache_cluster.rb +1 -1
  166. data/modules/mu/config/cache_cluster.yml +0 -4
  167. data/modules/mu/config/container_cluster.rb +18 -9
  168. data/modules/mu/config/database.rb +6 -23
  169. data/modules/mu/config/firewall_rule.rb +9 -15
  170. data/modules/mu/config/folder.rb +22 -21
  171. data/modules/mu/config/habitat.rb +22 -21
  172. data/modules/mu/config/loadbalancer.rb +2 -2
  173. data/modules/mu/config/role.rb +9 -40
  174. data/modules/mu/config/server.rb +26 -5
  175. data/modules/mu/config/server_pool.rb +1 -1
  176. data/modules/mu/config/storage_pool.rb +2 -2
  177. data/modules/mu/config/user.rb +4 -0
  178. data/modules/mu/config/vpc.rb +350 -110
  179. data/modules/mu/defaults/{amazon_images.yaml → AWS.yaml} +37 -39
  180. data/modules/mu/defaults/Azure.yaml +17 -0
  181. data/modules/mu/defaults/Google.yaml +24 -0
  182. data/modules/mu/defaults/README.md +1 -1
  183. data/modules/mu/deploy.rb +168 -125
  184. data/modules/mu/groomer.rb +2 -1
  185. data/modules/mu/groomers/ansible.rb +104 -32
  186. data/modules/mu/groomers/chef.rb +96 -44
  187. data/modules/mu/kittens.rb +20602 -0
  188. data/modules/mu/logger.rb +38 -11
  189. data/modules/mu/master.rb +90 -8
  190. data/modules/mu/master/chef.rb +2 -3
  191. data/modules/mu/master/ldap.rb +0 -1
  192. data/modules/mu/master/ssl.rb +250 -0
  193. data/modules/mu/mommacat.rb +917 -513
  194. data/modules/scratchpad.erb +1 -1
  195. data/modules/tests/super_complex_bok.yml +0 -0
  196. data/modules/tests/super_simple_bok.yml +0 -0
  197. data/roles/mu-master.json +2 -1
  198. data/spec/azure_creds +5 -0
  199. data/spec/mu.yaml +56 -0
  200. data/spec/mu/clouds/azure_spec.rb +164 -27
  201. data/spec/spec_helper.rb +5 -0
  202. data/test/clean_up.py +0 -0
  203. data/test/exec_inspec.py +0 -0
  204. data/test/exec_mu_install.py +0 -0
  205. data/test/exec_retry.py +0 -0
  206. data/test/smoke_test.rb +0 -0
  207. metadata +90 -118
  208. data/cookbooks/mu-jenkins/Berksfile +0 -14
  209. data/cookbooks/mu-jenkins/CHANGELOG.md +0 -13
  210. data/cookbooks/mu-jenkins/LICENSE +0 -37
  211. data/cookbooks/mu-jenkins/README.md +0 -105
  212. data/cookbooks/mu-jenkins/attributes/default.rb +0 -42
  213. data/cookbooks/mu-jenkins/files/default/cleanup_deploy_config.xml +0 -73
  214. data/cookbooks/mu-jenkins/files/default/deploy_config.xml +0 -44
  215. data/cookbooks/mu-jenkins/metadata.rb +0 -21
  216. data/cookbooks/mu-jenkins/recipes/default.rb +0 -195
  217. data/cookbooks/mu-jenkins/recipes/node-ssh-config.rb +0 -54
  218. data/cookbooks/mu-jenkins/recipes/public_key.rb +0 -24
  219. data/cookbooks/mu-jenkins/templates/default/example_job.config.xml.erb +0 -24
  220. data/cookbooks/mu-jenkins/templates/default/org.jvnet.hudson.plugins.SSHBuildWrapper.xml.erb +0 -14
  221. data/cookbooks/mu-jenkins/templates/default/ssh_config.erb +0 -6
  222. data/cookbooks/nagios/Berksfile +0 -11
  223. data/cookbooks/nagios/CHANGELOG.md +0 -589
  224. data/cookbooks/nagios/CONTRIBUTING.md +0 -11
  225. data/cookbooks/nagios/LICENSE +0 -37
  226. data/cookbooks/nagios/README.md +0 -328
  227. data/cookbooks/nagios/TESTING.md +0 -2
  228. data/cookbooks/nagios/attributes/config.rb +0 -171
  229. data/cookbooks/nagios/attributes/default.rb +0 -228
  230. data/cookbooks/nagios/chefignore +0 -102
  231. data/cookbooks/nagios/definitions/command.rb +0 -33
  232. data/cookbooks/nagios/definitions/contact.rb +0 -33
  233. data/cookbooks/nagios/definitions/contactgroup.rb +0 -33
  234. data/cookbooks/nagios/definitions/host.rb +0 -33
  235. data/cookbooks/nagios/definitions/hostdependency.rb +0 -33
  236. data/cookbooks/nagios/definitions/hostescalation.rb +0 -34
  237. data/cookbooks/nagios/definitions/hostgroup.rb +0 -33
  238. data/cookbooks/nagios/definitions/nagios_conf.rb +0 -38
  239. data/cookbooks/nagios/definitions/resource.rb +0 -33
  240. data/cookbooks/nagios/definitions/service.rb +0 -33
  241. data/cookbooks/nagios/definitions/servicedependency.rb +0 -33
  242. data/cookbooks/nagios/definitions/serviceescalation.rb +0 -34
  243. data/cookbooks/nagios/definitions/servicegroup.rb +0 -33
  244. data/cookbooks/nagios/definitions/timeperiod.rb +0 -33
  245. data/cookbooks/nagios/libraries/base.rb +0 -314
  246. data/cookbooks/nagios/libraries/command.rb +0 -91
  247. data/cookbooks/nagios/libraries/contact.rb +0 -230
  248. data/cookbooks/nagios/libraries/contactgroup.rb +0 -112
  249. data/cookbooks/nagios/libraries/custom_option.rb +0 -36
  250. data/cookbooks/nagios/libraries/data_bag_helper.rb +0 -23
  251. data/cookbooks/nagios/libraries/default.rb +0 -90
  252. data/cookbooks/nagios/libraries/host.rb +0 -412
  253. data/cookbooks/nagios/libraries/hostdependency.rb +0 -181
  254. data/cookbooks/nagios/libraries/hostescalation.rb +0 -173
  255. data/cookbooks/nagios/libraries/hostgroup.rb +0 -119
  256. data/cookbooks/nagios/libraries/nagios.rb +0 -282
  257. data/cookbooks/nagios/libraries/resource.rb +0 -59
  258. data/cookbooks/nagios/libraries/service.rb +0 -455
  259. data/cookbooks/nagios/libraries/servicedependency.rb +0 -215
  260. data/cookbooks/nagios/libraries/serviceescalation.rb +0 -195
  261. data/cookbooks/nagios/libraries/servicegroup.rb +0 -144
  262. data/cookbooks/nagios/libraries/timeperiod.rb +0 -160
  263. data/cookbooks/nagios/libraries/users_helper.rb +0 -54
  264. data/cookbooks/nagios/metadata.rb +0 -25
  265. data/cookbooks/nagios/recipes/_load_databag_config.rb +0 -153
  266. data/cookbooks/nagios/recipes/_load_default_config.rb +0 -241
  267. data/cookbooks/nagios/recipes/apache.rb +0 -48
  268. data/cookbooks/nagios/recipes/default.rb +0 -204
  269. data/cookbooks/nagios/recipes/nginx.rb +0 -82
  270. data/cookbooks/nagios/recipes/pagerduty.rb +0 -143
  271. data/cookbooks/nagios/recipes/server_package.rb +0 -40
  272. data/cookbooks/nagios/recipes/server_source.rb +0 -164
  273. data/cookbooks/nagios/templates/default/apache2.conf.erb +0 -96
  274. data/cookbooks/nagios/templates/default/cgi.cfg.erb +0 -266
  275. data/cookbooks/nagios/templates/default/commands.cfg.erb +0 -13
  276. data/cookbooks/nagios/templates/default/contacts.cfg.erb +0 -37
  277. data/cookbooks/nagios/templates/default/hostgroups.cfg.erb +0 -25
  278. data/cookbooks/nagios/templates/default/hosts.cfg.erb +0 -15
  279. data/cookbooks/nagios/templates/default/htpasswd.users.erb +0 -6
  280. data/cookbooks/nagios/templates/default/nagios.cfg.erb +0 -22
  281. data/cookbooks/nagios/templates/default/nginx.conf.erb +0 -62
  282. data/cookbooks/nagios/templates/default/pagerduty.cgi.erb +0 -185
  283. data/cookbooks/nagios/templates/default/resource.cfg.erb +0 -27
  284. data/cookbooks/nagios/templates/default/servicedependencies.cfg.erb +0 -15
  285. data/cookbooks/nagios/templates/default/servicegroups.cfg.erb +0 -14
  286. data/cookbooks/nagios/templates/default/services.cfg.erb +0 -14
  287. data/cookbooks/nagios/templates/default/templates.cfg.erb +0 -31
  288. data/cookbooks/nagios/templates/default/timeperiods.cfg.erb +0 -13
  289. data/extras/image-generators/aws/centos6.yaml +0 -18
  290. data/modules/mu/defaults/google_images.yaml +0 -16
  291. data/roles/mu-master-jenkins.json +0 -24
@@ -19,38 +19,22 @@ module MU
19
19
  class AWS
20
20
  # A database as configured in {MU::Config::BasketofKittens::databases}
21
21
  class Database < MU::Cloud::Database
22
- @deploy = nil
23
- @config = nil
24
- attr_reader :mu_name
25
- attr_reader :cloud_id
26
- attr_reader :config
27
- attr_reader :groomer
28
-
29
- @cloudformation_data = {}
30
- attr_reader :cloudformation_data
31
-
32
- # @param mommacat [MU::MommaCat]: A {MU::Mommacat} object containing the deploy of which this resource is/will be a member.
33
- # @param kitten_cfg [Hash]: The fully parsed and resolved {MU::Config} resource descriptor as defined in {MU::Config::BasketofKittens::databases}
34
- def initialize(mommacat: nil, kitten_cfg: nil, mu_name: nil, cloud_id: nil)
35
- @deploy = mommacat
36
- @config = MU::Config.manxify(kitten_cfg)
37
- @cloud_id ||= cloud_id
38
- # @mu_name = mu_name ? mu_name : @deploy.getResourceName(@config["name"])
22
+
23
+ # Initialize this cloud resource object. Calling +super+ will invoke the initializer defined under {MU::Cloud}, which should set the attribtues listed in {MU::Cloud::PUBLIC_ATTRS} as well as applicable dependency shortcuts, like +@vpc+, for us.
24
+ # @param args [Hash]: Hash of named arguments passed via Ruby's double-splat
25
+ def initialize(**args)
26
+ super
39
27
  @config["groomer"] = MU::Config.defaultGroomer unless @config["groomer"]
40
28
  @groomclass = MU::Groomer.loadGroomer(@config["groomer"])
41
29
 
42
- if !mu_name.nil?
43
- @mu_name = mu_name
44
- else
45
- @mu_name ||=
46
- if @config and @config['engine'] and @config["engine"].match(/^sqlserver/)
47
- @deploy.getResourceName(@config["name"], max_length: 15)
48
- else
49
- @deploy.getResourceName(@config["name"], max_length: 63)
50
- end
30
+ @mu_name ||=
31
+ if @config and @config['engine'] and @config["engine"].match(/^sqlserver/)
32
+ @deploy.getResourceName(@config["name"], max_length: 15)
33
+ else
34
+ @deploy.getResourceName(@config["name"], max_length: 63)
35
+ end
51
36
 
52
- @mu_name.gsub(/(--|-$)/i, "").gsub(/(_)/, "-").gsub!(/^[^a-z]/i, "")
53
- end
37
+ @mu_name.gsub(/(--|-$)/i, "").gsub(/(_)/, "-").gsub!(/^[^a-z]/i, "")
54
38
  end
55
39
 
56
40
  # Called automatically by {MU::Deploy#createResources}
@@ -189,8 +173,8 @@ module MU
189
173
  def self.find(cloud_id: nil, region: MU.curRegion, tag_key: "Name", tag_value: nil, credentials: nil, flags: {})
190
174
  map = {}
191
175
  if cloud_id
192
- db = MU::Cloud::AWS::Database.getDatabaseById(cloud_id, region: region, credentials: credentials)
193
- map[cloud_id] = db if db
176
+ resp = MU::Cloud::AWS::Database.getDatabaseById(cloud_id, region: region, credentials: credentials)
177
+ map[cloud_id] = resp if resp
194
178
  end
195
179
 
196
180
  if tag_value
@@ -312,6 +296,7 @@ module MU
312
296
 
313
297
  if %w{existing_snapshot new_snapshot}.include?(@config["creation_style"])
314
298
  config[:db_snapshot_identifier] = @config["snapshot_id"]
299
+ config[:db_cluster_identifier] = @config["cluster_identifier"] if @config["add_cluster_node"]
315
300
  end
316
301
 
317
302
  if @config["creation_style"] == "point_in_time"
@@ -384,11 +369,11 @@ module MU
384
369
  MU::Cloud::AWS.rds(region: @config['region'], credentials: @config['credentials']).wait_until(:db_instance_available, db_instance_identifier: @config['identifier']) do |waiter|
385
370
  # Does create_db_instance implement wait_until_available ?
386
371
  waiter.max_attempts = nil
387
- waiter.before_attempt do |attempts|
388
- MU.log "Waiting for RDS database #{@config['identifier']} to be ready..", MU::NOTICE if attempts % 10 == 0
372
+ waiter.before_attempt do |w_attempts|
373
+ MU.log "Waiting for RDS database #{@config['identifier']} to be ready..", MU::NOTICE if w_attempts % 10 == 0
389
374
  end
390
- waiter.before_wait do |attempts, resp|
391
- throw :success if resp.db_instances.first.db_instance_status == "available"
375
+ waiter.before_wait do |w_attempts, r|
376
+ throw :success if r.db_instances.first.db_instance_status == "available"
392
377
  throw :failure if Time.now - wait_start_time > 3600
393
378
  end
394
379
  end
@@ -453,11 +438,11 @@ module MU
453
438
  MU::Cloud::AWS.rds(region: @config['region'], credentials: @config['credentials']).wait_until(:db_instance_available, db_instance_identifier: @config['identifier']) do |waiter|
454
439
  # Does create_db_instance implement wait_until_available ?
455
440
  waiter.max_attempts = nil
456
- waiter.before_attempt do |attempts|
457
- MU.log "Waiting for RDS database #{@config['identifier'] } to be ready..", MU::NOTICE if attempts % 10 == 0
441
+ waiter.before_attempt do |w_attempts|
442
+ MU.log "Waiting for RDS database #{@config['identifier'] } to be ready..", MU::NOTICE if w_attempts % 10 == 0
458
443
  end
459
- waiter.before_wait do |attempts, resp|
460
- throw :success if resp.db_instances.first.db_instance_status == "available"
444
+ waiter.before_wait do |w_attempts, r|
445
+ throw :success if r.db_instances.first.db_instance_status == "available"
461
446
  throw :failure if Time.now - wait_start_time > 2400
462
447
  end
463
448
  end
@@ -532,6 +517,10 @@ module MU
532
517
  cluster_config_struct[:use_latest_restorable_time] = true if @config["restore_time"] == "latest"
533
518
  end
534
519
 
520
+ if @config['cloudwatch_logs']
521
+ cluster_config_struct[:enable_cloudwatch_logs_exports ] = @config['cloudwatch_logs']
522
+ end
523
+
535
524
  attempts = 0
536
525
  begin
537
526
  resp =
@@ -655,8 +644,8 @@ module MU
655
644
  }
656
645
 
657
646
  @config['vpc'] = {
658
- "vpc_id" => vpc_id,
659
- "subnets" => mu_subnets
647
+ "vpc_id" => vpc_id,
648
+ "subnets" => mu_subnets
660
649
  }
661
650
  # Default VPC has only public subnets by default so setting publicly_accessible = true
662
651
  @config["publicly_accessible"] = true
@@ -798,7 +787,15 @@ module MU
798
787
 
799
788
  # Called automatically by {MU::Deploy#createResources}
800
789
  def groom
801
- unless @config["create_cluster"]
790
+ if @config["create_cluster"]
791
+ @config['cluster_node_count'] ||= 1
792
+ if @config['cluster_mode'] == "serverless"
793
+ MU::Cloud::AWS.rds(region: @config['region'], credentials: @config['credentials']).modify_current_db_cluster_capacity(
794
+ db_cluster_identifier: @cloud_id,
795
+ capacity: @config['cluster_node_count']
796
+ )
797
+ end
798
+ else
802
799
  database = MU::Cloud::AWS::Database.getDatabaseById(@config['identifier'], region: @config['region'], credentials: @config['credentials'])
803
800
 
804
801
  # Run SQL on deploy
@@ -1428,18 +1425,31 @@ module MU
1428
1425
  }
1429
1426
  }
1430
1427
 
1428
+
1431
1429
  schema = {
1432
1430
  "db_parameter_group_parameters" => rds_parameters_primitive,
1433
1431
  "cluster_parameter_group_parameters" => rds_parameters_primitive,
1432
+ "parameter_group_family" => {
1433
+ "type" => "String",
1434
+ "description" => "An RDS parameter group family. See also https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_WorkingWithParamGroups.html"
1435
+ },
1434
1436
  "cluster_mode" => {
1435
1437
  "type" => "string",
1436
1438
  "description" => "The DB engine mode of the DB cluster",
1437
1439
  "enum" => ["provisioned", "serverless", "parallelquery", "global"],
1438
1440
  "default" => "provisioned"
1439
1441
  },
1442
+ "cloudwatch_logs" => {
1443
+ "type" => "array",
1444
+ "default" => ["error"],
1445
+ "items" => {
1446
+ "type" => "string",
1447
+ "enum" => ["error", "general", "audit", "slow_query"],
1448
+ }
1449
+ },
1440
1450
  "serverless_scaling" => {
1441
1451
  "type" => "object",
1442
- "descriptions" => "Scaling configuration for a +serverless+ Aurora cluster",
1452
+ "description" => "Scaling configuration for a +serverless+ Aurora cluster",
1443
1453
  "default" => {
1444
1454
  "auto_pause" => false,
1445
1455
  "min_capacity" => 2,
@@ -1505,10 +1515,45 @@ module MU
1505
1515
  def self.validateConfig(db, configurator)
1506
1516
  ok = true
1507
1517
 
1518
+ if db['creation_style'] == "existing_snapshot" and
1519
+ !db['create_cluster'] and
1520
+ db['identifier'] and db['identifier'].match(/:cluster-snapshot:/)
1521
+ MU.log "Database #{db['name']}: Existing snapshot #{db['identifier']} looks like a cluster snapshot, but create_cluster is not set. Add 'create_cluster: true' if you're building an RDS cluster.", MU::ERR
1522
+ ok = false
1523
+ end
1524
+
1525
+ pgroup_families = []
1526
+ engines = {}
1527
+
1528
+ marker = nil
1529
+ begin
1530
+ resp = MU::Cloud::AWS.rds(credentials: db['credentials'], region: db['region']).describe_db_engine_versions(marker: marker)
1531
+ marker = resp.marker
1532
+
1533
+ if resp and resp.db_engine_versions
1534
+ resp.db_engine_versions.each { |version|
1535
+ engines[version.engine] ||= {
1536
+ "versions" => [],
1537
+ "families" => []
1538
+ }
1539
+ engines[version.engine]['versions'] << version.engine_version
1540
+ engines[version.engine]['families'] << version.db_parameter_group_family
1541
+
1542
+ }
1543
+ engines.keys.each { |engine|
1544
+ engines[engine]["versions"].uniq!
1545
+ engines[engine]["families"].uniq!
1546
+ }
1547
+
1548
+ else
1549
+ MU.log "Failed to get list of valid RDS engine versions in #{db['region']}, proceeding without proper validation", MU::WARN
1550
+ end
1551
+ end while !marker.nil?
1552
+
1508
1553
  if db['create_cluster'] or db['engine'] == "aurora" or db["member_of_cluster"]
1509
1554
  case db['engine']
1510
1555
  when "mysql", "aurora", "aurora-mysql"
1511
- if db["engine_version"] == "5.6" or db["cluster_mode"] == "serverless"
1556
+ if db["engine_version"].match(/^5\.6/) or db["cluster_mode"] == "serverless"
1512
1557
  db["engine"] = "aurora"
1513
1558
  else
1514
1559
  db["engine"] = "aurora-mysql"
@@ -1517,10 +1562,40 @@ module MU
1517
1562
  db["engine"] = "aurora-postgresql"
1518
1563
  else
1519
1564
  ok = false
1520
- MU.log "Requested a clustered database, but engine #{db['engine']} is not supported for clustering", MU::ERR
1565
+ MU.log "Database #{db['name']}: Requested a clustered database, but engine #{db['engine']} is not supported for clustering", MU::ERR
1521
1566
  end
1522
1567
  end
1523
1568
 
1569
+ if db['engine'].match(/^aurora/) and !db['create_cluster'] and !db['add_cluster_node']
1570
+ MU.log "Database #{db['name']}: #{db['engine']} looks like a cluster engine, but create_cluster is not set. Add 'create_cluster: true' if you're building an RDS cluster.", MU::ERR
1571
+ ok = false
1572
+ end
1573
+
1574
+ if engines.size > 0
1575
+ if !engines[db['engine']]
1576
+ MU.log "RDS engine #{db['engine']} is not supported in #{db['region']}", MU::ERR, details: engines.keys.sort
1577
+ ok = false
1578
+ else
1579
+ if db["engine_version"] and
1580
+ engines[db['engine']]['versions'].size > 0 and
1581
+ !engines[db['engine']]['versions'].include?(db['engine_version']) and
1582
+ !engines[db['engine']]['versions'].grep(/^#{Regexp.quote(db["engine_version"])}.+/)
1583
+ MU.log "RDS engine '#{db['engine']}' version '#{db['engine_version']}' is not supported in #{db['region']}", MU::ERR, details: { "Known-good versions:" => engines[db['engine']]['versions'].uniq.sort }
1584
+ ok = false
1585
+ end
1586
+ if db["parameter_group_family"] and
1587
+ engines[db['engine']]['families'].size > 0 and
1588
+ !engines[db['engine']]['families'].include?(db['parameter_group_family'])
1589
+ MU.log "RDS engine '#{db['engine']}' parameter group family '#{db['parameter_group_family']}' is not supported in #{db['region']}", MU::ERR, details: { "Valid parameter families:" => engines[db['engine']]['families'].uniq.sort }
1590
+ ok = false
1591
+ end
1592
+ end
1593
+ end
1594
+
1595
+ if db['parameter_group_family'] and pgroup_families.size > 0 and
1596
+ !pgroup_families.include?(db['parameter_group_family'])
1597
+ end
1598
+
1524
1599
  db["license_model"] ||=
1525
1600
  if ["postgres", "postgresql", "aurora-postgresql"].include?(db["engine"])
1526
1601
  "postgresql-license"
@@ -1605,7 +1680,7 @@ module MU
1605
1680
  end
1606
1681
 
1607
1682
  if db["vpc"]
1608
- if db["vpc"]["subnet_pref"] == "all_public" and !db['publicly_accessible']
1683
+ if db["vpc"]["subnet_pref"] == "all_public" and !db['publicly_accessible'] and (db["vpc"]['subnets'].nil? or db["vpc"]['subnets'].empty?)
1609
1684
  MU.log "Setting publicly_accessible to true on database '#{db['name']}', since deploying into public subnets.", MU::WARN
1610
1685
  db['publicly_accessible'] = true
1611
1686
  elsif db["vpc"]["subnet_pref"] == "all_private" and db['publicly_accessible']
@@ -19,22 +19,11 @@ module MU
19
19
  # A DNS Zone as configured in {MU::Config::BasketofKittens::dnszones}
20
20
  class DNSZone < MU::Cloud::DNSZone
21
21
 
22
- @config = nil
23
- attr_reader :mu_name
24
- attr_reader :cloud_id
25
- attr_reader :config
26
-
27
- @cloudformation_data = {}
28
- attr_reader :cloudformation_data
29
-
30
- # @param mommacat [MU::MommaCat]: A {MU::Mommacat} object containing the deploy of which this resource is/will be a member.
31
- # @param kitten_cfg [Hash]: The fully parsed and resolved {MU::Config} resource descriptor as defined in {MU::Config::BasketofKittens::dnszones}
32
- def initialize(mommacat: nil, kitten_cfg: nil, mu_name: nil, cloud_id: nil)
33
- @deploy = mommacat
34
- @config = MU::Config.manxify(kitten_cfg)
35
- unless @mu_name
36
- @mu_name = mu_name ? mu_name : @deploy.getResourceName(@config["name"])
37
- end
22
+ # Initialize this cloud resource object. Calling +super+ will invoke the initializer defined under {MU::Cloud}, which should set the attribtues listed in {MU::Cloud::PUBLIC_ATTRS} as well as applicable dependency shortcuts, like +@vpc+, for us.
23
+ # @param args [Hash]: Hash of named arguments passed via Ruby's double-splat
24
+ def initialize(**args)
25
+ super
26
+ @mu_name ||= @deploy.getResourceName(@config["name"])
38
27
 
39
28
  MU.setVar("curRegion", @config['region']) if !@config['region'].nil?
40
29
  end
@@ -399,8 +388,8 @@ module MU
399
388
  if !alias_zone.nil?
400
389
  target_zone = "/hostedzone/"+alias_zone if !alias_zone.match(/^\/hostedzone\//)
401
390
  else
402
- MU::Cloud::AWS.listRegions.each { |region|
403
- MU::Cloud::AWS.elb(region: region).describe_load_balancers.load_balancer_descriptions.each { |elb|
391
+ MU::Cloud::AWS.listRegions.each { |r|
392
+ MU::Cloud::AWS.elb(region: r).describe_load_balancers.load_balancer_descriptions.each { |elb|
404
393
  elb_dns = elb.dns_name.downcase
405
394
  elb_dns.chomp!(".")
406
395
  if target_name == elb_dns
@@ -3,21 +3,11 @@ module MU
3
3
  class AWS
4
4
  # An API as configured in {MU::Config::BasketofKittens::endpoints}
5
5
  class Endpoint < MU::Cloud::Endpoint
6
- @deploy = nil
7
- @config = nil
8
- attr_reader :mu_name
9
- attr_reader :config
10
- attr_reader :cloud_id
11
-
12
- @cloudformation_data = {}
13
- attr_reader :cloudformation_data
14
-
15
- # @param mommacat [MU::MommaCat]: A {MU::Mommacat} object containing the deploy of which this resource is/will be a member.
16
- # @param kitten_cfg [Hash]: The fully parsed and resolved {MU::Config} resource descriptor as defined in {MU::Config::BasketofKittens::endpoints}
17
- def initialize(mommacat: nil, kitten_cfg: nil, mu_name: nil, cloud_id: nil)
18
- @deploy = mommacat
19
- @config = MU::Config.manxify(kitten_cfg)
20
- @cloud_id ||= cloud_id
6
+
7
+ # Initialize this cloud resource object. Calling +super+ will invoke the initializer defined under {MU::Cloud}, which should set the attribtues listed in {MU::Cloud::PUBLIC_ATTRS} as well as applicable dependency shortcuts, like +@vpc+, for us.
8
+ # @param args [Hash]: Hash of named arguments passed via Ruby's double-splat
9
+ def initialize(**args)
10
+ super
21
11
  @mu_name ||= @deploy.getResourceName(@config["name"])
22
12
  end
23
13
 
@@ -18,30 +18,19 @@ module MU
18
18
  class AWS
19
19
  # A firewall ruleset as configured in {MU::Config::BasketofKittens::firewall_rules}
20
20
  class FirewallRule < MU::Cloud::FirewallRule
21
+ require "mu/clouds/aws/vpc"
21
22
 
22
- @deploy = nil
23
- @config = nil
24
23
  @admin_sgs = Hash.new
25
24
  @admin_sg_semaphore = Mutex.new
26
25
 
27
- attr_reader :mu_name
28
- attr_reader :config
29
- attr_reader :cloud_id
30
-
31
- # @param mommacat [MU::MommaCat]: A {MU::Mommacat} object containing the deploy of which this resource is/will be a member.
32
- # @param kitten_cfg [Hash]: The fully parsed and resolved {MU::Config} resource descriptor as defined in {MU::Config::BasketofKittens::firewall_rules}
33
- def initialize(mommacat: nil, kitten_cfg: nil, mu_name: nil, cloud_id: nil)
34
- @deploy = mommacat
35
- @config = MU::Config.manxify(kitten_cfg)
36
- @cloud_id ||= cloud_id
37
- if !mu_name.nil?
38
- @mu_name = mu_name
26
+ # Initialize this cloud resource object. Calling +super+ will invoke the initializer defined under {MU::Cloud}, which should set the attribtues listed in {MU::Cloud::PUBLIC_ATTRS} as well as applicable dependency shortcuts, like +@vpc+, for us.
27
+ # @param args [Hash]: Hash of named arguments passed via Ruby's double-splat
28
+ def initialize(**args)
29
+ super
30
+ if !@vpc.nil?
31
+ @mu_name ||= @deploy.getResourceName(@config['name'], need_unique_string: true)
39
32
  else
40
- if !@vpc.nil?
41
- @mu_name = @deploy.getResourceName(@config['name'], need_unique_string: true)
42
- else
43
- @mu_name = @deploy.getResourceName(@config['name'])
44
- end
33
+ @mu_name ||= @deploy.getResourceName(@config['name'])
45
34
  end
46
35
 
47
36
  end
@@ -86,7 +75,7 @@ module MU
86
75
  retry
87
76
  end
88
77
 
89
- MU::MommaCat.createStandardTags(secgroup.group_id, region: @config['region'], credentials: @config['credentials'])
78
+ MU::Cloud::AWS.createStandardTags(secgroup.group_id, region: @config['region'], credentials: @config['credentials'])
90
79
  MU::MommaCat.createTag(secgroup.group_id, "Name", groupname, region: @config['region'], credentials: @config['credentials'])
91
80
 
92
81
  if @config['optional_tags']
@@ -170,7 +159,6 @@ module MU
170
159
  else
171
160
  rule["port_range"] = port_range
172
161
  end
173
- rule["description"] = comment if comment
174
162
  ec2_rule = convertToEc2([rule])
175
163
 
176
164
  begin
@@ -212,32 +200,27 @@ module MU
212
200
  end
213
201
 
214
202
  # Locate an existing security group or groups and return an array containing matching AWS resource descriptors for those that match.
215
- # @param cloud_id [String]: The cloud provider's identifier for this resource.
216
- # @param region [String]: The cloud provider region
217
- # @param tag_key [String]: A tag key to search.
218
- # @param tag_value [String]: The value of the tag specified by tag_key to match when searching by tag.
219
- # @param flags [Hash]: Optional flags
220
203
  # @return [Array<Hash<String,OpenStruct>>]: The cloud provider's complete descriptions of matching FirewallRules
221
- def self.find(cloud_id: nil, region: MU.curRegion, tag_key: "Name", tag_value: nil, credentials: nil, flags: {})
204
+ def self.find(**args)
222
205
 
223
- if !cloud_id.nil? and !cloud_id.empty?
206
+ if !args[:cloud_id].nil? and !args[:cloud_id].empty?
224
207
  begin
225
- resp = MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_security_groups(group_ids: [cloud_id])
226
- return {cloud_id => resp.data.security_groups.first}
208
+ resp = MU::Cloud::AWS.ec2(region: args[:region], credentials: args[:credentials]).describe_security_groups(group_ids: [args[:cloud_id]])
209
+ return {args[:cloud_id] => resp.data.security_groups.first}
227
210
  rescue ArgumentError => e
228
- MU.log "Attempting to load #{cloud_id}: #{e.inspect}", MU::WARN, details: caller
211
+ MU.log "Attempting to load #{args[:cloud_id]}: #{e.inspect}", MU::WARN, details: caller
229
212
  return {}
230
213
  rescue Aws::EC2::Errors::InvalidGroupNotFound => e
231
- MU.log "Attempting to load #{cloud_id}: #{e.inspect}", MU::DEBUG, details: caller
214
+ MU.log "Attempting to load #{args[:cloud_id]}: #{e.inspect}", MU::DEBUG, details: caller
232
215
  return {}
233
216
  end
234
217
  end
235
218
 
236
219
  map = {}
237
- if !tag_key.nil? and !tag_value.nil?
238
- resp = MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_security_groups(
220
+ if !args[:tag_key].nil? and !args[:tag_value].nil?
221
+ resp = MU::Cloud::AWS.ec2(region: args[:region], credentials: args[:credentials]).describe_security_groups(
239
222
  filters: [
240
- {name: "tag:#{tag_key}", values: [tag_value]}
223
+ {name: "tag:#{args[:tag_key]}", values: [args[:tag_value]]}
241
224
  ]
242
225
  )
243
226
  if !resp.nil?
@@ -269,19 +252,26 @@ module MU
269
252
  # @param region [String]: The cloud provider region
270
253
  # @return [void]
271
254
  def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
272
- tagfilters = [
255
+ filters = nil
256
+ if flags and flags["vpc_id"]
257
+ filters = [
258
+ {name: "vpc-id", values: [flags["vpc_id"]]}
259
+ ]
260
+ else
261
+ filters = [
273
262
  {name: "tag:MU-ID", values: [MU.deploy_id]}
274
- ]
275
- if !ignoremaster
276
- tagfilters << {name: "tag:MU-MASTER-IP", values: [MU.mu_public_ip]}
263
+ ]
264
+ if !ignoremaster
265
+ filters << {name: "tag:MU-MASTER-IP", values: [MU.mu_public_ip]}
266
+ end
277
267
  end
278
268
 
279
269
  # Some services create sneaky rogue ENIs which then block removal of
280
270
  # associated security groups. Find them and fry them.
281
- MU::Cloud::AWS::VPC.purge_interfaces(noop, tagfilters, region: region, credentials: credentials)
271
+ MU::Cloud::AWS::VPC.purge_interfaces(noop, filters, region: region, credentials: credentials)
282
272
 
283
273
  resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_security_groups(
284
- filters: tagfilters
274
+ filters: filters
285
275
  )
286
276
 
287
277
  resp.data.security_groups.each { |sg|
@@ -361,11 +351,14 @@ module MU
361
351
  }
362
352
 
363
353
  resp.data.security_groups.each { |sg|
354
+ next if sg.group_name == "default"
364
355
  MU.log "Removing EC2 Security Group #{sg.group_name}"
365
356
 
366
357
  retries = 0
367
358
  begin
368
359
  MU::Cloud::AWS.ec2(credentials: credentials, region: region).delete_security_group(group_id: sg.group_id) if !noop
360
+ rescue Aws::EC2::Errors::CannotDelete => e
361
+ MU.log e.message, MU::WARN
369
362
  rescue Aws::EC2::Errors::InvalidGroupNotFound
370
363
  MU.log "EC2 Security Group #{sg.group_name} disappeared before I could delete it!", MU::WARN
371
364
  rescue Aws::EC2::Errors::DependencyViolation, Aws::EC2::Errors::InvalidGroupInUse
@@ -488,28 +481,109 @@ module MU
488
481
  end
489
482
 
490
483
  ec2_rules = convertToEc2(rules)
484
+ ext_permissions = MU.structToHash(cloud_desc.ip_permissions)
485
+
486
+ # Purge any old rules that we're sure we created (check the comment)
487
+ # but which are no longer configured.
488
+ ext_permissions.each { |ext_rule|
489
+ haverule = false
490
+ ec2_rules.each { |rule|
491
+ if rule[:from_port] == ext_rule[:from_port] and
492
+ rule[:to_port] == ext_rule[:to_port] and
493
+ rule[:ip_protocol] == ext_rule[:ip_protocol]
494
+ haverule = true
495
+ break
496
+ end
497
+ }
498
+ next if haverule
499
+
500
+ mu_comments = false
501
+ (ext_rule[:user_id_group_pairs] + ext_rule[:ip_ranges]).each { |entry|
502
+ if entry[:description] == "Added by Mu"
503
+ mu_comments = true
504
+ else
505
+ mu_comments = false
506
+ break
507
+ end
508
+ }
509
+
510
+ if mu_comments
511
+ ext_rule.keys.each { |k|
512
+ if ext_rule[k].nil? or ext_rule[k] == []
513
+ ext_rule.delete(k)
514
+ end
515
+ }
516
+ MU.log "Removing unconfigured rule in #{@mu_name}", MU::WARN, details: ext_rule
517
+ MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).revoke_security_group_ingress(
518
+ group_id: @cloud_id,
519
+ ip_permissions: [ext_rule]
520
+ )
521
+ end
522
+
523
+ }
491
524
 
492
525
  # Creating an empty security group is ok, so don't freak out if we get
493
526
  # a null rule list.
494
527
  if !ec2_rules.nil?
495
528
  ec2_rules.uniq!
496
- MU.log "Setting rules in Security Group #{@mu_name} (#{@cloud_id})", details: ec2_rules
497
529
  retries = 0
498
- if rules != nil
499
- MU.log "Rules for EC2 Security Group #{@mu_name} (#{@cloud_id}): #{ec2_rules}", MU::DEBUG
530
+ ec2_rules.each { |rule|
531
+ haverule = nil
532
+ different = false
533
+ ext_permissions.each { |ext_rule|
534
+ if rule[:from_port] == ext_rule[:from_port] and
535
+ rule[:to_port] == ext_rule[:to_port] and
536
+ rule[:ip_protocol] == ext_rule[:ip_protocol]
537
+ haverule = ext_rule
538
+ ext_rule.keys.each { |k|
539
+ if ext_rule[k].nil? or ext_rule[k] == []
540
+ haverule.delete(k)
541
+ end
542
+ different = true if rule[k] != ext_rule[k]
543
+ }
544
+ break
545
+ end
546
+ }
547
+ if haverule and !different
548
+ MU.log "Security Group rule already up-to-date in #{@mu_name}", MU::DEBUG, details: rule
549
+ next
550
+ end
551
+
552
+ MU.log "Setting #{ingress ? "ingress" : "egress"} rule in Security Group #{@mu_name} (#{@cloud_id})", MU::NOTICE, details: rule
500
553
  begin
554
+
501
555
  if ingress
556
+ if haverule
557
+ begin
558
+ MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).revoke_security_group_ingress(
559
+ group_id: @cloud_id,
560
+ ip_permissions: [haverule]
561
+ )
562
+ rescue Aws::EC2::Errors::InvalidPermissionNotFound => e
563
+ end
564
+ end
502
565
  MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).authorize_security_group_ingress(
503
- group_id: @cloud_id,
504
- ip_permissions: ec2_rules
566
+ group_id: @cloud_id,
567
+ ip_permissions: [rule]
505
568
  )
506
569
  end
570
+
507
571
  if egress
572
+ if haverule
573
+ begin
574
+ MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).revoke_security_group_egress(
575
+ group_id: @cloud_id,
576
+ ip_permissions: [haverule]
577
+ )
578
+ rescue Aws::EC2::Errors::InvalidPermissionNotFound => e
579
+ end
580
+ end
508
581
  MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).authorize_security_group_egress(
509
- group_id: @cloud_id,
510
- ip_permissions: ec2_rules
582
+ group_id: @cloud_id,
583
+ ip_permissions: [rule]
511
584
  )
512
585
  end
586
+
513
587
  rescue Aws::EC2::Errors::InvalidGroupNotFound => e
514
588
  MU.log "#{@mu_name} (#{@cloud_id}) does not yet exist", MU::WARN
515
589
  retries = retries + 1
@@ -520,9 +594,9 @@ module MU
520
594
  raise MuError, "#{@mu_name} does not exist", e.backtrace
521
595
  end
522
596
  rescue Aws::EC2::Errors::InvalidPermissionDuplicate => e
523
- MU.log "Attempt to add duplicate rule to #{@mu_name}", MU::DEBUG, details: ec2_rules
597
+ MU.log "Attempt to add duplicate rule to #{@mu_name}", MU::DEBUG, details: rule
524
598
  end
525
- end
599
+ }
526
600
  end
527
601
 
528
602
  end
@@ -538,6 +612,8 @@ module MU
538
612
 
539
613
  rules.each { |rule|
540
614
  ec2_rule = {}
615
+ rule["comment"] ||= "Added by Mu"
616
+
541
617
 
542
618
  rule['proto'] ||= "tcp"
543
619
  ec2_rule[:ip_protocol] = rule['proto']
@@ -564,9 +640,9 @@ module MU
564
640
  end
565
641
 
566
642
  if (!defined? rule['hosts'] or !rule['hosts'].is_a?(Array)) and
567
- (!defined? rule['sgs'] or !rule['sgs'].is_a?(Array)) and
568
- (!defined? rule['lbs'] or !rule['lbs'].is_a?(Array))
569
- raise MuError, "One of 'hosts', 'sgs', or 'lbs' in rules provided to createEc2SG must be an array."
643
+ (!defined? rule['sgs'] or !rule['sgs'].is_a?(Array)) and
644
+ (!defined? rule['lbs'] or !rule['lbs'].is_a?(Array))
645
+ rule['hosts'] = ["0.0.0.0/0"]
570
646
  end
571
647
  ec2_rule[:ip_ranges] = []
572
648
  ec2_rule[:user_id_group_pairs] = []
@@ -576,11 +652,7 @@ module MU
576
652
  rule['hosts'].each { |cidr|
577
653
  next if cidr.nil? # XXX where is that coming from?
578
654
  cidr = cidr + "/32" if cidr.match(/^\d+\.\d+\.\d+\.\d+$/)
579
- if rule['description']
580
- ec2_rule[:ip_ranges] << {cidr_ip: cidr, description: rule['description']}
581
- else
582
- ec2_rule[:ip_ranges] << {cidr_ip: cidr}
583
- end
655
+ ec2_rule[:ip_ranges] << {cidr_ip: cidr, description: rule['comment']}
584
656
  }
585
657
  end
586
658
 
@@ -627,25 +699,25 @@ module MU
627
699
  rule['sgs'].uniq!
628
700
  rule['sgs'].each { |sg_name|
629
701
  dependencies # Make sure our cache is fresh
630
- if sg_name == @config['name']
631
- sg = self
702
+ sg = @deploy.findLitterMate(type: "firewall_rule", name: sg_name) if @deploy
703
+ sg ||= if sg_name == @config['name']
704
+ self
632
705
  elsif @dependencies.has_key?("firewall_rule") and
633
706
  @dependencies["firewall_rule"].has_key?(sg_name)
634
- sg = @dependencies["firewall_rule"][sg_name]
635
- else
636
- if sg_name.match(/^sg-/)
637
- found_sgs = MU::MommaCat.findStray("AWS", "firewall_rule", cloud_id: sg_name, region: @config['region'], calling_deploy: @deploy, dummy_ok: true)
638
- else
639
- found_sgs = MU::MommaCat.findStray("AWS", "firewall_rule", name: sg_name, region: @config['region'], deploy_id: MU.deploy_id, calling_deploy: @deploy)
640
- end
641
- if found_sgs.nil? or found_sgs.size == 0
642
- raise MuError, "Attempted to reference non-existent Security Group #{sg_name} while building #{@mu_name}"
643
- end
644
- sg = found_sgs.first
707
+ @dependencies["firewall_rule"][sg_name]
708
+ elsif sg_name.match(/^sg-/)
709
+ found_sgs = MU::MommaCat.findStray("AWS", "firewall_rule", cloud_id: sg_name, region: @config['region'], calling_deploy: @deploy, dummy_ok: true)
710
+ found_sgs.first if found_sgs
645
711
  end
712
+
713
+ if sg.nil?
714
+ raise MuError, "FirewallRule #{@config['name']} referenced security group '#{sg_name}' in a rule, but I can't find it anywhere!"
715
+ end
716
+
646
717
  ec2_rule[:user_id_group_pairs] << {
647
718
  user_id: MU.account_number,
648
- group_id: sg.cloud_id
719
+ group_id: sg.cloud_id,
720
+ description: rule['comment']
649
721
  }
650
722
  }
651
723
  end