cloud-mu 1.9.0.pre.beta

Sign up to get free protection for your applications and to get access to all the features.
Files changed (618) hide show
  1. checksums.yaml +7 -0
  2. data/Berksfile +56 -0
  3. data/Berksfile.lock +250 -0
  4. data/Jenkinsfile +184 -0
  5. data/LICENSE.md +37 -0
  6. data/README.md +26 -0
  7. data/bin/mu-aws-setup +376 -0
  8. data/bin/mu-cleanup +68 -0
  9. data/bin/mu-configure +1133 -0
  10. data/bin/mu-deploy +166 -0
  11. data/bin/mu-firewall-allow-clients +30 -0
  12. data/bin/mu-gcp-setup +200 -0
  13. data/bin/mu-gen-docs +34 -0
  14. data/bin/mu-gen-env +42 -0
  15. data/bin/mu-load-config.rb +158 -0
  16. data/bin/mu-node-manage +683 -0
  17. data/bin/mu-self-update +228 -0
  18. data/bin/mu-ssh +23 -0
  19. data/bin/mu-tunnel-nagios +144 -0
  20. data/bin/mu-upload-chef-artifacts +757 -0
  21. data/bin/mu-user-manage +275 -0
  22. data/cookbooks/awscli/LICENSE +37 -0
  23. data/cookbooks/awscli/README.md +58 -0
  24. data/cookbooks/awscli/attributes/default.rb +1 -0
  25. data/cookbooks/awscli/libraries/instance_metadata.rb +21 -0
  26. data/cookbooks/awscli/metadata.rb +20 -0
  27. data/cookbooks/awscli/recipes/default.rb +56 -0
  28. data/cookbooks/awscli/templates/default/config.erb +18 -0
  29. data/cookbooks/mu-activedirectory/CHANGELOG.md +13 -0
  30. data/cookbooks/mu-activedirectory/LICENSE +37 -0
  31. data/cookbooks/mu-activedirectory/README.md +6 -0
  32. data/cookbooks/mu-activedirectory/attributes/default.rb +98 -0
  33. data/cookbooks/mu-activedirectory/files/default/password-auth +32 -0
  34. data/cookbooks/mu-activedirectory/files/default/sshd_pol.pp +0 -0
  35. data/cookbooks/mu-activedirectory/files/default/sshd_pol.te +32 -0
  36. data/cookbooks/mu-activedirectory/files/default/syslogd_oddjobd.pp +0 -0
  37. data/cookbooks/mu-activedirectory/files/default/syslogd_oddjobd.te +10 -0
  38. data/cookbooks/mu-activedirectory/files/default/system-auth +34 -0
  39. data/cookbooks/mu-activedirectory/files/default/winbindpol.pp +0 -0
  40. data/cookbooks/mu-activedirectory/files/default/winbindpol.te +37 -0
  41. data/cookbooks/mu-activedirectory/libraries/config.rb +106 -0
  42. data/cookbooks/mu-activedirectory/libraries/helper.rb +86 -0
  43. data/cookbooks/mu-activedirectory/metadata.rb +17 -0
  44. data/cookbooks/mu-activedirectory/providers/domain.rb +152 -0
  45. data/cookbooks/mu-activedirectory/providers/domain_controller.rb +89 -0
  46. data/cookbooks/mu-activedirectory/providers/domain_node.rb +275 -0
  47. data/cookbooks/mu-activedirectory/recipes/default.rb +8 -0
  48. data/cookbooks/mu-activedirectory/recipes/domain-controller.rb +44 -0
  49. data/cookbooks/mu-activedirectory/recipes/domain-node.rb +50 -0
  50. data/cookbooks/mu-activedirectory/recipes/domain.rb +43 -0
  51. data/cookbooks/mu-activedirectory/recipes/sssd.rb +185 -0
  52. data/cookbooks/mu-activedirectory/resources/domain.rb +25 -0
  53. data/cookbooks/mu-activedirectory/resources/domain_controller.rb +25 -0
  54. data/cookbooks/mu-activedirectory/resources/domain_node.rb +20 -0
  55. data/cookbooks/mu-activedirectory/templates/default/dhclient-eth0.conf.erb +4 -0
  56. data/cookbooks/mu-activedirectory/templates/default/interface +0 -0
  57. data/cookbooks/mu-activedirectory/templates/default/krb5.conf.erb +23 -0
  58. data/cookbooks/mu-activedirectory/templates/default/ntp.conf.erb +56 -0
  59. data/cookbooks/mu-activedirectory/templates/default/smb.conf.erb +33 -0
  60. data/cookbooks/mu-activedirectory/templates/default/sssd.conf.erb +60 -0
  61. data/cookbooks/mu-activedirectory/templates/windows/Backup.xml.erb +20 -0
  62. data/cookbooks/mu-activedirectory/templates/windows/bkupInfo.xml.erb +1 -0
  63. data/cookbooks/mu-activedirectory/templates/windows/gpreprt.xml.erb +198 -0
  64. data/cookbooks/mu-activedirectory/templates/windows/gptmpl.inf.erb +12 -0
  65. data/cookbooks/mu-activedirectory/templates/windows/manifest.xml.erb +1 -0
  66. data/cookbooks/mu-firewall/CHANGELOG.md +11 -0
  67. data/cookbooks/mu-firewall/LICENSE +37 -0
  68. data/cookbooks/mu-firewall/README.md +5 -0
  69. data/cookbooks/mu-firewall/attributes/default.rb +3 -0
  70. data/cookbooks/mu-firewall/metadata.rb +16 -0
  71. data/cookbooks/mu-firewall/recipes/default.rb +10 -0
  72. data/cookbooks/mu-glusterfs/CHANGELOG.md +13 -0
  73. data/cookbooks/mu-glusterfs/LICENSE +37 -0
  74. data/cookbooks/mu-glusterfs/README.md +5 -0
  75. data/cookbooks/mu-glusterfs/attributes/default.rb +34 -0
  76. data/cookbooks/mu-glusterfs/metadata.rb +17 -0
  77. data/cookbooks/mu-glusterfs/recipes/client.rb +62 -0
  78. data/cookbooks/mu-glusterfs/recipes/default.rb +16 -0
  79. data/cookbooks/mu-glusterfs/recipes/samba.rb +57 -0
  80. data/cookbooks/mu-glusterfs/recipes/server.rb +200 -0
  81. data/cookbooks/mu-glusterfs/templates/default/mu-gluster-client.erb +71 -0
  82. data/cookbooks/mu-glusterfs/templates/default/smb.conf.erb +14 -0
  83. data/cookbooks/mu-jenkins/CHANGELOG.md +13 -0
  84. data/cookbooks/mu-jenkins/LICENSE +37 -0
  85. data/cookbooks/mu-jenkins/README.md +105 -0
  86. data/cookbooks/mu-jenkins/attributes/default.rb +42 -0
  87. data/cookbooks/mu-jenkins/files/default/cleanup_deploy_config.xml +73 -0
  88. data/cookbooks/mu-jenkins/files/default/deploy_config.xml +44 -0
  89. data/cookbooks/mu-jenkins/metadata.rb +21 -0
  90. data/cookbooks/mu-jenkins/recipes/default.rb +195 -0
  91. data/cookbooks/mu-jenkins/recipes/node-ssh-config.rb +54 -0
  92. data/cookbooks/mu-jenkins/recipes/public_key.rb +24 -0
  93. data/cookbooks/mu-jenkins/templates/default/example_job.config.xml.erb +24 -0
  94. data/cookbooks/mu-jenkins/templates/default/org.jvnet.hudson.plugins.SSHBuildWrapper.xml.erb +14 -0
  95. data/cookbooks/mu-jenkins/templates/default/ssh_config.erb +6 -0
  96. data/cookbooks/mu-master/CHANGELOG.md +13 -0
  97. data/cookbooks/mu-master/LICENSE +37 -0
  98. data/cookbooks/mu-master/README.md +6 -0
  99. data/cookbooks/mu-master/attributes/default.rb +95 -0
  100. data/cookbooks/mu-master/files/default/0-mu-log-server.conf +19 -0
  101. data/cookbooks/mu-master/files/default/addRSA.ldif +8 -0
  102. data/cookbooks/mu-master/files/default/check_mem.pl +197 -0
  103. data/cookbooks/mu-master/files/default/cloudamatic.png +0 -0
  104. data/cookbooks/mu-master/files/default/dirsrv_admin.pp +0 -0
  105. data/cookbooks/mu-master/files/default/dirsrv_admin.te +13 -0
  106. data/cookbooks/mu-master/files/default/nagios_selinux.pp +0 -0
  107. data/cookbooks/mu-master/files/default/nagios_selinux.te +51 -0
  108. data/cookbooks/mu-master/files/default/nagios_selinux_7.pp +0 -0
  109. data/cookbooks/mu-master/files/default/nagios_selinux_7.te +17 -0
  110. data/cookbooks/mu-master/files/default/pam_sshd +18 -0
  111. data/cookbooks/mu-master/files/default/ssl_enable.ldif +18 -0
  112. data/cookbooks/mu-master/files/default/syslogd_oddjobd.pp +0 -0
  113. data/cookbooks/mu-master/files/default/syslogd_oddjobd.te +10 -0
  114. data/cookbooks/mu-master/files/default/vimrc +19 -0
  115. data/cookbooks/mu-master/libraries/mu.rb +29 -0
  116. data/cookbooks/mu-master/metadata.rb +30 -0
  117. data/cookbooks/mu-master/providers/user.rb +41 -0
  118. data/cookbooks/mu-master/recipes/389ds.rb +164 -0
  119. data/cookbooks/mu-master/recipes/basepackages.rb +58 -0
  120. data/cookbooks/mu-master/recipes/caching_nameserver.rb +37 -0
  121. data/cookbooks/mu-master/recipes/default.rb +451 -0
  122. data/cookbooks/mu-master/recipes/eks-kubectl.rb +41 -0
  123. data/cookbooks/mu-master/recipes/firewall-holes.rb +70 -0
  124. data/cookbooks/mu-master/recipes/init.rb +542 -0
  125. data/cookbooks/mu-master/recipes/ssl-certs.rb +109 -0
  126. data/cookbooks/mu-master/recipes/sssd.rb +89 -0
  127. data/cookbooks/mu-master/recipes/update_nagios_only.rb +242 -0
  128. data/cookbooks/mu-master/recipes/vault.rb +111 -0
  129. data/cookbooks/mu-master/resources/user.rb +19 -0
  130. data/cookbooks/mu-master/templates/default/389-directory-setup.inf.erb +28 -0
  131. data/cookbooks/mu-master/templates/default/chef-server.rb.erb +18 -0
  132. data/cookbooks/mu-master/templates/default/dhclient-eth0.conf.erb +9 -0
  133. data/cookbooks/mu-master/templates/default/mu-momma-cat.erb +149 -0
  134. data/cookbooks/mu-master/templates/default/mu.rc.erb +9 -0
  135. data/cookbooks/mu-master/templates/default/openssl.cnf.erb +354 -0
  136. data/cookbooks/mu-master/templates/default/sssd.conf.erb +44 -0
  137. data/cookbooks/mu-master/templates/default/web_app.conf.erb +90 -0
  138. data/cookbooks/mu-mongo/CHANGELOG.md +13 -0
  139. data/cookbooks/mu-mongo/LICENSE +37 -0
  140. data/cookbooks/mu-mongo/README.md +5 -0
  141. data/cookbooks/mu-mongo/attributes/default.rb +22 -0
  142. data/cookbooks/mu-mongo/files/default/keyfile +16 -0
  143. data/cookbooks/mu-mongo/files/default/remove_nodes.js +5 -0
  144. data/cookbooks/mu-mongo/metadata.rb +17 -0
  145. data/cookbooks/mu-mongo/recipes/default.rb +149 -0
  146. data/cookbooks/mu-mongo/recipes/yum-update-rule.rb +18 -0
  147. data/cookbooks/mu-mongo/templates/default/mongo_create_openfema_db.js.erb +2 -0
  148. data/cookbooks/mu-mongo/templates/default/mongo_init.js.erb +1 -0
  149. data/cookbooks/mu-mongo/templates/default/mongo_logrotate.erb +14 -0
  150. data/cookbooks/mu-mongo/templates/default/mongo_replset_addnodes.js.erb +6 -0
  151. data/cookbooks/mu-mongo/templates/default/replset_init.js.erb +2 -0
  152. data/cookbooks/mu-openvpn/CHANGELOG.md +13 -0
  153. data/cookbooks/mu-openvpn/LICENSE +37 -0
  154. data/cookbooks/mu-openvpn/README.md +6 -0
  155. data/cookbooks/mu-openvpn/attributes/default.rb +119 -0
  156. data/cookbooks/mu-openvpn/metadata.rb +18 -0
  157. data/cookbooks/mu-openvpn/recipes/default.rb +108 -0
  158. data/cookbooks/mu-openvpn/templates/default/users.json.erb +42 -0
  159. data/cookbooks/mu-php54/CHANGELOG.md +12 -0
  160. data/cookbooks/mu-php54/LICENSE +37 -0
  161. data/cookbooks/mu-php54/README.md +0 -0
  162. data/cookbooks/mu-php54/files/centos/php.ini +1802 -0
  163. data/cookbooks/mu-php54/files/ubuntu/php.ini +1870 -0
  164. data/cookbooks/mu-php54/metadata.rb +21 -0
  165. data/cookbooks/mu-php54/recipes/default.rb +97 -0
  166. data/cookbooks/mu-splunk/CHANGELOG.md +37 -0
  167. data/cookbooks/mu-splunk/LICENSE +37 -0
  168. data/cookbooks/mu-splunk/README.md +451 -0
  169. data/cookbooks/mu-splunk/attributes/default.rb +95 -0
  170. data/cookbooks/mu-splunk/attributes/upgrade.rb +49 -0
  171. data/cookbooks/mu-splunk/definitions/splunk_installer.rb +103 -0
  172. data/cookbooks/mu-splunk/files/default/splunk-nocheck +10 -0
  173. data/cookbooks/mu-splunk/libraries/helpers.rb +72 -0
  174. data/cookbooks/mu-splunk/libraries/splunk_app_provider.rb +156 -0
  175. data/cookbooks/mu-splunk/libraries/splunk_app_resource.rb +43 -0
  176. data/cookbooks/mu-splunk/metadata.json +30 -0
  177. data/cookbooks/mu-splunk/metadata.rb +17 -0
  178. data/cookbooks/mu-splunk/recipes/client.rb +143 -0
  179. data/cookbooks/mu-splunk/recipes/default.rb +31 -0
  180. data/cookbooks/mu-splunk/recipes/disabled.rb +41 -0
  181. data/cookbooks/mu-splunk/recipes/install_forwarder.rb +23 -0
  182. data/cookbooks/mu-splunk/recipes/install_server.rb +23 -0
  183. data/cookbooks/mu-splunk/recipes/server.rb +53 -0
  184. data/cookbooks/mu-splunk/recipes/service.rb +95 -0
  185. data/cookbooks/mu-splunk/recipes/setup_auth.rb +49 -0
  186. data/cookbooks/mu-splunk/recipes/setup_ssl.rb +63 -0
  187. data/cookbooks/mu-splunk/recipes/upgrade.rb +94 -0
  188. data/cookbooks/mu-splunk/recipes/user.rb +34 -0
  189. data/cookbooks/mu-splunk/templates/default/base_logs_unix_inputs.conf.erb +26 -0
  190. data/cookbooks/mu-splunk/templates/default/inputs.conf.erb +13 -0
  191. data/cookbooks/mu-splunk/templates/default/outputs.conf.erb +9 -0
  192. data/cookbooks/mu-splunk/templates/default/splunk-init.erb +74 -0
  193. data/cookbooks/mu-splunk/templates/default/system-web.conf.erb +7 -0
  194. data/cookbooks/mu-tools/CHANGELOG.md +12 -0
  195. data/cookbooks/mu-tools/LICENSE +37 -0
  196. data/cookbooks/mu-tools/README.md +188 -0
  197. data/cookbooks/mu-tools/attributes/default.rb +142 -0
  198. data/cookbooks/mu-tools/attributes/ebs_rolling_snapshots.rb +3 -0
  199. data/cookbooks/mu-tools/files/amazon/etc/freshclam.conf +235 -0
  200. data/cookbooks/mu-tools/files/centos/CentOS-Base.repo +52 -0
  201. data/cookbooks/mu-tools/files/centos/etc/bashrc +93 -0
  202. data/cookbooks/mu-tools/files/centos/etc/freshclam.conf +235 -0
  203. data/cookbooks/mu-tools/files/centos/etc/login.defs +72 -0
  204. data/cookbooks/mu-tools/files/centos/etc/profile +77 -0
  205. data/cookbooks/mu-tools/files/centos/etc/security/limits.conf +57 -0
  206. data/cookbooks/mu-tools/files/centos/etc/sysconfig/init +19 -0
  207. data/cookbooks/mu-tools/files/centos/etc/sysctl.conf +82 -0
  208. data/cookbooks/mu-tools/files/centos-6/README_MU +0 -0
  209. data/cookbooks/mu-tools/files/centos-6/etc/audit/stig.rules +173 -0
  210. data/cookbooks/mu-tools/files/centos-6/etc/bashrc +90 -0
  211. data/cookbooks/mu-tools/files/centos-6/etc/login.defs +70 -0
  212. data/cookbooks/mu-tools/files/centos-6/etc/pam.d/su +12 -0
  213. data/cookbooks/mu-tools/files/centos-6/etc/profile +83 -0
  214. data/cookbooks/mu-tools/files/centos-6/etc/securetty +12 -0
  215. data/cookbooks/mu-tools/files/centos-6/etc/sysconfig/init +30 -0
  216. data/cookbooks/mu-tools/files/centos-6/etc/sysctl.conf +40 -0
  217. data/cookbooks/mu-tools/files/default/Mu_CA.pem +34 -0
  218. data/cookbooks/mu-tools/files/default/PSWindowsUpdate.zip +0 -0
  219. data/cookbooks/mu-tools/files/default/ebs_snapshots.py +123 -0
  220. data/cookbooks/mu-tools/files/default/etc/BANNER +0 -0
  221. data/cookbooks/mu-tools/files/default/etc/BANNER-FEDERAL +19 -0
  222. data/cookbooks/mu-tools/files/default/gpo_no_uac.zip +0 -0
  223. data/cookbooks/mu-tools/files/default/mypol.pp +0 -0
  224. data/cookbooks/mu-tools/files/default/mypol.te +37 -0
  225. data/cookbooks/mu-tools/files/default/nrpe_c7.pp +0 -0
  226. data/cookbooks/mu-tools/files/default/nrpe_c7.te +31 -0
  227. data/cookbooks/mu-tools/files/default/nrpe_check_disk.pp +0 -0
  228. data/cookbooks/mu-tools/files/default/nrpe_check_disk.te +11 -0
  229. data/cookbooks/mu-tools/files/default/nrpe_disk.pp +0 -0
  230. data/cookbooks/mu-tools/files/default/nrpe_disk.te +10 -0
  231. data/cookbooks/mu-tools/files/default/nrpe_file.pp +0 -0
  232. data/cookbooks/mu-tools/files/default/nrpe_file.te +31 -0
  233. data/cookbooks/mu-tools/files/default/ntrights +0 -0
  234. data/cookbooks/mu-tools/files/default/serverclass.conf +18 -0
  235. data/cookbooks/mu-tools/files/default/splunk-apps/base_logs_unix/local/app.conf +1 -0
  236. data/cookbooks/mu-tools/files/default/splunk-apps/base_logs_unix/local/inputs.conf +13 -0
  237. data/cookbooks/mu-tools/files/default/splunk-apps/base_logs_windows/local/app.conf +1 -0
  238. data/cookbooks/mu-tools/files/default/splunk-apps/base_logs_windows/local/inputs.conf +8 -0
  239. data/cookbooks/mu-tools/files/default/sshd_pol.pp +0 -0
  240. data/cookbooks/mu-tools/files/default/sshd_pol.te +32 -0
  241. data/cookbooks/mu-tools/files/redhat/etc/bashrc +93 -0
  242. data/cookbooks/mu-tools/files/redhat/etc/freshclam.conf +235 -0
  243. data/cookbooks/mu-tools/files/redhat/etc/login.defs +72 -0
  244. data/cookbooks/mu-tools/files/redhat/etc/profile +77 -0
  245. data/cookbooks/mu-tools/files/redhat/etc/security/limits.conf +57 -0
  246. data/cookbooks/mu-tools/files/redhat/etc/sysconfig/init +19 -0
  247. data/cookbooks/mu-tools/files/redhat/etc/sysctl.conf +82 -0
  248. data/cookbooks/mu-tools/files/redhat-6/README_MU +0 -0
  249. data/cookbooks/mu-tools/files/redhat-6/etc/audit/stig.rules +173 -0
  250. data/cookbooks/mu-tools/files/redhat-6/etc/bashrc +90 -0
  251. data/cookbooks/mu-tools/files/redhat-6/etc/login.defs +70 -0
  252. data/cookbooks/mu-tools/files/redhat-6/etc/pam.d/su +12 -0
  253. data/cookbooks/mu-tools/files/redhat-6/etc/profile +83 -0
  254. data/cookbooks/mu-tools/files/redhat-6/etc/securetty +12 -0
  255. data/cookbooks/mu-tools/files/redhat-6/etc/sysconfig/init +30 -0
  256. data/cookbooks/mu-tools/files/redhat-6/etc/sysctl.conf +40 -0
  257. data/cookbooks/mu-tools/files/redhat-7.1/etc/freshclam.conf +235 -0
  258. data/cookbooks/mu-tools/files/ubuntu-12.04/etc/bash.bashrc +64 -0
  259. data/cookbooks/mu-tools/files/ubuntu-12.04/etc/common-session +30 -0
  260. data/cookbooks/mu-tools/files/ubuntu-12.04/etc/login.defs +338 -0
  261. data/cookbooks/mu-tools/files/ubuntu-12.04/etc/profile +30 -0
  262. data/cookbooks/mu-tools/files/ubuntu-12.04/etc/security/limits.conf +56 -0
  263. data/cookbooks/mu-tools/files/ubuntu-12.04/etc/sysctl.conf +60 -0
  264. data/cookbooks/mu-tools/libraries/helper.rb +292 -0
  265. data/cookbooks/mu-tools/metadata.rb +28 -0
  266. data/cookbooks/mu-tools/recipes/add_admin_ssh_keys.rb +35 -0
  267. data/cookbooks/mu-tools/recipes/apply_security.rb +440 -0
  268. data/cookbooks/mu-tools/recipes/aws_api.rb +23 -0
  269. data/cookbooks/mu-tools/recipes/base_repositories.rb +31 -0
  270. data/cookbooks/mu-tools/recipes/cisbenchmark.rb +59 -0
  271. data/cookbooks/mu-tools/recipes/clamav.rb +53 -0
  272. data/cookbooks/mu-tools/recipes/cloudinit.rb +58 -0
  273. data/cookbooks/mu-tools/recipes/configure_oracle_tools.rb +81 -0
  274. data/cookbooks/mu-tools/recipes/disable-requiretty.rb +22 -0
  275. data/cookbooks/mu-tools/recipes/ebs_rolling_snapshots.rb +75 -0
  276. data/cookbooks/mu-tools/recipes/efs.rb +70 -0
  277. data/cookbooks/mu-tools/recipes/eks.rb +160 -0
  278. data/cookbooks/mu-tools/recipes/gcloud.rb +98 -0
  279. data/cookbooks/mu-tools/recipes/google_api.rb +25 -0
  280. data/cookbooks/mu-tools/recipes/maldet.rb +67 -0
  281. data/cookbooks/mu-tools/recipes/nagios.rb +19 -0
  282. data/cookbooks/mu-tools/recipes/newclient.rb +23 -0
  283. data/cookbooks/mu-tools/recipes/nrpe.rb +115 -0
  284. data/cookbooks/mu-tools/recipes/python_pip.rb +35 -0
  285. data/cookbooks/mu-tools/recipes/retrieve_application.rb +51 -0
  286. data/cookbooks/mu-tools/recipes/rsyslog.rb +65 -0
  287. data/cookbooks/mu-tools/recipes/set_local_fw.rb +57 -0
  288. data/cookbooks/mu-tools/recipes/set_mu_hostname.rb +81 -0
  289. data/cookbooks/mu-tools/recipes/split_var_partitions.rb +86 -0
  290. data/cookbooks/mu-tools/recipes/splunk-client.rb +69 -0
  291. data/cookbooks/mu-tools/recipes/splunk-server.rb +104 -0
  292. data/cookbooks/mu-tools/recipes/store_inspec_attr.rb +8 -0
  293. data/cookbooks/mu-tools/recipes/updates.rb +96 -0
  294. data/cookbooks/mu-tools/recipes/windows-client.rb +202 -0
  295. data/cookbooks/mu-tools/resources/aws_windows.rb +33 -0
  296. data/cookbooks/mu-tools/resources/disk.rb +88 -0
  297. data/cookbooks/mu-tools/resources/mommacat_request.rb +11 -0
  298. data/cookbooks/mu-tools/resources/scheduled_tasks.rb +29 -0
  299. data/cookbooks/mu-tools/resources/sshd_service.rb +45 -0
  300. data/cookbooks/mu-tools/resources/windows_users.rb +242 -0
  301. data/cookbooks/mu-tools/templates/amazon/sshd_config.erb +168 -0
  302. data/cookbooks/mu-tools/templates/centos-6/sshd_config.erb +212 -0
  303. data/cookbooks/mu-tools/templates/centos-7/sshd_config.erb +215 -0
  304. data/cookbooks/mu-tools/templates/default/0-mu-log-client.conf.erb +13 -0
  305. data/cookbooks/mu-tools/templates/default/conf.maldet.erb +137 -0
  306. data/cookbooks/mu-tools/templates/default/etc_hosts.erb +30 -0
  307. data/cookbooks/mu-tools/templates/default/etc_pamd_password-auth.erb +14 -0
  308. data/cookbooks/mu-tools/templates/default/etc_pamd_system-auth.erb +14 -0
  309. data/cookbooks/mu-tools/templates/default/etc_sysconfig_network.erb +12 -0
  310. data/cookbooks/mu-tools/templates/default/kubeconfig.erb +29 -0
  311. data/cookbooks/mu-tools/templates/default/kubelet.service.erb +35 -0
  312. data/cookbooks/mu-tools/templates/default/maldet_scanall.sh.erb +15 -0
  313. data/cookbooks/mu-tools/templates/default/nrpe.cfg.erb +233 -0
  314. data/cookbooks/mu-tools/templates/redhat-6/sshd_config.erb +213 -0
  315. data/cookbooks/mu-tools/templates/redhat-7/sshd_config.erb +215 -0
  316. data/cookbooks/mu-tools/templates/ubuntu-12.04/sshd_config.erb +146 -0
  317. data/cookbooks/mu-tools/templates/ubuntu-14.04/sshd_config.erb +145 -0
  318. data/cookbooks/mu-tools/templates/windows/Backup.xml.erb +20 -0
  319. data/cookbooks/mu-tools/templates/windows/bkupInfo.xml.erb +1 -0
  320. data/cookbooks/mu-tools/templates/windows/gpreprt.xml.erb +214 -0
  321. data/cookbooks/mu-tools/templates/windows/gptmpl.inf.erb +12 -0
  322. data/cookbooks/mu-tools/templates/windows/manifest.xml.erb +1 -0
  323. data/cookbooks/mu-tools/templates/windows/set_ad_dns_scheduled_task.ps1.erb +6 -0
  324. data/cookbooks/mu-tools/templates/windows/sshd_config.erb +136 -0
  325. data/cookbooks/mu-utility/CHANGELOG.md +12 -0
  326. data/cookbooks/mu-utility/LICENSE +37 -0
  327. data/cookbooks/mu-utility/README.md +6 -0
  328. data/cookbooks/mu-utility/attributes/default.rb +1 -0
  329. data/cookbooks/mu-utility/libraries/matchers.rb +21 -0
  330. data/cookbooks/mu-utility/metadata.rb +16 -0
  331. data/cookbooks/mu-utility/recipes/apt.rb +23 -0
  332. data/cookbooks/mu-utility/recipes/cleanup_image_helper.rb +118 -0
  333. data/cookbooks/mu-utility/recipes/iptables.rb +26 -0
  334. data/cookbooks/mu-utility/recipes/luks.rb +18 -0
  335. data/cookbooks/mu-utility/recipes/nat.rb +104 -0
  336. data/cookbooks/mu-utility/recipes/php.rb +33 -0
  337. data/cookbooks/mu-utility/recipes/rdp_gateway.rb +83 -0
  338. data/cookbooks/mu-utility/recipes/remi.rb +44 -0
  339. data/cookbooks/mu-utility/recipes/vim.rb +26 -0
  340. data/cookbooks/mu-utility/recipes/windows_basics.rb +37 -0
  341. data/cookbooks/mu-utility/recipes/zip.rb +26 -0
  342. data/cookbooks/mu-utility/templates/default/BundleConfig.xml.erb +34 -0
  343. data/cookbooks/mu-utility/templates/default/config.xml.erb +60 -0
  344. data/cookbooks/nagios/Berksfile +8 -0
  345. data/cookbooks/nagios/CHANGELOG.md +589 -0
  346. data/cookbooks/nagios/CONTRIBUTING.md +11 -0
  347. data/cookbooks/nagios/LICENSE +37 -0
  348. data/cookbooks/nagios/README.md +328 -0
  349. data/cookbooks/nagios/TESTING.md +2 -0
  350. data/cookbooks/nagios/attributes/config.rb +171 -0
  351. data/cookbooks/nagios/attributes/default.rb +228 -0
  352. data/cookbooks/nagios/chefignore +102 -0
  353. data/cookbooks/nagios/definitions/command.rb +33 -0
  354. data/cookbooks/nagios/definitions/contact.rb +33 -0
  355. data/cookbooks/nagios/definitions/contactgroup.rb +33 -0
  356. data/cookbooks/nagios/definitions/host.rb +33 -0
  357. data/cookbooks/nagios/definitions/hostdependency.rb +33 -0
  358. data/cookbooks/nagios/definitions/hostescalation.rb +34 -0
  359. data/cookbooks/nagios/definitions/hostgroup.rb +33 -0
  360. data/cookbooks/nagios/definitions/nagios_conf.rb +38 -0
  361. data/cookbooks/nagios/definitions/resource.rb +33 -0
  362. data/cookbooks/nagios/definitions/service.rb +33 -0
  363. data/cookbooks/nagios/definitions/servicedependency.rb +33 -0
  364. data/cookbooks/nagios/definitions/serviceescalation.rb +34 -0
  365. data/cookbooks/nagios/definitions/servicegroup.rb +33 -0
  366. data/cookbooks/nagios/definitions/timeperiod.rb +33 -0
  367. data/cookbooks/nagios/libraries/base.rb +314 -0
  368. data/cookbooks/nagios/libraries/command.rb +91 -0
  369. data/cookbooks/nagios/libraries/contact.rb +230 -0
  370. data/cookbooks/nagios/libraries/contactgroup.rb +112 -0
  371. data/cookbooks/nagios/libraries/custom_option.rb +36 -0
  372. data/cookbooks/nagios/libraries/data_bag_helper.rb +23 -0
  373. data/cookbooks/nagios/libraries/default.rb +90 -0
  374. data/cookbooks/nagios/libraries/host.rb +412 -0
  375. data/cookbooks/nagios/libraries/hostdependency.rb +181 -0
  376. data/cookbooks/nagios/libraries/hostescalation.rb +173 -0
  377. data/cookbooks/nagios/libraries/hostgroup.rb +119 -0
  378. data/cookbooks/nagios/libraries/nagios.rb +282 -0
  379. data/cookbooks/nagios/libraries/resource.rb +59 -0
  380. data/cookbooks/nagios/libraries/service.rb +455 -0
  381. data/cookbooks/nagios/libraries/servicedependency.rb +215 -0
  382. data/cookbooks/nagios/libraries/serviceescalation.rb +195 -0
  383. data/cookbooks/nagios/libraries/servicegroup.rb +144 -0
  384. data/cookbooks/nagios/libraries/timeperiod.rb +160 -0
  385. data/cookbooks/nagios/libraries/users_helper.rb +54 -0
  386. data/cookbooks/nagios/metadata.rb +25 -0
  387. data/cookbooks/nagios/recipes/_load_databag_config.rb +153 -0
  388. data/cookbooks/nagios/recipes/_load_default_config.rb +241 -0
  389. data/cookbooks/nagios/recipes/apache.rb +48 -0
  390. data/cookbooks/nagios/recipes/default.rb +204 -0
  391. data/cookbooks/nagios/recipes/nginx.rb +82 -0
  392. data/cookbooks/nagios/recipes/pagerduty.rb +143 -0
  393. data/cookbooks/nagios/recipes/server_package.rb +40 -0
  394. data/cookbooks/nagios/recipes/server_source.rb +164 -0
  395. data/cookbooks/nagios/templates/default/apache2.conf.erb +96 -0
  396. data/cookbooks/nagios/templates/default/cgi.cfg.erb +266 -0
  397. data/cookbooks/nagios/templates/default/commands.cfg.erb +13 -0
  398. data/cookbooks/nagios/templates/default/contacts.cfg.erb +37 -0
  399. data/cookbooks/nagios/templates/default/hostgroups.cfg.erb +25 -0
  400. data/cookbooks/nagios/templates/default/hosts.cfg.erb +15 -0
  401. data/cookbooks/nagios/templates/default/htpasswd.users.erb +6 -0
  402. data/cookbooks/nagios/templates/default/nagios.cfg.erb +22 -0
  403. data/cookbooks/nagios/templates/default/nginx.conf.erb +62 -0
  404. data/cookbooks/nagios/templates/default/pagerduty.cgi.erb +185 -0
  405. data/cookbooks/nagios/templates/default/resource.cfg.erb +27 -0
  406. data/cookbooks/nagios/templates/default/servicedependencies.cfg.erb +15 -0
  407. data/cookbooks/nagios/templates/default/servicegroups.cfg.erb +14 -0
  408. data/cookbooks/nagios/templates/default/services.cfg.erb +14 -0
  409. data/cookbooks/nagios/templates/default/templates.cfg.erb +31 -0
  410. data/cookbooks/nagios/templates/default/timeperiods.cfg.erb +13 -0
  411. data/cookbooks/s3fs/CHANGELOG.md +13 -0
  412. data/cookbooks/s3fs/LICENSE +37 -0
  413. data/cookbooks/s3fs/README.md +6 -0
  414. data/cookbooks/s3fs/attributes/default.rb +15 -0
  415. data/cookbooks/s3fs/files/default/fuse-2.9.3.zip +0 -0
  416. data/cookbooks/s3fs/metadata.rb +16 -0
  417. data/cookbooks/s3fs/recipes/default.rb +91 -0
  418. data/data_bags/demo/app.json +7 -0
  419. data/data_bags/nagios_services/chef.json +6 -0
  420. data/data_bags/nagios_services/linux_diskspace.json +5 -0
  421. data/data_bags/nagios_services/momma_cat.json +6 -0
  422. data/data_bags/nagios_services/mu-master-memory.json +5 -0
  423. data/data_bags/nagios_services/nagios_ui.json +6 -0
  424. data/data_bags/nagios_services/node_ssh.json +6 -0
  425. data/data_bags/nagios_services/ssh.json +6 -0
  426. data/demo/lambda_test.yaml +29 -0
  427. data/environments/DEV.json +8 -0
  428. data/environments/PROD.json +8 -0
  429. data/environments/dev.json +8 -0
  430. data/environments/development.json +8 -0
  431. data/environments/prod.json +8 -0
  432. data/extras/README.md +1 -0
  433. data/extras/admin-role-binding.yaml +16 -0
  434. data/extras/admin-user.yaml +6 -0
  435. data/extras/aws-auth-cm.yaml.erb +12 -0
  436. data/extras/clean-stock-amis +48 -0
  437. data/extras/git-fix-permissions-hook +12 -0
  438. data/extras/gitlab-eks-helper.sh.erb +20 -0
  439. data/extras/image-generators/README.md +2 -0
  440. data/extras/image-generators/aws/centos6.yaml +18 -0
  441. data/extras/image-generators/aws/centos7-govcloud.yaml +24 -0
  442. data/extras/image-generators/aws/centos7.yaml +17 -0
  443. data/extras/image-generators/aws/rhel7.yaml +17 -0
  444. data/extras/image-generators/aws/win2k12.yaml +16 -0
  445. data/extras/image-generators/aws/win2k16.yaml +16 -0
  446. data/extras/image-generators/aws/windows.yaml +18 -0
  447. data/extras/image-generators/gcp/centos6.yaml +17 -0
  448. data/extras/lambda_waf_domain_blacklist.py +103 -0
  449. data/extras/platform_berksfile_base +50 -0
  450. data/extras/ruby_rpm/build.sh +17 -0
  451. data/extras/ruby_rpm/muby.spec +44 -0
  452. data/extras/vault_tools/README.md +6 -0
  453. data/extras/vault_tools/export_vaults.sh +3 -0
  454. data/extras/vault_tools/recreate_vaults.sh +5 -0
  455. data/extras/vault_tools/test_vaults.sh +5 -0
  456. data/install/README.md +8 -0
  457. data/install/cfn_create_mu_master.json +1034 -0
  458. data/install/chef-server.rb.erb +19 -0
  459. data/install/deprecated-bash-library.sh +1891 -0
  460. data/install/images/Usage.png +0 -0
  461. data/install/installer +71 -0
  462. data/install/jenkinskeys.rb +8 -0
  463. data/install/user-dot-murc.erb +14 -0
  464. data/modules/html.erb +19 -0
  465. data/modules/mommacat.ru +426 -0
  466. data/modules/mu/cleanup.rb +339 -0
  467. data/modules/mu/cloud.rb +1446 -0
  468. data/modules/mu/clouds/README.md +201 -0
  469. data/modules/mu/clouds/aws/alarm.rb +319 -0
  470. data/modules/mu/clouds/aws/cache_cluster.rb +1010 -0
  471. data/modules/mu/clouds/aws/collection.rb +373 -0
  472. data/modules/mu/clouds/aws/container_cluster.rb +667 -0
  473. data/modules/mu/clouds/aws/database.rb +1836 -0
  474. data/modules/mu/clouds/aws/dnszone.rb +911 -0
  475. data/modules/mu/clouds/aws/firewall_rule.rb +641 -0
  476. data/modules/mu/clouds/aws/folder.rb +92 -0
  477. data/modules/mu/clouds/aws/function.rb +349 -0
  478. data/modules/mu/clouds/aws/group.rb +251 -0
  479. data/modules/mu/clouds/aws/loadbalancer.rb +888 -0
  480. data/modules/mu/clouds/aws/log.rb +363 -0
  481. data/modules/mu/clouds/aws/msg_queue.rb +480 -0
  482. data/modules/mu/clouds/aws/notification.rb +139 -0
  483. data/modules/mu/clouds/aws/role.rb +656 -0
  484. data/modules/mu/clouds/aws/search_domain.rb +646 -0
  485. data/modules/mu/clouds/aws/server.rb +2294 -0
  486. data/modules/mu/clouds/aws/server_pool.rb +1388 -0
  487. data/modules/mu/clouds/aws/storage_pool.rb +495 -0
  488. data/modules/mu/clouds/aws/user.rb +382 -0
  489. data/modules/mu/clouds/aws/userdata/README.md +4 -0
  490. data/modules/mu/clouds/aws/userdata/linux.erb +179 -0
  491. data/modules/mu/clouds/aws/userdata/windows.erb +278 -0
  492. data/modules/mu/clouds/aws/vpc.rb +1943 -0
  493. data/modules/mu/clouds/aws.rb +1009 -0
  494. data/modules/mu/clouds/cloudformation/alarm.rb +146 -0
  495. data/modules/mu/clouds/cloudformation/cache_cluster.rb +167 -0
  496. data/modules/mu/clouds/cloudformation/collection.rb +117 -0
  497. data/modules/mu/clouds/cloudformation/database.rb +278 -0
  498. data/modules/mu/clouds/cloudformation/dnszone.rb +274 -0
  499. data/modules/mu/clouds/cloudformation/firewall_rule.rb +308 -0
  500. data/modules/mu/clouds/cloudformation/loadbalancer.rb +193 -0
  501. data/modules/mu/clouds/cloudformation/log.rb +170 -0
  502. data/modules/mu/clouds/cloudformation/server.rb +370 -0
  503. data/modules/mu/clouds/cloudformation/server_pool.rb +279 -0
  504. data/modules/mu/clouds/cloudformation/vpc.rb +322 -0
  505. data/modules/mu/clouds/cloudformation.rb +733 -0
  506. data/modules/mu/clouds/docker.rb +30 -0
  507. data/modules/mu/clouds/google/container_cluster.rb +290 -0
  508. data/modules/mu/clouds/google/database.rb +152 -0
  509. data/modules/mu/clouds/google/firewall_rule.rb +267 -0
  510. data/modules/mu/clouds/google/group.rb +164 -0
  511. data/modules/mu/clouds/google/loadbalancer.rb +479 -0
  512. data/modules/mu/clouds/google/server.rb +1510 -0
  513. data/modules/mu/clouds/google/server_pool.rb +274 -0
  514. data/modules/mu/clouds/google/user.rb +266 -0
  515. data/modules/mu/clouds/google/userdata/README.md +4 -0
  516. data/modules/mu/clouds/google/userdata/linux.erb +137 -0
  517. data/modules/mu/clouds/google/userdata/windows.erb +275 -0
  518. data/modules/mu/clouds/google/vpc.rb +890 -0
  519. data/modules/mu/clouds/google.rb +811 -0
  520. data/modules/mu/config/README.md +11 -0
  521. data/modules/mu/config/alarm.rb +271 -0
  522. data/modules/mu/config/cache_cluster.rb +172 -0
  523. data/modules/mu/config/collection.rb +87 -0
  524. data/modules/mu/config/container_cluster.rb +103 -0
  525. data/modules/mu/config/container_cluster.yml +36 -0
  526. data/modules/mu/config/database.rb +458 -0
  527. data/modules/mu/config/database.yml +26 -0
  528. data/modules/mu/config/dnszone.rb +327 -0
  529. data/modules/mu/config/firewall_rule.rb +118 -0
  530. data/modules/mu/config/folder.rb +70 -0
  531. data/modules/mu/config/function.rb +140 -0
  532. data/modules/mu/config/group.rb +64 -0
  533. data/modules/mu/config/loadbalancer.rb +482 -0
  534. data/modules/mu/config/log.rb +47 -0
  535. data/modules/mu/config/log.yml +6 -0
  536. data/modules/mu/config/msg_queue.rb +47 -0
  537. data/modules/mu/config/msg_queue.yml +9 -0
  538. data/modules/mu/config/notification.rb +44 -0
  539. data/modules/mu/config/project.rb +71 -0
  540. data/modules/mu/config/role.rb +102 -0
  541. data/modules/mu/config/search_domain.rb +61 -0
  542. data/modules/mu/config/search_domain.yml +25 -0
  543. data/modules/mu/config/server.rb +587 -0
  544. data/modules/mu/config/server.yml +8 -0
  545. data/modules/mu/config/server_pool.rb +216 -0
  546. data/modules/mu/config/server_pool.yml +71 -0
  547. data/modules/mu/config/storage_pool.rb +145 -0
  548. data/modules/mu/config/user.rb +78 -0
  549. data/modules/mu/config/vpc.rb +743 -0
  550. data/modules/mu/config/vpc.yml +6 -0
  551. data/modules/mu/config.rb +2000 -0
  552. data/modules/mu/defaults/README.md +2 -0
  553. data/modules/mu/defaults/amazon_images.yaml +121 -0
  554. data/modules/mu/defaults/google_images.yaml +16 -0
  555. data/modules/mu/deploy.rb +686 -0
  556. data/modules/mu/groomer.rb +123 -0
  557. data/modules/mu/groomers/README.md +58 -0
  558. data/modules/mu/groomers/chef.rb +1024 -0
  559. data/modules/mu/kittens.rb +11319 -0
  560. data/modules/mu/logger.rb +208 -0
  561. data/modules/mu/master/README.md +27 -0
  562. data/modules/mu/master/chef.rb +471 -0
  563. data/modules/mu/master/ldap.rb +1005 -0
  564. data/modules/mu/master.rb +415 -0
  565. data/modules/mu/mommacat.rb +2703 -0
  566. data/modules/mu-load-config.rb +1 -0
  567. data/modules/mu.rb +724 -0
  568. data/modules/scratchpad.erb +1 -0
  569. data/modules/tests/super_complex_bok.yml +41 -0
  570. data/modules/tests/super_simple_bok.yml +40 -0
  571. data/mu.gemspec +62 -0
  572. data/roles/demo-dbservice-configure.json +19 -0
  573. data/roles/demo-portal-configure.json +19 -0
  574. data/roles/mu-master-jenkins.json +24 -0
  575. data/roles/mu-master-nagios-only.json +13 -0
  576. data/roles/mu-master.json +12 -0
  577. data/roles/mu-node.json +19 -0
  578. data/roles/mu-splunk-server.json +13 -0
  579. data/roles/mu-splunk.json +13 -0
  580. data/test/clean_up.py +25 -0
  581. data/test/demo-test-profile/README.md +3 -0
  582. data/test/demo-test-profile/controls/flask.rb +84 -0
  583. data/test/demo-test-profile/inspec.lock +7 -0
  584. data/test/demo-test-profile/inspec.yml +11 -0
  585. data/test/etco-test-profile/README.md +3 -0
  586. data/test/etco-test-profile/controls/all-in-one.rb +182 -0
  587. data/test/etco-test-profile/inspec.lock +7 -0
  588. data/test/etco-test-profile/inspec.yml +11 -0
  589. data/test/exec_inspec.py +246 -0
  590. data/test/exec_mu_install.py +241 -0
  591. data/test/exec_retry.py +44 -0
  592. data/test/mu-master-test/README.md +3 -0
  593. data/test/mu-master-test/controls/all_in_one.rb +557 -0
  594. data/test/mu-master-test/inspec.lock +3 -0
  595. data/test/mu-master-test/inspec.yml +11 -0
  596. data/test/mu-tools-test/README.md +3 -0
  597. data/test/mu-tools-test/controls/base.rb +265 -0
  598. data/test/mu-tools-test/inspec.lock +3 -0
  599. data/test/mu-tools-test/inspec.yml +8 -0
  600. data/test/simple-server-php-test/README.md +3 -0
  601. data/test/simple-server-php-test/controls/apachephp.rb +25 -0
  602. data/test/simple-server-php-test/controls/example.rb +19 -0
  603. data/test/simple-server-php-test/inspec.lock +7 -0
  604. data/test/simple-server-php-test/inspec.yml +12 -0
  605. data/test/simple-server-rails-test/README.md +3 -0
  606. data/test/simple-server-rails-test/controls/rails.rb +188 -0
  607. data/test/simple-server-rails-test/inspec.lock +7 -0
  608. data/test/simple-server-rails-test/inspec.yml +11 -0
  609. data/test/simple-windows-test/README.md +3 -0
  610. data/test/simple-windows-test/controls/windows.rb +20 -0
  611. data/test/simple-windows-test/inspec.lock +7 -0
  612. data/test/simple-windows-test/inspec.yml +11 -0
  613. data/test/smoke_test.rb +75 -0
  614. data/test/wordpress-test/README.md +3 -0
  615. data/test/wordpress-test/controls/wordpress.rb +97 -0
  616. data/test/wordpress-test/inspec.lock +7 -0
  617. data/test/wordpress-test/inspec.yml +11 -0
  618. metadata +979 -0
