cloud-mu 1.9.0.pre.beta

Sign up to get free protection for your applications and to get access to all the features.
Files changed (618) hide show
  1. checksums.yaml +7 -0
  2. data/Berksfile +56 -0
  3. data/Berksfile.lock +250 -0
  4. data/Jenkinsfile +184 -0
  5. data/LICENSE.md +37 -0
  6. data/README.md +26 -0
  7. data/bin/mu-aws-setup +376 -0
  8. data/bin/mu-cleanup +68 -0
  9. data/bin/mu-configure +1133 -0
  10. data/bin/mu-deploy +166 -0
  11. data/bin/mu-firewall-allow-clients +30 -0
  12. data/bin/mu-gcp-setup +200 -0
  13. data/bin/mu-gen-docs +34 -0
  14. data/bin/mu-gen-env +42 -0
  15. data/bin/mu-load-config.rb +158 -0
  16. data/bin/mu-node-manage +683 -0
  17. data/bin/mu-self-update +228 -0
  18. data/bin/mu-ssh +23 -0
  19. data/bin/mu-tunnel-nagios +144 -0
  20. data/bin/mu-upload-chef-artifacts +757 -0
  21. data/bin/mu-user-manage +275 -0
  22. data/cookbooks/awscli/LICENSE +37 -0
  23. data/cookbooks/awscli/README.md +58 -0
  24. data/cookbooks/awscli/attributes/default.rb +1 -0
  25. data/cookbooks/awscli/libraries/instance_metadata.rb +21 -0
  26. data/cookbooks/awscli/metadata.rb +20 -0
  27. data/cookbooks/awscli/recipes/default.rb +56 -0
  28. data/cookbooks/awscli/templates/default/config.erb +18 -0
  29. data/cookbooks/mu-activedirectory/CHANGELOG.md +13 -0
  30. data/cookbooks/mu-activedirectory/LICENSE +37 -0
  31. data/cookbooks/mu-activedirectory/README.md +6 -0
  32. data/cookbooks/mu-activedirectory/attributes/default.rb +98 -0
  33. data/cookbooks/mu-activedirectory/files/default/password-auth +32 -0
  34. data/cookbooks/mu-activedirectory/files/default/sshd_pol.pp +0 -0
  35. data/cookbooks/mu-activedirectory/files/default/sshd_pol.te +32 -0
  36. data/cookbooks/mu-activedirectory/files/default/syslogd_oddjobd.pp +0 -0
  37. data/cookbooks/mu-activedirectory/files/default/syslogd_oddjobd.te +10 -0
  38. data/cookbooks/mu-activedirectory/files/default/system-auth +34 -0
  39. data/cookbooks/mu-activedirectory/files/default/winbindpol.pp +0 -0
  40. data/cookbooks/mu-activedirectory/files/default/winbindpol.te +37 -0
  41. data/cookbooks/mu-activedirectory/libraries/config.rb +106 -0
  42. data/cookbooks/mu-activedirectory/libraries/helper.rb +86 -0
  43. data/cookbooks/mu-activedirectory/metadata.rb +17 -0
  44. data/cookbooks/mu-activedirectory/providers/domain.rb +152 -0
  45. data/cookbooks/mu-activedirectory/providers/domain_controller.rb +89 -0
  46. data/cookbooks/mu-activedirectory/providers/domain_node.rb +275 -0
  47. data/cookbooks/mu-activedirectory/recipes/default.rb +8 -0
  48. data/cookbooks/mu-activedirectory/recipes/domain-controller.rb +44 -0
  49. data/cookbooks/mu-activedirectory/recipes/domain-node.rb +50 -0
  50. data/cookbooks/mu-activedirectory/recipes/domain.rb +43 -0
  51. data/cookbooks/mu-activedirectory/recipes/sssd.rb +185 -0
  52. data/cookbooks/mu-activedirectory/resources/domain.rb +25 -0
  53. data/cookbooks/mu-activedirectory/resources/domain_controller.rb +25 -0
  54. data/cookbooks/mu-activedirectory/resources/domain_node.rb +20 -0
  55. data/cookbooks/mu-activedirectory/templates/default/dhclient-eth0.conf.erb +4 -0
  56. data/cookbooks/mu-activedirectory/templates/default/interface +0 -0
  57. data/cookbooks/mu-activedirectory/templates/default/krb5.conf.erb +23 -0
  58. data/cookbooks/mu-activedirectory/templates/default/ntp.conf.erb +56 -0
  59. data/cookbooks/mu-activedirectory/templates/default/smb.conf.erb +33 -0
  60. data/cookbooks/mu-activedirectory/templates/default/sssd.conf.erb +60 -0
  61. data/cookbooks/mu-activedirectory/templates/windows/Backup.xml.erb +20 -0
  62. data/cookbooks/mu-activedirectory/templates/windows/bkupInfo.xml.erb +1 -0
  63. data/cookbooks/mu-activedirectory/templates/windows/gpreprt.xml.erb +198 -0
  64. data/cookbooks/mu-activedirectory/templates/windows/gptmpl.inf.erb +12 -0
  65. data/cookbooks/mu-activedirectory/templates/windows/manifest.xml.erb +1 -0
  66. data/cookbooks/mu-firewall/CHANGELOG.md +11 -0
  67. data/cookbooks/mu-firewall/LICENSE +37 -0
  68. data/cookbooks/mu-firewall/README.md +5 -0
  69. data/cookbooks/mu-firewall/attributes/default.rb +3 -0
  70. data/cookbooks/mu-firewall/metadata.rb +16 -0
  71. data/cookbooks/mu-firewall/recipes/default.rb +10 -0
  72. data/cookbooks/mu-glusterfs/CHANGELOG.md +13 -0
  73. data/cookbooks/mu-glusterfs/LICENSE +37 -0
  74. data/cookbooks/mu-glusterfs/README.md +5 -0
  75. data/cookbooks/mu-glusterfs/attributes/default.rb +34 -0
  76. data/cookbooks/mu-glusterfs/metadata.rb +17 -0
  77. data/cookbooks/mu-glusterfs/recipes/client.rb +62 -0
  78. data/cookbooks/mu-glusterfs/recipes/default.rb +16 -0
  79. data/cookbooks/mu-glusterfs/recipes/samba.rb +57 -0
  80. data/cookbooks/mu-glusterfs/recipes/server.rb +200 -0
  81. data/cookbooks/mu-glusterfs/templates/default/mu-gluster-client.erb +71 -0
  82. data/cookbooks/mu-glusterfs/templates/default/smb.conf.erb +14 -0
  83. data/cookbooks/mu-jenkins/CHANGELOG.md +13 -0
  84. data/cookbooks/mu-jenkins/LICENSE +37 -0
  85. data/cookbooks/mu-jenkins/README.md +105 -0
  86. data/cookbooks/mu-jenkins/attributes/default.rb +42 -0
  87. data/cookbooks/mu-jenkins/files/default/cleanup_deploy_config.xml +73 -0
  88. data/cookbooks/mu-jenkins/files/default/deploy_config.xml +44 -0
  89. data/cookbooks/mu-jenkins/metadata.rb +21 -0
  90. data/cookbooks/mu-jenkins/recipes/default.rb +195 -0
  91. data/cookbooks/mu-jenkins/recipes/node-ssh-config.rb +54 -0
  92. data/cookbooks/mu-jenkins/recipes/public_key.rb +24 -0
  93. data/cookbooks/mu-jenkins/templates/default/example_job.config.xml.erb +24 -0
  94. data/cookbooks/mu-jenkins/templates/default/org.jvnet.hudson.plugins.SSHBuildWrapper.xml.erb +14 -0
  95. data/cookbooks/mu-jenkins/templates/default/ssh_config.erb +6 -0
  96. data/cookbooks/mu-master/CHANGELOG.md +13 -0
  97. data/cookbooks/mu-master/LICENSE +37 -0
  98. data/cookbooks/mu-master/README.md +6 -0
  99. data/cookbooks/mu-master/attributes/default.rb +95 -0
  100. data/cookbooks/mu-master/files/default/0-mu-log-server.conf +19 -0
  101. data/cookbooks/mu-master/files/default/addRSA.ldif +8 -0
  102. data/cookbooks/mu-master/files/default/check_mem.pl +197 -0
  103. data/cookbooks/mu-master/files/default/cloudamatic.png +0 -0
  104. data/cookbooks/mu-master/files/default/dirsrv_admin.pp +0 -0
  105. data/cookbooks/mu-master/files/default/dirsrv_admin.te +13 -0
  106. data/cookbooks/mu-master/files/default/nagios_selinux.pp +0 -0
  107. data/cookbooks/mu-master/files/default/nagios_selinux.te +51 -0
  108. data/cookbooks/mu-master/files/default/nagios_selinux_7.pp +0 -0
  109. data/cookbooks/mu-master/files/default/nagios_selinux_7.te +17 -0
  110. data/cookbooks/mu-master/files/default/pam_sshd +18 -0
  111. data/cookbooks/mu-master/files/default/ssl_enable.ldif +18 -0
  112. data/cookbooks/mu-master/files/default/syslogd_oddjobd.pp +0 -0
  113. data/cookbooks/mu-master/files/default/syslogd_oddjobd.te +10 -0
  114. data/cookbooks/mu-master/files/default/vimrc +19 -0
  115. data/cookbooks/mu-master/libraries/mu.rb +29 -0
  116. data/cookbooks/mu-master/metadata.rb +30 -0
  117. data/cookbooks/mu-master/providers/user.rb +41 -0
  118. data/cookbooks/mu-master/recipes/389ds.rb +164 -0
  119. data/cookbooks/mu-master/recipes/basepackages.rb +58 -0
  120. data/cookbooks/mu-master/recipes/caching_nameserver.rb +37 -0
  121. data/cookbooks/mu-master/recipes/default.rb +451 -0
  122. data/cookbooks/mu-master/recipes/eks-kubectl.rb +41 -0
  123. data/cookbooks/mu-master/recipes/firewall-holes.rb +70 -0
  124. data/cookbooks/mu-master/recipes/init.rb +542 -0
  125. data/cookbooks/mu-master/recipes/ssl-certs.rb +109 -0
  126. data/cookbooks/mu-master/recipes/sssd.rb +89 -0
  127. data/cookbooks/mu-master/recipes/update_nagios_only.rb +242 -0
  128. data/cookbooks/mu-master/recipes/vault.rb +111 -0
  129. data/cookbooks/mu-master/resources/user.rb +19 -0
  130. data/cookbooks/mu-master/templates/default/389-directory-setup.inf.erb +28 -0
  131. data/cookbooks/mu-master/templates/default/chef-server.rb.erb +18 -0
  132. data/cookbooks/mu-master/templates/default/dhclient-eth0.conf.erb +9 -0
  133. data/cookbooks/mu-master/templates/default/mu-momma-cat.erb +149 -0
  134. data/cookbooks/mu-master/templates/default/mu.rc.erb +9 -0
  135. data/cookbooks/mu-master/templates/default/openssl.cnf.erb +354 -0
  136. data/cookbooks/mu-master/templates/default/sssd.conf.erb +44 -0
  137. data/cookbooks/mu-master/templates/default/web_app.conf.erb +90 -0
  138. data/cookbooks/mu-mongo/CHANGELOG.md +13 -0
  139. data/cookbooks/mu-mongo/LICENSE +37 -0
  140. data/cookbooks/mu-mongo/README.md +5 -0
  141. data/cookbooks/mu-mongo/attributes/default.rb +22 -0
  142. data/cookbooks/mu-mongo/files/default/keyfile +16 -0
  143. data/cookbooks/mu-mongo/files/default/remove_nodes.js +5 -0
  144. data/cookbooks/mu-mongo/metadata.rb +17 -0
  145. data/cookbooks/mu-mongo/recipes/default.rb +149 -0
  146. data/cookbooks/mu-mongo/recipes/yum-update-rule.rb +18 -0
  147. data/cookbooks/mu-mongo/templates/default/mongo_create_openfema_db.js.erb +2 -0
  148. data/cookbooks/mu-mongo/templates/default/mongo_init.js.erb +1 -0
  149. data/cookbooks/mu-mongo/templates/default/mongo_logrotate.erb +14 -0
  150. data/cookbooks/mu-mongo/templates/default/mongo_replset_addnodes.js.erb +6 -0
  151. data/cookbooks/mu-mongo/templates/default/replset_init.js.erb +2 -0
  152. data/cookbooks/mu-openvpn/CHANGELOG.md +13 -0
  153. data/cookbooks/mu-openvpn/LICENSE +37 -0
  154. data/cookbooks/mu-openvpn/README.md +6 -0
  155. data/cookbooks/mu-openvpn/attributes/default.rb +119 -0
  156. data/cookbooks/mu-openvpn/metadata.rb +18 -0
  157. data/cookbooks/mu-openvpn/recipes/default.rb +108 -0
  158. data/cookbooks/mu-openvpn/templates/default/users.json.erb +42 -0
  159. data/cookbooks/mu-php54/CHANGELOG.md +12 -0
  160. data/cookbooks/mu-php54/LICENSE +37 -0
  161. data/cookbooks/mu-php54/README.md +0 -0
  162. data/cookbooks/mu-php54/files/centos/php.ini +1802 -0
  163. data/cookbooks/mu-php54/files/ubuntu/php.ini +1870 -0
  164. data/cookbooks/mu-php54/metadata.rb +21 -0
  165. data/cookbooks/mu-php54/recipes/default.rb +97 -0
  166. data/cookbooks/mu-splunk/CHANGELOG.md +37 -0
  167. data/cookbooks/mu-splunk/LICENSE +37 -0
  168. data/cookbooks/mu-splunk/README.md +451 -0
  169. data/cookbooks/mu-splunk/attributes/default.rb +95 -0
  170. data/cookbooks/mu-splunk/attributes/upgrade.rb +49 -0
  171. data/cookbooks/mu-splunk/definitions/splunk_installer.rb +103 -0
  172. data/cookbooks/mu-splunk/files/default/splunk-nocheck +10 -0
  173. data/cookbooks/mu-splunk/libraries/helpers.rb +72 -0
  174. data/cookbooks/mu-splunk/libraries/splunk_app_provider.rb +156 -0
  175. data/cookbooks/mu-splunk/libraries/splunk_app_resource.rb +43 -0
  176. data/cookbooks/mu-splunk/metadata.json +30 -0
  177. data/cookbooks/mu-splunk/metadata.rb +17 -0
  178. data/cookbooks/mu-splunk/recipes/client.rb +143 -0
  179. data/cookbooks/mu-splunk/recipes/default.rb +31 -0
  180. data/cookbooks/mu-splunk/recipes/disabled.rb +41 -0
  181. data/cookbooks/mu-splunk/recipes/install_forwarder.rb +23 -0
  182. data/cookbooks/mu-splunk/recipes/install_server.rb +23 -0
  183. data/cookbooks/mu-splunk/recipes/server.rb +53 -0
  184. data/cookbooks/mu-splunk/recipes/service.rb +95 -0
  185. data/cookbooks/mu-splunk/recipes/setup_auth.rb +49 -0
  186. data/cookbooks/mu-splunk/recipes/setup_ssl.rb +63 -0
  187. data/cookbooks/mu-splunk/recipes/upgrade.rb +94 -0
  188. data/cookbooks/mu-splunk/recipes/user.rb +34 -0
  189. data/cookbooks/mu-splunk/templates/default/base_logs_unix_inputs.conf.erb +26 -0
  190. data/cookbooks/mu-splunk/templates/default/inputs.conf.erb +13 -0
  191. data/cookbooks/mu-splunk/templates/default/outputs.conf.erb +9 -0
  192. data/cookbooks/mu-splunk/templates/default/splunk-init.erb +74 -0
  193. data/cookbooks/mu-splunk/templates/default/system-web.conf.erb +7 -0
  194. data/cookbooks/mu-tools/CHANGELOG.md +12 -0
  195. data/cookbooks/mu-tools/LICENSE +37 -0
  196. data/cookbooks/mu-tools/README.md +188 -0
  197. data/cookbooks/mu-tools/attributes/default.rb +142 -0
  198. data/cookbooks/mu-tools/attributes/ebs_rolling_snapshots.rb +3 -0
  199. data/cookbooks/mu-tools/files/amazon/etc/freshclam.conf +235 -0
  200. data/cookbooks/mu-tools/files/centos/CentOS-Base.repo +52 -0
  201. data/cookbooks/mu-tools/files/centos/etc/bashrc +93 -0
  202. data/cookbooks/mu-tools/files/centos/etc/freshclam.conf +235 -0
  203. data/cookbooks/mu-tools/files/centos/etc/login.defs +72 -0
  204. data/cookbooks/mu-tools/files/centos/etc/profile +77 -0
  205. data/cookbooks/mu-tools/files/centos/etc/security/limits.conf +57 -0
  206. data/cookbooks/mu-tools/files/centos/etc/sysconfig/init +19 -0
  207. data/cookbooks/mu-tools/files/centos/etc/sysctl.conf +82 -0
  208. data/cookbooks/mu-tools/files/centos-6/README_MU +0 -0
  209. data/cookbooks/mu-tools/files/centos-6/etc/audit/stig.rules +173 -0
  210. data/cookbooks/mu-tools/files/centos-6/etc/bashrc +90 -0
  211. data/cookbooks/mu-tools/files/centos-6/etc/login.defs +70 -0
  212. data/cookbooks/mu-tools/files/centos-6/etc/pam.d/su +12 -0
  213. data/cookbooks/mu-tools/files/centos-6/etc/profile +83 -0
  214. data/cookbooks/mu-tools/files/centos-6/etc/securetty +12 -0
  215. data/cookbooks/mu-tools/files/centos-6/etc/sysconfig/init +30 -0
  216. data/cookbooks/mu-tools/files/centos-6/etc/sysctl.conf +40 -0
  217. data/cookbooks/mu-tools/files/default/Mu_CA.pem +34 -0
  218. data/cookbooks/mu-tools/files/default/PSWindowsUpdate.zip +0 -0
  219. data/cookbooks/mu-tools/files/default/ebs_snapshots.py +123 -0
  220. data/cookbooks/mu-tools/files/default/etc/BANNER +0 -0
  221. data/cookbooks/mu-tools/files/default/etc/BANNER-FEDERAL +19 -0
  222. data/cookbooks/mu-tools/files/default/gpo_no_uac.zip +0 -0
  223. data/cookbooks/mu-tools/files/default/mypol.pp +0 -0
  224. data/cookbooks/mu-tools/files/default/mypol.te +37 -0
  225. data/cookbooks/mu-tools/files/default/nrpe_c7.pp +0 -0
  226. data/cookbooks/mu-tools/files/default/nrpe_c7.te +31 -0
  227. data/cookbooks/mu-tools/files/default/nrpe_check_disk.pp +0 -0
  228. data/cookbooks/mu-tools/files/default/nrpe_check_disk.te +11 -0
  229. data/cookbooks/mu-tools/files/default/nrpe_disk.pp +0 -0
  230. data/cookbooks/mu-tools/files/default/nrpe_disk.te +10 -0
  231. data/cookbooks/mu-tools/files/default/nrpe_file.pp +0 -0
  232. data/cookbooks/mu-tools/files/default/nrpe_file.te +31 -0
  233. data/cookbooks/mu-tools/files/default/ntrights +0 -0
  234. data/cookbooks/mu-tools/files/default/serverclass.conf +18 -0
  235. data/cookbooks/mu-tools/files/default/splunk-apps/base_logs_unix/local/app.conf +1 -0
  236. data/cookbooks/mu-tools/files/default/splunk-apps/base_logs_unix/local/inputs.conf +13 -0
  237. data/cookbooks/mu-tools/files/default/splunk-apps/base_logs_windows/local/app.conf +1 -0
  238. data/cookbooks/mu-tools/files/default/splunk-apps/base_logs_windows/local/inputs.conf +8 -0
  239. data/cookbooks/mu-tools/files/default/sshd_pol.pp +0 -0
  240. data/cookbooks/mu-tools/files/default/sshd_pol.te +32 -0
  241. data/cookbooks/mu-tools/files/redhat/etc/bashrc +93 -0
  242. data/cookbooks/mu-tools/files/redhat/etc/freshclam.conf +235 -0
  243. data/cookbooks/mu-tools/files/redhat/etc/login.defs +72 -0
  244. data/cookbooks/mu-tools/files/redhat/etc/profile +77 -0
  245. data/cookbooks/mu-tools/files/redhat/etc/security/limits.conf +57 -0
  246. data/cookbooks/mu-tools/files/redhat/etc/sysconfig/init +19 -0
  247. data/cookbooks/mu-tools/files/redhat/etc/sysctl.conf +82 -0
  248. data/cookbooks/mu-tools/files/redhat-6/README_MU +0 -0
  249. data/cookbooks/mu-tools/files/redhat-6/etc/audit/stig.rules +173 -0
  250. data/cookbooks/mu-tools/files/redhat-6/etc/bashrc +90 -0
  251. data/cookbooks/mu-tools/files/redhat-6/etc/login.defs +70 -0
  252. data/cookbooks/mu-tools/files/redhat-6/etc/pam.d/su +12 -0
  253. data/cookbooks/mu-tools/files/redhat-6/etc/profile +83 -0
  254. data/cookbooks/mu-tools/files/redhat-6/etc/securetty +12 -0
  255. data/cookbooks/mu-tools/files/redhat-6/etc/sysconfig/init +30 -0
  256. data/cookbooks/mu-tools/files/redhat-6/etc/sysctl.conf +40 -0
  257. data/cookbooks/mu-tools/files/redhat-7.1/etc/freshclam.conf +235 -0
  258. data/cookbooks/mu-tools/files/ubuntu-12.04/etc/bash.bashrc +64 -0
  259. data/cookbooks/mu-tools/files/ubuntu-12.04/etc/common-session +30 -0
  260. data/cookbooks/mu-tools/files/ubuntu-12.04/etc/login.defs +338 -0
  261. data/cookbooks/mu-tools/files/ubuntu-12.04/etc/profile +30 -0
  262. data/cookbooks/mu-tools/files/ubuntu-12.04/etc/security/limits.conf +56 -0
  263. data/cookbooks/mu-tools/files/ubuntu-12.04/etc/sysctl.conf +60 -0
  264. data/cookbooks/mu-tools/libraries/helper.rb +292 -0
  265. data/cookbooks/mu-tools/metadata.rb +28 -0
  266. data/cookbooks/mu-tools/recipes/add_admin_ssh_keys.rb +35 -0
  267. data/cookbooks/mu-tools/recipes/apply_security.rb +440 -0
  268. data/cookbooks/mu-tools/recipes/aws_api.rb +23 -0
  269. data/cookbooks/mu-tools/recipes/base_repositories.rb +31 -0
  270. data/cookbooks/mu-tools/recipes/cisbenchmark.rb +59 -0
  271. data/cookbooks/mu-tools/recipes/clamav.rb +53 -0
  272. data/cookbooks/mu-tools/recipes/cloudinit.rb +58 -0
  273. data/cookbooks/mu-tools/recipes/configure_oracle_tools.rb +81 -0
  274. data/cookbooks/mu-tools/recipes/disable-requiretty.rb +22 -0
  275. data/cookbooks/mu-tools/recipes/ebs_rolling_snapshots.rb +75 -0
  276. data/cookbooks/mu-tools/recipes/efs.rb +70 -0
  277. data/cookbooks/mu-tools/recipes/eks.rb +160 -0
  278. data/cookbooks/mu-tools/recipes/gcloud.rb +98 -0
  279. data/cookbooks/mu-tools/recipes/google_api.rb +25 -0
  280. data/cookbooks/mu-tools/recipes/maldet.rb +67 -0
  281. data/cookbooks/mu-tools/recipes/nagios.rb +19 -0
  282. data/cookbooks/mu-tools/recipes/newclient.rb +23 -0
  283. data/cookbooks/mu-tools/recipes/nrpe.rb +115 -0
  284. data/cookbooks/mu-tools/recipes/python_pip.rb +35 -0
  285. data/cookbooks/mu-tools/recipes/retrieve_application.rb +51 -0
  286. data/cookbooks/mu-tools/recipes/rsyslog.rb +65 -0
  287. data/cookbooks/mu-tools/recipes/set_local_fw.rb +57 -0
  288. data/cookbooks/mu-tools/recipes/set_mu_hostname.rb +81 -0
  289. data/cookbooks/mu-tools/recipes/split_var_partitions.rb +86 -0
  290. data/cookbooks/mu-tools/recipes/splunk-client.rb +69 -0
  291. data/cookbooks/mu-tools/recipes/splunk-server.rb +104 -0
  292. data/cookbooks/mu-tools/recipes/store_inspec_attr.rb +8 -0
  293. data/cookbooks/mu-tools/recipes/updates.rb +96 -0
  294. data/cookbooks/mu-tools/recipes/windows-client.rb +202 -0
  295. data/cookbooks/mu-tools/resources/aws_windows.rb +33 -0
  296. data/cookbooks/mu-tools/resources/disk.rb +88 -0
  297. data/cookbooks/mu-tools/resources/mommacat_request.rb +11 -0
  298. data/cookbooks/mu-tools/resources/scheduled_tasks.rb +29 -0
  299. data/cookbooks/mu-tools/resources/sshd_service.rb +45 -0
  300. data/cookbooks/mu-tools/resources/windows_users.rb +242 -0
  301. data/cookbooks/mu-tools/templates/amazon/sshd_config.erb +168 -0
  302. data/cookbooks/mu-tools/templates/centos-6/sshd_config.erb +212 -0
  303. data/cookbooks/mu-tools/templates/centos-7/sshd_config.erb +215 -0
  304. data/cookbooks/mu-tools/templates/default/0-mu-log-client.conf.erb +13 -0
  305. data/cookbooks/mu-tools/templates/default/conf.maldet.erb +137 -0
  306. data/cookbooks/mu-tools/templates/default/etc_hosts.erb +30 -0
  307. data/cookbooks/mu-tools/templates/default/etc_pamd_password-auth.erb +14 -0
  308. data/cookbooks/mu-tools/templates/default/etc_pamd_system-auth.erb +14 -0
  309. data/cookbooks/mu-tools/templates/default/etc_sysconfig_network.erb +12 -0
  310. data/cookbooks/mu-tools/templates/default/kubeconfig.erb +29 -0
  311. data/cookbooks/mu-tools/templates/default/kubelet.service.erb +35 -0
  312. data/cookbooks/mu-tools/templates/default/maldet_scanall.sh.erb +15 -0
  313. data/cookbooks/mu-tools/templates/default/nrpe.cfg.erb +233 -0
  314. data/cookbooks/mu-tools/templates/redhat-6/sshd_config.erb +213 -0
  315. data/cookbooks/mu-tools/templates/redhat-7/sshd_config.erb +215 -0
  316. data/cookbooks/mu-tools/templates/ubuntu-12.04/sshd_config.erb +146 -0
  317. data/cookbooks/mu-tools/templates/ubuntu-14.04/sshd_config.erb +145 -0
  318. data/cookbooks/mu-tools/templates/windows/Backup.xml.erb +20 -0
  319. data/cookbooks/mu-tools/templates/windows/bkupInfo.xml.erb +1 -0
  320. data/cookbooks/mu-tools/templates/windows/gpreprt.xml.erb +214 -0
  321. data/cookbooks/mu-tools/templates/windows/gptmpl.inf.erb +12 -0
  322. data/cookbooks/mu-tools/templates/windows/manifest.xml.erb +1 -0
  323. data/cookbooks/mu-tools/templates/windows/set_ad_dns_scheduled_task.ps1.erb +6 -0
  324. data/cookbooks/mu-tools/templates/windows/sshd_config.erb +136 -0
  325. data/cookbooks/mu-utility/CHANGELOG.md +12 -0
  326. data/cookbooks/mu-utility/LICENSE +37 -0
  327. data/cookbooks/mu-utility/README.md +6 -0
  328. data/cookbooks/mu-utility/attributes/default.rb +1 -0
  329. data/cookbooks/mu-utility/libraries/matchers.rb +21 -0
  330. data/cookbooks/mu-utility/metadata.rb +16 -0
  331. data/cookbooks/mu-utility/recipes/apt.rb +23 -0
  332. data/cookbooks/mu-utility/recipes/cleanup_image_helper.rb +118 -0
  333. data/cookbooks/mu-utility/recipes/iptables.rb +26 -0
  334. data/cookbooks/mu-utility/recipes/luks.rb +18 -0
  335. data/cookbooks/mu-utility/recipes/nat.rb +104 -0
  336. data/cookbooks/mu-utility/recipes/php.rb +33 -0
  337. data/cookbooks/mu-utility/recipes/rdp_gateway.rb +83 -0
  338. data/cookbooks/mu-utility/recipes/remi.rb +44 -0
  339. data/cookbooks/mu-utility/recipes/vim.rb +26 -0
  340. data/cookbooks/mu-utility/recipes/windows_basics.rb +37 -0
  341. data/cookbooks/mu-utility/recipes/zip.rb +26 -0
  342. data/cookbooks/mu-utility/templates/default/BundleConfig.xml.erb +34 -0
  343. data/cookbooks/mu-utility/templates/default/config.xml.erb +60 -0
  344. data/cookbooks/nagios/Berksfile +8 -0
  345. data/cookbooks/nagios/CHANGELOG.md +589 -0
  346. data/cookbooks/nagios/CONTRIBUTING.md +11 -0
  347. data/cookbooks/nagios/LICENSE +37 -0
  348. data/cookbooks/nagios/README.md +328 -0
  349. data/cookbooks/nagios/TESTING.md +2 -0
  350. data/cookbooks/nagios/attributes/config.rb +171 -0
  351. data/cookbooks/nagios/attributes/default.rb +228 -0
  352. data/cookbooks/nagios/chefignore +102 -0
  353. data/cookbooks/nagios/definitions/command.rb +33 -0
  354. data/cookbooks/nagios/definitions/contact.rb +33 -0
  355. data/cookbooks/nagios/definitions/contactgroup.rb +33 -0
  356. data/cookbooks/nagios/definitions/host.rb +33 -0
  357. data/cookbooks/nagios/definitions/hostdependency.rb +33 -0
  358. data/cookbooks/nagios/definitions/hostescalation.rb +34 -0
  359. data/cookbooks/nagios/definitions/hostgroup.rb +33 -0
  360. data/cookbooks/nagios/definitions/nagios_conf.rb +38 -0
  361. data/cookbooks/nagios/definitions/resource.rb +33 -0
  362. data/cookbooks/nagios/definitions/service.rb +33 -0
  363. data/cookbooks/nagios/definitions/servicedependency.rb +33 -0
  364. data/cookbooks/nagios/definitions/serviceescalation.rb +34 -0
  365. data/cookbooks/nagios/definitions/servicegroup.rb +33 -0
  366. data/cookbooks/nagios/definitions/timeperiod.rb +33 -0
  367. data/cookbooks/nagios/libraries/base.rb +314 -0
  368. data/cookbooks/nagios/libraries/command.rb +91 -0
  369. data/cookbooks/nagios/libraries/contact.rb +230 -0
  370. data/cookbooks/nagios/libraries/contactgroup.rb +112 -0
  371. data/cookbooks/nagios/libraries/custom_option.rb +36 -0
  372. data/cookbooks/nagios/libraries/data_bag_helper.rb +23 -0
  373. data/cookbooks/nagios/libraries/default.rb +90 -0
  374. data/cookbooks/nagios/libraries/host.rb +412 -0
  375. data/cookbooks/nagios/libraries/hostdependency.rb +181 -0
  376. data/cookbooks/nagios/libraries/hostescalation.rb +173 -0
  377. data/cookbooks/nagios/libraries/hostgroup.rb +119 -0
  378. data/cookbooks/nagios/libraries/nagios.rb +282 -0
  379. data/cookbooks/nagios/libraries/resource.rb +59 -0
  380. data/cookbooks/nagios/libraries/service.rb +455 -0
  381. data/cookbooks/nagios/libraries/servicedependency.rb +215 -0
  382. data/cookbooks/nagios/libraries/serviceescalation.rb +195 -0
  383. data/cookbooks/nagios/libraries/servicegroup.rb +144 -0
  384. data/cookbooks/nagios/libraries/timeperiod.rb +160 -0
  385. data/cookbooks/nagios/libraries/users_helper.rb +54 -0
  386. data/cookbooks/nagios/metadata.rb +25 -0
  387. data/cookbooks/nagios/recipes/_load_databag_config.rb +153 -0
  388. data/cookbooks/nagios/recipes/_load_default_config.rb +241 -0
  389. data/cookbooks/nagios/recipes/apache.rb +48 -0
  390. data/cookbooks/nagios/recipes/default.rb +204 -0
  391. data/cookbooks/nagios/recipes/nginx.rb +82 -0
  392. data/cookbooks/nagios/recipes/pagerduty.rb +143 -0
  393. data/cookbooks/nagios/recipes/server_package.rb +40 -0
  394. data/cookbooks/nagios/recipes/server_source.rb +164 -0
  395. data/cookbooks/nagios/templates/default/apache2.conf.erb +96 -0
  396. data/cookbooks/nagios/templates/default/cgi.cfg.erb +266 -0
  397. data/cookbooks/nagios/templates/default/commands.cfg.erb +13 -0
  398. data/cookbooks/nagios/templates/default/contacts.cfg.erb +37 -0
  399. data/cookbooks/nagios/templates/default/hostgroups.cfg.erb +25 -0
  400. data/cookbooks/nagios/templates/default/hosts.cfg.erb +15 -0
  401. data/cookbooks/nagios/templates/default/htpasswd.users.erb +6 -0
  402. data/cookbooks/nagios/templates/default/nagios.cfg.erb +22 -0
  403. data/cookbooks/nagios/templates/default/nginx.conf.erb +62 -0
  404. data/cookbooks/nagios/templates/default/pagerduty.cgi.erb +185 -0
  405. data/cookbooks/nagios/templates/default/resource.cfg.erb +27 -0
  406. data/cookbooks/nagios/templates/default/servicedependencies.cfg.erb +15 -0
  407. data/cookbooks/nagios/templates/default/servicegroups.cfg.erb +14 -0
  408. data/cookbooks/nagios/templates/default/services.cfg.erb +14 -0
  409. data/cookbooks/nagios/templates/default/templates.cfg.erb +31 -0
  410. data/cookbooks/nagios/templates/default/timeperiods.cfg.erb +13 -0
  411. data/cookbooks/s3fs/CHANGELOG.md +13 -0
  412. data/cookbooks/s3fs/LICENSE +37 -0
  413. data/cookbooks/s3fs/README.md +6 -0
  414. data/cookbooks/s3fs/attributes/default.rb +15 -0
  415. data/cookbooks/s3fs/files/default/fuse-2.9.3.zip +0 -0
  416. data/cookbooks/s3fs/metadata.rb +16 -0
  417. data/cookbooks/s3fs/recipes/default.rb +91 -0
  418. data/data_bags/demo/app.json +7 -0
  419. data/data_bags/nagios_services/chef.json +6 -0
  420. data/data_bags/nagios_services/linux_diskspace.json +5 -0
  421. data/data_bags/nagios_services/momma_cat.json +6 -0
  422. data/data_bags/nagios_services/mu-master-memory.json +5 -0
  423. data/data_bags/nagios_services/nagios_ui.json +6 -0
  424. data/data_bags/nagios_services/node_ssh.json +6 -0
  425. data/data_bags/nagios_services/ssh.json +6 -0
  426. data/demo/lambda_test.yaml +29 -0
  427. data/environments/DEV.json +8 -0
  428. data/environments/PROD.json +8 -0
  429. data/environments/dev.json +8 -0
  430. data/environments/development.json +8 -0
  431. data/environments/prod.json +8 -0
  432. data/extras/README.md +1 -0
  433. data/extras/admin-role-binding.yaml +16 -0
  434. data/extras/admin-user.yaml +6 -0
  435. data/extras/aws-auth-cm.yaml.erb +12 -0
  436. data/extras/clean-stock-amis +48 -0
  437. data/extras/git-fix-permissions-hook +12 -0
  438. data/extras/gitlab-eks-helper.sh.erb +20 -0
  439. data/extras/image-generators/README.md +2 -0
  440. data/extras/image-generators/aws/centos6.yaml +18 -0
  441. data/extras/image-generators/aws/centos7-govcloud.yaml +24 -0
  442. data/extras/image-generators/aws/centos7.yaml +17 -0
  443. data/extras/image-generators/aws/rhel7.yaml +17 -0
  444. data/extras/image-generators/aws/win2k12.yaml +16 -0
  445. data/extras/image-generators/aws/win2k16.yaml +16 -0
  446. data/extras/image-generators/aws/windows.yaml +18 -0
  447. data/extras/image-generators/gcp/centos6.yaml +17 -0
  448. data/extras/lambda_waf_domain_blacklist.py +103 -0
  449. data/extras/platform_berksfile_base +50 -0
  450. data/extras/ruby_rpm/build.sh +17 -0
  451. data/extras/ruby_rpm/muby.spec +44 -0
  452. data/extras/vault_tools/README.md +6 -0
  453. data/extras/vault_tools/export_vaults.sh +3 -0
  454. data/extras/vault_tools/recreate_vaults.sh +5 -0
  455. data/extras/vault_tools/test_vaults.sh +5 -0
  456. data/install/README.md +8 -0
  457. data/install/cfn_create_mu_master.json +1034 -0
  458. data/install/chef-server.rb.erb +19 -0
  459. data/install/deprecated-bash-library.sh +1891 -0
  460. data/install/images/Usage.png +0 -0
  461. data/install/installer +71 -0
  462. data/install/jenkinskeys.rb +8 -0
  463. data/install/user-dot-murc.erb +14 -0
  464. data/modules/html.erb +19 -0
  465. data/modules/mommacat.ru +426 -0
  466. data/modules/mu/cleanup.rb +339 -0
  467. data/modules/mu/cloud.rb +1446 -0
  468. data/modules/mu/clouds/README.md +201 -0
  469. data/modules/mu/clouds/aws/alarm.rb +319 -0
  470. data/modules/mu/clouds/aws/cache_cluster.rb +1010 -0
  471. data/modules/mu/clouds/aws/collection.rb +373 -0
  472. data/modules/mu/clouds/aws/container_cluster.rb +667 -0
  473. data/modules/mu/clouds/aws/database.rb +1836 -0
  474. data/modules/mu/clouds/aws/dnszone.rb +911 -0
  475. data/modules/mu/clouds/aws/firewall_rule.rb +641 -0
  476. data/modules/mu/clouds/aws/folder.rb +92 -0
  477. data/modules/mu/clouds/aws/function.rb +349 -0
  478. data/modules/mu/clouds/aws/group.rb +251 -0
  479. data/modules/mu/clouds/aws/loadbalancer.rb +888 -0
  480. data/modules/mu/clouds/aws/log.rb +363 -0
  481. data/modules/mu/clouds/aws/msg_queue.rb +480 -0
  482. data/modules/mu/clouds/aws/notification.rb +139 -0
  483. data/modules/mu/clouds/aws/role.rb +656 -0
  484. data/modules/mu/clouds/aws/search_domain.rb +646 -0
  485. data/modules/mu/clouds/aws/server.rb +2294 -0
  486. data/modules/mu/clouds/aws/server_pool.rb +1388 -0
  487. data/modules/mu/clouds/aws/storage_pool.rb +495 -0
  488. data/modules/mu/clouds/aws/user.rb +382 -0
  489. data/modules/mu/clouds/aws/userdata/README.md +4 -0
  490. data/modules/mu/clouds/aws/userdata/linux.erb +179 -0
  491. data/modules/mu/clouds/aws/userdata/windows.erb +278 -0
  492. data/modules/mu/clouds/aws/vpc.rb +1943 -0
  493. data/modules/mu/clouds/aws.rb +1009 -0
  494. data/modules/mu/clouds/cloudformation/alarm.rb +146 -0
  495. data/modules/mu/clouds/cloudformation/cache_cluster.rb +167 -0
  496. data/modules/mu/clouds/cloudformation/collection.rb +117 -0
  497. data/modules/mu/clouds/cloudformation/database.rb +278 -0
  498. data/modules/mu/clouds/cloudformation/dnszone.rb +274 -0
  499. data/modules/mu/clouds/cloudformation/firewall_rule.rb +308 -0
  500. data/modules/mu/clouds/cloudformation/loadbalancer.rb +193 -0
  501. data/modules/mu/clouds/cloudformation/log.rb +170 -0
  502. data/modules/mu/clouds/cloudformation/server.rb +370 -0
  503. data/modules/mu/clouds/cloudformation/server_pool.rb +279 -0
  504. data/modules/mu/clouds/cloudformation/vpc.rb +322 -0
  505. data/modules/mu/clouds/cloudformation.rb +733 -0
  506. data/modules/mu/clouds/docker.rb +30 -0
  507. data/modules/mu/clouds/google/container_cluster.rb +290 -0
  508. data/modules/mu/clouds/google/database.rb +152 -0
  509. data/modules/mu/clouds/google/firewall_rule.rb +267 -0
  510. data/modules/mu/clouds/google/group.rb +164 -0
  511. data/modules/mu/clouds/google/loadbalancer.rb +479 -0
  512. data/modules/mu/clouds/google/server.rb +1510 -0
  513. data/modules/mu/clouds/google/server_pool.rb +274 -0
  514. data/modules/mu/clouds/google/user.rb +266 -0
  515. data/modules/mu/clouds/google/userdata/README.md +4 -0
  516. data/modules/mu/clouds/google/userdata/linux.erb +137 -0
  517. data/modules/mu/clouds/google/userdata/windows.erb +275 -0
  518. data/modules/mu/clouds/google/vpc.rb +890 -0
  519. data/modules/mu/clouds/google.rb +811 -0
  520. data/modules/mu/config/README.md +11 -0
  521. data/modules/mu/config/alarm.rb +271 -0
  522. data/modules/mu/config/cache_cluster.rb +172 -0
  523. data/modules/mu/config/collection.rb +87 -0
  524. data/modules/mu/config/container_cluster.rb +103 -0
  525. data/modules/mu/config/container_cluster.yml +36 -0
  526. data/modules/mu/config/database.rb +458 -0
  527. data/modules/mu/config/database.yml +26 -0
  528. data/modules/mu/config/dnszone.rb +327 -0
  529. data/modules/mu/config/firewall_rule.rb +118 -0
  530. data/modules/mu/config/folder.rb +70 -0
  531. data/modules/mu/config/function.rb +140 -0
  532. data/modules/mu/config/group.rb +64 -0
  533. data/modules/mu/config/loadbalancer.rb +482 -0
  534. data/modules/mu/config/log.rb +47 -0
  535. data/modules/mu/config/log.yml +6 -0
  536. data/modules/mu/config/msg_queue.rb +47 -0
  537. data/modules/mu/config/msg_queue.yml +9 -0
  538. data/modules/mu/config/notification.rb +44 -0
  539. data/modules/mu/config/project.rb +71 -0
  540. data/modules/mu/config/role.rb +102 -0
  541. data/modules/mu/config/search_domain.rb +61 -0
  542. data/modules/mu/config/search_domain.yml +25 -0
  543. data/modules/mu/config/server.rb +587 -0
  544. data/modules/mu/config/server.yml +8 -0
  545. data/modules/mu/config/server_pool.rb +216 -0
  546. data/modules/mu/config/server_pool.yml +71 -0
  547. data/modules/mu/config/storage_pool.rb +145 -0
  548. data/modules/mu/config/user.rb +78 -0
  549. data/modules/mu/config/vpc.rb +743 -0
  550. data/modules/mu/config/vpc.yml +6 -0
  551. data/modules/mu/config.rb +2000 -0
  552. data/modules/mu/defaults/README.md +2 -0
  553. data/modules/mu/defaults/amazon_images.yaml +121 -0
  554. data/modules/mu/defaults/google_images.yaml +16 -0
  555. data/modules/mu/deploy.rb +686 -0
  556. data/modules/mu/groomer.rb +123 -0
  557. data/modules/mu/groomers/README.md +58 -0
  558. data/modules/mu/groomers/chef.rb +1024 -0
  559. data/modules/mu/kittens.rb +11319 -0
  560. data/modules/mu/logger.rb +208 -0
  561. data/modules/mu/master/README.md +27 -0
  562. data/modules/mu/master/chef.rb +471 -0
  563. data/modules/mu/master/ldap.rb +1005 -0
  564. data/modules/mu/master.rb +415 -0
  565. data/modules/mu/mommacat.rb +2703 -0
  566. data/modules/mu-load-config.rb +1 -0
  567. data/modules/mu.rb +724 -0
  568. data/modules/scratchpad.erb +1 -0
  569. data/modules/tests/super_complex_bok.yml +41 -0
  570. data/modules/tests/super_simple_bok.yml +40 -0
  571. data/mu.gemspec +62 -0
  572. data/roles/demo-dbservice-configure.json +19 -0
  573. data/roles/demo-portal-configure.json +19 -0
  574. data/roles/mu-master-jenkins.json +24 -0
  575. data/roles/mu-master-nagios-only.json +13 -0
  576. data/roles/mu-master.json +12 -0
  577. data/roles/mu-node.json +19 -0
  578. data/roles/mu-splunk-server.json +13 -0
  579. data/roles/mu-splunk.json +13 -0
  580. data/test/clean_up.py +25 -0
  581. data/test/demo-test-profile/README.md +3 -0
  582. data/test/demo-test-profile/controls/flask.rb +84 -0
  583. data/test/demo-test-profile/inspec.lock +7 -0
  584. data/test/demo-test-profile/inspec.yml +11 -0
  585. data/test/etco-test-profile/README.md +3 -0
  586. data/test/etco-test-profile/controls/all-in-one.rb +182 -0
  587. data/test/etco-test-profile/inspec.lock +7 -0
  588. data/test/etco-test-profile/inspec.yml +11 -0
  589. data/test/exec_inspec.py +246 -0
  590. data/test/exec_mu_install.py +241 -0
  591. data/test/exec_retry.py +44 -0
  592. data/test/mu-master-test/README.md +3 -0
  593. data/test/mu-master-test/controls/all_in_one.rb +557 -0
  594. data/test/mu-master-test/inspec.lock +3 -0
  595. data/test/mu-master-test/inspec.yml +11 -0
  596. data/test/mu-tools-test/README.md +3 -0
  597. data/test/mu-tools-test/controls/base.rb +265 -0
  598. data/test/mu-tools-test/inspec.lock +3 -0
  599. data/test/mu-tools-test/inspec.yml +8 -0
  600. data/test/simple-server-php-test/README.md +3 -0
  601. data/test/simple-server-php-test/controls/apachephp.rb +25 -0
  602. data/test/simple-server-php-test/controls/example.rb +19 -0
  603. data/test/simple-server-php-test/inspec.lock +7 -0
  604. data/test/simple-server-php-test/inspec.yml +12 -0
  605. data/test/simple-server-rails-test/README.md +3 -0
  606. data/test/simple-server-rails-test/controls/rails.rb +188 -0
  607. data/test/simple-server-rails-test/inspec.lock +7 -0
  608. data/test/simple-server-rails-test/inspec.yml +11 -0
  609. data/test/simple-windows-test/README.md +3 -0
  610. data/test/simple-windows-test/controls/windows.rb +20 -0
  611. data/test/simple-windows-test/inspec.lock +7 -0
  612. data/test/simple-windows-test/inspec.yml +11 -0
  613. data/test/smoke_test.rb +75 -0
  614. data/test/wordpress-test/README.md +3 -0
  615. data/test/wordpress-test/controls/wordpress.rb +97 -0
  616. data/test/wordpress-test/inspec.lock +7 -0
  617. data/test/wordpress-test/inspec.yml +11 -0
  618. metadata +979 -0
