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
@@ -17,21 +17,11 @@ module MU
17
17
  class AWS
18
18
  # A search_domain as configured in {MU::Config::BasketofKittens::search_domains}
19
19
  class SearchDomain < MU::Cloud::SearchDomain
20
- @deploy = nil
21
- @config = nil
22
- attr_reader :mu_name
23
- attr_reader :config
24
- attr_reader :cloud_id
25
-
26
- @cloudformation_data = {}
27
- attr_reader :cloudformation_data
28
-
29
- # @param mommacat [MU::MommaCat]: A {MU::Mommacat} object containing the deploy of which this resource is/will be a member.
30
- # @param kitten_cfg [Hash]: The fully parsed and resolved {MU::Config} resource descriptor as defined in {MU::Config::BasketofKittens::search_domains}
31
- def initialize(mommacat: nil, kitten_cfg: nil, mu_name: nil, cloud_id: nil)
32
- @deploy = mommacat
33
- @config = MU::Config.manxify(kitten_cfg)
34
- @cloud_id ||= cloud_id
20
+
21
+ # 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.
22
+ # @param args [Hash]: Hash of named arguments passed via Ruby's double-splat
23
+ def initialize(**args)
24
+ super
35
25
  @mu_name ||= @deploy.getResourceName(@config["name"])
36
26
  end
37
27
 
@@ -180,19 +170,26 @@ module MU
180
170
  # @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource
181
171
  def self.schema(config)
182
172
  toplevel_required = ["elasticsearch_version", "instance_type"]
