cloud-mu 1.9.0.pre.beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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