@@ -0,0 +1,1388 @@
1
+ # Copyright:: Copyright (c) 2014 eGlobalTech, Inc., all rights reserved
2
+ #
3
+ # Licensed under the BSD-3 license (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License in the root of the project or at
6
+ #
7
+ # http://egt-labs.com/mu/LICENSE.html
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module MU
16
+ class Cloud
17
+ class AWS
18
+ # A server pool as configured in {MU::Config::BasketofKittens::server_pools}
19
+ class ServerPool < MU::Cloud::ServerPool
20
+
21
+ @deploy = nil
22
+ @config = nil
23
+ attr_reader :mu_name
24
+ attr_reader :cloud_id
25
+ attr_reader :config
26
+
27
+ # @param mommacat [MU::MommaCat]: A {MU::Mommacat} object containing the deploy of which this resource is/will be a member.
28
+ # @param kitten_cfg [Hash]: The fully parsed and resolved {MU::Config} resource descriptor as defined in {MU::Config::BasketofKittens::server_pools}
29
+ def initialize(mommacat: nil, kitten_cfg: nil, mu_name: nil, cloud_id: nil)
30
+ @deploy = mommacat
31
+ @config = MU::Config.manxify(kitten_cfg)
32
+ @cloud_id ||= cloud_id
33
+ if !mu_name.nil?
34
+ @mu_name = mu_name
35
+ elsif @config['scrub_mu_isms']
36
+ @mu_name = @config['name']
37
+ else
38
+ @mu_name = @deploy.getResourceName(@config['name'])
39
+ end
40
+ end
41
+
42
+ # Called automatically by {MU::Deploy#createResources}
43
+ def create
44
+ MU.setVar("curRegion", @config['region']) if !@config['region'].nil?
45
+
46
+ createUpdateLaunchConfig
47
+
48
+ asg_options = buildOptionsHash
49
+
50
+ MU.log "Creating AutoScale group #{@mu_name}", details: asg_options
51
+
52
+ zones_to_try = @config["zones"]
53
+ begin
54
+ asg = MU::Cloud::AWS.autoscale(@config['region']).create_auto_scaling_group(asg_options)
55
+ rescue Aws::AutoScaling::Errors::ValidationError => e
56
+ if zones_to_try != nil and zones_to_try.size > 0
57
+ MU.log "#{e.message}, retrying with individual AZs", MU::WARN
58
+ asg_options[:availability_zones] = [zones_to_try.pop]
59
+ retry
60
+ else
61
+ MU.log e.message, MU::ERR, details: asg_options
62
+ raise MuError, "#{e.message} creating AutoScale group #{@mu_name}"
63
+ end
64
+ end
65
+
66
+ if zones_to_try != nil and zones_to_try.size < @config["zones"].size
67
+ zones_to_try.each { |zone|
68
+ begin
69
+ MU::Cloud::AWS.autoscale(@config['region']).update_auto_scaling_group(
70
+ auto_scaling_group_name: @mu_name,
71
+ availability_zones: [zone]
72
+ )
73
+ rescue Aws::AutoScaling::Errors::ValidationError => e
74
+ MU.log "Couldn't enable Availability Zone #{zone} for AutoScale Group #{@mu_name} (#{e.message})", MU::WARN
75
+ end
76
+ }
77
+
78
+ end
79
+
80
+ @cloud_id = @mu_name
81
+
82
+
83
+ # Wait and see if we successfully bring up some instances
84
+ attempts = 0
85
+ begin
86
+ sleep 5
87
+ desc = MU::Cloud::AWS.autoscale(@config['region']).describe_auto_scaling_groups(auto_scaling_group_names: [@mu_name]).auto_scaling_groups.first
88
+ MU.log "Looking for #{desc.min_size} instances in #{@mu_name}, found #{desc.instances.size}", MU::DEBUG
89
+ attempts = attempts + 1
90
+ if attempts > 25 and desc.instances.size == 0
91
+ MU.log "No instances spun up after #{5*attempts} seconds, something's wrong with Autoscale group #{@mu_name}", MU::ERR, details: MU::Cloud::AWS.autoscale(@config['region']).describe_scaling_activities(auto_scaling_group_name: @mu_name).activities
92
+ raise MuError, "No instances spun up after #{5*attempts} seconds, something's wrong with Autoscale group #{@mu_name}"
93
+ end
94
+ end while desc.instances.size < desc.min_size
95
+ MU.log "#{desc.instances.size} instances spinning up in #{@mu_name}"
96
+
97
+ # If we're holding to bootstrap some nodes, do so, then set our min/max
98
+ # sizes to their real values.
99
+ if @config["wait_for_nodes"] > 0
100
+ MU.log "Waiting for #{@config["wait_for_nodes"]} nodes to fully bootstrap before proceeding"
101
+ parent_thread_id = Thread.current.object_id
102
+ groomthreads = Array.new
103
+ desc.instances.each { |member|
104
+ begin
105
+ groomthreads << Thread.new {
106
+ Thread.abort_on_exception = false
107
+ MU.dupGlobals(parent_thread_id)
108
+ MU.log "Initializing #{member.instance_id} in ServerPool #{@mu_name}"
109
+ MU::MommaCat.lock(member.instance_id+"-mommagroom")
110
+ kitten = MU::Cloud::Server.new(mommacat: @deploy, kitten_cfg: @config, cloud_id: member.instance_id)
111
+ MU::MommaCat.lock("#{kitten.cloudclass.name}_#{kitten.config["name"]}-dependencies")
112
+ MU::MommaCat.unlock("#{kitten.cloudclass.name}_#{kitten.config["name"]}-dependencies")
113
+ if !kitten.postBoot(member.instance_id)
114
+ raise MU::Groomer::RunError, "Failure grooming #{member.instance_id}"
115
+ end
116
+ kitten.groom
117
+ MU::MommaCat.unlockAll
118
+ }
119
+ rescue MU::Groomer::RunError => e
120
+ MU.log "Proceeding after failed initial Groomer run, but #{member.instance_id} may not behave as expected!", MU::WARN, details: e.inspect
121
+ rescue Exception => e
122
+ if !member.nil? and !done
123
+ MU.log "Aborted before I could finish setting up #{@config['name']}, cleaning it up. Stack trace will print once cleanup is complete.", MU::WARN if !@deploy.nocleanup
124
+ MU::MommaCat.unlockAll
125
+ if !@deploy.nocleanup
126
+ Thread.new {
127
+ MU.dupGlobals(parent_thread_id)
128
+ MU::Cloud::AWS::Server.terminateInstance(id: member.instance_id)
129
+ }
130
+ end
131
+ end
132
+ raise MuError, e.inspect
133
+ end
134
+ }
135
+ groomthreads.each { |t|
136
+ t.join
137
+ }
138
+ MU.log "Setting min_size to #{@config['min_size']} and max_size to #{@config['max_size']}"
139
+ MU::Cloud::AWS.autoscale(@config['region']).update_auto_scaling_group(
140
+ auto_scaling_group_name: @mu_name,
141
+ min_size: @config['min_size'],
142
+ max_size: @config['max_size']
143
+ )
144
+ end
145
+
146
+ if @config['scale_in_protection']
147
+ need_instances = @config['scale_in_protection'].match(/^\d+$/) ? @config['scale_in_protection'].to_i : @config['min_size']
148
+ setScaleInProtection(need_instances)
149
+ end
150
+
151
+ MU.log "See /var/log/mu-momma-cat.log for asynchronous bootstrap progress.", MU::NOTICE
152
+
153
+ return asg
154
+ end
155
+
156
+ # Make sure we have a set of instances with scale-in protection set which jives with our config
157
+ # @param need_instances [Integer]: The number of instanceswhich must have scale-in protection set
158
+ def setScaleInProtection(need_instances = @config['min_size'])
159
+ live_instances = []
160
+ begin
161
+ desc = MU::Cloud::AWS.autoscale(@config['region']).describe_auto_scaling_groups(auto_scaling_group_names: [@mu_name]).auto_scaling_groups.first
162
+
163
+ live_instances = desc.instances.map { |i| i.instance_id }
164
+ already_set = 0
165
+ desc.instances.each { |i|
166
+ already_set += 1 if i.protected_from_scale_in
167
+ }
168
+ if live_instances.size < need_instances
169
+ sleep 5
170
+ elsif already_set > need_instances
171
+ unset_me = live_instances.sample(already_set - need_instances)
172
+ MU.log "Disabling scale-in protection for #{unset_me.size.to_s} instances in #{@mu_name}", MU::NOTICE, details: unset_me
173
+ MU::Cloud::AWS.autoscale(@config['region']).set_instance_protection(
174
+ auto_scaling_group_name: @mu_name,
175
+ instance_ids: unset_me,
176
+ protected_from_scale_in: false
177
+ )
178
+ elsif already_set < need_instances
179
+ live_instances = live_instances.sample(need_instances)
180
+ MU.log "Enabling scale-in protection for #{@config['scale_in_protection']} instances in #{@mu_name}", details: live_instances
181
+ begin
182
+ MU::Cloud::AWS.autoscale(@config['region']).set_instance_protection(
183
+ auto_scaling_group_name: @mu_name,
184
+ instance_ids: live_instances,
185
+ protected_from_scale_in: true
186
+ )
187
+ rescue Aws::AutoScaling::Errors::ValidationError => e
188
+ if e.message.match(/not in InService/i)
189
+ sleep 5
190
+ retry
191
+ else
192
+ raise e
193
+ end
194
+ end
195
+ end
196
+ end while live_instances.size < need_instances
197
+ end
198
+
199
+ # List out the nodes that are members of this pool
200
+ # @return [Array<MU::Cloud::Server>]
201
+ def listNodes
202
+ nodes = []
203
+ me = MU::Cloud::AWS::ServerPool.find(cloud_id: cloud_id)
204
+ if me and me.first and me.first.instances
205
+ me.first.instances.each { |instance|
206
+ found = MU::MommaCat.findStray("AWS", "server", cloud_id: instance.instance_id, region: @config["region"], dummy_ok: true)
207
+ nodes.concat(found)
208
+ }
209
+ end
210
+ nodes
211
+ end
212
+
213
+ # Called automatically by {MU::Deploy#createResources}
214
+ def groom
215
+ if @config['schedule']
216
+ ext_actions = MU::Cloud::AWS.autoscale(@config['region']).describe_scheduled_actions(
217
+ auto_scaling_group_name: @mu_name
218
+ ).scheduled_update_group_actions
219
+
220
+
221
+ @config['schedule'].each { |s|
222
+ sched_config = {
223
+ :auto_scaling_group_name => @mu_name,
224
+ :scheduled_action_name => s['action_name']
225
+ }
226
+ ['max_size', 'min_size', 'desired_capacity', 'recurrence'].each { |flag|
227
+ sched_config[flag.to_sym] = s[flag] if s[flag]
228
+ }
229
+ ['start_time', 'end_time'].each { |flag|
230
+ sched_config[flag.to_sym] = Time.parse(s[flag]) if s[flag]
231
+ }
232
+ action_already_correct = false
233
+ ext_actions.each { |ext|
234
+ if s['action_name'] == ext.scheduled_action_name
235
+ if !MU.hashCmp(MU.structToHash(ext), sched_config, missing_is_default: true)
236
+ MU.log "Removing scheduled action #{s['action_name']} from AutoScale group #{@mu_name}"
237
+ MU::Cloud::AWS.autoscale(@config['region']).delete_scheduled_action(
238
+ auto_scaling_group_name: @mu_name,
239
+ scheduled_action_name: s['action_name']
240
+ )
241
+ else
242
+ action_already_correct = true
243
+ end
244
+ break
245
+ end
246
+ }
247
+ if !action_already_correct
248
+ MU.log "Adding scheduled action to AutoScale group #{@mu_name}", MU::NOTICE, details: sched_config
249
+ MU::Cloud::AWS.autoscale(@config['region']).put_scheduled_update_group_action(
250
+ sched_config
251
+ )
252
+ end
253
+ }
254
+ end
255
+
256
+ createUpdateLaunchConfig
257
+
258
+ current = cloud_desc
259
+ asg_options = buildOptionsHash
260
+
261
+ need_tag_update = false
262
+ oldtags = current.tags.map { |t|
263
+ t.key+" "+t.value+" "+t.propagate_at_launch.to_s
264
+ }
265
+ tag_conf = { :tags => asg_options[:tags] }
266
+ tag_conf[:tags].each { |t|
267
+ if !oldtags.include?(t[:key]+" "+t[:value]+" "+t[:propagate_at_launch].to_s)
268
+ need_tag_update = true
269
+ end
270
+ t[:resource_id] = @mu_name
271
+ t[:resource_type] = "auto-scaling-group"
272
+ }
273
+
274
+ if need_tag_update
275
+ MU.log "Updating ServerPool #{@mu_name} with new tags", MU::NOTICE, details: tag_conf[:tags]
276
+
277
+ MU::Cloud::AWS.autoscale(@config['region']).create_or_update_tags(tag_conf)
278
+ current.instances.each { |instance|
279
+ tag_conf[:tags].each { |t|
280
+ MU::MommaCat.createTag(instance.instance_id, t[:key], t[:value], region: @config['region'])
281
+ }
282
+ }
283
+ end
284
+
285
+ # XXX actually compare for changes instead of just blindly updating
286
+ #pp current
287
+ #pp asg_options
288
+ asg_options.delete(:tags)
289
+ asg_options[:min_size] = @config["min_size"]
290
+ asg_options[:max_size] = @config["max_size"]
291
+ asg_options[:new_instances_protected_from_scale_in] = (@config['scale_in_protection'] == "all")
292
+ tg_arns = []
293
+ if asg_options[:target_group_arns]
294
+ MU::Cloud::AWS.autoscale(@config['region']).attach_load_balancer_target_groups(
295
+ auto_scaling_group_name: @mu_name,
296
+ target_group_arns: asg_options[:target_group_arns]
297
+ )
298
+ tg_arns = asg_options[:target_group_arns].dup
299
+ asg_options.delete(:target_group_arns)
300
+ end
301
+
302
+ MU::Cloud::AWS.autoscale(@config['region']).update_auto_scaling_group(asg_options)
303
+
304
+ if @config['scale_in_protection']
305
+ if @config['scale_in_protection'] == "all"
306
+ setScaleInProtection(listNodes.size)
307
+ elsif @config['scale_in_protection'] == "initial"
308
+ setScaleInProtection(@config['min_size'])
309
+ elsif @config['scale_in_protection'].match(/^\d+$/)
310
+ setScaleInProtection(@config['scale_in_protection'].to_i)
311
+ end
312
+ else
313
+ setScaleInProtection(0)
314
+ end
315
+
316
+ ext_pols = MU::Cloud::AWS.autoscale(@config['region']).describe_policies(
317
+ auto_scaling_group_name: @mu_name
318
+ ).scaling_policies
319
+ if @config["scaling_policies"] and @config["scaling_policies"].size > 0
320
+ legit_policies = []
321
+ @config["scaling_policies"].each { |policy|
322
+ legit_policies << @deploy.getResourceName("#{@config['name']}-#{policy['name']}")
323
+ }
324
+ # Delete any scaling policies we're not configured for
325
+ ext_pols.each { |ext|
326
+ if !legit_policies.include?(ext.policy_name)
327
+ MU.log "Scaling policy #{ext.policy_name} is not named in scaling_policies, removing from #{@mu_name}", MU::NOTICE, details: ext
328
+ MU::Cloud::AWS.autoscale(@config['region']).delete_policy(
329
+ auto_scaling_group_name: @mu_name,
330
+ policy_name: ext.policy_name
331
+ )
332
+ end
333
+ }
334
+
335
+ @config["scaling_policies"].each { |policy|
336
+ policy_name = @deploy.getResourceName("#{@config['name']}-#{policy['name']}")
337
+ policy_params = {
338
+ :auto_scaling_group_name => @mu_name,
339
+ :policy_name => policy_name,
340
+ :policy_type => policy['policy_type']
341
+ }
342
+
343
+ if policy["policy_type"] == "SimpleScaling"
344
+ policy_params[:cooldown] = policy['cooldown']
345
+ policy_params[:scaling_adjustment] = policy['adjustment']
346
+ policy_params[:adjustment_type] = policy['type']
347
+ elsif policy["policy_type"] == "TargetTrackingScaling"
348
+ def strToSym(hash)
349
+ newhash = {}
350
+ hash.each_pair { |k, v|
351
+ if v.is_a?(Hash)
352
+ newhash[k.to_sym] = strToSym(v)
353
+ else
354
+ newhash[k.to_sym] = v
355
+ end
356
+ }
357
+ newhash
358
+ end
359
+ policy_params[:target_tracking_configuration] = strToSym(policy['target_tracking_configuration'])
360
+ if policy_params[:target_tracking_configuration][:predefined_metric_specification] and
361
+ policy_params[:target_tracking_configuration][:predefined_metric_specification][:predefined_metric_type] == "ALBRequestCountPerTarget"
362
+ lb_path = nil
363
+ lb = @deploy.deployment["loadbalancers"].values.first
364
+ if @deploy.deployment["loadbalancers"].size > 1
365
+ MU.log "Multiple load balancers attached to Autoscale group #{@mu_name}, guessing wildly which one to use for TargetTrackingScaling policy", MU::WARN
366
+ end
367
+ if lb["targetgroups"].size > 1
368
+ MU.log "Multiple target groups attached to Autoscale group #{@mu_name}, guessing wildly which one to use for TargetTrackingScaling policy", MU::WARN
369
+ end
370
+ lb_path = lb["arn"].split(/:/)[5].sub(/^loadbalancer\//, "")+"/"+lb["targetgroups"].values.first.split(/:/)[5]
371
+
372
+ policy_params[:target_tracking_configuration][:predefined_metric_specification][:resource_label] = lb_path
373
+ end
374
+ policy_params[:estimated_instance_warmup] = policy['estimated_instance_warmup']
375
+ elsif policy["policy_type"] == "StepScaling"
376
+ step_adjustments = []
377
+ policy['step_adjustments'].each{|step|
378
+ step_adjustments << {:metric_interval_lower_bound => step["lower_bound"], :metric_interval_upper_bound => step["upper_bound"], :scaling_adjustment => step["adjustment"]}
379
+ }
380
+ policy_params[:metric_aggregation_type] = policy['metric_aggregation_type']
381
+ policy_params[:step_adjustments] = step_adjustments
382
+ policy_params[:estimated_instance_warmup] = policy['estimated_instance_warmup']
383
+ policy_params[:adjustment_type] = policy['type']
384
+ end
385
+
386
+ policy_params[:min_adjustment_magnitude] = policy['min_adjustment_magnitude'] if !policy['min_adjustment_magnitude'].nil?
387
+
388
+ policy_already_correct = false
389
+ ext_pols.each { |ext|
390
+ if ext.policy_name == policy_name
391
+ if !MU.hashCmp(MU.structToHash(ext), policy_params, missing_is_default: true)
392
+ MU::Cloud::AWS.autoscale(@config['region']).delete_policy(
393
+ auto_scaling_group_name: @mu_name,
394
+ policy_name: policy_name
395
+ )
396
+ else
397
+ policy_already_correct = true
398
+ end
399
+ break
400
+ end
401
+ }
402
+ if !policy_already_correct
403
+ MU.log "Putting scaling policy #{policy_name} for #{@mu_name}", MU::NOTICE, details: policy_params
404
+ resp = MU::Cloud::AWS.autoscale(@config['region']).put_scaling_policy(policy_params)
405
+ end
406
+
407
+
408
+ # If we are creating alarms for scaling policies we need to have the autoscaling policy ARN
409
+ # To make life easier we're creating the alarms here
410
+ if policy.has_key?("alarms") && !policy["alarms"].empty?
411
+ policy["alarms"].each { |alarm|
412
+ alarm["alarm_actions"] = [] if !alarm.has_key?("alarm_actions")
413
+ alarm["ok_actions"] = [] if !alarm.has_key?("ok_actions")
414
+ alarm["alarm_actions"] << resp.policy_arn
415
+ alarm["dimensions"] = [{name: "AutoScalingGroupName", value: asg_options[:auto_scaling_group_name]}]
416
+
417
+ if alarm["enable_notifications"]
418
+ topic_arn = MU::Cloud::AWS::Notification.createTopic(alarm["notification_group"], region: @config["region"])
419
+ MU::Cloud::AWS::Notification.subscribe(arn: topic_arn, protocol: alarm["notification_type"], endpoint: alarm["notification_endpoint"], region: @config["region"])
420
+ alarm["alarm_actions"] << topic_arn
421
+ alarm["ok_actions"] << topic_arn
422
+ end
423
+
424
+ MU::Cloud::AWS::Alarm.setAlarm(
425
+ name: "#{MU.deploy_id}-#{alarm["name"]}".upcase,
426
+ ok_actions: alarm["ok_actions"],
427
+ alarm_actions: alarm["alarm_actions"],
428
+ insufficient_data_actions: alarm["no_data_actions"],
429
+ metric_name: alarm["metric_name"],
430
+ namespace: alarm["namespace"],
431
+ statistic: alarm["statistic"],
432
+ dimensions: alarm["dimensions"],
433
+ period: alarm["period"],
434
+ unit: alarm["unit"],
435
+ evaluation_periods: alarm["evaluation_periods"],
436
+ threshold: alarm["threshold"],
437
+ comparison_operator: alarm["comparison_operator"],
438
+ region: @config["region"]
439
+ )
440
+ }
441
+ end
442
+ }
443
+ end
444
+
445
+ end
446
+
447
+ # Retrieve the AWS descriptor for this Autoscale group
448
+ # @return [OpenStruct]
449
+ def cloud_desc
450
+ MU::Cloud::AWS.autoscale(@config['region']).describe_auto_scaling_groups(
451
+ auto_scaling_group_names: [@mu_name]
452
+ ).auto_scaling_groups.first
453
+ end
454
+
455
+ # Canonical Amazon Resource Number for this resource
456
+ # @return [String]
457
+ def arn
458
+ cloud_desc.auto_scaling_group_arn
459
+ end
460
+
461
+ # Retrieve deployment metadata for this Autoscale group
462
+ # @return [Hash]
463
+ def notify
464
+ return MU.structToHash(cloud_desc)
465
+ end
466
+
467
+ # Locate an existing ServerPool or ServerPools and return an array containing matching AWS resource descriptors for those that match.
468
+ # @param cloud_id [String]: The cloud provider's identifier for this resource.
469
+ # @param region [String]: The cloud provider region
470
+ # @param tag_key [String]: A tag key to search.
471
+ # @param tag_value [String]: The value of the tag specified by tag_key to match when searching by tag.
472
+ # @param flags [Hash]: Optional flags
473
+ # @return [Array<Hash<String,OpenStruct>>]: The cloud provider's complete descriptions of matching ServerPools
474
+ def self.find(cloud_id: nil, region: MU.curRegion, tag_key: "Name", tag_value: nil, flags: {})
475
+ found = []
476
+ if cloud_id
477
+ resp = MU::Cloud::AWS.autoscale(region).describe_auto_scaling_groups({
478
+ auto_scaling_group_names: [
479
+ cloud_id
480
+ ],
481
+ })
482
+ return resp.auto_scaling_groups
483
+ end
484
+ # TODO implement the tag-based search
485
+ return found
486
+ end
487
+
488
+ # Cloud-specific configuration properties.
489
+ # @param config [MU::Config]: The calling MU::Config object
490
+ # @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource
491
+ def self.schema(config)
492
+ toplevel_required = []
493
+
494
+ schema = {
495
+ "generate_iam_role" => {
496
+ "type" => "boolean",
497
+ "default" => true,
498
+ "description" => "Generate a unique IAM profile for this Server or ServerPool.",
499
+ },
500
+ "iam_role" => {
501
+ "type" => "string",
502
+ "description" => "An Amazon IAM instance profile, from which to harvest role policies to merge into this node's own instance profile. If generate_iam_role is false, will simple use this profile.",
503
+ },
504
+ "iam_policies" => {
505
+ "type" => "array",
506
+ "items" => {
507
+ "description" => "Amazon-compatible role policies which will be merged into this node's own instance profile. Not valid with generate_iam_role set to false. Our parser expects the role policy document to me embedded under a named container, e.g. { 'name_of_policy':'{ <policy document> } }",
508
+ "type" => "object"
509
+ }
510
+ },
511
+ "canned_iam_policies" => {
512
+ "type" => "array",
513
+ "items" => {
514
+ "description" => "IAM policies to attach, pre-defined by Amazon (e.g. AmazonEKSWorkerNodePolicy)",
515
+ "type" => "string"
516
+ }
517
+ },
518
+ "schedule" => {
519
+ "type" => "array",
520
+ "items" => {
521
+ "type" => "object",
522
+ "required" => ["action_name"],
523
+ "description" => "Tell AutoScale to alter min/max/desired for this group at a scheduled time, optionally repeating.",
524
+ "properties" => {
525
+ "action_name" => {
526
+ "type" => "string",
527
+ "description" => "A name for this scheduled action, e.g. 'scale-down-over-night'"
528
+ },
529
+ "start_time" => {
530
+ "type" => "string",
531
+ "description" => "When should this one-off scheduled behavior take effect? Times are UTC. Must be a valid Ruby Time.parse() string, e.g. '20:00' or '2014-05-12T08:00:00Z'. If declared along with 'recurrence,' AutoScaling performs the action at this time, and then performs the action based on the specified recurrence."
532
+ },
533
+ "end_time" => {
534
+ "type" => "string",
535
+ "description" => "When should this scheduled behavior end? Times are UTC. Must be a valid Ruby Time.parse() string, e.g. '20:00' or '2014-05-12T08:00:00Z'"
536
+ },
537
+ "recurrence" => {
538
+ "type" => "string",
539
+ "description" => "A recurring schedule for this action, in Unix cron syntax format (e.g. '0 20 * * *'). Times are UTC."
540
+ },
541
+ "min_size" => {"type" => "integer"},
542
+ "max_size" => {"type" => "integer"},
543
+ "desired_capacity" => {
544
+ "type" => "integer",
545
+ "description" => "The number of Amazon EC2 instances that should be running in the group. Should be between min_size and max_size."
546
+ },
547
+
548
+ }
549
+ }
550
+ },
551
+ "scale_in_protection" => {
552
+ "type" => "string",
553
+ "description" => "Protect instances from scale-in termination. Can be 'all', 'initial' (essentially 'min_size'), or an number; note the number needs to be a string, so put it in quotes",
554
+ "pattern" => "^(all|initial|\\d+)$"
555
+ },
556
+ "scale_with_alb_traffic" => {
557
+ "type" => "float",
558
+ "description" => "Shorthand for creating a target_tracking_configuration to scale on ALBRequestCountPerTarget with some reasonable defaults"
559
+ },
560
+ "scale_with_cpu" => {
561
+ "type" => "float",
562
+ "description" => "Shorthand for creating a target_tracking_configuration to scale on ASGAverageCPUUtilization with some reasonable defaults"
563
+ },
564
+ "scale_with_network_in" => {
565
+ "type" => "float",
566
+ "description" => "Shorthand for creating a target_tracking_configuration to scale on ASGAverageNetworkIn with some reasonable defaults"
567
+ },
568
+ "scale_with_network_out" => {
569
+ "type" => "float",
570
+ "description" => "Shorthand for creating a target_tracking_configuration to scale on ASGAverageNetworkOut with some reasonable defaults"
571
+ },
572
+ "termination_policies" => {
573
+ "type" => "array",
574
+ "minItems" => 1,
575
+ "items" => {
576
+ "type" => "String",
577
+ "default" => "Default",
578
+ "enum" => MU::Cloud::AWS.autoscale.describe_termination_policy_types.termination_policy_types
579
+ }
580
+ },
581
+ "scaling_policies" => {
582
+ "type" => "array",
583
+ "minItems" => 1,
584
+ "items" => {
585
+ "type" => "object",
586
+ "required" => ["name"],
587
+ "additionalProperties" => false,
588
+ "description" => "A custom AWS Autoscale scaling policy for this pool.",
589
+ "properties" => {
590
+ "name" => {
591
+ "type" => "string"
592
+ },
593
+ "alarms" => MU::Config::Alarm.inline,
594
+ "type" => {
595
+ "type" => "string",
596
+ "enum" => ["ChangeInCapacity", "ExactCapacity", "PercentChangeInCapacity"],
597
+ "description" => "Specifies whether 'adjustment' is an absolute number or a percentage of the current capacity for SimpleScaling and StepScaling. Valid values are ChangeInCapacity, ExactCapacity, and PercentChangeInCapacity."
598
+ },
599
+ "adjustment" => {
600
+ "type" => "integer",
601
+ "description" => "The number of instances by which to scale. 'type' determines the interpretation of this number (e.g., as an absolute number or as a percentage of the existing Auto Scaling group size). A positive increment adds to the current capacity and a negative value removes from the current capacity. Used only when policy_type is set to 'SimpleScaling'"
602
+ },
603
+ "cooldown" => {
604
+ "type" => "integer",
605
+ "default" => 1,
606
+ "description" => "The amount of time, in seconds, after a scaling activity completes and before the next scaling activity can start."
607
+ },
608
+ "min_adjustment_magnitude" => {
609
+ "type" => "integer",
610
+ "description" => "Used when 'type' is set to 'PercentChangeInCapacity', the scaling policy changes the DesiredCapacity of the Auto Scaling group by at least the number of instances specified in the value."
611
+ },
612
+ "policy_type" => {
613
+ "type" => "string",
614
+ "enum" => ["SimpleScaling", "StepScaling", "TargetTrackingScaling"],
615
+ "description" => "'StepScaling' will add capacity based on the magnitude of the alarm breach, 'SimpleScaling' will add capacity based on the 'adjustment' value provided. Defaults to 'SimpleScaling'.",
616
+ "default" => "SimpleScaling"
617
+ },
618
+ "metric_aggregation_type" => {
619
+ "type" => "string",
620
+ "enum" => ["Minimum", "Maximum", "Average"],
621
+ "description" => "Defaults to 'Average' if not specified. Required when policy_type is set to 'StepScaling'",
622
+ "default" => "Average"
623
+ },
624
+ "step_adjustments" => {
625
+ "type" => "array",
626
+ "minItems" => 1,
627
+ "items" => {
628
+ "type" => "object",
629
+ "title" => "admin",
630
+ "description" => "Requires policy_type 'StepScaling'",
631
+ "required" => ["adjustment"],
632
+ "additionalProperties" => false,
633
+ "properties" => {
634
+ "adjustment" => {
635
+ "type" => "integer",
636
+ "description" => "The number of instances by which to scale at this specific step. Postive value when adding capacity, negative value when removing capacity"
637
+ },
638
+ "lower_bound" => {
639
+ "type" => "integer",
640
+ "description" => "The lower bound value in percentage points above/below the alarm threshold at which to add/remove capacity for this step. Positive value when adding capacity and negative when removing capacity. If this is the first step and capacity is being added this value will most likely be 0"
641
+ },
642
+ "upper_bound" => {
643
+ "type" => "integer",
644
+ "description" => "The upper bound value in percentage points above/below the alarm threshold at which to add/remove capacity for this step. Positive value when adding capacity and negative when removing capacity. If this is the first step and capacity is being removed this value will most likely be 0"
645
+ }
646
+ }
647
+ }
648
+ },
649
+ "estimated_instance_warmup" => {
650
+ "type" => "integer",
651
+ "description" => "Required when policy_type is set to 'StepScaling'"
652
+ },
653
+ "target_tracking_configuration" => {
654
+ "type" => "object",
655
+ "description" => "Required when policy_type is set to 'TargetTrackingScaling' https://docs.aws.amazon.com/sdkforruby/api/Aws/AutoScaling/Types/TargetTrackingConfiguration.html",
656
+ "required" => ["target_value"],
657
+ "additionalProperties" => false,
658
+ "properties" => {
659
+ "target_value" => {
660
+ "type" => "float",
661
+ "description" => "The target value for the metric."
662
+ },
663
+ "disable_scale_in" => {
664
+ "type" => "boolean",
665
+ "description" => "If set to true, new instances created by this policy will not be subject to termination by scaling in.",
666
+ "default" => false
667
+ },
668
+ "predefined_metric_specification" => {
669
+ "description" => "A predefined metric. You can specify either a predefined metric or a customized metric. https://docs.aws.amazon.com/sdkforruby/api/Aws/AutoScaling/Types/PredefinedMetricSpecification.html",
670
+ "type" => "string",
671
+ "enum" => ["ASGAverageCPUUtilization", "ASGAverageNetworkIn", "ASGAverageNetworkOut", "ALBRequestCountPerTarget"],
672
+ "default" => "ASGAverageCPUUtilization"
673
+ },
674
+ "customized_metric_specification" => {
675
+ "type" => "object",
676
+ "description" => "A customized metric. You can specify either a predefined metric or a customized metric. https://docs.aws.amazon.com/sdkforruby/api/Aws/AutoScaling/Types/TargetTrackingConfiguration.html#customized_metric_specification-instance_method",
677
+ "additionalProperties" => false,
678
+ "required" => ["metric_name", "namespace", "statistic"],
679
+ "properties" => {
680
+ "metric_name" => {
681
+ "type" => "string",
682
+ "description" => "The name of the attribute to monitor eg. CPUUtilization."
683
+ },
684
+ "namespace" => {
685
+ "type" => "string",
686
+ "description" => "The name of container 'metric_name' belongs to eg. 'AWS/ApplicationELB'"
687
+ },
688
+ "statistic" => {
689
+ "type" => "string",
690
+ "enum" => ["Average", "Minimum", "Maximum", "SampleCount", "Sum"]
691
+ },
692
+ "unit" => {
693
+ "type" => "string",
694
+ "description" => "Associated with the 'metric', usually something like Megabits or Seconds"
695
+ },
696
+ "dimensions" => {
697
+ "type" => "array",
698
+ "description" => "What resource to monitor with the alarm we are implicitly declaring",
699
+ "items" => {
700
+ "type" => "object",
701
+ "additionalProperties" => false,
702
+ "required" => ["name", "value"],
703
+ "properties" => {
704
+ "name" => {
705
+ "type" => "string",
706
+ "description" => "The type of resource we're monitoring, e.g. InstanceId or AutoScalingGroupName"
707
+ },
708
+ "value" => {
709
+ "type" => "string",
710
+ "description" => "The name or cloud identifier of the resource we're monitoring"
711
+ }
712
+ }
713
+ }
714
+ }
715
+ }
716
+ }
717
+ }
718
+ }
719
+ }
720
+ }
721
+ },
722
+ "ingress_rules" => {
723
+ "items" => {
724
+ "properties" => {
725
+ "sgs" => {
726
+ "type" => "array",
727
+ "items" => {
728
+ "description" => "Other AWS Security Groups; resources that are associated with this group will have this rule applied to their traffic",
729
+ "type" => "string"
730
+ }
731
+ },
732
+ "lbs" => {
733
+ "type" => "array",
734
+ "items" => {
735
+ "description" => "AWS Load Balancers which will have this rule applied to their traffic",
736
+ "type" => "string"
737
+ }
738
+ }
739
+ }
740
+ }
741
+ }
742
+ }
743
+ [toplevel_required, schema]
744
+ end
745
+
746
+ # Cloud-specific pre-processing of {MU::Config::BasketofKittens::server_pools}, bare and unvalidated.
747
+ # @param pool [Hash]: The resource to process and validate
748
+ # @param configurator [MU::Config]: The overall deployment configurator of which this resource is a member
749
+ # @return [Boolean]: True if validation succeeded, False otherwise
750
+ def self.validateConfig(pool, configurator)
751
+ ok = true
752
+
753
+ if pool["termination_policy"]
754
+ valid_policies = MU::Cloud::AWS.autoscale(pool['region']).describe_termination_policy_types.termination_policy_types
755
+ if !valid_policies.include?(pool["termination_policy"])
756
+ ok = false
757
+ MU.log "Termination policy #{pool["termination_policy"]} is not valid in region #{pool['region']}", MU::ERR, details: valid_policies
758
+ end
759
+ end
760
+
761
+ if !pool["schedule"].nil?
762
+ pool["schedule"].each { |s|
763
+ if !s['min_size'] and !s['max_size'] and !s['desired_capacity']
764
+ MU.log "Scheduled action for AutoScale group #{pool['name']} must declare at least one of min_size, max_size, or desired_capacity", MU::ERR
765
+ ok = false
766
+ end
767
+ if !s['start_time'] and !s['recurrence']
768
+ MU.log "Scheduled action for AutoScale group #{pool['name']} must declare at least one of start_time or recurrence", MU::ERR
769
+ ok = false
770
+ end
771
+ ['start_time', 'end_time'].each { |time|
772
+ next if !s[time]
773
+ begin
774
+ Time.parse(s[time])
775
+ rescue Exception => e
776
+ MU.log "Failed to parse #{time} '#{s[time]}' in scheduled action for AutoScale group #{pool['name']}: #{e.message}", MU::ERR
777
+ ok = false
778
+ end
779
+ }
780
+ if s['recurrence'] and !s['recurrence'].match(/^\s*[\d\-\*]+\s+[\d\-\*]+\s[\d\-\*]+\s[\d\-\*]+\s[\d\-\*]\s*$/)
781
+ MU.log "Failed to parse recurrence '#{s['recurrence']}' in scheduled action for AutoScale group #{pool['name']}: does not appear to be a valid cron string", MU::ERR
782
+ ok = false
783
+ end
784
+ }
785
+ end
786
+
787
+ scale_aliases = {
788
+ "scale_with_alb_traffic" => "ALBRequestCountPerTarget",
789
+ "scale_with_cpu" => "ASGAverageCPUUtilization",
790
+ "scale_with_network_in" => "ASGAverageNetworkIn",
791
+ "scale_with_network_out" => "ASGAverageNetworkOut"
792
+ }
793
+
794
+ scale_aliases.keys.each { |sp|
795
+ if pool[sp]
796
+ pool['scaling_policies'] ||= []
797
+ pool['scaling_policies'] << {
798
+ 'name' => scale_aliases[sp],
799
+ 'adjustment' => 1,
800
+ 'policy_type' => "TargetTrackingScaling",
801
+ 'estimated_instance_warmup' => 60,
802
+ 'target_tracking_configuration' => {
803
+ 'target_value' => pool[sp],
804
+ 'predefined_metric_specification' => scale_aliases[sp]
805
+ }
806
+ }
807
+ end
808
+ }
809
+
810
+ if !pool["basis"]["launch_config"].nil?
811
+ launch = pool["basis"]["launch_config"]
812
+ launch['iam_policies'] ||= pool['iam_policies']
813
+
814
+ launch['size'] = MU::Cloud::AWS::Server.validateInstanceType(launch["size"], pool["region"])
815
+ ok = false if launch['size'].nil?
816
+ if !launch['generate_iam_role']
817
+ if !launch['iam_role'] and pool['cloud'] != "CloudFormation"
818
+ MU.log "Must set iam_role if generate_iam_role set to false", MU::ERR
819
+ ok = false
820
+ end
821
+ if !launch['iam_policies'].nil? and launch['iam_policies'].size > 0
822
+ MU.log "Cannot mix iam_policies with generate_iam_role set to false", MU::ERR
823
+ ok = false
824
+ end
825
+ else
826
+ role = {
827
+ "name" => pool["name"],
828
+ "can_assume" => [
829
+ {
830
+ "entity_id" => "ec2.amazonaws.com",
831
+ "entity_type" => "service"
832
+ }
833
+ ],
834
+ "policies" => [
835
+ {
836
+ "name" => "MuSecrets",
837
+ "permissions" => ["s3:GetObject"],
838
+ "targets" => [
839
+ {
840
+ "identifier" => 'arn:'+(MU::Cloud::AWS.isGovCloud?(pool['region']) ? "aws-us-gov" : "aws")+':s3:::'+MU.adminBucketName+'/Mu_CA.pem'
841
+ }
842
+ ]
843
+ }
844
+ ]
845
+ }
846
+ if launch['iam_policies']
847
+ role['iam_policies'] = launch['iam_policies'].dup
848
+ end
849
+ if pool['canned_policies']
850
+ role['import'] = pool['canned_policies'].dup
851
+ end
852
+ if pool['iam_role']
853
+ # XXX maybe break this down into policies and add those?
854
+ end
855
+
856
+ configurator.insertKitten(role, "roles")
857
+ pool["dependencies"] ||= []
858
+ pool["dependencies"] << {
859
+ "type" => "role",
860
+ "name" => pool["name"]
861
+ }
862
+ end
863
+ launch["ami_id"] ||= launch["image_id"]
864
+ if launch["server"].nil? and launch["instance_id"].nil? and launch["ami_id"].nil?
865
+ if MU::Config.amazon_images.has_key?(pool['platform']) and
866
+ MU::Config.amazon_images[pool['platform']].has_key?(pool['region'])
867
+ launch['ami_id'] = configurator.getTail("pool"+pool['name']+"AMI", value: MU::Config.amazon_images[pool['platform']][pool['region']], prettyname: "pool"+pool['name']+"AMI", cloudtype: "AWS::EC2::Image::Id")
868
+
869
+ else
870
+ ok = false
871
+ MU.log "One of the following MUST be specified for launch_config: server, ami_id, instance_id.", MU::ERR
872
+ end
873
+ end
874
+ if launch["server"] != nil
875
+ pool["dependencies"] << {"type" => "server", "name" => launch["server"]}
876
+ # XXX I dunno, maybe toss an error if this isn't done already
877
+ # servers.each { |server|
878
+ # if server["name"] == launch["server"]
879
+ # server["create_ami"] = true
880
+ # end
881
+ # }
882
+ end
883
+ end
884
+
885
+ if !pool["scaling_policies"].nil?
886
+ pool["scaling_policies"].each { |policy|
887
+ if policy['type'] != "PercentChangeInCapacity" and !policy['min_adjustment_magnitude'].nil?
888
+ MU.log "Cannot specify scaling policy min_adjustment_magnitude if type is not PercentChangeInCapacity", MU::ERR
889
+ ok = false
890
+ end
891
+
892
+ if policy["policy_type"] == "SimpleScaling"
893
+ unless policy["cooldown"] && policy["adjustment"]
894
+ MU.log "You must specify 'cooldown' and 'adjustment' when 'policy_type' is set to 'SimpleScaling'", MU::ERR
895
+ ok = false
896
+ end
897
+ unless policy['type']
898
+ MU.log "You must specify a 'type' when 'policy_type' is set to 'SimpleScaling'", MU::ERR
899
+ ok = false
900
+ end
901
+ elsif policy["policy_type"] == "TargetTrackingScaling"
902
+ unless policy["target_tracking_configuration"]
903
+ MU.log "You must specify 'target_tracking_configuration' when 'policy_type' is set to 'TargetTrackingScaling'", MU::ERR
904
+ ok = false
905
+ end
906
+ unless policy["target_tracking_configuration"]["customized_metric_specification"] or
907
+ policy["target_tracking_configuration"]["predefined_metric_specification"]
908
+ MU.log "Your target_tracking_configuration must specify one of customized_metric_specification or predefined_metric_specification when 'policy_type' is set to 'TargetTrackingScaling'", MU::ERR
909
+ ok = false
910
+ end
911
+ # we gloss over an annoying layer of indirection in the API here
912
+ if policy["target_tracking_configuration"]["predefined_metric_specification"]
913
+ policy["target_tracking_configuration"]["predefined_metric_specification"] = {
914
+ "predefined_metric_type" => policy["target_tracking_configuration"]["predefined_metric_specification"]
915
+ }
916
+ end
917
+ elsif policy["policy_type"] == "StepScaling"
918
+ if policy["step_adjustments"].nil? || policy["step_adjustments"].empty?
919
+ MU.log "You must specify 'step_adjustments' when 'policy_type' is set to 'StepScaling'", MU::ERR
920
+ ok = false
921
+ end
922
+ unless policy['type']
923
+ MU.log "You must specify a 'type' when 'policy_type' is set to 'StepScaling'", MU::ERR
924
+ ok = false
925
+ end
926
+
927
+ policy["step_adjustments"].each{ |step|
928
+ if step["adjustment"].nil?
929
+ MU.log "You must specify 'adjustment' for 'step_adjustments' when 'policy_type' is set to 'StepScaling'", MU::ERR
930
+ ok = false
931
+ end
932
+
933
+ if step["adjustment"] >= 1 && policy["estimated_instance_warmup"].nil?
934
+ MU.log "You must specify 'estimated_instance_warmup' when 'policy_type' is set to 'StepScaling' and adding capacity", MU::ERR
935
+ ok = false
936
+ end
937
+
938
+ if step["lower_bound"].nil? && step["upper_bound"].nil?
939
+ MU.log "You must specify 'lower_bound' and/or upper_bound for 'step_adjustments' when 'policy_type' is set to 'StepScaling'", MU::ERR
940
+ ok = false
941
+ end
942
+ }
943
+ end
944
+
945
+ if policy["alarms"] && !policy["alarms"].empty?
946
+ policy["alarms"].each { |alarm|
947
+ alarm["name"] = "scaling-policy-#{pool["name"]}-#{alarm["name"]}"
948
+ alarm['dimensions'] = [] if !alarm['dimensions']
949
+ alarm['dimensions'] << { "name" => pool["name"], "cloud_class" => "AutoScalingGroupName" }
950
+ alarm["namespace"] = "AWS/EC2" if alarm["namespace"].nil?
951
+ alarm['cloud'] = pool['cloud']
952
+ # ok = false if !insertKitten(alarm, "alarms")
953
+ }
954
+ end
955
+ }
956
+ end
957
+ ok
958
+ end
959
+
960
+ # Remove all autoscale groups associated with the currently loaded deployment.
961
+ # @param noop [Boolean]: If true, will only print what would be done
962
+ # @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
963
+ # @param region [String]: The cloud provider region
964
+ # @return [void]
965
+ def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, flags: {})
966
+ filters = [{name: "key", values: ["MU-ID"]}]
967
+ if !ignoremaster
968
+ filters << {name: "key", values: ["MU-MASTER-IP"]}
969
+ end
970
+ resp = MU::Cloud::AWS.autoscale(region).describe_tags(
971
+ filters: filters,
972
+ max_records: 100
973
+ )
974
+
975
+ return nil if resp.tags.nil? or resp.tags.size == 0
976
+
977
+ maybe_purge = []
978
+ no_purge = []
979
+ resp.data.tags.each { |asg|
980
+ if asg.resource_type != "auto-scaling-group"
981
+ no_purge << asg.resource_id
982
+ end
983
+ if asg.key == "MU-MASTER-IP" and asg.value != MU.mu_public_ip and !ignoremaster
984
+ no_purge << asg.resource_id
985
+ end
986
+ if asg.key == "MU-ID" and asg.value == MU.deploy_id
987
+ maybe_purge << asg.resource_id
988
+ end
989
+ }
990
+
991
+
992
+ maybe_purge.each { |resource_id|
993
+ next if no_purge.include?(resource_id)
994
+ MU.log "Removing AutoScale group #{resource_id}"
995
+ next if noop
996
+ retries = 0
997
+ begin
998
+ MU::Cloud::AWS.autoscale(region).delete_auto_scaling_group(
999
+ auto_scaling_group_name: resource_id,
1000
+ # XXX this should obey @force
1001
+ force_delete: true
1002
+ )
1003
+ rescue Aws::AutoScaling::Errors::InternalFailure => e
1004
+ if retries < 5
1005
+ MU.log "Got #{e.inspect} while removing AutoScale group #{resource_id}.", MU::WARN
1006
+ sleep 10
1007
+ retry
1008
+ else
1009
+ MU.log "Failed to delete AutoScale group #{resource_id}", MU::ERR
1010
+ end
1011
+ end
1012
+
1013
+ # MU::Cloud::AWS::Server.removeIAMProfile(resource_id)
1014
+
1015
+ # Generally there should be a launch_configuration of the same name
1016
+ # XXX search for these independently, too?
1017
+ retries = 0
1018
+ begin
1019
+ MU.log "Removing AutoScale Launch Configuration #{resource_id}"
1020
+ MU::Cloud::AWS.autoscale(region).delete_launch_configuration(
1021
+ launch_configuration_name: resource_id
1022
+ )
1023
+ rescue Aws::AutoScaling::Errors::ValidationError => e
1024
+ MU.log "No such Launch Configuration #{resource_id}"
1025
+ rescue Aws::AutoScaling::Errors::InternalFailure => e
1026
+ if retries < 5
1027
+ MU.log "Got #{e.inspect} while removing Launch Configuration #{resource_id}.", MU::WARN
1028
+ sleep 10
1029
+ retry
1030
+ else
1031
+ MU.log "Failed to delete Launch Configuration #{resource_id}", MU::ERR
1032
+ end
1033
+ end
1034
+ }
1035
+ return nil
1036
+ end
1037
+
1038
+ private
1039
+
1040
+ def createUpdateLaunchConfig
1041
+ return if !@config['basis'] or !@config['basis']["launch_config"]
1042
+
1043
+ instance_secret = Password.random(50)
1044
+ @deploy.saveNodeSecret("default", instance_secret, "instance_secret")
1045
+
1046
+ nodes_name = @deploy.getResourceName(@config['basis']["launch_config"]["name"])
1047
+ if !@config['basis']['launch_config']["server"].nil?
1048
+ #XXX this isn't how we find these; use findStray or something
1049
+ if @deploy.deployment["images"].nil? or @deploy.deployment["images"][@config['basis']['launch_config']["server"]].nil?
1050
+ raise MuError, "#{@mu_name} needs an AMI from server #{@config['basis']['launch_config']["server"]}, but I don't see one anywhere"
1051
+ end
1052
+ @config['basis']['launch_config']["ami_id"] = @deploy.deployment["images"][@config['basis']['launch_config']["server"]]["image_id"]
1053
+ MU.log "Using AMI '#{@config['basis']['launch_config']["ami_id"]}' from sibling server #{@config['basis']['launch_config']["server"]} in ServerPool #{@mu_name}"
1054
+ elsif !@config['basis']['launch_config']["instance_id"].nil?
1055
+ @config['basis']['launch_config']["ami_id"] = MU::Cloud::AWS::Server.createImage(
1056
+ name: @mu_name,
1057
+ instance_id: @config['basis']['launch_config']["instance_id"]
1058
+ )
1059
+ end
1060
+ MU::Cloud::AWS::Server.waitForAMI(@config['basis']['launch_config']["ami_id"])
1061
+
1062
+ oldlaunch = MU::Cloud::AWS.autoscale(@config['region']).describe_launch_configurations(
1063
+ launch_configuration_names: [@mu_name]
1064
+ ).launch_configurations.first
1065
+
1066
+ userdata = MU::Cloud.fetchUserdata(
1067
+ platform: @config["platform"],
1068
+ cloud: "aws",
1069
+ template_variables: {
1070
+ "deployKey" => Base64.urlsafe_encode64(@deploy.public_key),
1071
+ "deploySSHKey" => @deploy.ssh_public_key,
1072
+ "muID" => @deploy.deploy_id,
1073
+ "muUser" => MU.chef_user,
1074
+ "publicIP" => MU.mu_public_ip,
1075
+ "windowsAdminName" => @config['windows_admin_username'],
1076
+ "skipApplyUpdates" => @config['skipinitialupdates'],
1077
+ "resourceName" => @config["name"],
1078
+ "resourceType" => "server_pool",
1079
+ "platform" => @config["platform"]
1080
+ },
1081
+ custom_append: @config['userdata_script']
1082
+ )
1083
+
1084
+ # Figure out which devices are embedded in the AMI already.
1085
+ image = MU::Cloud::AWS.ec2.describe_images(image_ids: [@config["basis"]["launch_config"]["ami_id"]]).images.first
1086
+
1087
+ if image.nil?
1088
+ raise "#{@config["basis"]["launch_config"]["ami_id"]} does not exist, cannot update/create launch config #{@mu_name}"
1089
+ end
1090
+
1091
+ ext_disks = {}
1092
+ if !image.block_device_mappings.nil?
1093
+ image.block_device_mappings.each { |disk|
1094
+ if !disk.device_name.nil? and !disk.device_name.empty? and !disk.ebs.nil? and !disk.ebs.empty?
1095
+ ext_disks[disk.device_name] = MU.structToHash(disk.ebs)
1096
+ if ext_disks[disk.device_name].has_key?(:snapshot_id)
1097
+ ext_disks[disk.device_name].delete(:encrypted)
1098
+ end
1099
+ end
1100
+ }
1101
+ end
1102
+
1103
+ storage = []
1104
+ if !@config["basis"]["launch_config"]["storage"].nil?
1105
+ @config["basis"]["launch_config"]["storage"].each { |vol|
1106
+ if ext_disks.has_key?(vol["device"])
1107
+ if ext_disks[vol["device"]].has_key?(:snapshot_id)
1108
+ vol.delete("encrypted")
1109
+ end
1110
+ end
1111
+ mapping, cfm_mapping = MU::Cloud::AWS::Server.convertBlockDeviceMapping(vol)
1112
+ storage << mapping
1113
+ }
1114
+ end
1115
+
1116
+ storage.concat(MU::Cloud::AWS::Server.ephemeral_mappings)
1117
+
1118
+ if !oldlaunch.nil?
1119
+ olduserdata = Base64.decode64(oldlaunch.user_data)
1120
+ if userdata != olduserdata or
1121
+ oldlaunch.image_id != @config["basis"]["launch_config"]["ami_id"] or
1122
+ oldlaunch.ebs_optimized != @config["basis"]["launch_config"]["ebs_optimized"] or
1123
+ oldlaunch.instance_type != @config["basis"]["launch_config"]["size"] or
1124
+ oldlaunch.instance_monitoring.enabled != @config["basis"]["launch_config"]["monitoring"]
1125
+ # XXX check more things
1126
+ # launch.block_device_mappings != storage
1127
+ # XXX block device comparison isn't this simple
1128
+ return
1129
+ end
1130
+
1131
+ # Put our Autoscale group onto a temporary launch config
1132
+ begin
1133
+
1134
+ MU::Cloud::AWS.autoscale(@config['region']).create_launch_configuration(
1135
+ launch_configuration_name: @mu_name+"-TMP",
1136
+ user_data: Base64.encode64(olduserdata),
1137
+ image_id: oldlaunch.image_id,
1138
+ key_name: oldlaunch.key_name,
1139
+ security_groups: oldlaunch.security_groups,
1140
+ instance_type: oldlaunch.instance_type,
1141
+ block_device_mappings: storage,
1142
+ instance_monitoring: oldlaunch.instance_monitoring,
1143
+ iam_instance_profile: oldlaunch.iam_instance_profile,
1144
+ ebs_optimized: oldlaunch.ebs_optimized,
1145
+ associate_public_ip_address: oldlaunch.associate_public_ip_address
1146
+ )
1147
+ rescue ::Aws::AutoScaling::Errors::ValidationError => e
1148
+ if e.message.match(/Member must have length less than or equal to (\d+)/)
1149
+ MU.log "Userdata script too long updating #{@mu_name} Launch Config (#{Base64.encode64(userdata).size.to_s}/#{Regexp.last_match[1]} bytes)", MU::ERR
1150
+ else
1151
+ MU.log "Error updating #{@mu_name} Launch Config", MU::ERR, details: e.message
1152
+ end
1153
+ raise e.message
1154
+ end
1155
+
1156
+
1157
+ MU::Cloud::AWS.autoscale(@config['region']).update_auto_scaling_group(
1158
+ auto_scaling_group_name: @mu_name,
1159
+ launch_configuration_name: @mu_name+"-TMP"
1160
+ )
1161
+ # ...now back to an identical one with the "real" name
1162
+ MU::Cloud::AWS.autoscale(@config['region']).delete_launch_configuration(
1163
+ launch_configuration_name: @mu_name
1164
+ )
1165
+ end
1166
+
1167
+ # Now to build the new one
1168
+ sgs = []
1169
+ if @dependencies.has_key?("firewall_rule")
1170
+ @dependencies['firewall_rule'].values.each { |sg|
1171
+ sgs << sg.cloud_id
1172
+ }
1173
+ end
1174
+
1175
+ launch_options = {
1176
+ :launch_configuration_name => @mu_name,
1177
+ :user_data => Base64.encode64(userdata),
1178
+ :image_id => @config["basis"]["launch_config"]["ami_id"],
1179
+ :key_name => @deploy.ssh_key_name,
1180
+ :security_groups => sgs,
1181
+ :instance_type => @config["basis"]["launch_config"]["size"],
1182
+ :block_device_mappings => storage,
1183
+ :instance_monitoring => {:enabled => @config["basis"]["launch_config"]["monitoring"]},
1184
+ :ebs_optimized => @config["basis"]["launch_config"]["ebs_optimized"]
1185
+ }
1186
+ if @config["vpc"] or @config["vpc_zone_identifier"]
1187
+ launch_options[:associate_public_ip_address] = @config["associate_public_ip"]
1188
+ end
1189
+ ["kernel_id", "ramdisk_id", "spot_price"].each { |arg|
1190
+ if @config['basis']['launch_config'][arg]
1191
+ launch_options[arg.to_sym] = @config['basis']['launch_config'][arg]
1192
+ end
1193
+ }
1194
+ rolename = nil
1195
+ ['generate_iam_role', 'iam_policies', 'canned_iam_policies', 'iam_role'].each { |field|
1196
+ @config['basis']['launch_config'][field] ||= @config[field]
1197
+ }
1198
+
1199
+ if @config['basis']['launch_config']['generate_iam_role']
1200
+ # Using ARN instead of IAM instance profile name to hopefully get around some random AWS failures
1201
+ rolename, cfm_role_name, cfm_prof_name, arn = MU::Cloud::AWS::Server.createIAMProfile(@mu_name, base_profile: @config['basis']['launch_config']['iam_role'], extra_policies: @config['basis']['launch_config']['iam_policies'], canned_policies: @config['basis']['launch_config']['canned_iam_policies'])
1202
+ launch_options[:iam_instance_profile] = rolename
1203
+ elsif @config['basis']['launch_config']['iam_role'].nil?
1204
+ raise MuError, "#{@mu_name} has generate_iam_role set to false, but no iam_role assigned."
1205
+ else
1206
+ launch_options[:iam_instance_profile] = @config['basis']['launch_config']['iam_role']
1207
+ end
1208
+
1209
+ @config['iam_role'] = rolename ? rolename : launch_options[:iam_instance_profile]
1210
+
1211
+ if rolename
1212
+ MU::Cloud::AWS::Server.addStdPoliciesToIAMProfile(rolename, region: @config['region'])
1213
+ else
1214
+ MU::Cloud::AWS::Server.addStdPoliciesToIAMProfile(@config['iam_role'], region: @config['region'])
1215
+ end
1216
+
1217
+ lc_attempts = 0
1218
+ begin
1219
+ MU::Cloud::AWS.autoscale(@config['region']).create_launch_configuration(launch_options)
1220
+ rescue Aws::AutoScaling::Errors::ValidationError => e
1221
+ if lc_attempts > 3
1222
+ MU.log "Got error while creating #{@mu_name} Launch Config: #{e.message}, retrying in 10s", MU::WARN
1223
+ end
1224
+ sleep 5
1225
+ lc_attempts += 1
1226
+ retry
1227
+ end
1228
+
1229
+ if !oldlaunch.nil?
1230
+ # Tell the ASG to use the new one, and nuke the old one
1231
+ MU::Cloud::AWS.autoscale(@config['region']).update_auto_scaling_group(
1232
+ auto_scaling_group_name: @mu_name,
1233
+ launch_configuration_name: @mu_name
1234
+ )
1235
+ MU::Cloud::AWS.autoscale(@config['region']).delete_launch_configuration(
1236
+ launch_configuration_name: @mu_name+"-TMP"
1237
+ )
1238
+ MU.log "Launch Configuration #{@mu_name} replaced"
1239
+ else
1240
+ MU.log "Launch Configuration #{@mu_name} created"
1241
+ end
1242
+
1243
+ end
1244
+
1245
+ def buildOptionsHash
1246
+ asg_options = {
1247
+ :auto_scaling_group_name => @mu_name,
1248
+ :launch_configuration_name => @mu_name,
1249
+ :default_cooldown => @config["default_cooldown"],
1250
+ :health_check_type => @config["health_check_type"],
1251
+ :health_check_grace_period => @config["health_check_grace_period"],
1252
+ :tags => []
1253
+ }
1254
+
1255
+ MU::MommaCat.listStandardTags.each_pair { |name, value|
1256
+ asg_options[:tags] << {key: name, value: value, propagate_at_launch: true}
1257
+ }
1258
+
1259
+ if @config['optional_tags']
1260
+ MU::MommaCat.listOptionalTags.each_pair { |name, value|
1261
+ asg_options[:tags] << {key: name, value: value, propagate_at_launch: true}
1262
+ }
1263
+ end
1264
+
1265
+ if @config['tags']
1266
+ @config['tags'].each { |tag|
1267
+ asg_options[:tags] << {key: tag['key'], value: tag['value'], propagate_at_launch: true}
1268
+ }
1269
+ end
1270
+
1271
+ if @dependencies.has_key?("container_cluster")
1272
+ @dependencies['container_cluster'].values.each { |cc|
1273
+ if cc.config['flavor'] == "EKS"
1274
+ asg_options[:tags] << {
1275
+ key: "kubernetes.io/cluster/#{cc.mu_name}",
1276
+ value: "owned",
1277
+ propagate_at_launch: true
1278
+ }
1279
+ end
1280
+ }
1281
+ end
1282
+
1283
+ if @config["wait_for_nodes"] > 0
1284
+ asg_options[:min_size] = @config["wait_for_nodes"]
1285
+ asg_options[:max_size] = @config["wait_for_nodes"]
1286
+ else
1287
+ asg_options[:min_size] = @config["min_size"]
1288
+ asg_options[:max_size] = @config["max_size"]
1289
+ end
1290
+
1291
+ if @config["loadbalancers"]
1292
+ lbs = []
1293
+ tg_arns = []
1294
+ # XXX refactor this into the LoadBalancer resource
1295
+ @config["loadbalancers"].each { |lb|
1296
+ if lb["existing_load_balancer"]
1297
+ lbs << lb["existing_load_balancer"]
1298
+ @deploy.deployment["loadbalancers"] = Array.new if !@deploy.deployment["loadbalancers"]
1299
+ @deploy.deployment["loadbalancers"] << {
1300
+ "name" => lb["existing_load_balancer"],
1301
+ "awsname" => lb["existing_load_balancer"]
1302
+ # XXX probably have to query API to get the DNS name of this one
1303
+ }
1304
+ elsif lb["concurrent_load_balancer"]
1305
+ raise MuError, "No loadbalancers exist! I need one named #{lb['concurrent_load_balancer']}" if !@deploy.deployment["loadbalancers"]
1306
+ found = false
1307
+ @deploy.deployment["loadbalancers"].each_pair { |lb_name, deployed_lb|
1308
+ if lb_name == lb['concurrent_load_balancer']
1309
+ lbs << deployed_lb["awsname"]
1310
+ if deployed_lb.has_key?("targetgroups")
1311
+ deployed_lb["targetgroups"].each_pair { |tg_name, tg_arn|
1312
+ tg_arns << tg_arn
1313
+ }
1314
+ end
1315
+ found = true
1316
+ end
1317
+ }
1318
+ raise MuError, "I need a loadbalancer named #{lb['concurrent_load_balancer']}, but none seems to have been created!" if !found
1319
+ end
1320
+ }
1321
+ if tg_arns.size > 0
1322
+ asg_options[:target_group_arns] = tg_arns
1323
+ else
1324
+ asg_options[:load_balancer_names] = lbs
1325
+ end
1326
+ end
1327
+ asg_options[:termination_policies] = @config["termination_policies"] if @config["termination_policies"]
1328
+ asg_options[:desired_capacity] = @config["desired_capacity"] if @config["desired_capacity"]
1329
+
1330
+ if @config["vpc_zone_identifier"]
1331
+ asg_options[:vpc_zone_identifier] = @config["vpc_zone_identifier"]
1332
+ elsif @config["vpc"]
1333
+
1334
+ subnet_ids = []
1335
+
1336
+ if !@config["vpc"]["subnets"].nil? and @config["vpc"]["subnets"].size > 0
1337
+ @config["vpc"]["subnets"].each { |subnet|
1338
+ subnet_obj = @vpc.getSubnet(cloud_id: subnet["subnet_id"], name: subnet["subnet_name"])
1339
+ next if !subnet_obj
1340
+ subnet_ids << subnet_obj.cloud_id
1341
+ }
1342
+ else
1343
+ @vpc.subnets.each { |subnet_obj|
1344
+ next if subnet_obj.private? and ["all_public", "public"].include?(@config["vpc"]["subnet_pref"])
1345
+ next if !subnet_obj.private? and ["all_private", "private"].include?(@config["vpc"]["subnet_pref"])
1346
+ subnet_ids << subnet_obj.cloud_id
1347
+ }
1348
+ end
1349
+ if subnet_ids.size == 0
1350
+ raise MuError, "No valid subnets found for #{@mu_name} from #{@config["vpc"]}"
1351
+ end
1352
+ asg_options[:vpc_zone_identifier] = subnet_ids.join(",")
1353
+ end
1354
+
1355
+
1356
+ if @config['basis']["server"]
1357
+ nodes_name = @deploy.getResourceName(@config['basis']["server"])
1358
+ srv_name = @config['basis']["server"]
1359
+ # XXX cloudformation bits
1360
+ if @deploy.deployment['servers'] != nil and
1361
+ @deploy.deployment['servers'][srv_name] != nil
1362
+ asg_options[:instance_id] = @deploy.deployment['servers'][srv_name]["instance_id"]
1363
+ end
1364
+ elsif @config['basis']["instance_id"]
1365
+ # TODO should go fetch the name tag or something
1366
+ nodes_name = @deploy.getResourceName(@config['basis']["instance_id"].gsub(/-/, ""))
1367
+ # XXX cloudformation bits
1368
+ asg_options[:instance_id] = @config['basis']["instance_id"]
1369
+ end
1370
+
1371
+ if !asg_options[:vpc_zone_identifier].nil? and asg_options[:vpc_zone_identifier].empty?
1372
+ asg_options.delete(:vpc_zone_identifier)
1373
+ end
1374
+
1375
+ # Do the dance of specifying individual zones if we haven't asked to
1376
+ # use particular VPC subnets.
1377
+ if @config['zones'].nil? and asg_options[:vpc_zone_identifier].nil?
1378
+ @config["zones"] = MU::Cloud::AWS.listAZs(@config['region'])
1379
+ MU.log "Using zones from #{@config['region']}", MU::DEBUG, details: @config['zones']
1380
+ end
1381
+ asg_options[:availability_zones] = @config["zones"] if @config["zones"] != nil
1382
+ asg_options
1383
+ end
1384
+
1385
+ end
1386
+ end
1387
+ end
1388
+ end