183
- versions = MU::Cloud::AWS.elasticsearch.list_elasticsearch_versions.elasticsearch_versions
184
- instance_types = nil
185
- begin
186
- instance_types = MU::Cloud::AWS.elasticsearch.list_elasticsearch_instance_types(
173
+
174
+ versions = begin
175
+ MU::Cloud::AWS.elasticsearch.list_elasticsearch_versions.elasticsearch_versions
176
+ rescue MuError => e
177
+ ["7.1", "6.8", "6.7", "6.5", "6.4", "6.3", "6.2", "6.0", "5.6"]
178
+ end
179
+ instance_types = begin
180
+ MU::Cloud::AWS.elasticsearch.list_elasticsearch_instance_types(
187
181
  elasticsearch_version: "6.3"
188
182
  ).elasticsearch_instance_types
183
+ rescue MuError
184
+ ["c5.large.elasticsearch", "c5.xlarge.elasticsearch", "c5.2xlarge.elasticsearch", "c5.4xlarge.elasticsearch", "c5.9xlarge.elasticsearch", "c5.18xlarge.elasticsearch", "i3.large.elasticsearch", "i3.xlarge.elasticsearch", "i3.2xlarge.elasticsearch", "i3.4xlarge.elasticsearch", "i3.8xlarge.elasticsearch", "i3.16xlarge.elasticsearch", "m5.large.elasticsearch", "m5.xlarge.elasticsearch", "m5.2xlarge.elasticsearch", "m5.4xlarge.elasticsearch", "m5.12xlarge.elasticsearch", "r5.large.elasticsearch", "r5.xlarge.elasticsearch", "r5.2xlarge.elasticsearch", "r5.4xlarge.elasticsearch", "r5.12xlarge.elasticsearch", "t2.small.elasticsearch", "t2.medium.elasticsearch", "c4.large.elasticsearch", "c4.xlarge.elasticsearch", "c4.2xlarge.elasticsearch", "c4.4xlarge.elasticsearch", "c4.8xlarge.elasticsearch", "i2.xlarge.elasticsearch", "i2.2xlarge.elasticsearch", "m4.large.elasticsearch", "m4.xlarge.elasticsearch", "m4.2xlarge.elasticsearch", "m4.4xlarge.elasticsearch", "m4.10xlarge.elasticsearch", "r4.large.elasticsearch", "r4.xlarge.elasticsearch", "r4.2xlarge.elasticsearch", "r4.4xlarge.elasticsearch", "r4.8xlarge.elasticsearch", "r4.16xlarge.elasticsearch", "m3.medium.elasticsearch", "m3.large.elasticsearch", "m3.xlarge.elasticsearch", "m3.2xlarge.elasticsearch", "r3.large.elasticsearch", "r3.xlarge.elasticsearch", "r3.2xlarge.elasticsearch", "r3.4xlarge.elasticsearch", "r3.8xlarge.elasticsearch"]
189
185
  rescue Aws::ElasticsearchService::Errors::ValidationException
190
186
  # Some regions (GovCloud) lag
191
- instance_types = MU::Cloud::AWS.elasticsearch.list_elasticsearch_instance_types(
187
+ MU::Cloud::AWS.elasticsearch.list_elasticsearch_instance_types(
192
188
  elasticsearch_version: "6.2"
193
189
  ).elasticsearch_instance_types
194
190
  end
195
191
 
192
+
196
193
  schema = {
197
194
  "name" => {
198
195
  "type" => "string",
@@ -75,31 +75,26 @@ module MU
75
75
  @ephemeral_mappings
76
76
  end
77
77
 
78
- attr_reader :mu_name
79
- attr_reader :config
80
- attr_reader :deploy
81
- attr_reader :cloud_id
82
- attr_reader :cloud_desc
83
- attr_reader :groomer
84
- attr_accessor :mu_windows_name
85
-
86
- # @param mommacat [MU::MommaCat]: A {MU::Mommacat} object containing the deploy of which this resource is/will be a member.
87
- # @param kitten_cfg [Hash]: The fully parsed and resolved {MU::Config} resource descriptor as defined in {MU::Config::BasketofKittens::servers}
88
- def initialize(mommacat: nil, kitten_cfg: nil, mu_name: nil, cloud_id: nil)
89
- @deploy = mommacat
90
- @config = MU::Config.manxify(kitten_cfg)
91
- @cloud_id = cloud_id
92
-
93
- if @deploy
94
- @userdata = MU::Cloud.fetchUserdata(
78
+ # 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.
79
+ # @param args [Hash]: Hash of named arguments passed via Ruby's double-splat
80
+ def initialize(**args)
81
+ super
82
+ @userdata = if @config['userdata_script']
83
+ @config['userdata_script']
84
+ elsif @deploy and !@config['scrub_mu_isms']
85
+ MU::Cloud.fetchUserdata(
95
86
  platform: @config["platform"],
96
- cloud: "aws",
87
+ cloud: "AWS",
88
+ credentials: @config['credentials'],
97
89
  template_variables: {
98
90
  "deployKey" => Base64.urlsafe_encode64(@deploy.public_key),
99
91
  "deploySSHKey" => @deploy.ssh_public_key,
100
92
  "muID" => MU.deploy_id,
101
93
  "muUser" => MU.mu_user,
102
94
  "publicIP" => MU.mu_public_ip,
95
+ "mommaCatPort" => MU.mommaCatPort,
96
+ "adminBucketName" => MU::Cloud::AWS.adminBucketName(@credentials),
97
+ "chefVersion" => MU.chefVersion,
103
98
  "skipApplyUpdates" => @config['skipinitialupdates'],
104
99
  "windowsAdminName" => @config['windows_admin_username'],
105
100
  "resourceName" => @config["name"],
@@ -113,10 +108,8 @@ module MU
113
108
  @disk_devices = MU::Cloud::AWS::Server.disk_devices
114
109
  @ephemeral_mappings = MU::Cloud::AWS::Server.ephemeral_mappings
115
110
 
116
- if !mu_name.nil?
117
- @mu_name = mu_name
111
+ if !@mu_name.nil?
118
112
  @config['mu_name'] = @mu_name
119
- # describe
120
113
  @mu_windows_name = @deploydata['mu_windows_name'] if @mu_windows_name.nil? and @deploydata
121
114
  else
122
115
  if kitten_cfg.has_key?("basis")
@@ -126,9 +119,8 @@ module MU
126
119
  end
127
120
  @config['mu_name'] = @mu_name
128
121
 
129
- @config['instance_secret'] = Password.random(50)
130
122
  end
131
- @groomer = MU::Groomer.new(self)
123
+ @config['instance_secret'] ||= Password.random(50)
132
124
 
133
125
  end
134
126
 
@@ -246,7 +238,7 @@ module MU
246
238
  end
247
239
  MU::MommaCat.unlock(instance.instance_id+"-create")
248
240
  else
249
- MU::MommaCat.createStandardTags(instance.instance_id, region: @config['region'], credentials: @config['credentials'])
241
+ MU::Cloud::AWS.createStandardTags(instance.instance_id, region: @config['region'], credentials: @config['credentials'])
250
242
  MU::MommaCat.createTag(instance.instance_id, "Name", @mu_name, region: @config['region'], credentials: @config['credentials'])
251
243
  end
252
244
  done = true
@@ -288,8 +280,9 @@ module MU
288
280
  if @config['generate_iam_role']
289
281
  role = @deploy.findLitterMate(name: @config['name'], type: "roles")
290
282
  s3_objs = ["#{@deploy.deploy_id}-secret", "#{role.mu_name}.pfx", "#{role.mu_name}.crt", "#{role.mu_name}.key", "#{role.mu_name}-winrm.crt", "#{role.mu_name}-winrm.key"].map { |file|
291
- 'arn:'+(MU::Cloud::AWS.isGovCloud?(@config['region']) ? "aws-us-gov" : "aws")+':s3:::'+MU.adminBucketName+'/'+file
283
+ 'arn:'+(MU::Cloud::AWS.isGovCloud?(@config['region']) ? "aws-us-gov" : "aws")+':s3:::'+MU::Cloud::AWS.adminBucketName(@credentials)+'/'+file
292
284
  }
285
+ MU.log "Adding S3 read permissions to #{@mu_name}'s IAM profile", MU::NOTICE, details: s3_objs
293
286
  role.cloudobj.injectPolicyTargets("MuSecrets", s3_objs)
294
287
 
295
288
  @config['iam_role'] = role.mu_name
@@ -382,6 +375,15 @@ module MU
382
375
  instance_descriptor[:block_device_mappings].concat(@ephemeral_mappings)
383
376
  instance_descriptor[:monitoring] = {enabled: @config['monitoring']}
384
377
 
378
+ if @tags and @tags.size > 0
379
+ instance_descriptor[:tag_specifications] = [{
380
+ :resource_type => "instance",
381
+ :tags => @tags.keys.map { |k|
382
+ { :key => k, :value => @tags[k] }
383
+ }
384
+ }]
385
+ end
386
+
385
387
  MU.log "Creating EC2 instance #{node}"
386
388
  MU.log "Instance details for #{node}: #{instance_descriptor}", MU::DEBUG
387
389
  # if instance_descriptor[:block_device_mappings].empty?
@@ -391,6 +393,9 @@ module MU
391
393
  retries = 0
392
394
  begin
393
395
  response = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).run_instances(instance_descriptor)
396
+ rescue Aws::EC2::Errors::InvalidRequest => e
397
+ MU.log e.message, MU::ERR, details: instance_descriptor
398
+ raise e
394
399
  rescue Aws::EC2::Errors::InvalidGroupNotFound, Aws::EC2::Errors::InvalidSubnetIDNotFound, Aws::EC2::Errors::InvalidParameterValue => e
395
400
  if retries < 10
396
401
  if retries > 7
@@ -521,7 +526,7 @@ module MU
521
526
  return false if !MU::MommaCat.lock(instance.instance_id+"-orchestrate", true)
522
527
  return false if !MU::MommaCat.lock(instance.instance_id+"-groom", true)
523
528
 
524
- MU::MommaCat.createStandardTags(instance.instance_id, region: @config['region'], credentials: @config['credentials'])
529
+ MU::Cloud::AWS.createStandardTags(instance.instance_id, region: @config['region'], credentials: @config['credentials'])
525
530
  MU::MommaCat.createTag(instance.instance_id, "Name", node, region: @config['region'], credentials: @config['credentials'])
526
531
 
527
532
  if @config['optional_tags']
@@ -754,11 +759,11 @@ module MU
754
759
  # extra interfaces to accomodate.
755
760
  if !@config['vpc']['subnets'].nil? and @config['basis'].nil?
756
761
  device_index = 1
757
- @vpc.subnets { |subnet|
758
- subnet_id = subnet.cloud_id
762
+ @vpc.subnets { |s|
763
+ subnet_id = s.cloud_id
759
764
  MU.log "Adding network interface on subnet #{subnet_id} for #{node}"
760
765
  iface = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_network_interface(subnet_id: subnet_id).network_interface
761
- MU::MommaCat.createStandardTags(iface.network_interface_id, region: @config['region'], credentials: @config['credentials'])
766
+ MU::Cloud::AWS.createStandardTags(iface.network_interface_id, region: @config['region'], credentials: @config['credentials'])
762
767
  MU::MommaCat.createTag(iface.network_interface_id, "Name", node+"-ETH"+device_index.to_s, region: @config['region'], credentials: @config['credentials'])
763
768
 
764
769
  if @config['optional_tags']
@@ -968,9 +973,16 @@ module MU
968
973
  # @param tag_value [String]: The value of the tag specified by tag_key to match when searching by tag.
969
974
  # @param flags [Hash]: Optional flags
970
975
  # @return [Array<Hash<String,OpenStruct>>]: The cloud provider's complete descriptions of matching instances
971
- def self.find(cloud_id: nil, region: MU.curRegion, tag_key: "Name", tag_value: nil, credentials: nil, flags: {})
972
- # XXX put that 'ip' value into opts
973
- ip ||= flags['ip']
976
+ # def self.find(cloud_id: nil, region: MU.curRegion, tag_key: "Name", tag_value: nil, credentials: nil, flags: {})
977
+ def self.find(**args)
978
+ ip ||= args[:flags]['ip'] if args[:flags] and args[:flags]['ip']
979
+
980
+ cloud_id = args[:cloud_id]
981
+ region = args[:region]
982
+ credentials = args[:credentials]
983
+ tag_key = args[:tag_key]
984
+ tag_value = args[:tag_value]
985
+
974
986
  instance = nil
975
987
  if !region.nil?
976
988
  regions = [region]
@@ -984,21 +996,21 @@ module MU
984
996
 
985
997
  # If we got an instance id, go get it
986
998
  if !cloud_id.nil? and !cloud_id.empty?
987
- regions.each { |region|
999
+ regions.each { |r|
988
1000
  search_threads << Thread.new {
989
- MU.log "Hunting for instance with cloud id '#{cloud_id}' in #{region}", MU::DEBUG
1001
+ MU.log "Hunting for instance with cloud id '#{cloud_id}' in #{r}", MU::DEBUG
990
1002
  retries = 0
991
1003
  begin
992
- MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_instances(
1004
+ MU::Cloud::AWS.ec2(region: r, credentials: credentials).describe_instances(
993
1005
  instance_ids: [cloud_id],
994
1006
  filters: [
995
1007
  {name: "instance-state-name", values: ["running", "pending"]}
996
1008
  ]
997
1009
  ).reservations.each { |resp|
998
1010
  if !resp.nil? and !resp.instances.nil?
999
- resp.instances.each { |instance|
1011
+ resp.instances.each { |i|
1000
1012
  search_semaphore.synchronize {
1001
- found_instances[instance.instance_id] = instance
1013
+ found_instances[i.instance_id] = i
1002
1014
  }
1003
1015
  }
1004
1016
  end
@@ -1008,7 +1020,7 @@ module MU
1008
1020
  retries = retries + 1
1009
1021
  sleep 5
1010
1022
  else
1011
- raise MuError, "#{e.inspect} in region #{region}"
1023
+ raise MuError, "#{e.inspect} in region #{r}"
1012
1024
  end
1013
1025
  end
1014
1026
  }
@@ -1054,8 +1066,8 @@ module MU
1054
1066
  ]
1055
1067
  ).reservations.each { |resp|
1056
1068
  if !resp.nil? and resp.instances.size > 0
1057
- resp.instances.each { |instance|
1058
- found_instances[instance.instance_id] = instance
1069
+ resp.instances.each { |i|
1070
+ found_instances[i.instance_id] = i
1059
1071
  }
1060
1072
  end
1061
1073
  }
@@ -1229,7 +1241,7 @@ module MU
1229
1241
  end
1230
1242
  session.exec!(purgecmd)
1231
1243
  session.close
1232
- ami_id = MU::Cloud::AWS::Server.createImage(
1244
+ ami_ids = MU::Cloud::AWS::Server.createImage(
1233
1245
  name: @mu_name,
1234
1246
  instance_id: @cloud_id,
1235
1247
  storage: @config['storage'],
@@ -1240,11 +1252,11 @@ module MU
1240
1252
  tags: @config['tags'],
1241
1253
  credentials: @config['credentials']
1242
1254
  )
1243
- @deploy.notify("images", @config['name'], {"image_id" => ami_id})
1255
+ @deploy.notify("images", @config['name'], ami_ids)
1244
1256
  @config['image_created'] = true
1245
1257
  if img_cfg['image_then_destroy']
1246
- MU::Cloud::AWS::Server.waitForAMI(ami_id, region: @config['region'], credentials: @config['credentials'])
1247
- MU.log "AMI #{ami_id} ready, removing source node #{node}"
1258
+ MU::Cloud::AWS::Server.waitForAMI(ami_ids[@config['region']], region: @config['region'], credentials: @config['credentials'])
1259
+ MU.log "AMI #{ami_ids[@config['region']]} ready, removing source node #{node}"
1248
1260
  MU::Cloud::AWS::Server.terminateInstance(id: @cloud_id, region: @config['region'], deploy_id: @deploy.deploy_id, mu_name: @mu_name, credentials: @config['credentials'])
1249
1261
  destroy
1250
1262
  end
@@ -1259,6 +1271,8 @@ module MU
1259
1271
  "arn:"+(MU::Cloud::AWS.isGovCloud?(@config["region"]) ? "aws-us-gov" : "aws")+":ec2:"+@config['region']+":"+MU::Cloud::AWS.credToAcct(@config['credentials'])+":instance/"+@cloud_id
1260
1272
  end
1261
1273
 
1274
+ # Return the cloud provider's description for this instance
1275
+ # @return [Openstruct]
1262
1276
  def cloud_desc
1263
1277
  max_retries = 5
1264
1278
  retries = 0
@@ -1331,10 +1345,11 @@ module MU
1331
1345
  # @return [String]: The cloud provider identifier of the new machine image.
1332
1346
  def self.createImage(name: nil, instance_id: nil, storage: {}, exclude_storage: false, make_public: false, region: MU.curRegion, copy_to_regions: [], tags: [], credentials: nil)
1333
1347
  ami_descriptor = {
1334
- :instance_id => instance_id,
1335
- :name => name,
1336
- :description => "Image automatically generated by Mu from #{name}"
1348
+ :instance_id => instance_id,
1349
+ :name => name,
1350
+ :description => "Image automatically generated by Mu from #{name}"
1337
1351
  }
1352
+ ami_ids = {}
1338
1353
 
1339
1354
  storage_list = Array.new
1340
1355
  if exclude_storage
@@ -1367,8 +1382,11 @@ module MU
1367
1382
  MU.log "AMI #{name} already exists, skipping", MU::WARN
1368
1383
  return nil
1369
1384
  end
1385
+
1370
1386
  ami = resp.image_id
1371
- MU::MommaCat.createStandardTags(ami, region: region, credentials: credentials)
1387
+
1388
+ ami_ids[region] = ami
1389
+ MU::Cloud::AWS.createStandardTags(ami, region: region, credentials: credentials)
1372
1390
  MU::MommaCat.createTag(ami, "Name", name, region: region, credentials: credentials)
1373
1391
  MU.log "AMI of #{name} in region #{region}: #{ami}"
1374
1392
  if make_public
@@ -1394,8 +1412,9 @@ module MU
1394
1412
  description: "Image automatically generated by Mu from #{name}"
1395
1413
  )
1396
1414
  MU.log "Initiated copy of #{ami} from #{region} to #{r}: #{copy.image_id}"
1415
+ ami_ids[r] = copy.image_id
1397
1416
 
1398
- MU::MommaCat.createStandardTags(copy.image_id, region: r, credentials: credentials)
1417
+ MU::Cloud::AWS.createStandardTags(copy.image_id, region: r, credentials: credentials)
1399
1418
  MU::MommaCat.createTag(copy.image_id, "Name", name, region: r, credentials: credentials)
1400
1419
  if !tags.nil?
1401
1420
  tags.each { |tag|
@@ -1419,7 +1438,7 @@ module MU
1419
1438
  t.join
1420
1439
  }
1421
1440
 
1422
- return resp.image_id
1441
+ return ami_ids
1423
1442
  end
1424
1443
 
1425
1444
  # Given a cloud platform identifier for a machine image, wait until it's
@@ -1614,7 +1633,8 @@ module MU
1614
1633
  # @param dev [String]: Device name to use when attaching to instance
1615
1634
  # @param size [String]: Size (in gb) of the new volume
1616
1635
  # @param type [String]: Cloud storage type of the volume, if applicable
1617
- def addVolume(dev, size, type: "gp2")
1636
+ # @param delete_on_termination [Boolean]: Value of delete_on_termination flag to set
1637
+ def addVolume(dev, size, type: "gp2", delete_on_termination: false)
1618
1638
  if @cloud_id.nil? or @cloud_id.empty?
1619
1639
  MU.log "#{self} didn't have a cloud id, couldn't determine 'active?' status", MU::ERR
1620
1640
  return true
@@ -1625,10 +1645,26 @@ module MU
1625
1645
  ).reservations.each { |resp|
1626
1646
  if !resp.nil? and !resp.instances.nil?
1627
1647
  resp.instances.each { |instance|
1628
- az = instance.placement.availability_zone
1629
- instance.block_device_mappings.each { |vol|
1630
- if vol.device_name == dev
1648
+ az = instance.placement.availability_zone
1649
+ d_o_t_changed = true
1650
+ mappings = MU.structToHash(instance.block_device_mappings)
1651
+ mappings.each { |vol|
1652
+ if vol[:ebs]
1653
+ vol[:ebs].delete(:attach_time)
1654
+ vol[:ebs].delete(:status)
1655
+ end
1656
+ }
1657
+ mappings.each { |vol|
1658
+ if vol[:device_name] == dev
1631
1659
  MU.log "A volume #{dev} already attached to #{self}, skipping", MU::NOTICE
1660
+ if vol[:ebs][:delete_on_termination] != delete_on_termination
1661
+ vol[:ebs][:delete_on_termination] = delete_on_termination
1662
+ MU.log "Setting delete_on_termination flag to #{delete_on_termination.to_s} on #{@mu_name}'s #{dev}"
1663
+ MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).modify_instance_attribute(
1664
+ instance_id: @cloud_id,
1665
+ block_device_mappings: mappings
1666
+ )
1667
+ end
1632
1668
  return
1633
1669
  end
1634
1670
  }
@@ -1669,6 +1705,32 @@ module MU
1669
1705
  raise MuError, "Saw state '#{creation.state}' while creating #{size}GB #{type} volume on #{dev} for #{@cloud_id}"
1670
1706
  end
1671
1707
  end while attachment.state != "attached"
1708
+
1709
+ # Set delete_on_termination, which for some reason is an instance
1710
+ # attribute and not on the attachment
1711
+ mappings = MU.structToHash(cloud_desc.block_device_mappings)
1712
+ changed = false
1713
+
1714
+ mappings.each { |mapping|
1715
+ if mapping[:ebs]
1716
+ mapping[:ebs].delete(:attach_time)
1717
+ mapping[:ebs].delete(:status)
1718
+ end
1719
+ if mapping[:device_name] == dev and
1720
+ mapping[:ebs][:delete_on_termination] != delete_on_termination
1721
+ changed = true
1722
+ mapping[:ebs][:delete_on_termination] = delete_on_termination
1723
+ end
1724
+ }
1725
+
1726
+ if changed
1727
+ MU.log "Setting delete_on_termination flag to #{delete_on_termination.to_s} on #{@mu_name}'s #{dev}"
1728
+ MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).modify_instance_attribute(
1729
+ instance_id: @cloud_id,
1730
+ block_device_mappings: mappings
1731
+ )
1732
+ end
1733
+
1672
1734
  end
1673
1735
 
1674
1736
  # Determine whether the node in question exists at the Cloud provider
@@ -1940,7 +2002,7 @@ module MU
1940
2002
  end
1941
2003
  if !onlycloud and !mu_name.nil?
1942
2004
  # DNS cleanup is now done in MU::Cloud::DNSZone. Keeping this for now
1943
- if !zone_rrsets.empty?
2005
+ if !zone_rrsets.nil? and !zone_rrsets.empty?
1944
2006
  zone_rrsets.each { |rrset|
1945
2007
  if rrset.name.match(/^#{mu_name.downcase}\.server\.#{MU.myInstanceId}\.platform-mu/i)
1946
2008
  rrset.resource_records.each { |record|
@@ -1951,16 +2013,6 @@ module MU
1951
2013
  }
1952
2014
  end
1953
2015
 
1954
- # Expunge traces left in Chef, Puppet or what have you
1955
- MU::Groomer.supportedGroomers.each { |groomer|
1956
- groomclass = MU::Groomer.loadGroomer(groomer)
1957
- if !server_obj.nil? and !server_obj.config.nil? and !server_obj.config['vault_access'].nil?
1958
- groomclass.cleanup(mu_name, server_obj.config['vault_access'], noop)
1959
- else
1960
- groomclass.cleanup(mu_name, [], noop)
1961
- end
1962
- }
1963
-
1964
2016
  if !noop
1965
2017
  if !server_obj.nil? and !server_obj.config.nil?
1966
2018
  MU.mommacat.notify(MU::Cloud::Server.cfg_plural, server_obj.config['name'], {}, mu_name: server_obj.mu_name, remove: true) if MU.mommacat
@@ -1991,7 +2043,7 @@ module MU
1991
2043
  known_hosts_files << Etc.getpwnam("nagios").dir+"/.ssh/known_hosts"
1992
2044
  end
1993
2045
  known_hosts_files.each { |known_hosts|
1994
- next if !File.exists?(known_hosts)
2046
+ next if !File.exist?(known_hosts)
1995
2047
  MU.log "Cleaning up #{ips} from #{known_hosts}"
1996
2048
  if !noop
1997
2049
  File.open(known_hosts, File::CREAT|File::RDWR, 0644) { |f|
@@ -2066,6 +2118,22 @@ module MU
2066
2118
  end
2067
2119
  end
2068
2120
 
2121
+ # Return a BoK-style config hash describing a NAT instance. We use this
2122
+ # to approximate NAT gateway functionality with a plain instance.
2123
+ # @return [Hash]
2124
+ def self.genericNAT
2125
+ return {
2126
+ "cloud" => "AWS",
2127
+ "bastion" => true,
2128
+ "size" => "t2.small",
2129
+ "run_list" => [ "mu-utility::nat" ],
2130
+ "platform" => "centos7",
2131
+ "ssh_user" => "centos",
2132
+ "associate_public_ip" => true,
2133
+ "static_ip" => { "assign_ip" => true },
2134
+ }
2135
+ end
2136
+
2069
2137
  # Cloud-specific configuration properties.
2070
2138
  # @param config [MU::Config]: The calling MU::Config object
2071
2139
  # @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource
@@ -2074,11 +2142,7 @@ module MU
2074
2142
  schema = {
2075
2143
  "ami_id" => {
2076
2144
  "type" => "string",
2077
- "description" => "The Amazon EC2 AMI on which to base this instance. Will use the default appropriate for the platform, if not specified."
2078
- },
2079
- "image_id" => {
2080
- "type" => "string",
2081
- "description" => "Synonymous with ami_id"
2145
+ "description" => "Alias for +image_id+"
2082
2146
  },
2083
2147
  "generate_iam_role" => {
2084
2148
  "type" => "boolean",
@@ -2133,32 +2197,43 @@ module MU
2133
2197
  # @param region [String]: Region to check against
2134
2198
  # @return [String,nil]
2135
2199
  def self.validateInstanceType(size, region)
2136
- begin
2137
- types = (MU::Cloud::AWS.listInstanceTypes(region))[region]
2138
- rescue Aws::Pricing::Errors::UnrecognizedClientException
2200
+ size = size.dup.to_s
2201
+ types = begin
2202
+ (MU::Cloud::AWS.listInstanceTypes(region))[region]
2203
+ rescue Aws::Pricing::Errors::Unrecognitypes.has_key?(size)
2139
2204
  MU.log "Saw authentication error communicating with Pricing API, going to assume our instance type is correct", MU::WARN
2140
2205
  return size
2141
2206
  end
2207
+
2208
+ return size if types.has_key?(size)
2209
+
2142
2210
  if size.nil? or !types.has_key?(size)
2143
2211
  # See if it's a type we can approximate from one of the other clouds
2144
- gtypes = (MU::Cloud::Google.listInstanceTypes)[MU::Cloud::Google.myRegion]
2145
2212
  foundmatch = false
2146
- if gtypes and gtypes.size > 0 and gtypes.has_key?(size)
2147
- vcpu = gtypes[size]["vcpu"]
2148
- mem = gtypes[size]["memory"]
2149
- ecu = gtypes[size]["ecu"]
2150
- types.keys.sort.reverse.each { |type|
2151
- features = types[type]
2152
- next if ecu == "Variable" and ecu != features["ecu"]
2153
- next if features["vcpu"] != vcpu
2154
- if (features["memory"] - mem.to_f).abs < 0.10*mem
2155
- foundmatch = true
2156
- MU.log "You specified a Google Compute instance type '#{size}.' Approximating with Amazon EC2 type '#{type}.'", MU::WARN
2157
- size = type
2158
- break
2159
- end
2160
- }
2161
- end
2213
+
2214
+ MU::Cloud.availableClouds.each { |cloud|
2215
+ next if cloud == "AWS"
2216
+ cloudbase = Object.const_get("MU").const_get("Cloud").const_get(cloud)
2217
+ foreign_types = (cloudbase.listInstanceTypes)[cloudbase.myRegion]
2218
+ if foreign_types and foreign_types.size > 0 and foreign_types.has_key?(size)
2219
+ vcpu = foreign_types[size]["vcpu"]
2220
+ mem = foreign_types[size]["memory"]
2221
+ ecu = foreign_types[size]["ecu"]
2222
+ types.keys.sort.reverse.each { |type|
2223
+ features = types[type]
2224
+ next if ecu == "Variable" and ecu != features["ecu"]
2225
+ next if features["vcpu"] != vcpu
2226
+ if (features["memory"] - mem.to_f).abs < 0.10*mem
2227
+ foundmatch = true
2228
+ MU.log "You specified #{cloud} instance type '#{size}.' Approximating with Amazon EC2 type '#{type}.'", MU::WARN
2229
+ size = type
2230
+ break
2231
+ end
2232
+ }
2233
+ end
2234
+ break if foundmatch
2235
+ }
2236
+
2162
2237
  if !foundmatch
2163
2238
  MU.log "Invalid size '#{size}' for AWS EC2 instance in #{region}. Supported types:", MU::ERR, details: types.keys.sort.join(", ")
2164
2239
  return nil
@@ -2238,9 +2313,9 @@ module MU
2238
2313
  server['ami_id'] ||= server['image_id']
2239
2314
 
2240
2315
  if server['ami_id'].nil?
2241
- if MU::Config.amazon_images.has_key?(server['platform']) and
2242
- MU::Config.amazon_images[server['platform']].has_key?(server['region'])
2243
- server['ami_id'] = configurator.getTail("server"+server['name']+"AMI", value: MU::Config.amazon_images[server['platform']][server['region']], prettyname: "server"+server['name']+"AMI", cloudtype: "AWS::EC2::Image::Id")
2316
+ img_id = MU::Cloud.getStockImage("AWS", platform: server['platform'], region: server['region'])
2317
+ if img_id
2318
+ server['ami_id'] = configurator.getTail("server"+server['name']+"AMI", value: img_id, prettyname: "server"+server['name']+"AMI", cloudtype: "AWS::EC2::Image::Id")
2244
2319
  else
2245
2320
  MU.log "No AMI specified for #{server['name']} and no default available for platform #{server['platform']} in region #{server['region']}", MU::ERR, details: server
2246
2321
  ok = false
@@ -2268,6 +2343,21 @@ module MU
2268
2343
  ok
2269
2344
  end
2270
2345
 
2346
+ # Return the date/time a machine image was created.
2347
+ # @param ami_id [String]: AMI identifier of an Amazon Machine Image
2348
+ # @param credentials [String]
2349
+ # @return [DateTime]
2350
+ def self.imageTimeStamp(ami_id, credentials: nil, region: nil)
2351
+ begin
2352
+ img = MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_images(image_ids: [ami_id]).images.first
2353
+ return DateTime.new if img.nil?
2354
+ return DateTime.parse(img.creation_date)
2355
+ rescue Aws::EC2::Errors::InvalidAMIIDNotFound => e
2356
+ end
2357
+
2358
+ return DateTime.new
2359
+ end
2360
+
2271
2361
  private
2272
2362
 
2273
2363
  # Destroy a volume.