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,1510 @@
1
+ # Copyright:: Copyright (c) 2017 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
+ require 'net/ssh'
16
+ require 'net/ssh/multi'
17
+ require 'net/ssh/proxy/command'
18
+ autoload :OpenStruct, "ostruct"
19
+ autoload :Timeout, "timeout"
20
+ autoload :ERB, "erb"
21
+ autoload :Base64, "base64"
22
+ require 'open-uri'
23
+
24
+ module MU
25
+ class Cloud
26
+ class Google
27
+ # A server as configured in {MU::Config::BasketofKittens::servers}. In
28
+ # Google Cloud, this amounts to a single Instance in an Unmanaged
29
+ # Instance Group.
30
+ class Server < MU::Cloud::Server
31
+
32
+ attr_reader :mu_name
33
+ attr_reader :config
34
+ attr_reader :deploy
35
+ attr_reader :cloud_id
36
+ attr_reader :cloud_desc
37
+ attr_reader :groomer
38
+ attr_accessor :mu_windows_name
39
+
40
+ # @param mommacat [MU::MommaCat]: A {MU::Mommacat} object containing the deploy of which this resource is/will be a member.
41
+ # @param kitten_cfg [Hash]: The fully parsed and resolved {MU::Config} resource descriptor as defined in {MU::Config::BasketofKittens::servers}
42
+ def initialize(mommacat: nil, kitten_cfg: nil, mu_name: nil, cloud_id: nil)
43
+ @deploy = mommacat
44
+ @config = MU::Config.manxify(kitten_cfg)
45
+ @cloud_id = cloud_id
46
+
47
+ if @deploy
48
+ @userdata = MU::Cloud.fetchUserdata(
49
+ platform: @config["platform"],
50
+ cloud: "google",
51
+ template_variables: {
52
+ "deployKey" => Base64.urlsafe_encode64(@deploy.public_key),
53
+ "deploySSHKey" => @deploy.ssh_public_key,
54
+ "muID" => MU.deploy_id,
55
+ "muUser" => MU.mu_user,
56
+ "publicIP" => MU.mu_public_ip,
57
+ "skipApplyUpdates" => @config['skipinitialupdates'],
58
+ "windowsAdminName" => @config['windows_admin_username'],
59
+ "resourceName" => @config["name"],
60
+ "resourceType" => "server",
61
+ "platform" => @config["platform"]
62
+ },
63
+ custom_append: @config['userdata_script']
64
+ )
65
+ end
66
+
67
+ if !mu_name.nil?
68
+ @mu_name = mu_name
69
+ @config['mu_name'] = @mu_name
70
+ # describe
71
+ @mu_windows_name = @deploydata['mu_windows_name'] if @mu_windows_name.nil? and @deploydata
72
+ else
73
+ if kitten_cfg.has_key?("basis")
74
+ @mu_name = @deploy.getResourceName(@config['name'], need_unique_string: true)
75
+ else
76
+ @mu_name = @deploy.getResourceName(@config['name'])
77
+ end
78
+ @config['mu_name'] = @mu_name
79
+
80
+ @config['instance_secret'] = Password.random(50)
81
+ end
82
+ @config['ssh_user'] ||= "mu"
83
+ @groomer = MU::Groomer.new(self)
84
+
85
+ end
86
+
87
+ # Generate a server-class specific service account, used to grant
88
+ # permission to do various API things to a node.
89
+ # @param rolename [String]:
90
+ # @param project [String]:
91
+ # @param scopes [Array<String>]: https://developers.google.com/identity/protocols/googlescopes
92
+ def self.createServiceAccount(rolename, project: MU::Cloud::Google.defaultProject, scopes: ["https://www.googleapis.com/auth/compute.readonly", "https://www.googleapis.com/auth/logging.write", "https://www.googleapis.com/auth/cloud-platform"])
93
+ #https://www.googleapis.com/auth/devstorage.read_only ?
94
+ name = MU::Cloud::Google.nameStr(rolename)
95
+
96
+ saobj = MU::Cloud::Google.iam(:CreateServiceAccountRequest).new(
97
+ account_id: rolename.gsub(/[^a-z]/, ""), # XXX this mangling isn't required in the console, so why is it here?
98
+ service_account: MU::Cloud::Google.iam(:ServiceAccount).new(
99
+ display_name: rolename,
100
+ # do NOT specify project_id or name, we know that much
101
+ )
102
+ )
103
+ resp = MU::Cloud::Google.iam.create_service_account(
104
+ "projects/#{project}",
105
+ saobj
106
+ )
107
+ MU::Cloud::Google.compute(:ServiceAccount).new(
108
+ email: resp.email,
109
+ scopes: scopes
110
+ )
111
+ end
112
+
113
+ # Retrieve the cloud descriptor for this machine image, which can be
114
+ # a whole or partial URL. Will follow deprecation notices and retrieve
115
+ # the latest version, if applicable.
116
+ # @param image_id [String]: URL to a Google disk image
117
+ # @return [Google::Apis::ComputeBeta::Image]
118
+ def self.fetchImage(image_id)
119
+ img_proj = img_name = nil
120
+ begin
121
+ img_proj = image_id.gsub(/.*?\/?projects\/([^\/]+)\/.*/, '\1')
122
+ img_name = image_id.gsub(/.*?([^\/]+)$/, '\1')
123
+ img = MU::Cloud::Google.compute.get_image(img_proj, img_name)
124
+ if !img.deprecated.nil? and !img.deprecated.replacement.nil?
125
+ image_id = img.deprecated.replacement
126
+ end
127
+ end while !img.deprecated.nil? and img.deprecated.state == "DEPRECATED" and !img.deprecated.replacement.nil?
128
+ MU::Cloud::Google.compute.get_image(img_proj, img_name)
129
+ end
130
+
131
+ # Generator for disk configuration parameters for a Compute instance
132
+ # @param config [Hash]: The MU::Cloud::Server config hash for whom we're configuring disks
133
+ # @param create [Boolean]: Actually create extra (non-root) disks, or just the one declared as the root disk of the image
134
+ # @param disk_as_url [Boolean]: Whether to declare the disk type as a short string or full URL, which can vary depending on the calling resource
135
+ # @return [Array]: The Compute :AttachedDisk objects describing disks that've been created
136
+ def self.diskConfig(config, create = true, disk_as_url = true)
137
+ disks = []
138
+ puts config['image_id']
139
+ puts config['basis']
140
+
141
+ img = fetchImage(config['image_id'] || config['basis']['launch_config']['image_id'])
142
+
143
+ # XXX slurp settings from /dev/sda or w/e by convention?
144
+ disktype = "projects/#{config['project']}/zones/#{config['availability_zone']}/diskTypes/pd-standard"
145
+ disktype = "pd-standard" if !disk_as_url
146
+ # disk_type: projects/project/zones/#{config['availability_zone']}/diskTypes/pd-standard Other values include pd-ssd and local-ssd
147
+ imageobj = MU::Cloud::Google.compute(:AttachedDiskInitializeParams).new(
148
+ source_image: img.self_link,
149
+ disk_size_gb: 10, # this is binary? 2gb, that says
150
+ disk_type: disktype,
151
+ )
152
+ disks << MU::Cloud::Google.compute(:AttachedDisk).new(
153
+ auto_delete: true,
154
+ boot: true,
155
+ mode: "READ_WRITE",
156
+ type: "PERSISTENT",
157
+ initialize_params: imageobj
158
+ )
159
+ if config["storage"]
160
+ config["storage"].each { |vol|
161
+ devicename = vol['device'].gsub(/[^\w\-\.]/, "-").sub(/^[^\w]/, "")
162
+ disk_desc = {
163
+ :auto_delete => true,
164
+ :device_name => devicename, # XXX empty string is also legit
165
+ :mode => "READ_WRITE",
166
+ :type => "PERSISTENT" # SCRATCH is equivalent of ephemeral? cheap virtual memory disk? maybe ship a standard set
167
+ }
168
+
169
+ if vol['snapshot_id']
170
+ disk_desc[:source_snapshot] = vol['snapshot_id']
171
+ # XXX check existence in in validateConfig
172
+ elsif vol['somekindofidforaloosevolume']
173
+ disk_desc[:source] = vol['somekindofidforaloosevolume']
174
+ # XXX check existence in in validateConfig
175
+ end
176
+ # XXX I don't know how to do this in managed instance groups
177
+ #next
178
+ next if !create
179
+ diskname = MU::Cloud::Google.nameStr(config['mu_name']+"-"+devicename)
180
+ newdiskobj = MU::Cloud::Google.compute(:Disk).new(
181
+ size_gb: vol['size'],
182
+ description: MU.deploy_id,
183
+ zone: config['availability_zone'],
184
+ # type: "projects/#{config['project']}/zones/#{config['availability_zone']}/diskTypes/pd-ssd",
185
+ type: "projects/#{config['project']}/zones/#{config['availability_zone']}/diskTypes/pd-standard",
186
+ source_snapshot: vol['snapshot_id'],
187
+ # type: projects/project/zones/#{config['availability_zone']}/diskTypes/pd-standard Other values include pd-ssd and local-ssd
188
+ name: diskname
189
+ )
190
+ MU.log "Creating disk #{diskname}", details: newdiskobj
191
+
192
+ newdisk = MU::Cloud::Google.compute.insert_disk(
193
+ config['project'],
194
+ config['availability_zone'],
195
+ newdiskobj
196
+ )
197
+
198
+ disk_desc[:source] = newdisk.self_link
199
+
200
+ disks << MU::Cloud::Google.compute(:AttachedDisk).new(disk_desc)
201
+ }
202
+ end
203
+
204
+ disks
205
+ end
206
+
207
+ # Generator for disk configuration parameters for a Compute instance
208
+ # @param config [Hash]: The MU::Cloud::Server config hash for whom we're configuring network interfaces
209
+ # @param vpc [MU::Cloud::Google::VPC]: The VPC in which this interface should reside
210
+ # @return [Array]: Configuration objects for network interfaces, suitable for passing to the Compute API
211
+ def self.interfaceConfig(config, vpc)
212
+ subnet_cfg = config['vpc']
213
+ if config['vpc']['subnets'] and
214
+ !subnet_cfg['subnet_name'] and !subnet_cfg['subnet_id']
215
+ subnet_cfg = config['vpc']['subnets'].sample
216
+
217
+ end
218
+ subnet = vpc.getSubnet(name: subnet_cfg['subnet_name'], cloud_id: subnet_cfg['subnet_id'])
219
+ if subnet.nil?
220
+ raise MuError, "Couldn't find subnet details while configuring Server #{config['name']} (VPC: #{vpc.mu_name})"
221
+ end
222
+ base_iface_obj = {
223
+ :network => vpc.url,
224
+ :subnetwork => subnet.url
225
+ }
226
+ if config['associate_public_ip']
227
+ base_iface_obj[:access_configs] = [
228
+ MU::Cloud::Google.compute(:AccessConfig).new
229
+ ]
230
+ end
231
+ interfaces = [base_iface_obj]
232
+ # XXX add more if they asked for it (e.g. config['private_ip'])
233
+
234
+ interfaces
235
+ end
236
+
237
+ # Called automatically by {MU::Deploy#createResources}
238
+ def create
239
+
240
+ service_acct = MU::Cloud::Google::Server.createServiceAccount(
241
+ @mu_name.downcase,
242
+ project: @config['project']
243
+ )
244
+ MU::Cloud::Google.grantDeploySecretAccess(service_acct.email)
245
+
246
+ begin
247
+ disks = MU::Cloud::Google::Server.diskConfig(@config)
248
+ interfaces = MU::Cloud::Google::Server.interfaceConfig(@config, @vpc)
249
+
250
+ if @config['routes']
251
+ @config['routes'].each { |route|
252
+ @vpc.cloudobj.createRouteForInstance(route, self)
253
+ }
254
+ end
255
+
256
+ desc = {
257
+ :name => MU::Cloud::Google.nameStr(@mu_name),
258
+ :can_ip_forward => !@config['src_dst_check'],
259
+ :description => @deploy.deploy_id,
260
+ :service_accounts => [service_acct],
261
+ :network_interfaces => interfaces,
262
+ :machine_type => "zones/"+@config['availability_zone']+"/machineTypes/"+@config['size'],
263
+ :metadata => {
264
+ :items => [
265
+ {
266
+ :key => "ssh-keys",
267
+ :value => @config['ssh_user']+":"+@deploy.ssh_public_key
268
+ },
269
+ {
270
+ :key => "startup-script",
271
+ :value => @userdata
272
+ }
273
+ ]
274
+ },
275
+ :tags => MU::Cloud::Google.compute(:Tags).new(items: [MU::Cloud::Google.nameStr(@mu_name)])
276
+ }
277
+ desc[:disks] = disks if disks.size > 0
278
+
279
+ # Tags in GCP means something other than what we think of;
280
+ # labels are the thing you think you mean
281
+ desc[:labels] = {}
282
+ MU::MommaCat.listStandardTags.each_pair { |name, value|
283
+ if !value.nil?
284
+ desc[:labels][name.downcase] = value.downcase.gsub(/[^a-z0-9\-\_]/i, "_")
285
+ end
286
+ }
287
+ desc[:labels]["name"] = @mu_name.downcase
288
+
289
+
290
+ instanceobj = MU::Cloud::Google.compute(:Instance).new(desc)
291
+
292
+ MU.log "Creating instance #{@mu_name}"
293
+ begin
294
+ instance = MU::Cloud::Google.compute.insert_instance(
295
+ @config['project'],
296
+ @config['availability_zone'],
297
+ instanceobj
298
+ )
299
+ rescue ::Google::Apis::ClientError => e
300
+ MU.log e.message, MU::ERR
301
+ raise e
302
+ end
303
+ @cloud_id = instance.name # XXX or instance.target_link... pick a convention, would you?
304
+
305
+ if !@config['async_groom']
306
+ sleep 5
307
+ MU::MommaCat.lock(@cloud_id+"-create")
308
+ if !postBoot
309
+ MU.log "#{@config['name']} is already being groomed, skipping", MU::NOTICE
310
+ else
311
+ MU.log "Node creation complete for #{@config['name']}"
312
+ end
313
+ MU::MommaCat.unlock(@cloud_id+"-create")
314
+ end
315
+ done = false
316
+
317
+ @deploy.saveNodeSecret(@cloud_id, @config['instance_secret'], "instance_secret")
318
+ @config.delete("instance_secret")
319
+
320
+ if cloud_desc.nil? or cloud_desc.status != "RUNNING"
321
+ raiseert MuError, "#{@cloud_id} appears to have gone sideways mid-bootstrap #{cloud_desc.status if cloud_desc.nil?}"
322
+ end
323
+
324
+ notify
325
+
326
+ rescue Exception => e
327
+ if !cloud_desc.nil? and !done
328
+ MU.log "Aborted before I could finish setting up #{@config['name']}, cleaning it up. Stack trace will print once cleanup is complete.", MU::WARN if !@deploy.nocleanup
329
+ MU::MommaCat.unlockAll
330
+ if !@deploy.nocleanup
331
+ parent_thread_id = Thread.current.object_id
332
+ Thread.new {
333
+ MU.dupGlobals(parent_thread_id)
334
+ MU::Cloud::Google::Server.cleanup(noop: false, ignoremaster: false, skipsnapshots: true)
335
+ }
336
+ end
337
+ end
338
+ raise e
339
+ end
340
+
341
+ return @config
342
+ end
343
+
344
+ # Return a BoK-style config hash describing a NAT instance. We use this
345
+ # to approximate Amazon's NAT gateway functionality with a plain
346
+ # instance.
347
+ # @return [Hash]
348
+ def self.genericNAT
349
+ return {
350
+ "cloud" => "Google",
351
+ "size" => "g1-small",
352
+ "run_list" => [ "mu-utility::nat" ],
353
+ "platform" => "centos7",
354
+ "ssh_user" => "centos",
355
+ "associate_public_ip" => true,
356
+ "static_ip" => { "assign_ip" => true },
357
+ "routes" => [ {
358
+ "gateway" => "#INTERNET",
359
+ "priority" => 50,
360
+ "destination_network" => "0.0.0.0/0"
361
+ } ]
362
+ }
363
+ end
364
+
365
+ # Ask the Google API to stop this node
366
+ def stop
367
+ MU.log "Stopping #{@cloud_id}"
368
+ MU::Cloud::Google.compute.stop_instance(
369
+ @config['project'],
370
+ @config['availability_zone'],
371
+ @cloud_id
372
+ )
373
+ begin
374
+ sleep 5
375
+ end while cloud_desc.status != "TERMINATED" # means STOPPED
376
+ end
377
+
378
+ # Ask the Google API to start this node
379
+ def start
380
+ MU.log "Starting #{@cloud_id}"
381
+ MU::Cloud::Google.compute.start_instance(
382
+ @config['project'],
383
+ @config['availability_zone'],
384
+ @cloud_id
385
+ )
386
+ begin
387
+ sleep 5
388
+ end while cloud_desc.status != "RUNNING"
389
+ end
390
+
391
+ # Ask the Google API to restart this node
392
+ def reboot(hard = false)
393
+ return if @cloud_id.nil?
394
+
395
+ if hard
396
+ groupname = nil
397
+ if !@config['basis'].nil?
398
+ resp = MU::Cloud::AWS.autoscale(@config['region']).describe_auto_scaling_instances(
399
+ instance_ids: [@cloud_id]
400
+ )
401
+ groupname = resp.auto_scaling_instances.first.auto_scaling_group_name
402
+ MU.log "Pausing Autoscale processes in #{groupname}", MU::NOTICE
403
+ MU::Cloud::AWS.autoscale(@config['region']).suspend_processes(
404
+ auto_scaling_group_name: groupname
405
+ )
406
+ end
407
+ begin
408
+ MU.log "Stopping #{@mu_name} (#{@cloud_id})", MU::NOTICE
409
+ MU::Cloud::AWS.ec2(@config['region']).stop_instances(
410
+ instance_ids: [@cloud_id]
411
+ )
412
+ MU::Cloud::AWS.ec2(@config['region']).wait_until(:instance_stopped, instance_ids: [@cloud_id]) do |waiter|
413
+ waiter.before_attempt do |attempts|
414
+ MU.log "Waiting for #{@mu_name} to stop for hard reboot"
415
+ end
416
+ end
417
+ MU.log "Starting #{@mu_name} (#{@cloud_id})"
418
+ MU::Cloud::AWS.ec2(@config['region']).start_instances(
419
+ instance_ids: [@cloud_id]
420
+ )
421
+ ensure
422
+ if !groupname.nil?
423
+ MU.log "Resuming Autoscale processes in #{groupname}", MU::NOTICE
424
+ MU::Cloud::AWS.autoscale(@config['region']).resume_processes(
425
+ auto_scaling_group_name: groupname
426
+ )
427
+ end
428
+ end
429
+ else
430
+ MU.log "Rebooting #{@mu_name} (#{@cloud_id})"
431
+ MU::Cloud::AWS.ec2(@config['region']).reboot_instances(
432
+ instance_ids: [@cloud_id]
433
+ )
434
+ end
435
+ end
436
+
437
+ # Figure out what's needed to SSH into this server.
438
+ # @return [Array<String>]: nat_ssh_key, nat_ssh_user, nat_ssh_host, canonical_ip, ssh_user, ssh_key_name, alternate_names
439
+ def getSSHConfig
440
+ node, config, deploydata = describe(cloud_id: @cloud_id)
441
+ # XXX add some awesome alternate names from metadata and make sure they end
442
+ # up in MU::MommaCat's ssh config wangling
443
+ ssh_keydir = Etc.getpwuid(Process.uid).dir+"/.ssh"
444
+ return nil if @config.nil? or @deploy.nil?
445
+
446
+ nat_ssh_key = nat_ssh_user = nat_ssh_host = nil
447
+ if !@config["vpc"].nil? and !MU::Cloud::Google::VPC.haveRouteToInstance?(cloud_desc, region: @config['region'])
448
+
449
+ if !@nat.nil?
450
+ if @nat.cloud_desc.nil?
451
+ MU.log "NAT was missing cloud descriptor when called in #{@mu_name}'s getSSHConfig", MU::ERR
452
+ return nil
453
+ end
454
+ foo, bar, baz, nat_ssh_host, nat_ssh_user, nat_ssh_key = @nat.getSSHConfig
455
+ if nat_ssh_user.nil? and !nat_ssh_host.nil?
456
+ MU.log "#{@config["name"]} (#{MU.deploy_id}) is configured to use #{@config['vpc']} NAT #{nat_ssh_host}, but username isn't specified. Guessing root.", MU::ERR, details: caller
457
+ nat_ssh_user = "root"
458
+ end
459
+ end
460
+ end
461
+
462
+ if @config['ssh_user'].nil?
463
+ if windows?
464
+ @config['ssh_user'] = "Administrator"
465
+ else
466
+ @config['ssh_user'] = "root"
467
+ end
468
+ end
469
+
470
+ return [nat_ssh_key, nat_ssh_user, nat_ssh_host, canonicalIP, @config['ssh_user'], @deploy.ssh_key_name]
471
+
472
+ end
473
+
474
+ # Apply tags, bootstrap our configuration management, and other
475
+ # administravia for a new instance.
476
+ def postBoot(instance_id = nil)
477
+ if !instance_id.nil?
478
+ @cloud_id = instance_id
479
+ end
480
+
481
+ instance = cloud_desc
482
+
483
+ node, config, deploydata = describe(cloud_id: @cloud_id)
484
+ instance = cloud_desc
485
+ raise MuError, "Couldn't find instance of #{@mu_name} (#{@cloud_id})" if !instance
486
+ return false if !MU::MommaCat.lock(@cloud_id+"-orchestrate", true)
487
+ return false if !MU::MommaCat.lock(@cloud_id+"-groom", true)
488
+
489
+ # MU::MommaCat.createStandardTags(@cloud_id, region: @config['region'])
490
+ # MU::MommaCat.createTag(@cloud_id, "Name", node, region: @config['region'])
491
+ #
492
+ # if @config['optional_tags']
493
+ # MU::MommaCat.listOptionalTags.each { |key, value|
494
+ # MU::MommaCat.createTag(@cloud_id, key, value, region: @config['region'])
495
+ # }
496
+ # end
497
+ #
498
+ # if !@config['tags'].nil?
499
+ # @config['tags'].each { |tag|
500
+ # MU::MommaCat.createTag(@cloud_id, tag['key'], tag['value'], region: @config['region'])
501
+ # }
502
+ # end
503
+ # MU.log "Tagged #{node} (#{@cloud_id}) with MU-ID=#{MU.deploy_id}", MU::DEBUG
504
+ #
505
+ # Make double sure we don't lose a cached mu_windows_name value.
506
+ if windows? or !@config['active_directory'].nil?
507
+ if @mu_windows_name.nil?
508
+ @mu_windows_name = deploydata['mu_windows_name']
509
+ end
510
+ end
511
+
512
+ # punchAdminNAT
513
+ #
514
+ #
515
+ # # If we came up via AutoScale, the Alarm module won't have had our
516
+ # # instance ID to associate us with itself. So invoke that here.
517
+ # if !@config['basis'].nil? and @config["alarms"] and !@config["alarms"].empty?
518
+ # @config["alarms"].each { |alarm|
519
+ # alarm_obj = MU::MommaCat.findStray(
520
+ # "AWS",
521
+ # "alarms",
522
+ # region: @config["region"],
523
+ # deploy_id: @deploy.deploy_id,
524
+ # name: alarm['name']
525
+ # ).first
526
+ # alarm["dimensions"] = [{:name => "InstanceId", :value => @cloud_id}]
527
+ #
528
+ # if alarm["enable_notifications"]
529
+ # topic_arn = MU::Cloud::AWS::Notification.createTopic(alarm["notification_group"], region: @config["region"])
530
+ # MU::Cloud::AWS::Notification.subscribe(arn: topic_arn, protocol: alarm["notification_type"], endpoint: alarm["notification_endpoint"], region: @config["region"])
531
+ # alarm["alarm_actions"] = [topic_arn]
532
+ # alarm["ok_actions"] = [topic_arn]
533
+ # end
534
+ #
535
+ # alarm_name = alarm_obj ? alarm_obj.cloud_id : "#{node}-#{alarm['name']}".upcase
536
+ #
537
+ # MU::Cloud::AWS::Alarm.setAlarm(
538
+ # name: alarm_name,
539
+ # ok_actions: alarm["ok_actions"],
540
+ # alarm_actions: alarm["alarm_actions"],
541
+ # insufficient_data_actions: alarm["no_data_actions"],
542
+ # metric_name: alarm["metric_name"],
543
+ # namespace: alarm["namespace"],
544
+ # statistic: alarm["statistic"],
545
+ # dimensions: alarm["dimensions"],
546
+ # period: alarm["period"],
547
+ # unit: alarm["unit"],
548
+ # evaluation_periods: alarm["evaluation_periods"],
549
+ # threshold: alarm["threshold"],
550
+ # comparison_operator: alarm["comparison_operator"],
551
+ # region: @config["region"]
552
+ # )
553
+ # }
554
+ # end
555
+ #
556
+ # # We have issues sometimes where our dns_records are pointing at the wrong node name and IP address.
557
+ # # Make sure that doesn't happen. Happens with server pools only
558
+ # if @config['dns_records'] && !@config['dns_records'].empty?
559
+ # @config['dns_records'].each { |dnsrec|
560
+ # if dnsrec.has_key?("name")
561
+ # if dnsrec['name'].start_with?(MU.deploy_id.downcase) && !dnsrec['name'].start_with?(node.downcase)
562
+ # MU.log "DNS records for #{node} seem to be wrong, deleting from current config", MU::WARN, details: dnsrec
563
+ # dnsrec.delete('name')
564
+ # dnsrec.delete('target')
565
+ # end
566
+ # end
567
+ # }
568
+ # end
569
+
570
+ # Unless we're planning on associating a different IP later, set up a
571
+ # DNS entry for this thing and let it sync in the background. We'll
572
+ # come back to it later.
573
+ if @config['static_ip'].nil? && !@named
574
+ MU::MommaCat.nameKitten(self)
575
+ @named = true
576
+ end
577
+
578
+ nat_ssh_key, nat_ssh_user, nat_ssh_host, canonical_ip, ssh_user, ssh_key_name = getSSHConfig
579
+ if !nat_ssh_host and !MU::Cloud::Google::VPC.haveRouteToInstance?(cloud_desc, region: @config['region'])
580
+ # XXX check if canonical_ip is in the private ranges
581
+ # raise MuError, "#{node} has no NAT host configured, and I have no other route to it"
582
+ end
583
+
584
+ # # Set console termination protection. Autoscale nodes won't set this
585
+ # # by default.
586
+ # MU::Cloud::AWS.ec2(@config['region']).modify_instance_attribute(
587
+ # instance_id: @cloud_id,
588
+ # disable_api_termination: {:value => true}
589
+ # )
590
+
591
+ #MU.log "Let's deal with addressing", MU::WARN, details: cloud_desc
592
+ # If we asked for a public IP address, make sure we get one
593
+ # addrobj = MU::Cloud::Google.compute(:Address).new(
594
+ # name: @mu_name+"-public-ip",
595
+ # description: @deploy.deploy_id
596
+ # )
597
+ # addr_insert = MU::Cloud::Google.compute.insert_global_address(
598
+ # @config['project'],
599
+ ## @config['region'],
600
+ # addrobj
601
+ # )
602
+ # pp addr_insert
603
+ # raise "BOOP"
604
+ # has_elastic_ip = false
605
+ # if !instance.public_ip_address.nil?
606
+ # begin
607
+ # resp = MU::Cloud::AWS.ec2((@config['region'])).describe_addresses(public_ips: [instance.public_ip_address])
608
+ # if resp.addresses.size > 0 and resp.addresses.first.instance_id == @cloud_id
609
+ # has_elastic_ip = true
610
+ # end
611
+ # rescue Aws::EC2::Errors::InvalidAddressNotFound => e
612
+ # # XXX this is ok to ignore, it means the public IP isn't Elastic
613
+ # end
614
+ # end
615
+
616
+ # win_admin_password = nil
617
+ # ec2config_password = nil
618
+ # sshd_password = nil
619
+ # if windows?
620
+ # ssh_keydir = "#{Etc.getpwuid(Process.uid).dir}/.ssh"
621
+ # ssh_key_name = @deploy.ssh_key_name
622
+ #
623
+ # if @config['use_cloud_provider_windows_password']
624
+ # win_admin_password = getWindowsAdminPassword
625
+ # elsif @config['windows_auth_vault'] && !@config['windows_auth_vault'].empty?
626
+ # if @config["windows_auth_vault"].has_key?("password_field")
627
+ # win_admin_password = @groomer.getSecret(
628
+ # vault: @config['windows_auth_vault']['vault'],
629
+ # item: @config['windows_auth_vault']['item'],
630
+ # field: @config["windows_auth_vault"]["password_field"]
631
+ # )
632
+ # else
633
+ # win_admin_password = getWindowsAdminPassword
634
+ # end
635
+ #
636
+ # if @config["windows_auth_vault"].has_key?("ec2config_password_field")
637
+ # ec2config_password = @groomer.getSecret(
638
+ # vault: @config['windows_auth_vault']['vault'],
639
+ # item: @config['windows_auth_vault']['item'],
640
+ # field: @config["windows_auth_vault"]["ec2config_password_field"]
641
+ # )
642
+ # end
643
+ #
644
+ # if @config["windows_auth_vault"].has_key?("sshd_password_field")
645
+ # sshd_password = @groomer.getSecret(
646
+ # vault: @config['windows_auth_vault']['vault'],
647
+ # item: @config['windows_auth_vault']['item'],
648
+ # field: @config["windows_auth_vault"]["sshd_password_field"]
649
+ # )
650
+ # end
651
+ # end
652
+ #
653
+ # win_admin_password = MU.generateWindowsPassword if win_admin_password.nil?
654
+ # ec2config_password = MU.generateWindowsPassword if ec2config_password.nil?
655
+ # sshd_password = MU.generateWindowsPassword if sshd_password.nil?
656
+ #
657
+ # # We're creating the vault here so when we run
658
+ # # MU::Cloud::Server.initialSSHTasks and we need to set the Windows
659
+ # # Admin password we can grab it from said vault.
660
+ # creds = {
661
+ # "username" => @config['windows_admin_username'],
662
+ # "password" => win_admin_password,
663
+ # "ec2config_username" => "ec2config",
664
+ # "ec2config_password" => ec2config_password,
665
+ # "sshd_username" => "sshd_service",
666
+ # "sshd_password" => sshd_password
667
+ # }
668
+ # @groomer.saveSecret(vault: @mu_name, item: "windows_credentials", data: creds, permissions: "name:#{@mu_name}")
669
+ # end
670
+ #
671
+ #
672
+ #
673
+ # # If we've asked for additional subnets (and this @config is not a
674
+ # # member of a Server Pool, which has different semantics), create
675
+ # # extra interfaces to accomodate.
676
+ # if !@config['vpc']['subnets'].nil? and @config['basis'].nil?
677
+ # device_index = 1
678
+ # @vpc.subnets { |subnet|
679
+ # subnet_id = subnet.cloud_id
680
+ # MU.log "Adding network interface on subnet #{subnet_id} for #{node}"
681
+ # iface = MU::Cloud::AWS.ec2(@config['region']).create_network_interface(subnet_id: subnet_id).network_interface
682
+ # MU::MommaCat.createStandardTags(iface.network_interface_id, region: @config['region'])
683
+ # MU::MommaCat.createTag(iface.network_interface_id, "Name", node+"-ETH"+device_index.to_s, region: @config['region'])
684
+ #
685
+ # if @config['optional_tags']
686
+ # MU::MommaCat.listOptionalTags.each { |key, value|
687
+ # MU::MommaCat.createTag(iface.network_interface_id, key, value, region: @config['region'])
688
+ # }
689
+ # end
690
+ #
691
+ # if !@config['tags'].nil?
692
+ # @config['tags'].each { |tag|
693
+ # MU::MommaCat.createTag(iface.network_interface_id, tag['key'], tag['value'], region: @config['region'])
694
+ # }
695
+ # end
696
+ #
697
+ # MU::Cloud::AWS.ec2(@config['region']).attach_network_interface(
698
+ # network_interface_id: iface.network_interface_id,
699
+ # instance_id: @cloud_id,
700
+ # device_index: device_index
701
+ # )
702
+ # device_index = device_index + 1
703
+ # }
704
+ # end
705
+ # elsif !@config['static_ip'].nil?
706
+ # if !@config['static_ip']['ip'].nil?
707
+ # public_ip = MU::Cloud::AWS::Server.associateElasticIp(@cloud_id, classic: true, ip: @config['static_ip']['ip'])
708
+ # elsif !has_elastic_ip
709
+ # public_ip = MU::Cloud::AWS::Server.associateElasticIp(@cloud_id, classic: true)
710
+ # end
711
+ # end
712
+ #
713
+ #
714
+ # if !@config['image_then_destroy']
715
+ # notify
716
+ # end
717
+ #
718
+ # MU.log "EC2 instance #{node} has id #{@cloud_id}", MU::DEBUG
719
+ #
720
+ # @config["private_dns_name"] = instance.private_dns_name
721
+ # @config["public_dns_name"] = instance.public_dns_name
722
+ # @config["private_ip_address"] = instance.private_ip_address
723
+ # @config["public_ip_address"] = instance.public_ip_address
724
+ #
725
+ # ext_mappings = MU.structToHash(instance.block_device_mappings)
726
+ #
727
+ # # Root disk on standard CentOS AMI
728
+ # # tagVolumes(@cloud_id, "/dev/sda", "Name", "ROOT-"+MU.deploy_id+"-"+@config["name"].upcase)
729
+ # # Root disk on standard Ubuntu AMI
730
+ # # tagVolumes(@cloud_id, "/dev/sda1", "Name", "ROOT-"+MU.deploy_id+"-"+@config["name"].upcase)
731
+ #
732
+ # # Generic deploy ID tag
733
+ # # tagVolumes(@cloud_id)
734
+ #
735
+ # # Tag volumes with all our standard tags.
736
+ # # Maybe replace tagVolumes with this? There is one more place tagVolumes is called from
737
+ # volumes = MU::Cloud::AWS.ec2(@config['region']).describe_volumes(filters: [name: "attachment.instance-id", values: [@cloud_id]])
738
+ # volumes.each { |vol|
739
+ # vol.volumes.each { |volume|
740
+ # volume.attachments.each { |attachment|
741
+ # MU::MommaCat.listStandardTags.each_pair { |key, value|
742
+ # MU::MommaCat.createTag(attachment.volume_id, key, value, region: @config['region'])
743
+ #
744
+ # if attachment.device == "/dev/sda" or attachment.device == "/dev/sda1"
745
+ # MU::MommaCat.createTag(attachment.volume_id, "Name", "ROOT-#{MU.deploy_id}-#{@config["name"].upcase}", region: @config['region'])
746
+ # else
747
+ # MU::MommaCat.createTag(attachment.volume_id, "Name", "#{MU.deploy_id}-#{@config["name"].upcase}-#{attachment.device.upcase}", region: @config['region'])
748
+ # end
749
+ # }
750
+ #
751
+ # if @config['optional_tags']
752
+ # MU::MommaCat.listOptionalTags.each { |key, value|
753
+ # MU::MommaCat.createTag(attachment.volume_id, key, value, region: @config['region'])
754
+ # }
755
+ # end
756
+ #
757
+ # if @config['tags']
758
+ # @config['tags'].each { |tag|
759
+ # MU::MommaCat.createTag(attachment.volume_id, tag['key'], tag['value'], region: @config['region'])
760
+ # }
761
+ # end
762
+ # }
763
+ # }
764
+ # }
765
+ #
766
+ # canonical_name = instance.public_dns_name
767
+ # canonical_name = instance.private_dns_name if !canonical_name or nat_ssh_host != nil
768
+ # @config['canonical_name'] = canonical_name
769
+ #
770
+ # if !@config['add_private_ips'].nil?
771
+ # instance.network_interfaces.each { |int|
772
+ # if int.private_ip_address == instance.private_ip_address and int.private_ip_addresses.size < (@config['add_private_ips'] + 1)
773
+ # MU.log "Adding #{@config['add_private_ips']} extra private IP addresses to #{@cloud_id}"
774
+ # MU::Cloud::AWS.ec2(@config['region']).assign_private_ip_addresses(
775
+ # network_interface_id: int.network_interface_id,
776
+ # secondary_private_ip_address_count: @config['add_private_ips'],
777
+ # allow_reassignment: false
778
+ # )
779
+ # end
780
+ # }
781
+ # notify
782
+ # end
783
+ #
784
+ # windows? ? ssh_wait = 60 : ssh_wait = 30
785
+ # windows? ? max_retries = 50 : max_retries = 35
786
+ # begin
787
+ # session = getSSHSession(max_retries, ssh_wait)
788
+ # initialSSHTasks(session)
789
+ # rescue BootstrapTempFail
790
+ # sleep ssh_wait
791
+ # retry
792
+ # ensure
793
+ # session.close if !session.nil?
794
+ # end
795
+ #
796
+ # if @config["existing_deploys"] && !@config["existing_deploys"].empty?
797
+ # @config["existing_deploys"].each { |ext_deploy|
798
+ # if ext_deploy["cloud_id"]
799
+ # found = MU::MommaCat.findStray(
800
+ # @config['cloud'],
801
+ # ext_deploy["cloud_type"],
802
+ # cloud_id: ext_deploy["cloud_id"],
803
+ # region: @config['region'],
804
+ # dummy_ok: false
805
+ # ).first
806
+ #
807
+ # MU.log "Couldn't find existing resource #{ext_deploy["cloud_id"]}, #{ext_deploy["cloud_type"]}", MU::ERR if found.nil?
808
+ # @deploy.notify(ext_deploy["cloud_type"], found.config["name"], found.deploydata, mu_name: found.mu_name, triggering_node: @mu_name)
809
+ # elsif ext_deploy["mu_name"] && ext_deploy["deploy_id"]
810
+ # MU.log "#{ext_deploy["mu_name"]} / #{ext_deploy["deploy_id"]}"
811
+ # found = MU::MommaCat.findStray(
812
+ # @config['cloud'],
813
+ # ext_deploy["cloud_type"],
814
+ # deploy_id: ext_deploy["deploy_id"],
815
+ # mu_name: ext_deploy["mu_name"],
816
+ # region: @config['region'],
817
+ # dummy_ok: false
818
+ # ).first
819
+ #
820
+ # MU.log "Couldn't find existing resource #{ext_deploy["mu_name"]}/#{ext_deploy["deploy_id"]}, #{ext_deploy["cloud_type"]}", MU::ERR if found.nil?
821
+ # @deploy.notify(ext_deploy["cloud_type"], found.config["name"], found.deploydata, mu_name: ext_deploy["mu_name"], triggering_node: @mu_name)
822
+ # else
823
+ # MU.log "Trying to find existing deploy, but either the cloud_id is not valid or no mu_name and deploy_id where provided", MU::ERR
824
+ # end
825
+ # }
826
+ # end
827
+
828
+ # See if this node already exists in our config management. If it does,
829
+ # we're done.
830
+ if @groomer.haveBootstrapped?
831
+ MU.log "Node #{node} has already been bootstrapped, skipping groomer setup.", MU::NOTICE
832
+ @groomer.saveDeployData
833
+ MU::MommaCat.unlock(@cloud_id+"-orchestrate")
834
+ MU::MommaCat.unlock(@cloud_id+"-groom")
835
+ return true
836
+ end
837
+
838
+ @groomer.bootstrap
839
+
840
+ # Make sure we got our name written everywhere applicable
841
+ if !@named
842
+ MU::MommaCat.nameKitten(self)
843
+ @named = true
844
+ end
845
+
846
+ MU::MommaCat.unlock(@cloud_id+"-groom")
847
+ MU::MommaCat.unlock(@cloud_id+"-orchestrate")
848
+ return true
849
+ end #postBoot
850
+
851
+ # Locate an existing instance or instances and return an array containing matching AWS resource descriptors for those that match.
852
+ # @param cloud_id [String]: The cloud provider's identifier for this resource.
853
+ # @param region [String]: The cloud provider region
854
+ # @param tag_key [String]: A tag key to search.
855
+ # @param tag_value [String]: The value of the tag specified by tag_key to match when searching by tag.
856
+ # @param ip [String]: An IP address associated with the instance
857
+ # @param flags [Hash]: Optional flags
858
+ # @return [Array<Hash<String,OpenStruct>>]: The cloud provider's complete descriptions of matching instances
859
+ def self.find(cloud_id: nil, region: MU.curRegion, tag_key: "Name", tag_value: nil, ip: nil, flags: {})
860
+ # XXX put that 'ip' value into flags
861
+ instance = nil
862
+ flags["project"] ||= MU::Cloud::Google.defaultProject
863
+ if !region.nil? and MU::Cloud::Google.listRegions.include?(region)
864
+ regions = [region]
865
+ else
866
+ regions = MU::Cloud::Google.listRegions
867
+ end
868
+
869
+ found_instances = {}
870
+ search_semaphore = Mutex.new
871
+ search_threads = []
872
+
873
+ # If we got an instance id, go get it
874
+ if !cloud_id.nil? and !cloud_id.empty?
875
+ parent_thread_id = Thread.current.object_id
876
+ regions.each { |region|
877
+ search_threads << Thread.new {
878
+ Thread.abort_on_exception = false
879
+ MU.dupGlobals(parent_thread_id)
880
+ MU.log "Hunting for instance with cloud id '#{cloud_id}' in #{region}", MU::DEBUG
881
+ MU::Cloud::Google.listAZs(region).each { |az|
882
+ resp = nil
883
+ begin
884
+ resp = MU::Cloud::Google.compute.get_instance(
885
+ flags["project"],
886
+ az,
887
+ cloud_id
888
+ )
889
+ rescue ::Google::Apis::ClientError => e
890
+ raise e if !e.message.match(/^notFound: /)
891
+ end
892
+ found_instances[cloud_id] = resp if !resp.nil?
893
+ }
894
+ }
895
+ }
896
+ done_threads = []
897
+ begin
898
+ search_threads.each { |t|
899
+ joined = t.join(2)
900
+ done_threads << joined if !joined.nil?
901
+ }
902
+ end while found_instances.size < 1 and done_threads.size != search_threads.size
903
+ end
904
+
905
+ if found_instances.size > 0
906
+ return found_instances
907
+ end
908
+
909
+ # Ok, well, let's try looking it up by IP then
910
+ if instance.nil? and !ip.nil?
911
+ MU.log "Hunting for instance by IP '#{ip}'", MU::DEBUG
912
+ end
913
+
914
+ if !instance.nil?
915
+ return {instance.name => instance} if !instance.nil?
916
+ end
917
+
918
+ # Fine, let's try it by tag.
919
+ if !tag_value.nil?
920
+ MU.log "Searching for instance by tag '#{tag_key}=#{tag_value}'", MU::DEBUG
921
+ end
922
+
923
+ return found_instances
924
+ end
925
+
926
+ # Return a description of this resource appropriate for deployment
927
+ # metadata. Arguments reflect the return values of the MU::Cloud::[Resource].describe method
928
+ def notify
929
+ node, config, deploydata = describe(cloud_id: @cloud_id, update_cache: true)
930
+ deploydata = {} if deploydata.nil?
931
+
932
+ if cloud_desc.nil?
933
+ raise MuError, "Failed to load instance metadata for #{@config['mu_name']}/#{@cloud_id}"
934
+ end
935
+
936
+ interfaces = []
937
+ private_ips = []
938
+ public_ips = []
939
+
940
+ cloud_desc.network_interfaces.each { |iface|
941
+ private_ips << iface.network_ip
942
+ if iface.access_configs
943
+ iface.access_configs.each { |acfg|
944
+ public_ips << acfg.nat_ip if acfg.nat_ip
945
+ }
946
+ end
947
+ interfaces << {
948
+ "network_interface_id" => iface.name,
949
+ "subnet_id" => iface.subnetwork,
950
+ "vpc_id" => iface.network
951
+ }
952
+ }
953
+
954
+ deploydata = {
955
+ "nodename" => @mu_name,
956
+ "run_list" => @config['run_list'],
957
+ "image_created" => @config['image_created'],
958
+ # "iam_role" => @config['iam_role'],
959
+ "cloud_desc_id" => @cloud_id,
960
+ "private_ip_address" => private_ips.first,
961
+ "public_ip_address" => public_ips.first,
962
+ "private_ip_list" => private_ips,
963
+ # "key_name" => cloud_desc.key_name,
964
+ # "subnet_id" => cloud_desc.subnet_id,
965
+ # "cloud_desc_type" => cloud_desc.instance_type #,
966
+ # "network_interfaces" => interfaces,
967
+ # "config" => server
968
+ }
969
+
970
+ if !@mu_windows_name.nil?
971
+ deploydata["mu_windows_name"] = @mu_windows_name
972
+ end
973
+ if !@config['chef_data'].nil?
974
+ deploydata.merge!(@config['chef_data'])
975
+ end
976
+ deploydata["region"] = @config['region'] if !@config['region'].nil?
977
+ if !@named
978
+ MU::MommaCat.nameKitten(self)
979
+ @named = true
980
+ end
981
+
982
+ return deploydata
983
+ end
984
+
985
+ # Called automatically by {MU::Deploy#createResources}
986
+ def groom
987
+
988
+ MU::MommaCat.lock(@cloud_id+"-groom")
989
+
990
+ node, config, deploydata = describe(cloud_id: @cloud_id)
991
+
992
+ if node.nil? or node.empty?
993
+ raise MuError, "MU::Cloud::Google::Server.groom was called without a mu_name"
994
+ end
995
+
996
+ # Make double sure we don't lose a cached mu_windows_name value.
997
+ if windows? or !@config['active_directory'].nil?
998
+ if @mu_windows_name.nil?
999
+ @mu_windows_name = deploydata['mu_windows_name']
1000
+ end
1001
+ end
1002
+
1003
+ # punchAdminNAT
1004
+
1005
+ # MU::Cloud::AWS::Server.tagVolumes(@cloud_id)
1006
+
1007
+ # If we have a loadbalancer configured, attach us to it
1008
+ # if !@config['loadbalancers'].nil?
1009
+ # if @loadbalancers.nil?
1010
+ # raise MuError, "#{@mu_name} is configured to use LoadBalancers, but none have been loaded by dependencies()"
1011
+ # end
1012
+ # @loadbalancers.each { |lb|
1013
+ # lb.registerNode(@cloud_id)
1014
+ # }
1015
+ # end
1016
+
1017
+ # Let us into any databases we depend on.
1018
+ # This is probelmtic with autscaling - old ips are not removed, and access to the database can easily be given at the BoK level
1019
+ # if @dependencies.has_key?("database")
1020
+ # @dependencies['database'].values.each { |db|
1021
+ # db.allowHost(@deploydata["private_ip_address"]+"/32")
1022
+ # if @deploydata["public_ip_address"]
1023
+ # db.allowHost(@deploydata["public_ip_address"]+"/32")
1024
+ # end
1025
+ # }
1026
+ # end
1027
+
1028
+ @groomer.saveDeployData
1029
+
1030
+ begin
1031
+ @groomer.run(purpose: "Full Initial Run", max_retries: 15)
1032
+ rescue MU::Groomer::RunError
1033
+ MU.log "Proceeding after failed initial Groomer run, but #{node} may not behave as expected!", MU::WARN
1034
+ end
1035
+
1036
+ if !@config['create_image'].nil? and !@config['image_created']
1037
+ img_cfg = @config['create_image']
1038
+ # Scrub things that don't belong on an AMI
1039
+ session = getSSHSession
1040
+ sudo = purgecmd = ""
1041
+ sudo = "sudo" if @config['ssh_user'] != "root"
1042
+ if windows?
1043
+ purgecmd = "rm -rf /cygdrive/c/mu_installed_chef"
1044
+ else
1045
+ purgecmd = "rm -rf /opt/mu_installed_chef"
1046
+ end
1047
+ if img_cfg['image_then_destroy']
1048
+ if windows?
1049
+ purgecmd = "rm -rf /cygdrive/c/chef/ /home/#{@config['windows_admin_username']}/.ssh/authorized_keys /home/Administrator/.ssh/authorized_keys /cygdrive/c/mu-installer-ran-updates /cygdrive/c/mu_installed_chef"
1050
+ # session.exec!("powershell -Command \"& {(Get-WmiObject -Class Win32_Product -Filter \"Name='UniversalForwarder'\").Uninstall()}\"")
1051
+ else
1052
+ purgecmd = "#{sudo} rm -rf /root/.ssh/authorized_keys /etc/ssh/ssh_host_*key* /etc/chef /etc/opscode/* /.mu-installer-ran-updates /var/chef /opt/mu_installed_chef /opt/chef ; #{sudo} sed -i 's/^HOSTNAME=.*//' /etc/sysconfig/network"
1053
+ end
1054
+ end
1055
+ session.exec!(purgecmd)
1056
+ session.close
1057
+ stop
1058
+ image_id = MU::Cloud::Google::Server.createImage(
1059
+ name: MU::Cloud::Google.nameStr(@mu_name),
1060
+ instance_id: @cloud_id,
1061
+ region: @config['region'],
1062
+ storage: @config['storage'],
1063
+ family: ("mu-"+@config['platform']+"-"+MU.environment).downcase,
1064
+ project: @config['project'],
1065
+ exclude_storage: img_cfg['image_exclude_storage'],
1066
+ make_public: img_cfg['public'],
1067
+ tags: @config['tags'],
1068
+ zone: @config['availability_zone']
1069
+ )
1070
+ @deploy.notify("images", @config['name'], {"image_id" => image_id})
1071
+ @config['image_created'] = true
1072
+ if img_cfg['image_then_destroy']
1073
+ MU.log "Image #{image_id} ready, removing source node #{node}"
1074
+ MU::Cloud::Google.compute.delete_instance(
1075
+ @config['project'],
1076
+ @config['availability_zone'],
1077
+ @cloud_id
1078
+ )
1079
+ destroy
1080
+ else
1081
+ start
1082
+ end
1083
+ end
1084
+
1085
+ MU::MommaCat.unlock(@cloud_id+"-groom")
1086
+ end
1087
+
1088
+ # Create an image out of a running server. Requires either the name of a MU resource in the current deployment, or the cloud provider id of a running instance.
1089
+ # @param name [String]: The MU resource name of the server to use as the basis for this image.
1090
+ # @param instance_id [String]: The cloud provider resource identifier of the server to use as the basis for this image.
1091
+ # @param storage [Hash]: The storage devices to include in this image.
1092
+ # @param exclude_storage [Boolean]: Do not include the storage device profile of the running instance when creating this image.
1093
+ # @param region [String]: The cloud provider region
1094
+ # @param tags [Array<String>]: Extra/override tags to apply to the image.
1095
+ # @return [String]: The cloud provider identifier of the new machine image.
1096
+ def self.createImage(name: nil, instance_id: nil, storage: {}, exclude_storage: false, project: MU::Cloud::Google.defaultProject, make_public: false, tags: [], region: nil, family: "mu", zone: MU::Cloud::Google.listAZs.sample)
1097
+ instance = MU::Cloud::Server.find(cloud_id: instance_id, region: region)
1098
+ if instance.nil?
1099
+ raise MuError, "Failed to find instance '#{instance_id}' in createImage"
1100
+ end
1101
+
1102
+ labels = {}
1103
+ MU::MommaCat.listStandardTags.each_pair { |key, value|
1104
+ if !value.nil?
1105
+ labels[key.downcase] = value.downcase.gsub(/[^a-z0-9\-\_]/i, "_")
1106
+ end
1107
+ }
1108
+
1109
+ bootdisk = nil
1110
+ threads = []
1111
+ parent_thread_id = Thread.current.object_id
1112
+ instance[instance_id].disks.each { |disk|
1113
+ threads << Thread.new {
1114
+ Thread.abort_on_exception = false
1115
+ MU.dupGlobals(parent_thread_id)
1116
+ if disk.boot
1117
+ bootdisk = disk.source
1118
+ else
1119
+ snapobj = MU::Cloud::Google.compute(:Snapshot).new(
1120
+ name: name+"-"+disk.device_name,
1121
+ description: "Mu image created from #{name} (#{disk.device_name})"
1122
+ )
1123
+ diskname = disk.source.gsub(/.*?\//, "")
1124
+ MU.log "Creating snapshot of #{diskname} in #{zone}", MU::NOTICE, details: snapobj
1125
+ snap = MU::Cloud::Google.compute.create_disk_snapshot(
1126
+ project,
1127
+ zone,
1128
+ diskname,
1129
+ snapobj
1130
+ )
1131
+ MU::Cloud::Google.compute.set_snapshot_labels(
1132
+ project,
1133
+ snap.name,
1134
+ MU::Cloud::Google.compute(:GlobalSetLabelsRequest).new(
1135
+ label_fingerprint: snap.label_fingerprint,
1136
+ labels: labels.merge({
1137
+ "mu-device-name" => disk.device_name,
1138
+ "mu-parent-image" => name,
1139
+ "mu-orig-zone" => zone
1140
+ })
1141
+ )
1142
+ )
1143
+ end
1144
+ }
1145
+ }
1146
+ threads.each do |t|
1147
+ t.join
1148
+ end
1149
+
1150
+ labels["name"] = instance_id.downcase
1151
+ imageobj = MU::Cloud::Google.compute(:Image).new(
1152
+ name: name,
1153
+ source_disk: bootdisk,
1154
+ description: "Mu image created from #{name}",
1155
+ labels: labels,
1156
+ family: family
1157
+ )
1158
+
1159
+ newimage = MU::Cloud::Google.compute.insert_image(
1160
+ project,
1161
+ imageobj
1162
+ )
1163
+ newimage.name
1164
+ end
1165
+
1166
+ def cloud_desc
1167
+ max_retries = 5
1168
+ retries = 0
1169
+ if !@cloud_id.nil?
1170
+ begin
1171
+ return MU::Cloud::Google.compute.get_instance(
1172
+ @config['project'],
1173
+ @config['availability_zone'],
1174
+ @cloud_id
1175
+ )
1176
+ rescue ::Google::Apis::ClientError => e
1177
+ if e.message.match(/^notFound: /)
1178
+ return nil
1179
+ else
1180
+ raise e
1181
+ end
1182
+ end
1183
+ end
1184
+ nil
1185
+ end
1186
+
1187
+ def cloud_desc
1188
+ MU::Cloud::Google::Server.find(cloud_id: @cloud_id).values.first
1189
+ end
1190
+
1191
+ # Return the IP address that we, the Mu server, should be using to access
1192
+ # this host via the network. Note that this does not factor in SSH
1193
+ # bastion hosts that may be in the path, see getSSHConfig if that's what
1194
+ # you need.
1195
+ def canonicalIP
1196
+ mu_name, config, deploydata = describe(cloud_id: @cloud_id)
1197
+
1198
+ if !cloud_desc
1199
+ raise MuError, "Couldn't retrieve cloud descriptor for server #{self}"
1200
+ end
1201
+
1202
+ private_ips = []
1203
+ public_ips = []
1204
+
1205
+ cloud_desc.network_interfaces.each { |iface|
1206
+ private_ips << iface.network_ip
1207
+ if iface.access_configs
1208
+ iface.access_configs.each { |acfg|
1209
+ public_ips << acfg.nat_ip if acfg.nat_ip
1210
+ }
1211
+ end
1212
+ }
1213
+
1214
+ # Our deploydata gets corrupted often with server pools, this will cause us to use the wrong IP to identify a node
1215
+ # which will cause us to create certificates, DNS records and other artifacts with incorrect information which will cause our deploy to fail.
1216
+ # The cloud_id is always correct so lets use 'cloud_desc' to get the correct IPs
1217
+ if MU::Cloud::Google::VPC.haveRouteToInstance?(cloud_desc) or public_ips.size == 0
1218
+ @config['canonical_ip'] = private_ips.first
1219
+ return private_ips.first
1220
+ else
1221
+ @config['canonical_ip'] = public_ips.first
1222
+ return public_ips.first
1223
+ end
1224
+ end
1225
+
1226
+ # Retrieves the Cloud provider's randomly generated Windows password
1227
+ # Will only work on stock Amazon Windows AMIs or custom AMIs that where created with Administrator Password set to random in EC2Config
1228
+ # return [String]: A password string.
1229
+ def getWindowsAdminPassword
1230
+ end
1231
+
1232
+ # Add a volume to this instance
1233
+ # @param dev [String]: Device name to use when attaching to instance
1234
+ # @param size [String]: Size (in gb) of the new volume
1235
+ # @param type [String]: Cloud storage type of the volume, if applicable
1236
+ def addVolume(dev, size, type: "pd-standard")
1237
+ devname = dev.gsub(/.*?\/([^\/]+)$/, '\1')
1238
+ resname = MU::Cloud::Google.nameStr(@mu_name+"-"+devname)
1239
+ MU.log "Creating disk #{resname}"
1240
+
1241
+ description = @deploy ? @deploy.deploy_id : @mu_name+"-"+devname
1242
+
1243
+ newdiskobj = MU::Cloud::Google.compute(:Disk).new(
1244
+ size_gb: size,
1245
+ description: description,
1246
+ zone: @config['availability_zone'],
1247
+ # type: "projects/#{config['project']}/zones/#{config['availability_zone']}/diskTypes/pd-ssd",
1248
+ type: "projects/#{@config['project']}/zones/#{@config['availability_zone']}/diskTypes/pd-standard",
1249
+ # Other values include pd-ssd and local-ssd
1250
+ name: resname
1251
+ )
1252
+
1253
+ begin
1254
+ newdisk = MU::Cloud::Google.compute.insert_disk(
1255
+ @config['project'],
1256
+ @config['availability_zone'],
1257
+ newdiskobj
1258
+ )
1259
+ rescue ::Google::Apis::ClientError => e
1260
+ if e.message.match(/^alreadyExists: /)
1261
+ MU.log "Disk #{resname} already exists, ignoring request to create", MU::WARN
1262
+ return
1263
+ else
1264
+ raise e
1265
+ end
1266
+ end
1267
+
1268
+ attachobj = MU::Cloud::Google.compute(:AttachedDisk).new(
1269
+ auto_delete: true,
1270
+ device_name: devname,
1271
+ source: newdisk.self_link,
1272
+ type: "PERSISTENT"
1273
+ )
1274
+ attachment = MU::Cloud::Google.compute.attach_disk(
1275
+ @config['project'],
1276
+ @config['availability_zone'],
1277
+ @cloud_id,
1278
+ attachobj
1279
+ )
1280
+
1281
+ end
1282
+
1283
+ # Determine whether the node in question exists at the Cloud provider
1284
+ # layer.
1285
+ # @return [Boolean]
1286
+ def active?
1287
+ true
1288
+ end
1289
+
1290
+ # Remove all instances associated with the currently loaded deployment. Also cleans up associated volumes, droppings in the MU master's /etc/hosts and ~/.ssh, and in whatever Groomer was used.
1291
+ # @param noop [Boolean]: If true, will only print what would be done
1292
+ # @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
1293
+ # @param region [String]: The cloud provider region
1294
+ # @return [void]
1295
+ def self.cleanup(noop: false, ignoremaster: false, region: $MU_CFG['google']['region'], skipsnapshots: false, onlycloud: false, flags: {})
1296
+ flags["project"] ||= MU::Cloud::Google.defaultProject
1297
+ # XXX make damn sure MU.deploy_id is set
1298
+
1299
+ MU::Cloud::Google.listAZs(region).each { |az|
1300
+ disks = []
1301
+ resp = MU::Cloud::Google.compute.list_instances(
1302
+ flags["project"],
1303
+ az,
1304
+ filter: "description eq #{MU.deploy_id}"
1305
+ )
1306
+ if !resp.items.nil? and resp.items.size > 0
1307
+ resp.items.each { |instance|
1308
+ saname = instance.tags.items.first.gsub(/[^a-z]/, "") # XXX this nonsense again
1309
+ MU.log "Terminating instance #{instance.name}"
1310
+ if !instance.disks.nil? and instance.disks.size > 0
1311
+ instance.disks.each { |disk|
1312
+ disks << disk if !disk.auto_delete
1313
+ }
1314
+ end
1315
+ deletia = MU::Cloud::Google.compute.delete_instance(
1316
+ flags["project"],
1317
+ az,
1318
+ instance.name
1319
+ ) if !noop
1320
+ MU.log "Removing service account #{saname}"
1321
+ begin
1322
+ MU::Cloud::Google.iam.delete_project_service_account(
1323
+ "projects/#{flags["project"]}/serviceAccounts/#{saname}@#{flags["project"]}.iam.gserviceaccount.com"
1324
+ ) if !noop
1325
+ rescue ::Google::Apis::ClientError => e
1326
+ raise e if !e.message.match(/^notFound: /)
1327
+ end
1328
+ # XXX wait-loop on pending?
1329
+ # pp deletia
1330
+ }
1331
+ end
1332
+
1333
+ if disks.size > 0
1334
+ # XXX make sure we don't miss anything that got created with dumb flags
1335
+ end
1336
+ # XXX honor snapshotting
1337
+ MU::Cloud::Google.compute.delete(
1338
+ "disk",
1339
+ flags["project"],
1340
+ az,
1341
+ noop
1342
+ ) if !noop
1343
+ }
1344
+ end
1345
+
1346
+ # Cloud-specific configuration properties.
1347
+ # @param config [MU::Config]: The calling MU::Config object
1348
+ # @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource
1349
+ def self.schema(config)
1350
+ toplevel_required = []
1351
+ schema = {
1352
+ "image_id" => {
1353
+ "type" => "string",
1354
+ "description" => "The Google Cloud Platform Image on which to base this instance. Will use the default appropriate for the platform, if not specified."
1355
+ },
1356
+ "routes" => {
1357
+ "type" => "array",
1358
+ "items" => MU::Config::VPC.routeschema
1359
+ }
1360
+ }
1361
+ [toplevel_required, schema]
1362
+ end
1363
+
1364
+ # Confirm that the given instance size is valid for the given region.
1365
+ # If someone accidentally specified an equivalent size from some other cloud provider, return something that makes sense. If nothing makes sense, return nil.
1366
+ # @param size [String]: Instance type to check
1367
+ # @param region [String]: Region to check against
1368
+ # @return [String,nil]
1369
+ def self.validateInstanceType(size, region)
1370
+ types = (MU::Cloud::Google.listInstanceTypes(region))[region]
1371
+ if types and (size.nil? or !types.has_key?(size))
1372
+ # See if it's a type we can approximate from one of the other clouds
1373
+ atypes = (MU::Cloud::AWS.listInstanceTypes)[MU::Cloud::AWS.myRegion]
1374
+ foundmatch = false
1375
+ if atypes and atypes.size > 0 and atypes.has_key?(size)
1376
+ vcpu = atypes[size]["vcpu"]
1377
+ mem = atypes[size]["memory"]
1378
+ ecu = atypes[size]["ecu"]
1379
+ types.keys.sort.reverse.each { |type|
1380
+ features = types[type]
1381
+ next if ecu == "Variable" and ecu != features["ecu"]
1382
+ next if features["vcpu"] != vcpu
1383
+ if (features["memory"] - mem.to_f).abs < 0.10*mem
1384
+ foundmatch = true
1385
+ MU.log "You specified an Amazon instance type '#{size}.' Approximating with Google Compute type '#{type}.'", MU::WARN
1386
+ size = type
1387
+ break
1388
+ end
1389
+ }
1390
+ end
1391
+ if !foundmatch
1392
+ MU.log "Invalid size '#{size}' for Google Compute instance in #{region}. Supported types:", MU::ERR, details: types.keys.sort.join(", ")
1393
+ return nil
1394
+ end
1395
+ end
1396
+ size
1397
+ end
1398
+
1399
+
1400
+ # Cloud-specific pre-processing of {MU::Config::BasketofKittens::servers}, bare and unvalidated.
1401
+ # @param server [Hash]: The resource to process and validate
1402
+ # @param configurator [MU::Config]: The overall deployment configurator of which this resource is a member
1403
+ # @return [Boolean]: True if validation succeeded, False otherwise
1404
+ def self.validateConfig(server, configurator)
1405
+ ok = true
1406
+
1407
+ server['size'] = validateInstanceType(server["size"], server["region"])
1408
+ ok = false if server['size'].nil?
1409
+
1410
+ # If we're not targeting an availability zone, pick one randomly
1411
+ if !server['availability_zone']
1412
+ server['availability_zone'] = MU::Cloud::Google.listAZs(server['region']).sample
1413
+ end
1414
+
1415
+ subnets = nil
1416
+ if !server['vpc']
1417
+ vpcs = MU::Cloud::Google::VPC.find
1418
+ if vpcs["default"]
1419
+ server["vpc"] ||= {}
1420
+ server["vpc"]["vpc_id"] = vpcs["default"].self_link
1421
+ subnets = vpcs["default"].subnetworks
1422
+ MU.log "No VPC specified for Server #{server['name']}, using default VPC for project #{server['project']}", MU::NOTICE
1423
+ else
1424
+ ok = false
1425
+ MU.log "You must specify a target VPC when creating a Server", MU::ERR
1426
+ end
1427
+ end
1428
+
1429
+ if !server['vpc']['subnet_id'] and server['vpc']['subnet_name'].nil?
1430
+ if !subnets
1431
+ if server["vpc"]["vpc_id"]
1432
+ vpcs = MU::Cloud::Google::VPC.find(cloud_id: server["vpc"]["vpc_id"])
1433
+ subnets = vpcs["default"].subnetworks.sample
1434
+ end
1435
+ end
1436
+
1437
+ if subnets
1438
+ server['vpc']['subnet_id'] = subnets.delete_if { |subnet|
1439
+ !subnet.match(/regions\/#{Regexp.quote(server['region'])}\/subnetworks/)
1440
+ }.sample
1441
+ end
1442
+ if server['vpc']['subnet_id'].nil?
1443
+ ok = false
1444
+ MU.log "Failed to identify a subnet in my region (#{server['region']})", MU::ERR, details: server["vpc"]["vpc_id"]
1445
+ end
1446
+ end
1447
+
1448
+ if server['image_id'].nil?
1449
+ if MU::Config.google_images.has_key?(server['platform'])
1450
+ server['image_id'] = configurator.getTail("server"+server['name']+"Image", value: MU::Config.google_images[server['platform']], prettyname: "server"+server['name']+"Image", cloudtype: "Google::::Apis::ComputeBeta::Image")
1451
+ else
1452
+ MU.log "No image specified for #{server['name']} and no default available for platform #{server['platform']}", MU::ERR, details: server
1453
+ ok = false
1454
+ end
1455
+ end
1456
+
1457
+ real_image = nil
1458
+ begin
1459
+ real_image = MU::Cloud::Google::Server.fetchImage(server['image_id'].to_s)
1460
+ rescue ::Google::Apis::ClientError => e
1461
+ MU.log e.inspect, MU::WARN
1462
+ end
1463
+
1464
+ if real_image.nil?
1465
+ MU.log "Image #{server['image_id']} for server #{server['name']} does not appear to exist", MU::ERR
1466
+ ok = false
1467
+ else
1468
+ server['image_id'] = real_image.self_link
1469
+ server['image_id'].match(/projects\/([^\/]+)\/.*?\/([^\/]+)$/)
1470
+ img_project = Regexp.last_match[1]
1471
+ img_name = Regexp.last_match[2]
1472
+ begin
1473
+ snaps = MU::Cloud::Google.compute.list_snapshots(
1474
+ img_project,
1475
+ filter: "name eq #{img_name}-.*"
1476
+ )
1477
+ server['storage'] ||= []
1478
+ used_devs = server['storage'].map { |disk| disk['device'].gsub(/.*?\//, "") }
1479
+ snaps.items.each { |snap|
1480
+ next if !snap.labels.is_a?(Hash) or !snap.labels["mu-device-name"] or snap.labels["mu-parent-image"] != img_name
1481
+ devname = snap.labels["mu-device-name"]
1482
+
1483
+ if used_devs.include?(devname)
1484
+ MU.log "Device name #{devname} already declared in server #{server['name']} (snapshot #{snap.name} wants the name)", MU::ERR
1485
+ ok = false
1486
+ end
1487
+ server['storage'] << {
1488
+ "snapshot_id" => snap.self_link,
1489
+ "size" => snap.disk_size_gb,
1490
+ "delete_on_termination" => true,
1491
+ "device" => devname
1492
+ }
1493
+ used_devs << devname
1494
+ }
1495
+ rescue ::Google::Apis::ClientError => e
1496
+ # it's ok, sometimes we don't have permission to list snapshots
1497
+ # in other peoples' projects
1498
+ raise e if !e.message.match(/^forbidden: /)
1499
+ end
1500
+ end
1501
+
1502
+ ok
1503
+ end
1504
+
1505
+ private
1506
+
1507
+ end #class
1508
+ end #class
1509
+ end
1510
+ end #module