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,1446 @@
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
+ autoload :WinRM, "winrm"
16
+
17
+ module MU
18
+ # Plugins under this namespace serve as interfaces to cloud providers and
19
+ # other provisioning layers.
20
+ class Cloud
21
+ # An exception denoting an expected, temporary connection failure to a
22
+ # bootstrapping instance, e.g. for Windows instances that must reboot in
23
+ # mid-installation.
24
+ class BootstrapTempFail < MuNonFatal;
25
+ end
26
+
27
+ # An exception we can use with transient Net::SSH errors, which require
28
+ # special handling due to obnoxious asynchronous interrupt behaviors.
29
+ class NetSSHFail < MuNonFatal;
30
+ end
31
+
32
+ # Exception thrown when a request is made to an unimplemented cloud
33
+ # resource.
34
+ class MuCloudResourceNotImplemented < StandardError;
35
+ end
36
+
37
+ # Exception thrown when a request is made for an unsupported flag or feature
38
+ # in a cloud resource.
39
+ class MuCloudFlagNotImplemented < StandardError;
40
+ end
41
+
42
+ generic_class_methods = [:find, :cleanup, :validateConfig, :schema]
43
+ generic_instance_methods = [:create, :notify, :mu_name, :cloud_id, :config, :cloud_desc]
44
+
45
+ # Initialize empty classes for each of these. We'll fill them with code
46
+ # later; we're doing this here because otherwise the parser yells about
47
+ # missing classes, even though they're created at runtime.
48
+
49
+ # Stub base class; real implementations generated at runtime
50
+ class Collection;
51
+ end
52
+ # Stub base class; real implementations generated at runtime
53
+ class Database;
54
+ end
55
+ # Stub base class; real implementations generated at runtime
56
+ class DNSZone;
57
+ end
58
+ # Stub base class; real implementations generated at runtime
59
+ class FirewallRule;
60
+ end
61
+ # Stub base class; real implementations generated at runtime
62
+ class LoadBalancer;
63
+ end
64
+ # Stub base class; real implementations generated at runtime
65
+ class Server;
66
+ end
67
+ # Stub base class; real implementations generated at runtime
68
+ class ContainerCluster;
69
+ end
70
+ # Stub base class; real implementations generated at runtime
71
+ class ServerPool;
72
+ end
73
+ # Stub base class; real implementations generated at runtime
74
+ class VPC;
75
+ end
76
+ # Stub base class; real implementations generated at runtime
77
+ class CacheCluster;
78
+ end
79
+ # Stub base class; real implementations generated at runtime
80
+ class Alarm;
81
+ end
82
+ # Stub base class; real implementations generated at runtime
83
+ class Notification;
84
+ end
85
+ # Stub base class; real implementations generated at runtime
86
+ class Log;
87
+ end
88
+ # Stub base class; real implementations generated at runtime
89
+ class StoragePool;
90
+ end
91
+ # Stub base class; real implementations generated at runtime
92
+ class Function;
93
+ end
94
+ # Stub base class; real implementations generated at runtime
95
+ class SearchDomain;
96
+ end
97
+ # Stub base class; real implementations generated at runtime
98
+ class MsgQueue;
99
+ end
100
+ # Stub base class; real implementations generated at runtime
101
+ class Project;
102
+ end
103
+ # Stub base class; real implementations generated at runtime
104
+ class Folder;
105
+ end
106
+ # Stub base class; real implementations generated at runtime
107
+ class User;
108
+ end
109
+ # Stub base class; real implementations generated at runtime
110
+ class Group;
111
+ end
112
+ # Stub base class; real implementations generated at runtime
113
+ class Role;
114
+ end
115
+
116
+ # The types of cloud resources we can create, as class objects. Include
117
+ # methods a class implementing this resource type must support to be
118
+ # considered valid.
119
+ @@resource_types = {
120
+ :Collection => {
121
+ :has_multiples => false,
122
+ :can_live_in_vpc => false,
123
+ :cfg_name => "collection",
124
+ :cfg_plural => "collections",
125
+ :interface => self.const_get("Collection"),
126
+ :deps_wait_on_my_creation => true,
127
+ :waits_on_parent_completion => false,
128
+ :class => generic_class_methods,
129
+ :instance => generic_instance_methods
130
+ },
131
+ :Database => {
132
+ :has_multiples => true,
133
+ :can_live_in_vpc => true,
134
+ :cfg_name => "database",
135
+ :cfg_plural => "databases",
136
+ :interface => self.const_get("Database"),
137
+ :deps_wait_on_my_creation => true,
138
+ :waits_on_parent_completion => false,
139
+ :class => generic_class_methods,
140
+ :instance => generic_instance_methods + [:groom, :allowHost]
141
+ },
142
+ :DNSZone => {
143
+ :has_multiples => false,
144
+ :can_live_in_vpc => false,
145
+ :cfg_name => "dnszone",
146
+ :cfg_plural => "dnszones",
147
+ :interface => self.const_get("DNSZone"),
148
+ :deps_wait_on_my_creation => true,
149
+ :waits_on_parent_completion => true,
150
+ :class => generic_class_methods + [:genericMuDNSEntry, :createRecordsFromConfig],
151
+ :instance => generic_instance_methods
152
+ },
153
+ :FirewallRule => {
154
+ :has_multiples => false,
155
+ :can_live_in_vpc => true,
156
+ :cfg_name => "firewall_rule",
157
+ :cfg_plural => "firewall_rules",
158
+ :interface => self.const_get("FirewallRule"),
159
+ :deps_wait_on_my_creation => true,
160
+ :waits_on_parent_completion => false,
161
+ :class => generic_class_methods,
162
+ :instance => generic_instance_methods + [:groom, :addRule]
163
+ },
164
+ :LoadBalancer => {
165
+ :has_multiples => false,
166
+ :can_live_in_vpc => true,
167
+ :cfg_name => "loadbalancer",
168
+ :cfg_plural => "loadbalancers",
169
+ :interface => self.const_get("LoadBalancer"),
170
+ :deps_wait_on_my_creation => true,
171
+ :waits_on_parent_completion => false,
172
+ :class => generic_class_methods,
173
+ :instance => generic_instance_methods + [:registerNode]
174
+ },
175
+ :Server => {
176
+ :has_multiples => true,
177
+ :can_live_in_vpc => true,
178
+ :cfg_name => "server",
179
+ :cfg_plural => "servers",
180
+ :interface => self.const_get("Server"),
181
+ :deps_wait_on_my_creation => false,
182
+ :waits_on_parent_completion => false,
183
+ :class => generic_class_methods + [:validateInstanceType],
184
+ :instance => generic_instance_methods + [:groom, :postBoot, :getSSHConfig, :canonicalIP, :getWindowsAdminPassword, :active?, :groomer, :mu_windows_name, :mu_windows_name=, :reboot, :addVolume]
185
+ },
186
+ :ServerPool => {
187
+ :has_multiples => false,
188
+ :can_live_in_vpc => true,
189
+ :cfg_name => "server_pool",
190
+ :cfg_plural => "server_pools",
191
+ :interface => self.const_get("ServerPool"),
192
+ :deps_wait_on_my_creation => false,
193
+ :waits_on_parent_completion => true,
194
+ :class => generic_class_methods,
195
+ :instance => generic_instance_methods + [:groom, :listNodes]
196
+ },
197
+ :VPC => {
198
+ :has_multiples => false,
199
+ :can_live_in_vpc => false,
200
+ :cfg_name => "vpc",
201
+ :cfg_plural => "vpcs",
202
+ :interface => self.const_get("VPC"),
203
+ :deps_wait_on_my_creation => true,
204
+ :waits_on_parent_completion => false,
205
+ :class => generic_class_methods,
206
+ :instance => generic_instance_methods + [:groom, :subnets, :getSubnet, :listSubnets, :findBastion, :findNat]
207
+ },
208
+ :CacheCluster => {
209
+ :has_multiples => true,
210
+ :can_live_in_vpc => true,
211
+ :cfg_name => "cache_cluster",
212
+ :cfg_plural => "cache_clusters",
213
+ :interface => self.const_get("CacheCluster"),
214
+ :deps_wait_on_my_creation => true,
215
+ :waits_on_parent_completion => false,
216
+ :class => generic_class_methods,
217
+ :instance => generic_instance_methods + [:groom]
218
+ },
219
+ :Alarm => {
220
+ :has_multiples => false,
221
+ :can_live_in_vpc => false,
222
+ :cfg_name => "alarm",
223
+ :cfg_plural => "alarms",
224
+ :interface => self.const_get("Alarm"),
225
+ :deps_wait_on_my_creation => false,
226
+ :waits_on_parent_completion => true,
227
+ :class => generic_class_methods,
228
+ :instance => generic_instance_methods + [:groom]
229
+ },
230
+ :Notification => {
231
+ :has_multiples => false,
232
+ :can_live_in_vpc => false,
233
+ :cfg_name => "notification",
234
+ :cfg_plural => "notifications",
235
+ :interface => self.const_get("Notification"),
236
+ :deps_wait_on_my_creation => false,
237
+ :waits_on_parent_completion => false,
238
+ :class => generic_class_methods,
239
+ :instance => generic_instance_methods + [:groom]
240
+ },
241
+ :Log => {
242
+ :has_multiples => false,
243
+ :can_live_in_vpc => false,
244
+ :cfg_name => "log",
245
+ :cfg_plural => "logs",
246
+ :interface => self.const_get("Log"),
247
+ :deps_wait_on_my_creation => true,
248
+ :waits_on_parent_completion => true,
249
+ :class => generic_class_methods,
250
+ :instance => generic_instance_methods + [:groom]
251
+ },
252
+ :StoragePool => {
253
+ :has_multiples => false,
254
+ :can_live_in_vpc => true,
255
+ :cfg_name => "storage_pool",
256
+ :cfg_plural => "storage_pools",
257
+ :interface => self.const_get("StoragePool"),
258
+ :deps_wait_on_my_creation => true,
259
+ :waits_on_parent_completion => false,
260
+ :class => generic_class_methods,
261
+ :instance => generic_instance_methods + [:groom]
262
+ },
263
+ :Function => {
264
+ :has_multiples => false,
265
+ :can_live_in_vpc => true,
266
+ :cfg_name => "function",
267
+ :cfg_plural => "functions",
268
+ :interface => self.const_get("Function"),
269
+ :deps_wait_on_my_creation => true,
270
+ :waits_on_parent_completion => false,
271
+ :class => generic_class_methods,
272
+ :instance => generic_instance_methods
273
+ },
274
+ :ContainerCluster => {
275
+ :has_multiples => false,
276
+ :can_live_in_vpc => true,
277
+ :cfg_name => "container_cluster",
278
+ :cfg_plural => "container_clusters",
279
+ :interface => self.const_get("ContainerCluster"),
280
+ :deps_wait_on_my_creation => true,
281
+ :waits_on_parent_completion => false,
282
+ :class => generic_class_methods,
283
+ :instance => generic_instance_methods + [:groom]
284
+ },
285
+ :SearchDomain => {
286
+ :has_multiples => false,
287
+ :can_live_in_vpc => true,
288
+ :cfg_name => "search_domain",
289
+ :cfg_plural => "search_domains",
290
+ :interface => self.const_get("SearchDomain"),
291
+ :deps_wait_on_my_creation => true,
292
+ :waits_on_parent_completion => false,
293
+ :class => generic_class_methods,
294
+ :instance => generic_instance_methods + [:groom]
295
+ },
296
+ :MsgQueue => {
297
+ :has_multiples => false,
298
+ :can_live_in_vpc => false,
299
+ :cfg_name => "msg_queue",
300
+ :cfg_plural => "msg_queues",
301
+ :interface => self.const_get("MsgQueue"),
302
+ :deps_wait_on_my_creation => true,
303
+ :waits_on_parent_completion => true,
304
+ :class => generic_class_methods,
305
+ :instance => generic_instance_methods + [:groom]
306
+ },
307
+ :Project => {
308
+ :has_multiples => false,
309
+ :can_live_in_vpc => false,
310
+ :cfg_name => "project",
311
+ :cfg_plural => "projects",
312
+ :interface => self.const_get("Project"),
313
+ :deps_wait_on_my_creation => true,
314
+ :waits_on_parent_completion => true,
315
+ :class => generic_class_methods,
316
+ :instance => generic_instance_methods
317
+ },
318
+ :Folder => {
319
+ :has_multiples => false,
320
+ :can_live_in_vpc => false,
321
+ :cfg_name => "folder",
322
+ :cfg_plural => "folders",
323
+ :interface => self.const_get("Folder"),
324
+ :deps_wait_on_my_creation => true,
325
+ :waits_on_parent_completion => true,
326
+ :class => generic_class_methods,
327
+ :instance => generic_instance_methods
328
+ },
329
+ :User => {
330
+ :has_multiples => false,
331
+ :can_live_in_vpc => false,
332
+ :cfg_name => "user",
333
+ :cfg_plural => "users",
334
+ :interface => self.const_get("User"),
335
+ :deps_wait_on_my_creation => true,
336
+ :waits_on_parent_completion => true,
337
+ :class => generic_class_methods,
338
+ :instance => generic_instance_methods + [:groom]
339
+ },
340
+ :Group => {
341
+ :has_multiples => false,
342
+ :can_live_in_vpc => false,
343
+ :cfg_name => "group",
344
+ :cfg_plural => "groups",
345
+ :interface => self.const_get("Group"),
346
+ :deps_wait_on_my_creation => true,
347
+ :waits_on_parent_completion => true,
348
+ :class => generic_class_methods,
349
+ :instance => generic_instance_methods + [:groom]
350
+ },
351
+ :Role => {
352
+ :has_multiples => false,
353
+ :can_live_in_vpc => false,
354
+ :cfg_name => "role",
355
+ :cfg_plural => "roles",
356
+ :interface => self.const_get("Role"),
357
+ :deps_wait_on_my_creation => true,
358
+ :waits_on_parent_completion => true,
359
+ :class => generic_class_methods,
360
+ :instance => generic_instance_methods + [:groom]
361
+ }
362
+ }.freeze
363
+
364
+
365
+ # A list of supported cloud resource types as Mu classes
366
+ def self.resource_types;
367
+ @@resource_types
368
+ end
369
+
370
+ # Shorthand lookup for resource type names. Given any of the shorthand class name, configuration name (singular or plural), or full class name, return all four as a set.
371
+ # @param type [String]: A string that looks like our short or full class name or singular or plural configuration names.
372
+ # @return [Array]: Class name (Symbol), singular config name (String), plural config name (String), full class name (Object)
373
+ def self.getResourceNames(type)
374
+ @@resource_types.each_pair { |name, cloudclass|
375
+ if name == type.to_sym or
376
+ cloudclass[:cfg_name] == type or
377
+ cloudclass[:cfg_plural] == type or
378
+ Object.const_get("MU").const_get("Cloud").const_get(name) == type
379
+ cfg_name = cloudclass[:cfg_name]
380
+ type = name
381
+ return [type.to_sym, cloudclass[:cfg_name], cloudclass[:cfg_plural], Object.const_get("MU").const_get("Cloud").const_get(name), cloudclass]
382
+ end
383
+ }
384
+ [nil, nil, nil, nil, {}]
385
+ end
386
+
387
+ # Net::SSH exceptions seem to have their own behavior vis a vis threads,
388
+ # and our regular call stack gets circumvented when they're thrown. Cheat
389
+ # here to catch them gracefully.
390
+ def self.handleNetSSHExceptions
391
+ Thread.handle_interrupt(Net::SSH::Exception => :never) {
392
+ begin
393
+ Thread.handle_interrupt(Net::SSH::Exception => :immediate) {
394
+ MU.log "(Probably harmless) Caught a Net::SSH Exception in #{Thread.current.inspect}", MU::DEBUG, details: Thread.current.backtrace
395
+ }
396
+ ensure
397
+ # raise NetSSHFail, "Net::SSH had a nutty"
398
+ end
399
+ }
400
+ end
401
+
402
+ # List of known/supported Cloud providers
403
+ def self.supportedClouds
404
+ ["AWS", "CloudFormation", "Google"]
405
+ end
406
+
407
+ # Load the container class for each cloud we know about, and inject autoload
408
+ # code for each of its supported resource type classes.
409
+ MU::Cloud.supportedClouds.each { |cloud|
410
+ require "mu/clouds/#{cloud.downcase}"
411
+ }
412
+
413
+ # @return [Mutex]
414
+ def self.userdata_mutex
415
+ @userdata_mutex ||= Mutex.new
416
+ end
417
+
418
+ # Fetch our baseline userdata argument (read: "script that runs on first
419
+ # boot") for a given platform.
420
+ # *XXX* both the eval() and the blind File.read() based on the platform
421
+ # variable are dangerous without cleaning. Clean them.
422
+ # @param platform [String]: The target OS.
423
+ # @param template_variables [Hash]: A list of variable substitutions to pass as globals to the ERB parser when loading the userdata script.
424
+ # @param custom_append [String]: Arbitrary extra code to append to our default userdata behavior.
425
+ # @return [String]
426
+ def self.fetchUserdata(platform: "linux", template_variables: {}, custom_append: nil, cloud: "aws", scrub_mu_isms: false)
427
+ return nil if platform.nil? or platform.empty?
428
+ userdata_mutex.synchronize {
429
+ script = ""
430
+ if !scrub_mu_isms
431
+ if template_variables.nil? or !template_variables.is_a?(Hash)
432
+ raise MuError, "My second argument should be a hash of variables to pass into ERB templates"
433
+ end
434
+ $mu = OpenStruct.new(template_variables)
435
+ userdata_dir = File.expand_path(MU.myRoot+"/modules/mu/clouds/#{cloud}/userdata")
436
+ platform = "linux" if %w{centos centos6 centos7 ubuntu ubuntu14 rhel rhel7 rhel71 amazon}.include? platform
437
+ platform = "windows" if %w{win2k12r2 win2k12 win2k8 win2k8r2 win2k16}.include? platform
438
+ erbfile = "#{userdata_dir}/#{platform}.erb"
439
+ if !File.exist?(erbfile)
440
+ MU.log "No such userdata template '#{erbfile}'", MU::WARN, details: caller
441
+ return ""
442
+ end
443
+ userdata = File.read(erbfile)
444
+ begin
445
+ erb = ERB.new(userdata)
446
+ script = erb.result
447
+ rescue NameError => e
448
+ raise MuError, "Error parsing userdata script #{erbfile} as an ERB template: #{e.inspect}"
449
+ end
450
+ MU.log "Parsed #{erbfile} as ERB", MU::DEBUG, details: script
451
+ end
452
+
453
+ if !custom_append.nil?
454
+ if custom_append['path'].nil?
455
+ raise MuError, "Got a custom userdata script argument, but no ['path'] component"
456
+ end
457
+ erbfile = File.read(custom_append['path'])
458
+ MU.log "Loaded userdata script from #{custom_append['path']}"
459
+ if custom_append['use_erb']
460
+ begin
461
+ erb = ERB.new(erbfile, 1)
462
+ if custom_append['skip_std']
463
+ script = +erb.result
464
+ else
465
+ script = script+"\n"+erb.result
466
+ end
467
+ rescue NameError => e
468
+ raise MuError, "Error parsing userdata script #{erbfile} as an ERB template: #{e.inspect}"
469
+ end
470
+ MU.log "Parsed #{custom_append['path']} as ERB", MU::DEBUG, details: script
471
+ else
472
+ if custom_append['skip_std']
473
+ script = erbfile
474
+ else
475
+ script = script+"\n"+erbfile
476
+ end
477
+ MU.log "Parsed #{custom_append['path']} as flat file", MU::DEBUG, details: script
478
+ end
479
+ end
480
+ return script
481
+ }
482
+ end
483
+
484
+ @cloud_class_cache = {}
485
+ # Given a cloud layer and resource type, return the class which implements it.
486
+ # @param cloud [String]: The Cloud layer
487
+ # @param type [String]: The resource type. Can be the full class name, symbolic name, or Basket of Kittens configuration shorthand for the resource type.
488
+ # @return [Class]: The cloud-specific class implementing this resource
489
+ def self.loadCloudType(cloud, type)
490
+ raise MuError, "cloud argument to MU::Cloud.loadCloudType cannot be nil" if cloud.nil?
491
+ shortclass, cfg_name, cfg_plural, classname = MU::Cloud.getResourceNames(type)
492
+ if @cloud_class_cache.has_key?(cloud) and @cloud_class_cache[cloud].has_key?(type)
493
+ if @cloud_class_cache[cloud][type].nil?
494
+ raise MuError, "The '#{type}' resource is not supported in cloud #{cloud} (tried MU::#{cloud}::#{type})", caller
495
+ end
496
+ return @cloud_class_cache[cloud][type]
497
+ end
498
+
499
+ if cfg_name.nil?
500
+ raise MuError, "Can't find a cloud resource type named '#{type}'"
501
+ end
502
+ if !File.size?(MU.myRoot+"/modules/mu/clouds/#{cloud.downcase}.rb")
503
+ raise MuError, "Requested to use unsupported provisioning layer #{cloud}"
504
+ end
505
+ begin
506
+ require "mu/clouds/#{cloud.downcase}/#{cfg_name}"
507
+ rescue LoadError => e
508
+ raise MuCloudResourceNotImplemented, "MU::Cloud::#{cloud} does not currently implement #{shortclass}"
509
+ end
510
+ @cloud_class_cache[cloud] = {} if !@cloud_class_cache.has_key?(cloud)
511
+ begin
512
+ cloudclass = Object.const_get("MU").const_get("Cloud").const_get(cloud)
513
+ myclass = Object.const_get("MU").const_get("Cloud").const_get(cloud).const_get(type)
514
+ @@resource_types[type.to_sym][:class].each { |class_method|
515
+ if !myclass.respond_to?(class_method) or myclass.method(class_method).owner.to_s != "#<Class:#{myclass}>"
516
+ raise MuError, "MU::Cloud::#{cloud}::#{type} has not implemented required class method #{class_method}"
517
+ end
518
+ }
519
+ @@resource_types[type.to_sym][:instance].each { |instance_method|
520
+ if !myclass.public_instance_methods.include?(instance_method)
521
+ raise MuError, "MU::Cloud::#{cloud}::#{type} has not implemented required instance method #{instance_method}"
522
+ end
523
+ }
524
+ cloudclass.required_instance_methods.each { |instance_method|
525
+ if !myclass.public_instance_methods.include?(instance_method)
526
+ raise MuError, "MU::Cloud::#{cloud}::#{type} has not implemented required instance method #{instance_method}"
527
+ end
528
+ }
529
+
530
+ @cloud_class_cache[cloud][type] = myclass
531
+ return myclass
532
+ rescue NameError => e
533
+ @cloud_class_cache[cloud][type] = nil
534
+ raise MuError, "The '#{type}' resource is not supported in cloud #{cloud} (tried MU::#{cloud}::#{type})", e.backtrace
535
+ end
536
+ end
537
+
538
+ MU::Cloud.supportedClouds.each { |cloud|
539
+ Object.const_get("MU").const_get("Cloud").const_get(cloud).class_eval {
540
+
541
+ # Automatically load supported cloud resource classes when they're
542
+ # referenced.
543
+ def self.const_missing(symbol)
544
+ if MU::Cloud.resource_types.has_key?(symbol.to_sym)
545
+ return MU::Cloud.loadCloudType(name.sub(/.*?::([^:]+)$/, '\1'), symbol)
546
+ else
547
+ raise MuCloudResourceNotImplemented, "No such cloud resource #{name}:#{symbol}"
548
+ end
549
+ end
550
+ }
551
+ }
552
+
553
+ @@resource_types.each_pair { |name, attrs|
554
+ Object.const_get("MU").const_get("Cloud").const_get(name).class_eval {
555
+ attr_reader :cloud
556
+ attr_reader :environment
557
+ attr_reader :cloudclass
558
+ attr_reader :cloudobj
559
+ attr_reader :deploy_id
560
+ attr_reader :mu_name
561
+ attr_reader :cloud_id
562
+ attr_reader :url
563
+ attr_reader :config
564
+ attr_reader :deploydata
565
+ attr_reader :destroyed
566
+ attr_reader :cfm_template
567
+ attr_reader :cfm_name
568
+ attr_reader :delayed_save
569
+
570
+ def self.shortname
571
+ name.sub(/.*?::([^:]+)$/, '\1')
572
+ end
573
+
574
+ def self.cfg_plural
575
+ MU::Cloud.resource_types[shortname.to_sym][:cfg_plural]
576
+ end
577
+
578
+ def self.has_multiples
579
+ MU::Cloud.resource_types[shortname.to_sym][:has_multiples]
580
+ end
581
+
582
+ def self.cfg_name
583
+ MU::Cloud.resource_types[shortname.to_sym][:cfg_name]
584
+ end
585
+
586
+ def self.can_live_in_vpc
587
+ MU::Cloud.resource_types[shortname.to_sym][:can_live_in_vpc]
588
+ end
589
+
590
+ def self.waits_on_parent_completion
591
+ MU::Cloud.resource_types[shortname.to_sym][:waits_on_parent_completion]
592
+ end
593
+
594
+ def self.deps_wait_on_my_creation
595
+ MU::Cloud.resource_types[shortname.to_sym][:deps_wait_on_my_creation]
596
+ end
597
+
598
+ def groomer
599
+ return @cloudobj.groomer if !@cloudobj.nil?
600
+ nil
601
+ end
602
+
603
+ # Print something palatable when we're called in a string context.
604
+ def to_s
605
+ fullname = "#{self.class.shortname}"
606
+ if !@cloudobj.nil? and !@cloudobj.mu_name.nil?
607
+ @mu_name ||= @cloudobj.mu_name
608
+ end
609
+ if !@mu_name.nil? and !@mu_name.empty?
610
+ fullname = fullname + " '#{@mu_name}'"
611
+ end
612
+ if !@cloud_id.nil?
613
+ fullname = fullname + " (#{@cloud_id})"
614
+ end
615
+ return fullname
616
+ end
617
+
618
+
619
+ # @param mommacat [MU::MommaCat]: The deployment containing this cloud resource
620
+ # @param mu_name [String]: Optional- specify the full Mu resource name of an existing resource to load, instead of creating a new one
621
+ # @param cloud_id [String]: Optional- specify the cloud provider's identifier for an existing resource to load, instead of creating a new one
622
+ # @param kitten_cfg [Hash]: The parse configuration for this object from {MU::Config}
623
+ def initialize(mommacat: nil,
624
+ mu_name: nil,
625
+ cloud_id: nil,
626
+ kitten_cfg: nil,
627
+ delayed_save: false)
628
+ raise MuError, "Cannot invoke Cloud objects without a configuration" if kitten_cfg.nil?
629
+ @live = true
630
+ @deploy = mommacat
631
+ @config = kitten_cfg
632
+ @delayed_save = delayed_save
633
+ @cloud_id = cloud_id
634
+
635
+ if !@deploy.nil?
636
+ @deploy_id = @deploy.deploy_id
637
+ MU.log "Initializing an instance of #{self.class.name} in #{@deploy_id} #{mu_name}", MU::DEBUG, details: kitten_cfg
638
+ elsif mu_name.nil?
639
+ raise MuError, "Can't instantiate a MU::Cloud object with a live deploy or giving us a mu_name"
640
+ else
641
+ MU.log "Initializing an independent instance of #{self.class.name} named #{mu_name}", MU::DEBUG, details: kitten_cfg
642
+ end
643
+ if !kitten_cfg.has_key?("cloud")
644
+ kitten_cfg['cloud'] = MU::Config.defaultCloud
645
+ end
646
+ @cloud = kitten_cfg['cloud']
647
+ @cloudclass = MU::Cloud.loadCloudType(@cloud, self.class.shortname)
648
+ @environment = kitten_cfg['environment']
649
+ @method_semaphore = Mutex.new
650
+ @method_locks = {}
651
+ # XXX require subclass to provide attr_readers of @config and @deploy
652
+
653
+ @cloudobj = @cloudclass.new(mommacat: mommacat, kitten_cfg: kitten_cfg, cloud_id: cloud_id, mu_name: mu_name)
654
+
655
+ raise MuError, "Unknown error instantiating #{self}" if @cloudobj.nil?
656
+
657
+ # If we just loaded an existing object, go ahead and prepopulate the
658
+ # describe() cache
659
+ if !cloud_id.nil? or !mu_name.nil?
660
+ @cloudobj.describe(cloud_id: cloud_id)
661
+ @cloud_id ||= @cloudobj.cloud_id
662
+ end
663
+
664
+ @deploydata = @cloudobj.deploydata
665
+ @config = @cloudobj.config
666
+
667
+ # If we're going to be integrated into AD or otherwise need a short
668
+ # hostname, generate it now.
669
+ if self.class.shortname == "Server" and (@cloudobj.windows? or @config['active_directory']) and @cloudobj.mu_windows_name.nil?
670
+ if !@deploydata.nil? and !@deploydata['mu_windows_name'].nil?
671
+ @cloudobj.mu_windows_name = @deploydata['mu_windows_name']
672
+ else
673
+ # Use the same random differentiator as the "real" name if we're
674
+ # from a ServerPool. Helpful for admin sanity.
675
+ unq = @cloudobj.mu_name.sub(/^.*?-(...)$/, '\1')
676
+ if @config['basis'] and !unq.nil? and !unq.empty?
677
+ @cloudobj.mu_windows_name = @deploy.getResourceName(@config['name'], max_length: 15, need_unique_string: true, use_unique_string: unq, reuse_unique_string: true)
678
+ else
679
+ @cloudobj.mu_windows_name = @deploy.getResourceName(@config['name'], max_length: 15, need_unique_string: true)
680
+ end
681
+ end
682
+ end
683
+
684
+ # Register us with our parent deploy so that we can be found by our
685
+ # littermates if needed.
686
+ if !@deploy.nil? and !@cloudobj.mu_name.nil? and !@cloudobj.mu_name.empty?
687
+ describe # XXX is this actually safe here?
688
+ @deploy.addKitten(self.class.cfg_name, @config['name'], self)
689
+ elsif !@deploy.nil?
690
+ MU.log "#{self} didn't generate a mu_name after being loaded/initialized, dependencies on this resource will probably be confused!", MU::ERR
691
+ end
692
+
693
+ end
694
+
695
+ # Remove all metadata and cloud resources associated with this object
696
+ def destroy
697
+ if !@cloudobj.nil? and !@cloudobj.groomer.nil?
698
+ @cloudobj.groomer.cleanup
699
+ elsif !@groomer.nil?
700
+ @groomer.cleanup
701
+ end
702
+ if !@deploy.nil?
703
+ if !@cloudobj.nil? and !@config.nil? and !@cloudobj.mu_name.nil?
704
+ @deploy.notify(self.class.cfg_plural, @config['name'], nil, mu_name: @cloudobj.mu_name, remove: true, triggering_node: @cloudobj, delayed_save: @delayed_save)
705
+ elsif !@mu_name.nil?
706
+ @deploy.notify(self.class.cfg_plural, @config['name'], nil, mu_name: @mu_name, remove: true, triggering_node: self, delayed_save: @delayed_save)
707
+ end
708
+ @deploy.removeKitten(self)
709
+ end
710
+ # Make sure that if notify gets called again it won't go returning a
711
+ # bunch of now-bogus metadata.
712
+ @destroyed = true
713
+ if !@cloudobj.nil?
714
+ def @cloudobj.notify
715
+ {}
716
+ end
717
+ else
718
+ def notify
719
+ {}
720
+ end
721
+ end
722
+ end
723
+
724
+ def cloud_desc
725
+ describe
726
+ if !@cloudobj.nil?
727
+ @cloud_desc = @cloudobj.cloud_desc
728
+ @url = @cloudobj.url if @cloudobj.respond_to?(:url)
729
+ elsif !@config.nil? and !@cloud_id.nil?
730
+ # The find() method should be returning a Hash with the cloud_id
731
+ # as a key and a cloud platform descriptor as the value.
732
+ begin
733
+ matches = self.class.find(region: @config['region'], cloud_id: @cloud_id, flags: @config)
734
+ if !matches.nil? and matches.is_a?(Hash) and matches.has_key?(@cloud_id)
735
+ @cloud_desc = matches[@cloud_id]
736
+ else
737
+ MU.log "Failed to find a live #{self.class.shortname} with identifier #{@cloud_id} in #{@config['region']}, which has a record in deploy #{@deploy.deploy_id}", MU::WARN, details: caller
738
+ end
739
+ rescue Exception => e
740
+ MU.log "Got #{e.inspect} trying to find cloud handle for #{self.class.shortname} #{@mu_name} (#{@cloud_id})", MU::WARN
741
+ raise e
742
+ end
743
+ end
744
+
745
+ return @cloud_desc
746
+ end
747
+
748
+ # Retrieve all of the known metadata for this resource.
749
+ # @param cloud_id [String]: The cloud platform's identifier for the resource we're describing. Makes lookups more efficient.
750
+ # @param update_cache [Boolean]: Ignore cached data if we have any, instead reconsituting from original sources.
751
+ # @return [Array<Hash>]: mu_name, config, deploydata
752
+ def describe(cloud_id: nil, update_cache: false)
753
+ if cloud_id.nil? and !@cloudobj.nil?
754
+ @cloud_id ||= @cloudobj.cloud_id
755
+ end
756
+ res_type = self.class.cfg_plural
757
+ res_name = @config['name'] if !@config.nil?
758
+ deploydata = nil
759
+ if !@deploy.nil? and @deploy.is_a?(MU::MommaCat) and
760
+ !@deploy.deployment.nil? and
761
+ !@deploy.deployment[res_type].nil? and
762
+ !@deploy.deployment[res_type][res_name].nil?
763
+ deploydata = @deploy.deployment[res_type][res_name]
764
+ else
765
+ # XXX This should only happen on a brand new resource, but we should
766
+ # probably complain under other circumstances, if we can
767
+ # differentiate them.
768
+ end
769
+
770
+ if self.class.has_multiples and !@mu_name.nil? and deploydata.is_a?(Hash) and deploydata.has_key?(@mu_name)
771
+ @deploydata = deploydata[@mu_name]
772
+ elsif deploydata.is_a?(Hash)
773
+ @deploydata = deploydata
774
+ end
775
+
776
+ if @cloud_id.nil? and @deploydata.is_a?(Hash)
777
+ if @mu_name.nil? and @deploydata.has_key?('#MU_NAME')
778
+ @mu_name = @deploydata['#MU_NAME']
779
+ end
780
+ if @deploydata.has_key?('cloud_id')
781
+ @cloud_id ||= @deploydata['cloud_id']
782
+ else
783
+ # XXX temp hack to catch old Amazon-style identifiers. Remove this
784
+ # before supporting any other cloud layers, otherwise name
785
+ # collision is possible.
786
+ ["group_id", "instance_id", "awsname", "identifier", "vpc_id", "id"].each { |identifier|
787
+ if @deploydata.has_key?(identifier)
788
+ @cloud_id ||= @deploydata[identifier]
789
+ if @mu_name.nil? and (identifier == "awsname" or identifier == "identifier" or identifier == "group_id")
790
+ @mu_name = @deploydata[identifier]
791
+ end
792
+ break
793
+ end
794
+ }
795
+ end
796
+ end
797
+
798
+ return [@mu_name, @config, @deploydata]
799
+ end
800
+
801
+ # Fetch MU::Cloud objects for each of this object's dependencies, and
802
+ # return in an easily-navigable Hash. This can include things listed in
803
+ # @config['dependencies'], implicitly-defined dependencies such as
804
+ # add_firewall_rules or vpc stanzas, and may refer to objects internal
805
+ # to this deployment or external. Will populate the instance variables
806
+ # @dependencies (general dependencies, which can only be sibling
807
+ # resources in this deployment), as well as for certain config stanzas
808
+ # which can refer to external resources (@vpc, @loadbalancers,
809
+ # @add_firewall_rules)
810
+ def dependencies(use_cache: false)
811
+ @dependencies = {} if @dependencies.nil?
812
+ @loadbalancers = [] if @loadbalancers.nil?
813
+ if @config.nil?
814
+ return [@dependencies, @vpc, @loadbalancers]
815
+ end
816
+ if use_cache and @dependencies.size > 0
817
+ return [@dependencies, @vpc, @loadbalancers]
818
+ end
819
+ @config['dependencies'] = [] if @config['dependencies'].nil?
820
+
821
+ # First, general dependencies. These should all be fellow members of
822
+ # the current deployment.
823
+ @config['dependencies'].each { |dep|
824
+ @dependencies[dep['type']] ||= {}
825
+ next if @dependencies[dep['type']].has_key?(dep['name'])
826
+ handle = @deploy.findLitterMate(type: dep['type'], name: dep['name']) if !@deploy.nil?
827
+ if !handle.nil?
828
+ MU.log "Loaded dependency for #{self}: #{dep['name']} => #{handle}", MU::DEBUG
829
+ @dependencies[dep['type']][dep['name']] = handle
830
+ else
831
+ # XXX yell under circumstances where we should expect to have
832
+ # our stuff available already?
833
+ end
834
+ }
835
+
836
+ # Special dependencies: my containing VPC
837
+ if self.class.can_live_in_vpc and !@config['vpc'].nil?
838
+ MU.log "Loading VPC for #{self}", MU::DEBUG, details: @config['vpc']
839
+ if !@config['vpc']["vpc_name"].nil? and
840
+ @dependencies.has_key?("vpc") and
841
+ @dependencies["vpc"].has_key?(@config['vpc']["vpc_name"])
842
+ @vpc = @dependencies["vpc"][@config['vpc']["vpc_name"]]
843
+ else
844
+ tag_key, tag_value = @config['vpc']['tag'].split(/=/, 2) if !@config['vpc']['tag'].nil?
845
+ if !@config['vpc'].has_key?("vpc_id") and
846
+ !@config['vpc'].has_key?("deploy_id") and !@deploy.nil?
847
+ @config['vpc']["deploy_id"] = @deploy.deploy_id
848
+ end
849
+ vpcs = MU::MommaCat.findStray(
850
+ @config['cloud'],
851
+ "vpc",
852
+ deploy_id: @config['vpc']["deploy_id"],
853
+ cloud_id: @config['vpc']["vpc_id"],
854
+ name: @config['vpc']["vpc_name"],
855
+ tag_key: tag_key,
856
+ tag_value: tag_value,
857
+ region: @config['vpc']["region"],
858
+ calling_deploy: @deploy,
859
+ dummy_ok: true
860
+ )
861
+ @vpc = vpcs.first if !vpcs.nil? and vpcs.size > 0
862
+ end
863
+ if !@vpc.nil? and (
864
+ @config['vpc'].has_key?("nat_host_id") or
865
+ @config['vpc'].has_key?("nat_host_tag") or
866
+ @config['vpc'].has_key?("nat_host_ip") or
867
+ @config['vpc'].has_key?("nat_host_name")
868
+ )
869
+
870
+ nat_tag_key, nat_tag_value = @config['vpc']['nat_host_tag'].split(/=/, 2) if !@config['vpc']['nat_host_tag'].nil?
871
+
872
+ @nat = @vpc.findBastion(
873
+ nat_name: @config['vpc']['nat_host_name'],
874
+ nat_cloud_id: @config['vpc']['nat_host_id'],
875
+ nat_tag_key: nat_tag_key,
876
+ nat_tag_value: nat_tag_value,
877
+ nat_ip: @config['vpc']['nat_host_ip']
878
+ )
879
+
880
+ if @nat.nil?
881
+ if !@vpc.cloud_desc.nil?
882
+ @nat = @vpc.findNat(
883
+ nat_cloud_id: @config['vpc']['nat_host_id'],
884
+ nat_filter_key: "vpc-id",
885
+ region: @config['vpc']["region"],
886
+ nat_filter_value: @vpc.cloud_id
887
+ )
888
+ else
889
+ @nat = @vpc.findNat(
890
+ nat_cloud_id: @config['vpc']['nat_host_id'],
891
+ region: @config['vpc']["region"]
892
+ )
893
+ end
894
+ end
895
+ end
896
+ elsif self.class.cfg_name == "vpc"
897
+ @vpc = self
898
+ end
899
+
900
+ # Special dependencies: LoadBalancers I've asked to attach to an
901
+ # instance.
902
+ if @config.has_key?("loadbalancers")
903
+ @loadbalancers = [] if !@loadbalancers
904
+ @config['loadbalancers'].each { |lb|
905
+ MU.log "Loading LoadBalancer for #{self}", MU::DEBUG, details: lb
906
+ if @dependencies.has_key?("loadbalancer") and
907
+ @dependencies["loadbalancer"].has_key?(lb['concurrent_load_balancer'])
908
+ @loadbalancers << @dependencies["loadbalancer"][lb['concurrent_load_balancer']]
909
+ else
910
+ if !lb.has_key?("existing_load_balancer") and
911
+ !lb.has_key?("deploy_id") and !@deploy.nil?
912
+ lb["deploy_id"] = @deploy.deploy_id
913
+ end
914
+ lbs = MU::MommaCat.findStray(
915
+ @config['cloud'],
916
+ "loadbalancer",
917
+ deploy_id: lb["deploy_id"],
918
+ cloud_id: lb['existing_load_balancer'],
919
+ name: lb['concurrent_load_balancer'],
920
+ region: @config["region"],
921
+ calling_deploy: @deploy,
922
+ dummy_ok: true
923
+ )
924
+ @loadbalancers << lbs.first if !lbs.nil? and lbs.size > 0
925
+ end
926
+ }
927
+ end
928
+
929
+ return [@dependencies, @vpc, @loadbalancers]
930
+ end
931
+
932
+ def self.find(*flags)
933
+ allfound = {}
934
+
935
+ MU::Cloud.supportedClouds.each { |cloud|
936
+ begin
937
+ args = flags.first
938
+ # skip this cloud if we have a region argument that makes no
939
+ # sense there
940
+ cloudbase = Object.const_get("MU").const_get("Cloud").const_get(cloud)
941
+ if args[:region] and cloudbase.respond_to?(:listRegions)
942
+ next if !cloudbase.listRegions.include?(args[:region])
943
+ end
944
+ cloudclass = MU::Cloud.loadCloudType(cloud, shortname)
945
+
946
+ found = cloudclass.find(args)
947
+ if !found.nil?
948
+ if found.is_a?(Hash)
949
+ allfound.merge!(found)
950
+ else
951
+ raise MuError, "#{cloudclass}.find returned a non-Hash result"
952
+ end
953
+ end
954
+ rescue MuCloudResourceNotImplemented
955
+ end
956
+ }
957
+ allfound
958
+ end
959
+
960
+ if shortname == "DNSZone"
961
+ def self.genericMuDNSEntry(*flags)
962
+ # XXX have this switch on a global config for where Mu puts its DNS
963
+ cloudclass = MU::Cloud.loadCloudType(MU::Config.defaultCloud, "DNSZone")
964
+ cloudclass.genericMuDNSEntry(flags.first)
965
+ end
966
+ def self.createRecordsFromConfig(*flags)
967
+ cloudclass = MU::Cloud.loadCloudType(MU::Config.defaultCloud, "DNSZone")
968
+ if !flags.nil? and flags.size == 1
969
+ cloudclass.createRecordsFromConfig(flags.first)
970
+ else
971
+ cloudclass.createRecordsFromConfig(*flags)
972
+ end
973
+ end
974
+ end
975
+
976
+ if shortname == "Server"
977
+ def windows?
978
+ return true if %w{win2k16 win2k12r2 win2k12 win2k8 win2k8r2 windows}.include?(@config['platform'])
979
+ begin
980
+ return true if cloud_desc.respond_to?(:platform) and cloud_desc.platform == "Windows"
981
+ # XXX ^ that's AWS-speak, doesn't cover GCP or anything else; maybe we should require cloud layers to implement this so we can just call @cloudobj.windows?
982
+ rescue MU::MuError
983
+ return false
984
+ end
985
+ false
986
+ end
987
+
988
+ # Gracefully message and attempt to accommodate the common transient errors peculiar to Windows nodes
989
+ # @param e [Exception]: The exception that we're handling
990
+ # @param retries [Integer]: The current number of retries, which we'll increment and pass back to the caller
991
+ # @param rebootable_fails [Integer]: The current number of reboot-worthy failures, which we'll increment and pass back to the caller
992
+ # @param max_retries [Integer]: Maximum number of retries to attempt; we'll raise an exception if this is exceeded
993
+ # @param reboot_on_problems [Boolean]: Whether we should try to reboot a "stuck" machine
994
+ # @param retry_interval [Integer]: How many seconds to wait before returning for another attempt
995
+ def handleWindowsFail(e, retries, rebootable_fails, max_retries: 30, reboot_on_problems: false, retry_interval: 45)
996
+ msg = "WinRM connection to https://"+@mu_name+":5986/wsman: #{e.message}, waiting #{retry_interval}s (attempt #{retries}/#{max_retries})"
997
+ if e.class.name == "WinRM::WinRMAuthorizationError" or e.message.match(/execution expired/) and reboot_on_problems
998
+ if rebootable_fails > 0 and (rebootable_fails % 5) == 0
999
+ MU.log "#{@mu_name} still misbehaving, forcing Stop and Start from API", MU::WARN
1000
+ reboot(true) # vicious API stop/start
1001
+ sleep retry_interval*3
1002
+ rebootable_fails = 0
1003
+ else
1004
+ if rebootable_fails == 3
1005
+ MU.log "#{@mu_name} misbehaving, attempting to reboot from API", MU::WARN
1006
+ reboot # graceful API restart
1007
+ sleep retry_interval*2
1008
+ end
1009
+ rebootable_fails = rebootable_fails + 1
1010
+ end
1011
+ end
1012
+ if retries < max_retries
1013
+ if retries == 1 or (retries/max_retries <= 0.5 and (retries % 3) == 0 and retries != 0)
1014
+ MU.log msg, MU::NOTICE
1015
+ elsif retries/max_retries > 0.5
1016
+ MU.log msg, MU::WARN, details: e.inspect
1017
+ end
1018
+ sleep retry_interval
1019
+ retries = retries + 1
1020
+ else
1021
+ raise MuError, "#{@mu_name}: #{e.inspect} trying to connect with WinRM, max_retries exceeded", e.backtrace
1022
+ end
1023
+ return [retries, rebootable_fails]
1024
+ end
1025
+
1026
+ def windowsRebootPending?(shell = nil)
1027
+ if shell.nil?
1028
+ shell = getWinRMSession(1, 30)
1029
+ end
1030
+ # if (Get-Item "HKLM:/SOFTWARE/Microsoft/Windows/CurrentVersion/WindowsUpdate/Auto Update/RebootRequired" -EA Ignore) { exit 1 }
1031
+ cmd = %Q{
1032
+ if (Get-ChildItem "HKLM:/Software/Microsoft/Windows/CurrentVersion/Component Based Servicing/RebootPending" -EA Ignore) {
1033
+ echo "Component Based Servicing/RebootPending is true"
1034
+ exit 1
1035
+ }
1036
+ if (Get-ItemProperty "HKLM:/SYSTEM/CurrentControlSet/Control/Session Manager" -Name PendingFileRenameOperations -EA Ignore) {
1037
+ echo "Control/Session Manager/PendingFileRenameOperations is true"
1038
+ exit 1
1039
+ }
1040
+ try {
1041
+ $util = [wmiclass]"\\\\.\\root\\ccm\\clientsdk:CCM_ClientUtilities"
1042
+ $status = $util.DetermineIfRebootPending()
1043
+ if(($status -ne $null) -and $status.RebootPending){
1044
+ echo "WMI says RebootPending is true"
1045
+ exit 1
1046
+ }
1047
+ } catch {
1048
+ exit 0
1049
+ }
1050
+ exit 0
1051
+ }
1052
+ resp = shell.run(cmd)
1053
+ returnval = resp.exitcode == 0 ? false : true
1054
+ shell.close
1055
+ returnval
1056
+ end
1057
+
1058
+ # Basic setup tasks performed on a new node during its first WinRM
1059
+ # connection. Most of this is terrible Windows glue.
1060
+ # @param shell [WinRM::Shells::Powershell]: An active Powershell session to the new node.
1061
+ def initialWinRMTasks(shell)
1062
+ retries = 0
1063
+ rebootable_fails = 0
1064
+ begin
1065
+ if !@config['use_cloud_provider_windows_password']
1066
+ pw = @groomer.getSecret(
1067
+ vault: @config['mu_name'],
1068
+ item: "windows_credentials",
1069
+ field: "password"
1070
+ )
1071
+ win_check_for_pw = %Q{Add-Type -AssemblyName System.DirectoryServices.AccountManagement; $Creds = (New-Object System.Management.Automation.PSCredential("#{@config["windows_admin_username"]}", (ConvertTo-SecureString "#{pw}" -AsPlainText -Force)));$DS = New-Object System.DirectoryServices.AccountManagement.PrincipalContext([System.DirectoryServices.AccountManagement.ContextType]::Machine); $DS.ValidateCredentials($Creds.GetNetworkCredential().UserName, $Creds.GetNetworkCredential().password); echo $Result}
1072
+ resp = shell.run(win_check_for_pw)
1073
+ if resp.stdout.chomp != "True"
1074
+ win_set_pw = %Q{(([adsi]('WinNT://./#{@config["windows_admin_username"]}, user')).psbase.invoke('SetPassword', '#{pw}'))}
1075
+ resp = shell.run(win_set_pw)
1076
+ puts resp.stdout
1077
+ MU.log "Resetting Windows host password", MU::NOTICE, details: resp.stdout
1078
+ end
1079
+ end
1080
+
1081
+ # Install Cygwin here, because for some reason it breaks inside Chef
1082
+ # XXX would love to not do this here
1083
+ pkgs = ["bash", "mintty", "vim", "curl", "openssl", "wget", "lynx", "openssh"]
1084
+ admin_home = "c:/bin/cygwin/home/#{@config["windows_admin_username"]}"
1085
+ install_cygwin = %Q{
1086
+ If (!(Test-Path "c:/bin/cygwin/Cygwin.bat")){
1087
+ $WebClient = New-Object System.Net.WebClient
1088
+ $WebClient.DownloadFile("http://cygwin.com/setup-x86_64.exe","$env:Temp/setup-x86_64.exe")
1089
+ Start-Process -wait -FilePath $env:Temp/setup-x86_64.exe -ArgumentList "-q -n -l $env:Temp/cygwin -R c:/bin/cygwin -s http://mirror.cs.vt.edu/pub/cygwin/cygwin/ -P #{pkgs.join(',')}"
1090
+ }
1091
+ if(!(Test-Path #{admin_home})){
1092
+ New-Item -type directory -path #{admin_home}
1093
+ }
1094
+ if(!(Test-Path #{admin_home}/.ssh)){
1095
+ New-Item -type directory -path #{admin_home}/.ssh
1096
+ }
1097
+ if(!(Test-Path #{admin_home}/.ssh/authorized_keys)){
1098
+ New-Item #{admin_home}/.ssh/authorized_keys -type file -force -value "#{@deploy.ssh_public_key}"
1099
+ }
1100
+ }
1101
+ resp = shell.run(install_cygwin)
1102
+ if resp.exitcode != 0
1103
+ MU.log "Failed at installing Cygwin", MU::ERR, details: resp
1104
+ end
1105
+
1106
+ set_hostname = true
1107
+ hostname = nil
1108
+ if !@config['active_directory'].nil?
1109
+ if @config['active_directory']['node_type'] == "domain_controller" && @config['active_directory']['domain_controller_hostname']
1110
+ hostname = @config['active_directory']['domain_controller_hostname']
1111
+ @mu_windows_name = hostname
1112
+ set_hostname = true
1113
+ else
1114
+ # Do we have an AD specific hostname?
1115
+ hostname = @mu_windows_name
1116
+ set_hostname = true
1117
+ end
1118
+ else
1119
+ hostname = @mu_windows_name
1120
+ end
1121
+ resp = shell.run(%Q{hostname})
1122
+
1123
+ if resp.stdout.chomp != hostname
1124
+ resp = shell.run(%Q{Rename-Computer -NewName '#{hostname}' -Force -PassThru -Restart; Restart-Computer -Force})
1125
+ MU.log "Renaming Windows host to #{hostname}; this will trigger a reboot", MU::NOTICE, details: resp.stdout
1126
+ reboot(true)
1127
+ sleep 30
1128
+ end
1129
+ rescue WinRM::WinRMError, HTTPClient::ConnectTimeoutError => e
1130
+ retries, rebootable_fails = handleWindowsFail(e, retries, rebootable_fails, max_retries: 10, reboot_on_problems: true, retry_interval: 30)
1131
+ retry
1132
+ end
1133
+ end
1134
+
1135
+
1136
+ # Basic setup tasks performed on a new node during its first initial
1137
+ # ssh connection. Most of this is terrible Windows glue.
1138
+ # @param ssh [Net::SSH::Connection::Session]: The active SSH session to the new node.
1139
+ def initialSSHTasks(ssh)
1140
+ win_env_fix = %q{echo 'export PATH="$PATH:/cygdrive/c/opscode/chef/embedded/bin"' > "$HOME/chef-client"; echo 'prev_dir="`pwd`"; for __dir in /proc/registry/HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Session\ Manager/Environment;do cd "$__dir"; for __var in `ls * | grep -v TEMP | grep -v TMP`;do __var=`echo $__var | tr "[a-z]" "[A-Z]"`; test -z "${!__var}" && export $__var="`cat $__var`" >/dev/null 2>&1; done; done; cd "$prev_dir"; /cygdrive/c/opscode/chef/bin/chef-client.bat $@' >> "$HOME/chef-client"; chmod 700 "$HOME/chef-client"; ( grep "^alias chef-client=" "$HOME/.bashrc" || echo 'alias chef-client="$HOME/chef-client"' >> "$HOME/.bashrc" ) ; ( grep "^alias mu-groom=" "$HOME/.bashrc" || echo 'alias mu-groom="powershell -File \"c:/Program Files/Amazon/Ec2ConfigService/Scripts/UserScript.ps1\""' >> "$HOME/.bashrc" )}
1141
+ win_installer_check = %q{ls /proc/registry/HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows/CurrentVersion/Installer/}
1142
+ lnx_installer_check = %q{ps auxww | awk '{print $11}' | egrep '(/usr/bin/yum|apt-get|dpkg)'}
1143
+ lnx_updates_check = %q{( test -f /.mu-installer-ran-updates || ! test -d /var/lib/cloud/instance ) || echo "userdata still running"}
1144
+ win_set_pw = nil
1145
+
1146
+ if windows? and !@config['use_cloud_provider_windows_password']
1147
+ # This covers both the case where we have a windows password passed from a vault and where we need to use a a random Windows Admin password generated by MU::Cloud::Server.generateWindowsPassword
1148
+ pw = @groomer.getSecret(
1149
+ vault: @config['mu_name'],
1150
+ item: "windows_credentials",
1151
+ field: "password"
1152
+ )
1153
+ win_check_for_pw = %Q{powershell -Command '& {Add-Type -AssemblyName System.DirectoryServices.AccountManagement; $Creds = (New-Object System.Management.Automation.PSCredential("#{@config["windows_admin_username"]}", (ConvertTo-SecureString "#{pw}" -AsPlainText -Force)));$DS = New-Object System.DirectoryServices.AccountManagement.PrincipalContext([System.DirectoryServices.AccountManagement.ContextType]::Machine); $DS.ValidateCredentials($Creds.GetNetworkCredential().UserName, $Creds.GetNetworkCredential().password); echo $Result}'}
1154
+ win_set_pw = %Q{powershell -Command "& {(([adsi]('WinNT://./#{@config["windows_admin_username"]}, user')).psbase.invoke('SetPassword', '#{pw}'))}"}
1155
+ end
1156
+
1157
+ # There shouldn't be a use case where a domain joined computer goes through initialSSHTasks. Removing Active Directory specific computer rename.
1158
+ set_hostname = true
1159
+ hostname = nil
1160
+ if !@config['active_directory'].nil?
1161
+ if @config['active_directory']['node_type'] == "domain_controller" && @config['active_directory']['domain_controller_hostname']
1162
+ hostname = @config['active_directory']['domain_controller_hostname']
1163
+ @mu_windows_name = hostname
1164
+ set_hostname = true
1165
+ else
1166
+ # Do we have an AD specific hostname?
1167
+ hostname = @mu_windows_name
1168
+ set_hostname = true
1169
+ end
1170
+ else
1171
+ hostname = @mu_windows_name
1172
+ end
1173
+ win_check_for_hostname = %Q{powershell -Command '& {hostname}'}
1174
+ win_set_hostname = %Q{powershell -Command "& {Rename-Computer -NewName '#{hostname}' -Force -PassThru -Restart; Restart-Computer -Force }"}
1175
+
1176
+ begin
1177
+ # Set our admin password first, if we need to
1178
+ if windows? and !win_set_pw.nil? and !win_check_for_pw.nil?
1179
+ output = ssh.exec!(win_check_for_pw)
1180
+ raise MU::Cloud::BootstrapTempFail, "Got nil output from ssh session, waiting and retrying" if output.nil?
1181
+ if !output.match(/True/)
1182
+ MU.log "Setting Windows password for user #{@config['windows_admin_username']}", details: ssh.exec!(win_set_pw)
1183
+ end
1184
+ end
1185
+ if windows?
1186
+ output = ssh.exec!(win_env_fix)
1187
+ output = ssh.exec!(win_installer_check)
1188
+ raise MU::Cloud::BootstrapTempFail, "Got nil output from ssh session, waiting and retrying" if output.nil?
1189
+ if output.match(/InProgress/)
1190
+ raise MU::Cloud::BootstrapTempFail, "Windows Installer service is still doing something, need to wait"
1191
+ end
1192
+ if set_hostname and !@hostname_set and @mu_windows_name
1193
+ output = ssh.exec!(win_check_for_hostname)
1194
+ raise MU::Cloud::BootstrapTempFail, "Got nil output from ssh session, waiting and retrying" if output.nil?
1195
+ if !output.match(/#{@mu_windows_name}/)
1196
+ MU.log "Setting Windows hostname to #{@mu_windows_name}", details: ssh.exec!(win_set_hostname)
1197
+ @hostname_set = true
1198
+ # Reboot from the API too, in case Windows is flailing
1199
+ if !@cloudobj.nil?
1200
+ @cloudobj.reboot
1201
+ else
1202
+ reboot
1203
+ end
1204
+ raise MU::Cloud::BootstrapTempFail, "Set hostname in Windows, waiting for reboot"
1205
+ end
1206
+ end
1207
+ else
1208
+ output = ssh.exec!(lnx_installer_check)
1209
+ if !output.nil? and !output.empty?
1210
+ raise MU::Cloud::BootstrapTempFail, "Linux package manager is still doing something, need to wait (#{output})"
1211
+ end
1212
+ if !@config['skipinitialupdates']
1213
+ output = ssh.exec!(lnx_updates_check)
1214
+ if !output.nil? and output.match(/userdata still running/)
1215
+ raise MU::Cloud::BootstrapTempFail, "Waiting for initial userdata system updates to complete"
1216
+ end
1217
+ end
1218
+ end
1219
+ rescue RuntimeError => e
1220
+ raise MU::Cloud::BootstrapTempFail, "Got #{e.inspect} performing initial SSH connect tasks, will try again"
1221
+ end
1222
+
1223
+ end
1224
+
1225
+ # Get a privileged Powershell session on the server in question, using SSL-encrypted WinRM with certificate authentication.
1226
+ # @param max_retries [Integer]:
1227
+ # @param retry_interval [Integer]:
1228
+ # @param timeout [Integer]:
1229
+ # @param winrm_retries [Integer]:
1230
+ # @param reboot_on_problems [Boolean]:
1231
+ def getWinRMSession(max_retries = 40, retry_interval = 60, timeout: 30, winrm_retries: 5, reboot_on_problems: false)
1232
+ nat_ssh_key, nat_ssh_user, nat_ssh_host, canonical_ip, ssh_user, ssh_key_name = getSSHConfig
1233
+ @mu_name ||= @config['mu_name']
1234
+
1235
+ conn = nil
1236
+ shell = nil
1237
+ opts = nil
1238
+ # and now, a thing I really don't want to do
1239
+ MU::MommaCat.addInstanceToEtcHosts(canonical_ip, @mu_name)
1240
+
1241
+ # catch exceptions that circumvent our regular call stack
1242
+ Thread.abort_on_exception = false
1243
+ Thread.handle_interrupt(WinRM::WinRMWSManFault => :never) {
1244
+ begin
1245
+ Thread.handle_interrupt(WinRM::WinRMWSManFault => :immediate) {
1246
+ MU.log "(Probably harmless) Caught a WinRM::WinRMWSManFault in #{Thread.current.inspect}", MU::DEBUG, details: Thread.current.backtrace
1247
+ }
1248
+ ensure
1249
+ # Reraise something useful
1250
+ end
1251
+ }
1252
+
1253
+ retries = 0
1254
+ rebootable_fails = 0
1255
+ begin
1256
+ MU.log "Calling WinRM on #{@mu_name}", MU::DEBUG, details: opts
1257
+ opts = {
1258
+ endpoint: 'https://'+@mu_name+':5986/wsman',
1259
+ retry_limit: winrm_retries,
1260
+ no_ssl_peer_verification: true, # XXX this should not be necessary; we get 'hostname "foo" does not match the server certificate' even when it clearly does match
1261
+ ca_trust_path: "#{MU.mySSLDir}/Mu_CA.pem",
1262
+ transport: :ssl,
1263
+ operation_timeout: timeout,
1264
+ client_cert: "#{MU.mySSLDir}/#{@mu_name}-winrm.crt",
1265
+ client_key: "#{MU.mySSLDir}/#{@mu_name}-winrm.key"
1266
+ }
1267
+ conn = WinRM::Connection.new(opts)
1268
+ MU.log "WinRM connection to #{@mu_name} created", MU::DEBUG, details: conn
1269
+ shell = conn.shell(:powershell)
1270
+ shell.run('ipconfig') # verify that we can do something
1271
+ rescue Errno::EHOSTUNREACH, Errno::ECONNREFUSED, HTTPClient::ConnectTimeoutError, OpenSSL::SSL::SSLError, SocketError, WinRM::WinRMError, Timeout::Error => e
1272
+ retries, rebootable_fails = handleWindowsFail(e, retries, rebootable_fails, max_retries: max_retries, reboot_on_problems: reboot_on_problems, retry_interval: retry_interval)
1273
+ retry
1274
+ ensure
1275
+ MU::MommaCat.removeInstanceFromEtcHosts(@mu_name)
1276
+ end
1277
+
1278
+ shell
1279
+ end
1280
+
1281
+ # @param max_retries [Integer]: Number of connection attempts to make before giving up
1282
+ # @param retry_interval [Integer]: Number of seconds to wait between connection attempts
1283
+ # @return [Net::SSH::Connection::Session]
1284
+ def getSSHSession(max_retries = 12, retry_interval = 30)
1285
+ ssh_keydir = Etc.getpwnam(@deploy.mu_user).dir+"/.ssh"
1286
+ nat_ssh_key, nat_ssh_user, nat_ssh_host, canonical_ip, ssh_user, ssh_key_name = getSSHConfig
1287
+ session = nil
1288
+ retries = 0
1289
+
1290
+ # XXX WHY is this a thing
1291
+ Thread.handle_interrupt(Errno::ECONNREFUSED => :never) {
1292
+ }
1293
+
1294
+ begin
1295
+ MU::Cloud.handleNetSSHExceptions
1296
+ if !nat_ssh_host.nil?
1297
+ proxy_cmd = "ssh -q -o StrictHostKeyChecking=no -W %h:%p #{nat_ssh_user}@#{nat_ssh_host}"
1298
+ MU.log "Attempting SSH to #{canonical_ip} (#{@mu_name}) as #{ssh_user} with key #{@deploy.ssh_key_name} using proxy '#{proxy_cmd}'" if retries == 0
1299
+ proxy = Net::SSH::Proxy::Command.new(proxy_cmd)
1300
+ session = Net::SSH.start(
1301
+ canonical_ip,
1302
+ ssh_user,
1303
+ :config => false,
1304
+ :keys_only => true,
1305
+ :keys => [ssh_keydir+"/"+nat_ssh_key, ssh_keydir+"/"+@deploy.ssh_key_name],
1306
+ :verify_host_key => false,
1307
+ # :verbose => :info,
1308
+ :port => 22,
1309
+ :auth_methods => ['publickey'],
1310
+ :proxy => proxy
1311
+ )
1312
+ else
1313
+ MU.log "Attempting SSH to #{canonical_ip} (#{@mu_name}) as #{ssh_user} with key #{ssh_keydir}/#{@deploy.ssh_key_name}" if retries == 0
1314
+ session = Net::SSH.start(
1315
+ canonical_ip,
1316
+ ssh_user,
1317
+ :config => false,
1318
+ :keys_only => true,
1319
+ :keys => [ssh_keydir+"/"+@deploy.ssh_key_name],
1320
+ :verify_host_key => false,
1321
+ # :verbose => :info,
1322
+ :port => 22,
1323
+ :auth_methods => ['publickey']
1324
+ )
1325
+ end
1326
+ retries = 0
1327
+ rescue Net::SSH::HostKeyMismatch => e
1328
+ MU.log("Remembering new key: #{e.fingerprint}")
1329
+ e.remember_host!
1330
+ session.close
1331
+ retry
1332
+ rescue SystemCallError, Timeout::Error, Errno::ECONNRESET, Errno::EHOSTUNREACH, Net::SSH::Proxy::ConnectError, SocketError, Net::SSH::Disconnect, Net::SSH::AuthenticationFailed, IOError, Net::SSH::ConnectionTimeout, Net::SSH::Proxy::ConnectError, MU::Cloud::NetSSHFail => e
1333
+ begin
1334
+ session.close if !session.nil?
1335
+ rescue Net::SSH::Disconnect, IOError => e
1336
+ if windows?
1337
+ MU.log "Windows has probably closed the ssh session before we could. Waiting before trying again", MU::NOTICE
1338
+ else
1339
+ MU.log "ssh session was closed unexpectedly, waiting before trying again", MU::NOTICE
1340
+ end
1341
+ sleep 10
1342
+ end
1343
+
1344
+ if retries < max_retries
1345
+ retries = retries + 1
1346
+ msg = "ssh #{ssh_user}@#{@config['mu_name']}: #{e.message}, waiting #{retry_interval}s (attempt #{retries}/#{max_retries})", MU::WARN
1347
+ if retries == 1 or (retries/max_retries <= 0.5 and (retries % 3) == 0)
1348
+ MU.log msg, MU::NOTICE
1349
+ elsif retries/max_retries > 0.5
1350
+ MU.log msg, MU::WARN, details: e.inspect
1351
+ end
1352
+ sleep retry_interval
1353
+ retry
1354
+ else
1355
+ raise MuError, "#{@config['mu_name']}: #{e.inspect} trying to connect with SSH, max_retries exceeded", e.backtrace
1356
+ end
1357
+ end
1358
+ return session
1359
+ end
1360
+ end
1361
+
1362
+ # Wrapper for the cleanup class method of underlying cloud object implementations.
1363
+ def self.cleanup(*flags)
1364
+ params = flags.first
1365
+ clouds = MU::Cloud.supportedClouds
1366
+ if params[:cloud]
1367
+ clouds = [params[:cloud]]
1368
+ params.delete(:cloud)
1369
+ end
1370
+ clouds.each { |cloud|
1371
+ begin
1372
+ cloudclass = MU::Cloud.loadCloudType(cloud, shortname)
1373
+ raise MuCloudResourceNotImplemented if !cloudclass.respond_to?(:cleanup) or cloudclass.method(:cleanup).owner.to_s != "#<Class:#{cloudclass}>"
1374
+ MU.log "Invoking #{cloudclass}.cleanup from #{shortname}", MU::DEBUG, details: flags
1375
+ cloudclass.cleanup(params)
1376
+ rescue MuCloudResourceNotImplemented
1377
+ MU.log "No #{cloud} implementation of #{shortname}.cleanup, skipping", MU::DEBUG, details: flags
1378
+ end
1379
+ }
1380
+ MU::MommaCat.unlockAll
1381
+ end
1382
+
1383
+ # Wrap the instance methods that this cloud resource type has to
1384
+ # implement.
1385
+ MU::Cloud.resource_types[name.to_sym][:instance].each { |method|
1386
+ define_method method do |*args|
1387
+ return nil if @cloudobj.nil?
1388
+ MU.log "Invoking #{@cloudobj}.#{method}", MU::DEBUG
1389
+
1390
+ # Go ahead and guarantee that we can't accidentally trigger these
1391
+ # methods recursively.
1392
+ @method_semaphore.synchronize {
1393
+ # We're looking for recursion, not contention, so ignore some
1394
+ # obviously harmless things.
1395
+ if @method_locks.has_key?(method) and method != :findBastion and method != :cloud_id
1396
+ MU.log "Double-call to cloud method #{method} for #{self}", MU::DEBUG, details: caller + ["competing call stack:"] + @method_locks[method]
1397
+ end
1398
+ @method_locks[method] = caller
1399
+ }
1400
+
1401
+ # Make sure the describe() caches are fresh
1402
+ @cloudobj.describe if method != :describe
1403
+
1404
+ # Don't run through dependencies on simple attr_reader lookups
1405
+ if ![:dependencies, :cloud_id, :config, :mu_name].include?(method)
1406
+ @cloudobj.dependencies
1407
+ end
1408
+
1409
+ retval = nil
1410
+ if !args.nil? and args.size == 1
1411
+ retval = @cloudobj.method(method).call(args.first)
1412
+ elsif !args.nil? and args.size > 0
1413
+ retval = @cloudobj.method(method).call(*args)
1414
+ else
1415
+ retval = @cloudobj.method(method).call
1416
+ end
1417
+ if (method == :create or method == :groom or method == :postBoot) and
1418
+ (!@destroyed and !@cloudobj.destroyed)
1419
+ deploydata = @cloudobj.method(:notify).call
1420
+ if deploydata.nil? or !deploydata.is_a?(Hash)
1421
+ MU.log "#{self} notify method did not return a Hash of deployment data", MU::WARN
1422
+ deploydata = MU.structToHash(@cloudobj.cloud_desc)
1423
+ end
1424
+ deploydata['cloud_id'] = @cloudobj.cloud_id if !@cloudobj.cloud_id.nil?
1425
+ deploydata['mu_name'] = @cloudobj.mu_name if !@cloudobj.mu_name.nil?
1426
+ @deploy.notify(self.class.cfg_plural, @config['name'], deploydata, triggering_node: @cloudobj, delayed_save: @delayed_save) if !@deploy.nil?
1427
+ elsif method == :notify
1428
+ retval['cloud_id'] = @cloudobj.cloud_id if !@cloudobj.cloud_id.nil?
1429
+ retval['mu_name'] = @cloudobj.mu_name if !@cloudobj.mu_name.nil?
1430
+ @deploy.notify(self.class.cfg_plural, @config['name'], retval, triggering_node: @cloudobj, delayed_save: @delayed_save) if !@deploy.nil?
1431
+ end
1432
+ @method_semaphore.synchronize {
1433
+ @method_locks.delete(method)
1434
+ }
1435
+
1436
+ @deploydata = @cloudobj.deploydata
1437
+ @config = @cloudobj.config
1438
+ retval
1439
+ end
1440
+ } # end instance method list
1441
+ } # end dynamic class generation block
1442
+ } # end resource type iteration
1443
+
1444
+ end
1445
+
1446
+ end