cloud-mu 2.1.0beta → 3.0.0beta

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