@@ -0,0 +1,1024 @@
1
+ # Copyright:: Copyright (c) 2014 eGlobalTech, Inc., all rights reserved
2
+ #
3
+ # Licensed under the BSD-3 license (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License in the root of the project or at
6
+ #
7
+ # http://egt-labs.com/mu/LICENSE.html
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ module MU
17
+ # Plugins under this namespace serve as interfaces to host configuration
18
+ # management tools, like Chef or Puppet.
19
+ class Groomer
20
+ # Support for Chef as a host configuration management layer.
21
+ class Chef
22
+
23
+ # Wrapper class for temporary Exceptions. Gives our internals something
24
+ # to inherit that will log a notice message appropriately before
25
+ # bubbling up.
26
+ class MuNoSuchSecret < StandardError;end
27
+
28
+ Object.class_eval {
29
+ def self.const_missing(symbol)
30
+ if symbol.to_sym == :Chef or symbol.to_sym == :ChefVault
31
+ MU::Groomer::Chef.loadChefLib
32
+ return Object.const_get(symbol)
33
+ end
34
+ end
35
+ def const_missing(symbol)
36
+ if symbol.to_sym == :Chef or symbol.to_sym == :ChefVault
37
+ MU::Groomer::Chef.loadChefLib(@server.deploy.chef_user, @server.deploy.environment, @server.deploy.mu_user)
38
+ return Object.const_get(symbol)
39
+ end
40
+ end
41
+ }
42
+
43
+ @chefloaded = false
44
+ @chefload_semaphore = Mutex.new
45
+ # Autoload is too brain-damaged to get Chef's subclasses/submodules, so
46
+ # implement our own lazy loading.
47
+ def self.loadChefLib(user = MU.chef_user, env = "dev", mu_user = MU.mu_user)
48
+ @chefload_semaphore.synchronize {
49
+ if !@chefloaded
50
+ MU.log "Loading Chef libraries as user #{user}...", MU::DEBUG
51
+ start = Time.now
52
+ # need to find which classes are actually needed instead of loading chef
53
+ require 'chef'
54
+ require 'chef/api_client_v1'
55
+ require 'chef/knife'
56
+ require 'chef/knife/ssh'
57
+ require 'chef/knife/bootstrap'
58
+ require 'chef/knife/node_delete'
59
+ require 'chef/knife/client_delete'
60
+ require 'chef/knife/data_bag_delete'
61
+ require 'chef/knife/vault_delete'
62
+ require 'chef/scan_access_control'
63
+ require 'chef/file_access_control/unix'
64
+ require 'chef-vault'
65
+ require 'chef-vault/item'
66
+ # XXX kludge to get at knife-windows when it's installed from
67
+ # a git repo and bundler sticks it somewhere in a corner
68
+ $LOAD_PATH.each { |path|
69
+ if path.match(/\/gems\/aws\-sdk\-core\-\d+\.\d+\.\d+\/lib$/)
70
+ addpath = path.sub(/\/gems\/aws\-sdk\-core\-\d+\.\d+\.\d+\/lib$/, "")+"/bundler/gems"
71
+ Dir.glob(addpath+"/knife-windows-*").each { |version|
72
+ $LOAD_PATH << version+"/lib"
73
+ }
74
+ end
75
+ }
76
+ require 'chef/knife/bootstrap_windows_winrm'
77
+ require 'chef/knife/bootstrap_windows_ssh'
78
+ ::Chef::Config[:chef_server_url] = "https://#{MU.mu_public_addr}:7443/organizations/#{user}"
79
+ if File.exists?("#{Etc.getpwnam(mu_user).dir}/.chef/knife.rb")
80
+ MU.log "Loading Chef configuration from #{Etc.getpwnam(mu_user).dir}/.chef/knife.rb", MU::DEBUG
81
+ ::Chef::Config.from_file("#{Etc.getpwnam(mu_user).dir}/.chef/knife.rb")
82
+ end
83
+ ::Chef::Config[:environment] = env
84
+ ::Chef::Config[:yes] = true
85
+ if mu_user != "root"
86
+ ::Chef::Config.trusted_certs_dir = "#{Etc.getpwnam(mu_user).dir}/.chef/trusted_certs"
87
+ end
88
+ @chefloaded = true
89
+ MU.log "Chef libraries loaded (took #{(Time.now-start).to_s} seconds)", MU::DEBUG
90
+ end
91
+ }
92
+ end
93
+
94
+ @knife = "cd #{MU.myRoot} && env -i HOME=#{Etc.getpwnam(MU.mu_user).dir} PATH=/opt/chef/embedded/bin:/usr/bin:/usr/sbin knife"
95
+ # The canonical path to invoke Chef's *knife* utility with a clean environment.
96
+ # @return [String]
97
+ def self.knife;
98
+ @knife;
99
+ end
100
+
101
+ attr_reader :knife
102
+
103
+ @vault_opts = "--mode client -u #{MU.chef_user} -F json"
104
+ # The canonical set of arguments for most `knife vault` commands
105
+ # @return [String]
106
+ def self.vault_opts;
107
+ @vault_opts;
108
+ end
109
+
110
+ attr_reader :vault_opts
111
+
112
+ @chefclient = "env -i HOME=#{Etc.getpwuid(Process.uid).dir} PATH=/opt/chef/embedded/bin:/usr/bin:/usr/sbin chef-client"
113
+ # The canonical path to invoke Chef's *chef-client* utility with a clean environment.
114
+ # @return [String]
115
+ def self.chefclient;
116
+ @chefclient;
117
+ end
118
+
119
+ attr_reader :chefclient
120
+
121
+
122
+ # @param node [MU::Cloud::Server]: The server object on which we'll be operating
123
+ def initialize(node)
124
+ @config = node.config
125
+ @server = node
126
+ if node.mu_name.nil? or node.mu_name.empty?
127
+ raise MuError, "Cannot groom a server that doesn't tell me its mu_name"
128
+ end
129
+ @secrets_semaphore = Mutex.new
130
+ @secrets_granted = {}
131
+ end
132
+
133
+ # Indicate whether our server has been bootstrapped with Chef
134
+ def haveBootstrapped?
135
+ self.class.loadChefLib
136
+ MU.log "Chef config", MU::DEBUG, details: ::Chef::Config.inspect
137
+ nodelist = ::Chef::Node.list()
138
+ nodelist.has_key?(@server.mu_name)
139
+ end
140
+
141
+ # @param vault [String]: A repository of secrets to create/save into.
142
+ # @param item [String]: The item within the repository to create/save.
143
+ # @param data [Hash]: Data to save
144
+ # @param permissions [String]: An implementation-specific string describing what node or nodes should have access to this secret.
145
+ def self.saveSecret(vault: @server.mu_name, item: nil, data: nil, permissions: nil)
146
+ loadChefLib
147
+ if item.nil? or !item.is_a?(String)
148
+ raise MuError, "item argument to saveSecret must be a String"
149
+ end
150
+ if data.nil? or !data.is_a?(Hash)
151
+ raise MuError, "data argument to saveSecret must be a Hash"
152
+ end
153
+
154
+ cmd = "update"
155
+ begin
156
+ MU.log "Checking for existence of #{vault} #{item}", MU::DEBUG, details: caller
157
+ ::ChefVault::Item.load(vault, item)
158
+ rescue ::ChefVault::Exceptions::KeysNotFound
159
+ cmd = "create"
160
+ end
161
+ if permissions
162
+ MU.log "knife vault #{cmd} #{vault} #{item} --search #{permissions}"
163
+ ::Chef::Knife.run(['vault', cmd, vault, item, JSON.generate(data).gsub(/'/, '\\1'), '--search', permissions])
164
+ else
165
+ MU.log "knife vault #{cmd} #{vault} #{item}"
166
+ ::Chef::Knife.run(['vault', cmd, vault, item, JSON.generate(data).gsub(/'/, '\\1')])
167
+ end
168
+ end
169
+
170
+ # see {MU::Groomer::Chef.saveSecret}
171
+ def saveSecret(vault: @server.mu_name, item: nil, data: nil, permissions: "name:#{@server.mu_name}")
172
+ self.class.saveSecret(vault: vault, item: item, data: data, permissions: permissions)
173
+ end
174
+
175
+ # Retrieve sensitive data, which hopefully we're storing and retrieving
176
+ # in a secure fashion.
177
+ # @param vault [String]: A repository of secrets to search
178
+ # @param item [String]: The item within the repository to retrieve
179
+ # @param field [String]: OPTIONAL - A specific field within the item to return.
180
+ # @return [Hash]
181
+ def self.getSecret(vault: nil, item: nil, field: nil)
182
+ loadChefLib
183
+ loaded = nil
184
+
185
+ if !item.nil?
186
+ begin
187
+ loaded = ::ChefVault::Item.load(vault, item)
188
+ rescue ::ChefVault::Exceptions::KeysNotFound => e
189
+ raise MuNoSuchSecret, "Can't load the Chef Vault #{vault}:#{item}. Does it exist? Chef user: #{MU.chef_user}"
190
+ end
191
+ else
192
+ # If we didn't ask for a particular item, list what we have.
193
+ begin
194
+ loaded = ::Chef::DataBag.load(vault).keys.select { |k, v| !k.match(/_keys$/) }
195
+ rescue Net::HTTPServerException
196
+ raise MuNoSuchSecret, "Failed to retrieve Vault #{vault}"
197
+ end
198
+ end
199
+
200
+ if loaded.nil?
201
+ raise MuNoSuchSecret, "Failed to retrieve Vault #{vault}:#{item}"
202
+ end
203
+
204
+ if !field.nil?
205
+ if loaded.has_key?(field)
206
+ return loaded[field]
207
+ else
208
+ raise MuNoSuchSecret, "No such field in Vault #{vault}:#{item}"
209
+ end
210
+ else
211
+ return loaded
212
+ end
213
+ end
214
+
215
+ # see {MU::Groomer::Chef.getSecret}
216
+ def getSecret(vault: nil, item: nil, field: nil)
217
+ self.class.getSecret(vault: vault, item: item, field: field)
218
+ end
219
+
220
+ # Delete a Chef data bag / Vault
221
+ # @param vault [String]: A repository of secrets to delete
222
+ def self.deleteSecret(vault: nil, item: nil)
223
+ loadChefLib
224
+ raise MuError, "No vault specified, nothing to delete" if vault.nil?
225
+ MU.log "Deleting #{vault}:#{item} from vaults"
226
+ knife_db = nil
227
+ knife_cmds = []
228
+ if item.nil?
229
+ knife_cmds << ::Chef::Knife::DataBagDelete.new(['data', 'bag', 'delete', vault])
230
+ else
231
+ knife_cmds << ::Chef::Knife::DataBagDelete.new(['data', 'bag', 'delete', vault, item])
232
+ knife_cmds << ::Chef::Knife::DataBagDelete.new(['data', 'bag', 'delete', vault, item+"_keys"])
233
+ end
234
+ begin
235
+ knife_cmds.each { |knife_db|
236
+ knife_db.config[:yes] = true
237
+ knife_db.run
238
+ }
239
+ rescue Net::HTTPServerException => e
240
+ # We don't want to raise an error here. As an example we might be cleaning up a dead node in a server pool and this will then fail for no god reasons.
241
+ MU.log "Tried to delete vault #{vault} but got #{e.inspect}, giving up", MU::ERR
242
+ end
243
+ end
244
+
245
+ # see {MU::Groomer::Chef.deleteSecret}
246
+ def deleteSecret(vault: nil)
247
+ self.class.deleteSecret(vault: vault)
248
+ end
249
+
250
+ # Invoke the Chef client on the node at the other end of a provided SSH
251
+ # session.
252
+ # @param purpose [String]: A string describing the purpose of this client run.
253
+ # @param max_retries [Integer]: The maximum number of attempts at a successful run to make before giving up.
254
+ # @param output [Boolean]: Display Chef's regular (non-error) output to the console
255
+ # @param override_runlist [String]: Use the specified run list instead of the node's configured list
256
+ def run(purpose: "Chef run", update_runlist: true, max_retries: 5, output: true, override_runlist: nil, reboot_first_fail: false)
257
+ self.class.loadChefLib
258
+ if update_runlist and !@config['run_list'].nil?
259
+ knifeAddToRunList(multiple: @config['run_list'])
260
+ end
261
+
262
+ timeout = @server.windows? ? 1800 : 600
263
+ pending_reboot_count = 0
264
+ chef_node = ::Chef::Node.load(@server.mu_name)
265
+ if !@config['application_attributes'].nil?
266
+ MU.log "Setting node:#{@server.mu_name} application_attributes", MU::DEBUG, details: @config['application_attributes']
267
+ chef_node.normal.application_attributes = @config['application_attributes']
268
+ chef_node.save
269
+ end
270
+ if @server.deploy.original_config.has_key?('parameters')
271
+ MU.log "Setting node:#{@server.mu_name} parameters", MU::DEBUG, details: @server.deploy.original_config['parameters']
272
+ chef_node.normal['mu_parameters'] = @server.deploy.original_config['parameters']
273
+ chef_node.save
274
+ end
275
+ saveDeployData
276
+
277
+ retries = 0
278
+ try_upgrade = false
279
+ output = []
280
+ error_signal = "CHEF EXITED BADLY: "+(0...25).map { ('a'..'z').to_a[rand(26)] }.join
281
+ runstart = nil
282
+ cmd = nil
283
+ ssh = nil
284
+ winrm = nil
285
+ windows_try_ssh = false
286
+ begin
287
+ runstart = Time.new
288
+ if !@server.windows? or windows_try_ssh
289
+ MU.log "Invoking Chef over ssh on #{@server.mu_name}: #{purpose}"
290
+ ssh = @server.getSSHSession(@server.windows? ? 1 : max_retries)
291
+ if @server.windows?
292
+ cmd = "chef-client.bat --color || echo #{error_signal}"
293
+ elsif !@config["ssh_user"].nil? and !@config["ssh_user"].empty? and @config["ssh_user"] != "root"
294
+ upgrade_cmd = try_upgrade ? "sudo curl -L https://chef.io/chef/install.sh | sudo version=#{MU.chefVersion} sh &&" : ""
295
+ cmd = "#{upgrade_cmd} sudo chef-client --color || echo #{error_signal}"
296
+ else
297
+ upgrade_cmd = try_upgrade ? "curl -L https://chef.io/chef/install.sh | version=#{MU.chefVersion} sh &&" : ""
298
+ cmd = "#{upgrade_cmd} chef-client --color || echo #{error_signal}"
299
+ end
300
+ Timeout::timeout(timeout) {
301
+ retval = ssh.exec!(cmd) { |ch, stream, data|
302
+ puts data
303
+ output << data
304
+ raise MU::Cloud::BootstrapTempFail if data.match(/REBOOT_SCHEDULED| WARN: Reboot requested:/)
305
+ raise MU::Groomer::RunError, output.grep(/ ERROR: /).last if data.match(/#{error_signal}/)
306
+ }
307
+ }
308
+ else
309
+ MU.log "Invoking Chef over WinRM on #{@server.mu_name}: #{purpose}"
310
+ winrm = @server.getWinRMSession(haveBootstrapped? ? 1 : max_retries)
311
+ if @server.windows? and @server.windowsRebootPending?(winrm)
312
+ # Windows frequently gets stuck here
313
+ if retries > 5
314
+ @server.reboot(true)
315
+ elsif retries > 3
316
+ @server.reboot
317
+ end
318
+ raise MU::Groomer::RunError, "#{@server.mu_name} has a pending reboot"
319
+ end
320
+ if try_upgrade
321
+ pp winrm.run("Invoke-WebRequest -useb https://omnitruck.chef.io/install.ps1 | Invoke-Expression; Install-Project -version:#{MU.chefVersion} -download_directory:$HOME")
322
+ end
323
+ output = []
324
+ cmd = "c:/opscode/chef/bin/chef-client.bat --color"
325
+ if override_runlist
326
+ cmd = cmd + " -o '#{override_runlist}'"
327
+ end
328
+ resp = nil
329
+ Timeout::timeout(timeout) {
330
+ resp = winrm.run(cmd) do |stdout, stderr|
331
+ if stdout
332
+ print stdout if output
333
+ output << stdout
334
+ end
335
+ if stderr
336
+ MU.log stderr, MU::ERR
337
+ output << stderr
338
+ end
339
+ end
340
+ }
341
+ if resp.exitcode != 0
342
+ raise MU::Cloud::BootstrapTempFail if resp.exitcode == 35 or output.join("\n").match(/REBOOT_SCHEDULED| WARN: Reboot requested:/)
343
+ raise MU::Groomer::RunError, output.slice(output.length-50, output.length).join("")
344
+ end
345
+ end
346
+ rescue MU::Cloud::BootstrapTempFail
347
+ MU.log "#{@server.mu_name} rebooting from Chef, waiting then resuming", MU::NOTICE
348
+ sleep 30
349
+ # weird failures seem common in govcloud
350
+ if MU::Cloud::AWS.isGovCloud?(@config['region'])
351
+ @server.reboot(true)
352
+ sleep 30
353
+ end
354
+ retry
355
+ rescue RuntimeError, SystemCallError, Timeout::Error, SocketError, Errno::ECONNRESET, IOError, Net::SSH::Exception, MU::Groomer::RunError, WinRM::WinRMError, MU::MuError => e
356
+ begin
357
+ ssh.close if !ssh.nil?
358
+ rescue Net::SSH::Exception, IOError => e
359
+ if @server.windows?
360
+ MU.log "Windows has probably closed the ssh session before we could. Waiting before trying again", MU::DEBUG
361
+ else
362
+ MU.log "ssh session to #{@server.mu_name} was closed unexpectedly, waiting before trying again", MU::NOTICE
363
+ end
364
+ sleep 10
365
+ end
366
+ if e.instance_of?(MU::Groomer::RunError) and retries == 0 and max_retries > 1 and purpose != "Base Windows configuration"
367
+ MU.log "Got a run error, will attempt to install/update Chef Client on next attempt", MU::NOTICE
368
+ try_upgrade = true
369
+ else
370
+ try_upgrade = false
371
+ end
372
+
373
+ if e.is_a?(MU::Groomer::RunError)
374
+ if reboot_first_fail
375
+ try_upgrade = true
376
+ begin
377
+ preClean(true) # drop any Chef install that's not ours
378
+ @server.reboot # try gently rebooting the thing
379
+ rescue Exception => e # it's ok to fail here (and to ignore failure)
380
+ MU.log "preclean err #{e.inspect}", MU::ERR
381
+ end
382
+ reboot_first_fail = false
383
+ end
384
+ end
385
+
386
+ if retries < max_retries
387
+ retries += 1
388
+ MU.log "#{@server.mu_name}: Chef run '#{purpose}' failed after #{Time.new - runstart} seconds, retrying (#{retries}/#{max_retries})", MU::WARN, details: e.message.dup
389
+ if purpose != "Base Windows configuration"
390
+ windows_try_ssh = !windows_try_ssh
391
+ end
392
+ if e.is_a?(WinRM::WinRMError)
393
+ if @server.windows? and retries >= 3 and retries % 3 == 0
394
+ # Mix in a hard reboot if WinRM isn't answering
395
+ @server.reboot(true)
396
+ end
397
+ end
398
+ sleep 30
399
+ retry
400
+ else
401
+ raise MU::Groomer::RunError, "#{@server.mu_name}: Chef run '#{purpose}' failed #{max_retries} times, last error was: #{e.message}"
402
+ end
403
+ rescue Exception => e
404
+ raise MU::Groomer::RunError, "Caught unexpected #{e.inspect} on #{@server.mu_name} in @groomer.run"
405
+
406
+ end
407
+
408
+ saveDeployData
409
+ end
410
+
411
+ # Make sure we've got a Splunk admin vault for any mu-splunk-servers to
412
+ # use, and set it up if we don't.
413
+ def splunkVaultInit
414
+ self.class.loadChefLib
415
+ begin
416
+ loaded = ::ChefVault::Item.load("splunk", "admin_user")
417
+ rescue ::ChefVault::Exceptions::KeysNotFound => e
418
+ pw = Password.pronounceable(12..14)
419
+ creds = {
420
+ "username" => "admin",
421
+ "password" => pw,
422
+ "auth" => "admin:#{pw}"
423
+ }
424
+ saveSecret(
425
+ vault: "splunk",
426
+ item: "admin_user",
427
+ data: creds,
428
+ permissions: "role:mu-splunk-server"
429
+ )
430
+ end
431
+ end
432
+
433
+ # Expunge
434
+ def preClean(leave_ours = false)
435
+ remove_cmd = nil
436
+ if !@server.windows?
437
+ if @server.config['ssh_user'] == "root"
438
+ remove_cmd = "rm -rf /var/chef/ /etc/chef /opt/chef/ /usr/bin/chef-* ; yum -y erase chef ; rpm -e chef; apt-get -y remove chef ; touch /opt/mu_installed_chef"
439
+ else
440
+ remove_cmd = "sudo yum -y erase chef ; sudo rpm -e erase chef ; sudo rm -rf /var/chef/ /etc/chef /opt/chef/ /usr/bin/chef-* ; sudo apt-get -y remove chef ; sudo touch /opt/mu_installed_chef"
441
+ end
442
+ guardfile = "/opt/mu_installed_chef"
443
+
444
+ ssh = @server.getSSHSession(15)
445
+ if leave_ours
446
+ MU.log "Expunging pre-existing Chef install on #{@server.mu_name}, if we didn't create it", MU::NOTICE
447
+ begin
448
+ ssh.exec!(%Q{test -f #{guardfile} || (#{remove_cmd}) ; touch #{guardfile}})
449
+ rescue IOError => e
450
+ # TO DO - retry this in a cleaner way
451
+ MU.log "Got #{e.inspect} while trying to clean up chef, retrying", MU::NOTICE, details: %Q{test -f #{guardfile} || (#{remove_cmd}) ; touch #{guardfile}}
452
+ ssh = @server.getSSHSession(15)
453
+ ssh.exec!(%Q{test -f #{guardfile} || (#{remove_cmd}) ; touch #{guardfile}})
454
+ end
455
+ else
456
+ MU.log "Expunging pre-existing Chef install on #{@server.mu_name}", MU::NOTICE
457
+ ssh.exec!(remove_cmd)
458
+ end
459
+
460
+ ssh.close
461
+ else
462
+ remove_cmd = %Q{
463
+ $uninstall_string = (Get-ItemProperty HKLM:\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\* | Where-Object {$_.DisplayName -like "chef client*"}).UninstallString
464
+ if($uninstall_string){
465
+ $uninstall_string = ($uninstall_string -Replace "msiexec.exe","" -Replace "/I","" -Replace "/X","").Trim()
466
+ $($uninstall_string -Replace '[\\s\\t]+', ' ').Split() | ForEach {
467
+ start-process "msiexec.exe" -arg "/X $_ /qn" -Wait
468
+ }
469
+ }
470
+ Remove-Item c:/chef/ -Force -Recurse -ErrorAction Continue
471
+ Remove-Item c:/opscode/ -Force -Recurse -ErrorAction Continue
472
+ Remove-Item C:/Users/ADMINI~1/AppData/Local/Temp/bootstrap*.bat -Force -Recurse -ErrorAction Continue
473
+ Remove-Item C:/Users/ADMINI~1/AppData/Local/Temp/chef-* -Force -Recurse -ErrorAction Continue
474
+ }
475
+ shell = @server.getWinRMSession(15)
476
+ removechef = true
477
+ if leave_ours
478
+ resp = shell.run("Test-Path c:/mu_installed_chef")
479
+ if resp.stdout.chomp == "True"
480
+ MU.log "Found existing Chef installation created by Mu, leaving it alone"
481
+ removechef = false
482
+ end
483
+ end
484
+
485
+ # remove_cmd = %Q{$my_chef = (Get-ItemProperty $location | Where-Object {$_.DisplayName -like "chef client*"}).DisplayName
486
+ if removechef
487
+ MU.log "Expunging pre-existing Chef install on #{@server.mu_name}", MU::NOTICE, details: remove_cmd
488
+ # pp shell.run(remove_cmd)
489
+ end
490
+ end
491
+ end
492
+
493
+ # Forcibly (re)install Chef. Useful for upgrading or overwriting a
494
+ # broken existing install.
495
+ def reinstall
496
+ try_winrm = false
497
+ if !@server.windows?
498
+ cmd = %Q{curl -LO https://omnitruck.chef.io/install.sh && sudo bash ./install.sh -v #{MU.chefVersion} && rm install.sh}
499
+ else
500
+ try_winrm = true
501
+ cmd = %Q{Invoke-WebRequest -useb https://omnitruck.chef.io/install.ps1 | Invoke-Expression; Install-Project -version:#{MU.chefVersion} -download_directory:$HOME}
502
+ end
503
+
504
+ if try_winrm
505
+ begin
506
+ MU.log "Attempting Chef upgrade via WinRM on #{@server.mu_name}", MU::NOTICE, details: cmd
507
+ winrm = @server.getWinRMSession(1, 30, winrm_retries: 2)
508
+ pp winrm.run(cmd)
509
+ return
510
+ rescue Net::SSH::Disconnect, SystemCallError, Timeout::Error, Errno::ECONNRESET, Errno::EHOSTUNREACH, Net::SSH::Proxy::ConnectError, SocketError, Net::SSH::Disconnect, Net::SSH::AuthenticationFailed, IOError, Net::HTTPServerException, SystemExit, Errno::ECONNREFUSED, Errno::EPIPE, WinRM::WinRMError, HTTPClient::ConnectTimeoutError, RuntimeError, MU::Cloud::BootstrapTempFail, MU::MuError => e
511
+ MU.log "WinRM failure attempting Chef upgrade on #{@server.mu_name}, will fall back to ssh", MU::WARN
512
+ cmd = %Q{powershell.exe -inputformat none -noprofile "#{cmd}"}
513
+ end
514
+ end
515
+
516
+ MU.log "Attempting Chef upgrade via ssh on #{@server.mu_name}", MU::NOTICE, details: cmd
517
+ ssh = @server.getSSHSession(1)
518
+ retval = ssh.exec!(cmd) { |ch, stream, data|
519
+ puts data
520
+ }
521
+ end
522
+
523
+ # Bootstrap our server with Chef
524
+ def bootstrap
525
+ self.class.loadChefLib
526
+ stashHostSSLCertSecret
527
+ if !@config['cleaned_chef']
528
+ begin
529
+ leave_ours = @config['scrub_groomer'] ? false : true
530
+ preClean(leave_ours)
531
+ rescue RuntimeError => e
532
+ MU.log e.inspect, MU::ERR
533
+ sleep 10
534
+ retry
535
+ end
536
+ @config['cleaned_chef'] = true
537
+ end
538
+
539
+ nat_ssh_key, nat_ssh_user, nat_ssh_host, canonical_addr, ssh_user, ssh_key_name = @server.getSSHConfig
540
+
541
+ MU.log "Bootstrapping #{@server.mu_name} (#{canonical_addr}) with knife"
542
+
543
+ run_list = ["recipe[mu-tools::newclient]"]
544
+ run_list << "mu-tools::gcloud" if @server.cloud == "Google" or @server.config['cloud'] == "Google"
545
+
546
+ json_attribs = {}
547
+ if !@config['application_attributes'].nil?
548
+ json_attribs['application_attributes'] = @config['application_attributes']
549
+ json_attribs['skipinitialupdates'] = @config['skipinitialupdates']
550
+ end
551
+
552
+ if !@config['vault_access'].nil?
553
+ vault_access = @config['vault_access']
554
+ else
555
+ vault_access = []
556
+ end
557
+
558
+ @server.windows? ? max_retries = 25 : max_retries = 10
559
+ @server.windows? ? timeout = 1800 : timeout = 300
560
+ retries = 0
561
+ begin
562
+ if !@server.windows?
563
+ kb = ::Chef::Knife::Bootstrap.new([canonical_addr])
564
+ kb.config[:use_sudo] = true
565
+ kb.name_args = "#{canonical_addr}"
566
+ kb.config[:distro] = 'chef-full'
567
+ kb.config[:ssh_user] = ssh_user
568
+ kb.config[:forward_agent] = ssh_user
569
+ kb.config[:identity_file] = "#{Etc.getpwuid(Process.uid).dir}/.ssh/#{ssh_key_name}"
570
+ else
571
+ kb = ::Chef::Knife::BootstrapWindowsWinrm.new([@server.mu_name])
572
+ kb.name_args = [@server.mu_name]
573
+ kb.config[:manual] = true
574
+ kb.config[:winrm_transport] = :ssl
575
+ kb.config[:host] = @server.mu_name
576
+ kb.config[:winrm_port] = 5986
577
+ kb.config[:session_timeout] = timeout
578
+ kb.config[:operation_timeout] = timeout
579
+ kb.config[:winrm_authentication_protocol] = :cert
580
+ kb.config[:winrm_client_cert] = "#{MU.mySSLDir}/#{@server.mu_name}-winrm.crt"
581
+ kb.config[:winrm_client_key] = "#{MU.mySSLDir}/#{@server.mu_name}-winrm.key"
582
+ # kb.config[:ca_trust_file] = "#{MU.mySSLDir}/Mu_CA.pem"
583
+ # XXX ca_trust_file doesn't work for some reason, so we have to set the below for now
584
+ kb.config[:winrm_ssl_verify_mode] = :verify_none
585
+ kb.config[:msi_url] = "https://www.chef.io/chef/download?p=windows&pv=2012&m=x86_64&v=#{MU.chefVersion}"
586
+ end
587
+
588
+ # XXX this seems to break Knife Bootstrap
589
+ # if vault_access.size > 0
590
+ # v = {}
591
+ # vault_access.each { |vault|
592
+ # v[vault['vault']] = [] if v[vault['vault']].nil?
593
+ # v[vault['vault']] << vault['item']
594
+ # }
595
+ # kb.config[:bootstrap_vault_json] = JSON.generate(v)
596
+ # end
597
+
598
+ kb.config[:json_attribs] = JSON.generate(json_attribs) if json_attribs.size > 1
599
+ kb.config[:run_list] = run_list
600
+ kb.config[:chef_node_name] = @server.mu_name
601
+ kb.config[:bootstrap_version] = MU.chefVersion
602
+ # XXX key off of MU verbosity level
603
+ kb.config[:log_level] = :debug
604
+ # kb.config[:ssh_gateway] = "#{nat_ssh_user}@#{nat_ssh_host}" if !nat_ssh_host.nil? # Breaking bootsrap
605
+
606
+ MU.log "Knife Bootstrap settings for #{@server.mu_name} (#{canonical_addr}), timeout set to #{timeout.to_s}", MU::NOTICE, details: kb.config
607
+ if @server.windows? and @server.windowsRebootPending?
608
+ raise MU::Cloud::BootstrapTempFail, "#{@server.mu_name} has a pending reboot"
609
+ end
610
+ Timeout::timeout(timeout) {
611
+ require 'chef'
612
+ MU::Cloud.handleNetSSHExceptions
613
+ kb.run
614
+ }
615
+ # throws Net::HTTPServerException if we haven't really bootstrapped
616
+ ::Chef::Node.load(@server.mu_name)
617
+ rescue Net::SSH::Disconnect, SystemCallError, Timeout::Error, Errno::ECONNRESET, Errno::EHOSTUNREACH, Net::SSH::Proxy::ConnectError, SocketError, Net::SSH::Disconnect, Net::SSH::AuthenticationFailed, IOError, Net::HTTPServerException, SystemExit, Errno::ECONNREFUSED, Errno::EPIPE, WinRM::WinRMError, HTTPClient::ConnectTimeoutError, RuntimeError, MU::Cloud::BootstrapTempFail => e
618
+ if retries < max_retries
619
+ retries += 1
620
+ # Bad Chef installs are possible culprits of bootstrap failures, so
621
+ # try scrubbing them when that happens.
622
+ # On Windows, even a fresh install comes up screwy disturbingly
623
+ # often, so we let it start over from scratch if needed. Except for
624
+ # the first attempt, which usually fails due to WinRM funk.
625
+ if !e.is_a?(MU::Cloud::BootstrapTempFail) and
626
+ !(e.is_a?(WinRM::WinRMError) and @config['forced_preclean']) and
627
+ !@config['forced_preclean']
628
+ begin
629
+ preClean(false) # it's ok for this to fail
630
+ rescue Exception => e
631
+ end
632
+ MU::Groomer::Chef.cleanup(@server.mu_name, nodeonly: true)
633
+ @config['forced_preclean'] = true
634
+ @server.reboot if @server.windows? # *sigh*
635
+ end
636
+ MU.log "#{@server.mu_name}: Knife Bootstrap failed #{e.inspect}, retrying in #{(10*retries).to_s}s (#{retries} of #{max_retries})", MU::WARN, details: e.backtrace
637
+ sleep 10*retries
638
+ retry
639
+ else
640
+ raise MuError, "#{@server.mu_name}: Knife Bootstrap failed too many times with #{e.inspect}"
641
+ end
642
+ rescue Exception => e
643
+ MU.log e.inspect, MU::ERR, details: e.backtrace
644
+ sleep 10*retries
645
+ retry
646
+ end
647
+
648
+ # Now that we're done, remove one-shot bootstrap recipes from the
649
+ # node's final run list
650
+ ["mu-tools::newclient"].each { |recipe|
651
+ begin
652
+ ::Chef::Knife.run(['node', 'run_list', 'remove', @server.mu_name, "recipe[#{recipe}]"], {})
653
+ rescue SystemExit => e
654
+ MU.log "#{@server.mu_name}: Run list removal of recipe[#{recipe}] failed with #{e.inspect}", MU::WARN
655
+ end
656
+ }
657
+ knifeAddToRunList("role[mu-node]")
658
+
659
+ splunkVaultInit
660
+ grantSecretAccess(@server.mu_name, "windows_credentials") if @server.windows?
661
+ grantSecretAccess(@server.mu_name, "ssl_cert")
662
+
663
+ saveChefMetadata
664
+ knifeAddToRunList("recipe[mu-tools::updates]") if !@config['skipinitialupdates']
665
+ # Making sure all Windows nodes get the mu-tools::windows-client recipe
666
+ if @server.windows?
667
+ knifeAddToRunList("recipe[mu-tools::windows-client]")
668
+ run(purpose: "Base Windows configuration", update_runlist: false, max_retries: 20)
669
+ elsif !@config['skipinitialupdates']
670
+ run(purpose: "Base configuration", update_runlist: false, max_retries: 20)
671
+ end
672
+ ::Chef::Knife.run(['node', 'run_list', 'remove', @server.mu_name, "recipe[mu-tools::updates]"], {}) if !@config['skipinitialupdates']
673
+
674
+ # This will deal with Active Directory integration.
675
+ if !@config['active_directory'].nil?
676
+ if @config['active_directory']['domain_operation'] == "join"
677
+ knifeAddToRunList("recipe[mu-activedirectory::domain-node]")
678
+ run(purpose: "Join Active Directory", update_runlist: false, max_retries: max_retries)
679
+ elsif @config['active_directory']['domain_operation'] == "create"
680
+ knifeAddToRunList("recipe[mu-activedirectory::domain]")
681
+ run(purpose: "Create Active Directory Domain", update_runlist: false, max_retries: 15)
682
+ elsif @config['active_directory']['domain_operation'] == "add_controller"
683
+ knifeAddToRunList("recipe[mu-activedirectory::domain-controller]")
684
+ run(purpose: "Add Domain Controller to Active Directory", update_runlist: false, max_retries: 15)
685
+ end
686
+ end
687
+
688
+ if !@config['run_list'].nil?
689
+ knifeAddToRunList(multiple: @config['run_list'])
690
+ end
691
+
692
+ saveDeployData
693
+ end
694
+
695
+ # Synchronize the deployment structure managed by {MU::MommaCat} to Chef,
696
+ # so that nodes can access this metadata.
697
+ # @return [Hash]: The data synchronized.
698
+ def saveDeployData
699
+ self.class.loadChefLib
700
+ @server.describe(update_cache: true) # Make sure we're fresh
701
+ saveChefMetadata
702
+ begin
703
+ chef_node = ::Chef::Node.load(@server.mu_name)
704
+
705
+ # Our deploydata gets corrupted often with server pools, in this case the the deploy data structure of some nodes is corrupt the hashes can become too nested and also invalid.
706
+ # When we try to merge this invalid structure with our chef node structure we get a 'stack level too deep' error.
707
+ # The choice here is to either fail more gracefully or try to clean up our deployment data. This is an attempt to implement the second option
708
+ nodes_to_delete = []
709
+ node_class = nil
710
+ if @server.deploy.deployment.has_key?('servers')
711
+ @server.deploy.deployment['servers'].each_pair { |nodeclass, server_struct|
712
+ node_class = nodeclass
713
+ server_struct.each_pair { |name, server|
714
+ if server.is_a?(Hash) && !server.has_key?('nodename')
715
+ MU.log "#{name} deploy data is corrupt, trying to delete section before merging deployment metadata", MU::ERR, details: server
716
+ nodes_to_delete << name
717
+ end
718
+ }
719
+ }
720
+ end
721
+
722
+ if !nodes_to_delete.empty?
723
+ nodes_to_delete.each { |name|
724
+ @server.deploy.deployment['servers'][node_class].delete(name)
725
+ }
726
+ end
727
+
728
+ if chef_node.normal['deployment'] != @server.deploy.deployment
729
+ MU.log "Updating node: #{@server.mu_name} deployment attributes", details: @server.deploy.deployment
730
+ chef_node.normal['deployment'].merge!(@server.deploy.deployment)
731
+ chef_node.normal['deployment']['ssh_public_key'] = @server.deploy.ssh_public_key
732
+ chef_node.save
733
+ end
734
+ return chef_node['deployment']
735
+ rescue Net::HTTPServerException => e
736
+ MU.log "Attempted to save deployment to Chef node #{@server.mu_name} before it was bootstrapped.", MU::DEBUG
737
+ end
738
+ end
739
+
740
+ # Expunge Chef resources associated with a node.
741
+ # @param node [String]: The Mu name of the node in question.
742
+ # @param vaults_to_clean [Array<Hash>]: Some vaults to expunge
743
+ # @param noop [Boolean]: Skip actual deletion, just state what we'd do
744
+ # @param nodeonly [Boolean]: Just delete the node and its keys, but leave other artifacts
745
+ def self.cleanup(node, vaults_to_clean = [], noop = false, nodeonly: false)
746
+ loadChefLib
747
+ MU.log "Deleting Chef resources associated with #{node}"
748
+ if !nodeonly
749
+ vaults_to_clean.each { |vault|
750
+ MU::MommaCat.lock("vault-#{vault['vault']}", false, true)
751
+ MU.log "knife vault remove #{vault['vault']} #{vault['item']} --search name:#{node}", MU::NOTICE
752
+ ::Chef::Knife.run(['vault', 'remove', vault['vault'], vault['item'], "--search", "name:#{node}"]) if !noop
753
+ MU::MommaCat.unlock("vault-#{vault['vault']}")
754
+ }
755
+ end
756
+ MU.log "knife node delete #{node}"
757
+ if !noop
758
+ knife_nd = ::Chef::Knife::NodeDelete.new(['node', 'delete', node])
759
+ knife_nd.config[:yes] = true
760
+ begin
761
+ knife_nd.run
762
+ rescue Net::HTTPServerException
763
+ end
764
+ end
765
+ MU.log "knife client delete #{node}"
766
+ if !noop
767
+ knife_cd = ::Chef::Knife::ClientDelete.new(['client', 'delete', node])
768
+ knife_cd.config[:yes] = true
769
+ begin
770
+ knife_cd.run
771
+ rescue Net::HTTPServerException
772
+ end
773
+ end
774
+
775
+ return if nodeonly
776
+
777
+ begin
778
+ deleteSecret(vault: node) if !noop
779
+ rescue MuNoSuchSecret
780
+ end
781
+ ["crt", "key", "csr"].each { |ext|
782
+ if File.exists?("#{MU.mySSLDir}/#{node}.#{ext}")
783
+ MU.log "Removing #{MU.mySSLDir}/#{node}.#{ext}"
784
+ File.unlink("#{MU.mySSLDir}/#{node}.#{ext}") if !noop
785
+ end
786
+ }
787
+ end
788
+
789
+ # Allow a node access to a vault.
790
+ # @param host [String]:
791
+ # @param vault [String]:
792
+ # @param item [String]:
793
+ def self.grantSecretAccess(host, vault, item)
794
+ loadChefLib
795
+ MU::MommaCat.lock("vault-#{vault}", false, true)
796
+ MU.log "Granting #{host} access to #{vault} #{item}"
797
+ begin
798
+ ::Chef::Knife.run(['vault', 'update', vault, item, "--search", "name:#{host}"])
799
+ rescue Exception => e
800
+ MU.log e.inspect, MU::ERR, details: caller
801
+ end
802
+ MU::MommaCat.unlock("vault-#{vault}", true)
803
+ end
804
+
805
+ private
806
+
807
+ # Save common Mu attributes to this node's Chef node structure.
808
+ def saveChefMetadata
809
+ self.class.loadChefLib
810
+ nat_ssh_key, nat_ssh_user, nat_ssh_host, canonical_addr, ssh_user, ssh_key_name = @server.getSSHConfig
811
+ MU.log "Saving #{@server.mu_name} Chef artifacts"
812
+
813
+ begin
814
+ chef_node = ::Chef::Node.load(@server.mu_name)
815
+ rescue Net::HTTPServerException
816
+ raise MU::Groomer::RunError, "Couldn't load Chef node #{@server.mu_name}"
817
+ end
818
+
819
+ # Figure out what this node thinks its name is
820
+ system_name = chef_node['fqdn'] if !chef_node['fqdn'].nil?
821
+ MU.log "#{@server.mu_name} local name is #{system_name}", MU::DEBUG
822
+
823
+ chef_node.normal.app = @config['application_cookbook'] if !@config['application_cookbook'].nil?
824
+ chef_node.normal["service_name"] = @config["name"]
825
+ chef_node.normal["windows_admin_username"] = @config['windows_admin_username']
826
+ chef_node.chef_environment = MU.environment.downcase
827
+ if @server.config['cloud'] == "AWS"
828
+ chef_node.normal["ec2"] = MU.structToHash(@server.cloud_desc)
829
+ end
830
+
831
+ if @server.windows?
832
+ chef_node.normal['windows_admin_username'] = @config['windows_admin_username']
833
+ chef_node.normal['windows_auth_vault'] = @server.mu_name
834
+ chef_node.normal['windows_auth_item'] = "windows_credentials"
835
+ chef_node.normal['windows_auth_password_field'] = "password"
836
+ chef_node.normal['windows_auth_username_field'] = "username"
837
+ chef_node.normal['windows_ec2config_password_field'] = "ec2config_password"
838
+ chef_node.normal['windows_ec2config_username_field'] = "ec2config_username"
839
+ chef_node.normal['windows_sshd_password_field'] = "sshd_password"
840
+ chef_node.normal['windows_sshd_username_field'] = "sshd_username"
841
+ end
842
+
843
+ # If AD integration has been requested for this node, give Chef what it'll need.
844
+ if !@config['active_directory'].nil?
845
+ chef_node.normal['ad']['computer_name'] = @server.mu_windows_name
846
+ chef_node.normal['ad']['node_class'] = @config['name']
847
+ chef_node.normal['ad']['domain_name'] = @config['active_directory']['domain_name']
848
+ chef_node.normal['ad']['node_type'] = @config['active_directory']['node_type']
849
+ chef_node.normal['ad']['domain_operation'] = @config['active_directory']['domain_operation']
850
+ chef_node.normal['ad']['domain_controller_hostname'] = @config['active_directory']['domain_controller_hostname'] if @config['active_directory'].has_key?('domain_controller_hostname')
851
+ chef_node.normal['ad']['netbios_name'] = @config['active_directory']['short_domain_name']
852
+ chef_node.normal['ad']['computer_ou'] = @config['active_directory']['computer_ou'] if @config['active_directory'].has_key?('computer_ou')
853
+ chef_node.normal['ad']['domain_sid'] = @config['active_directory']['domain_sid'] if @config['active_directory'].has_key?('domain_sid')
854
+ chef_node.normal['ad']['dcs'] = @config['active_directory']['domain_controllers']
855
+ chef_node.normal['ad']['domain_join_vault'] = @config['active_directory']['domain_join_vault']['vault']
856
+ chef_node.normal['ad']['domain_join_item'] = @config['active_directory']['domain_join_vault']['item']
857
+ chef_node.normal['ad']['domain_join_username_field'] = @config['active_directory']['domain_join_vault']['username_field']
858
+ chef_node.normal['ad']['domain_join_password_field'] = @config['active_directory']['domain_join_vault']['password_field']
859
+ chef_node.normal['ad']['domain_admin_vault'] = @config['active_directory']['domain_admin_vault']['vault']
860
+ chef_node.normal['ad']['domain_admin_item'] = @config['active_directory']['domain_admin_vault']['item']
861
+ chef_node.normal['ad']['domain_admin_username_field'] = @config['active_directory']['domain_admin_vault']['username_field']
862
+ chef_node.normal['ad']['domain_admin_password_field'] = @config['active_directory']['domain_admin_vault']['password_field']
863
+ end
864
+
865
+ # Amazon-isms, possibly irrelevant
866
+ awscli_region_widget = {
867
+ "compile_time" => true,
868
+ "config_profiles" => {
869
+ "default" => {
870
+ "options" => {
871
+ "region" => @config['region']
872
+ }
873
+ }
874
+ }
875
+ }
876
+ chef_node.normal['awscli'] = awscli_region_widget
877
+
878
+ if !@server.cloud.nil?
879
+ chef_node.normal['cloudprovider'] = @server.cloud
880
+
881
+ # XXX In AWS this is an OpenStruct-ish thing, but it may not be in
882
+ # others.
883
+ chef_node.normal[@server.cloud.to_sym] = MU.structToHash(@server.cloud_desc)
884
+ end
885
+
886
+ tags = MU::MommaCat.listStandardTags
887
+ tags.merge!(MU::MommaCat.listOptionalTags) if @config['optional_tags']
888
+
889
+ if !@config['tags'].nil?
890
+ @config['tags'].each { |tag|
891
+ tags[tag['key']] = tag['value']
892
+ }
893
+ end
894
+
895
+ chef_node.normal['tags'] = tags
896
+ chef_node.save
897
+
898
+ # If we have a database make sure we grant access to that vault.
899
+ # In some cases the cached getLitter response will not have all the resources in the deploy, so lets not use the cache.
900
+ if @config.has_key?('dependencies')
901
+ deploy = MU::MommaCat.getLitter(MU.deploy_id, use_cache: false)
902
+ @config['dependencies'].each{ |dep|
903
+ if dep['type'] == "database" && deploy.deployment.has_key?("databases") && deploy.deployment["databases"].has_key?(dep['name'])
904
+ deploy.deployment["databases"][dep['name']].each { |name, database|
905
+ grantSecretAccess(database['vault_name'], database['vault_item']) if database.has_key?("vault_name") && database.has_key?("vault_item")
906
+ }
907
+ end
908
+ }
909
+ end
910
+
911
+ # Finally, grant us access to some pre-existing Vaults.
912
+ if !@config['vault_access'].nil?
913
+ @config['vault_access'].each { |vault|
914
+ grantSecretAccess(vault['vault'], vault['item'])
915
+ }
916
+ end
917
+ end
918
+
919
+ def grantSecretAccess(vault, item)
920
+ return if @secrets_granted["#{vault}:#{item}"] == item
921
+ self.class.grantSecretAccess(@server.mu_name, vault, item)
922
+ @secrets_granted["#{vault}:#{item}"] = item
923
+ end
924
+
925
+ def self.knifeCmd(cmd, showoutput = false)
926
+ MU.log "knife #{cmd}", MU::NOTICE if showoutput
927
+ output = `#{MU::Groomer::Chef.knife} #{cmd}`
928
+ exitstatus = $?.exitstatus
929
+
930
+ if showoutput
931
+ puts output
932
+ puts "Exit status: #{exitstatus}"
933
+ end
934
+ return [exitstatus, output]
935
+ end
936
+
937
+ def knifeCmd(cmd, showoutput = false)
938
+ self.class.knifeCmd(cmd, showoutput)
939
+ end
940
+
941
+ # Upload the certificate to a Chef Vault for this node
942
+ def stashHostSSLCertSecret
943
+ cert, key = @server.deploy.nodeSSLCerts(@server)
944
+ certdata = {
945
+ "data" => {
946
+ "node.crt" => cert.to_pem.chomp!.gsub(/\n/, "\\n"),
947
+ "node.key" => key.to_pem.chomp!.gsub(/\n/, "\\n")
948
+ }
949
+ }
950
+ saveSecret(item: "ssl_cert", data: certdata, permissions: nil)
951
+
952
+ saveSecret(item: "secrets", data: @config['secrets'], permissions: nil) if !@config['secrets'].nil?
953
+ certdata
954
+ end
955
+
956
+ # Add a role or recipe to a node. Optionally, throw a fit if it doesn't
957
+ # exist.
958
+ # @param rl_entry [String]: The run-list entry to add.
959
+ # @param type [String]: One of *role* or *recipe*.
960
+ # @param ignore_missing [Boolean]: If set to true, will merely warn about missing recipes/roles instead of throwing an exception.
961
+ # @param multiple [Array<String>]: Add more than one run_list entry. Overrides rl_entry.
962
+ # @return [void]
963
+ def knifeAddToRunList(rl_entry = nil, type="role", ignore_missing: false, multiple: [])
964
+ self.class.loadChefLib
965
+ return if rl_entry.nil? and multiple.size == 0
966
+ if multiple.size == 0
967
+ multiple = [rl_entry]
968
+ end
969
+ multiple.each { |rl_entry|
970
+ if !rl_entry.match(/^role|recipe\[/)
971
+ rl_entry = "#{type}[#{rl_entry}]"
972
+ end
973
+ }
974
+
975
+ if !ignore_missing
976
+ role_list = nil
977
+ recipe_list = nil
978
+ missing = false
979
+ multiple.each { |rl_entry|
980
+ # Rather than argue about whether to expect a bare rl_entry name or
981
+ # require rl_entry[rolename], let's just accomodate.
982
+ if rl_entry.match(/^role\[(.+?)\]/)
983
+ rl_entry_name = Regexp.last_match(1)
984
+ if role_list.nil?
985
+ query=%Q{#{MU::Groomer::Chef.knife} role list};
986
+ role_list = %x{#{query}}
987
+ end
988
+ if !role_list.match(/(^|\n)#{rl_entry_name}($|\n)/)
989
+ MU.log "Attempting to add non-existent #{rl_entry} to #{@server.mu_name}", MU::WARN
990
+ missing = true
991
+ end
992
+ elsif rl_entry.match(/^recipe\[(.+?)\]/)
993
+ rl_entry_name = Regexp.last_match(1)
994
+ if recipe_list.nil?
995
+ query=%Q{#{MU::Groomer::Chef.knife} recipe list};
996
+ recipe_list = %x{#{query}}
997
+ end
998
+ if !recipe_list.match(/(^|\n)#{rl_entry_name}($|\n)/)
999
+ MU.log "Attempting to add non-existent #{rl_entry} to #{@server.mu_name}", MU::WARN
1000
+ missing = true
1001
+ end
1002
+ end
1003
+
1004
+ if missing and !ignore_missing
1005
+ raise MuError, "Can't continue with missing roles/recipes for #{@server.mu_name}"
1006
+ end
1007
+ }
1008
+ end
1009
+
1010
+ rl_string = multiple.join(",")
1011
+ begin
1012
+ query=%Q{#{MU::Groomer::Chef.knife} node run_list add #{@server.mu_name} "#{rl_string}"};
1013
+ MU.log("Adding #{rl_string} to Chef run_list of #{@server.mu_name}")
1014
+ MU.log("Running #{query}", MU::DEBUG)
1015
+ output=%x{#{query}}
1016
+ # XXX rescue Exception is bad style
1017
+ rescue Exception => e
1018
+ raise MuError, "FAIL: #{MU::Groomer::Chef.knife} node run_list add #{@server.mu_name} \"#{rl_string}\": #{e.message} (output was #{output})"
1019
+ end
1020
+ end
1021
+
1022
+ end # class Chef
1023
+ end # class Groomer
1024
+ end # Module Mu