cloud-mu 3.5.0 → 3.6.3

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 (245) hide show
  1. checksums.yaml +4 -4
  2. data/Berksfile +5 -2
  3. data/Berksfile.lock +135 -0
  4. data/ansible/roles/mu-base/README.md +33 -0
  5. data/ansible/roles/mu-base/defaults/main.yml +2 -0
  6. data/ansible/roles/mu-base/files/check_apm.cfg +1 -0
  7. data/ansible/roles/mu-base/files/check_apm.sh +18 -0
  8. data/ansible/roles/mu-base/files/check_disk.cfg +1 -0
  9. data/ansible/roles/mu-base/files/check_elastic_shards.cfg +1 -0
  10. data/ansible/roles/mu-base/files/check_elastic_shards.sh +12 -0
  11. data/ansible/roles/mu-base/files/check_logstash.cfg +1 -0
  12. data/ansible/roles/mu-base/files/check_logstash.sh +14 -0
  13. data/ansible/roles/mu-base/files/check_mem.cfg +1 -0
  14. data/ansible/roles/mu-base/files/check_updates.cfg +1 -0
  15. data/ansible/roles/mu-base/files/logrotate.conf +35 -0
  16. data/ansible/roles/mu-base/files/nrpe-apm-sudo +1 -0
  17. data/ansible/roles/mu-base/files/nrpe-elasticshards-sudo +2 -0
  18. data/ansible/roles/mu-base/handlers/main.yml +5 -0
  19. data/ansible/roles/mu-base/meta/main.yml +53 -0
  20. data/ansible/roles/mu-base/tasks/main.yml +113 -0
  21. data/ansible/roles/mu-base/templates/nrpe.cfg.j2 +231 -0
  22. data/ansible/roles/mu-base/tests/inventory +2 -0
  23. data/ansible/roles/mu-base/tests/test.yml +5 -0
  24. data/ansible/roles/mu-base/vars/main.yml +1 -0
  25. data/ansible/roles/mu-compliance/README.md +33 -0
  26. data/ansible/roles/mu-compliance/defaults/main.yml +2 -0
  27. data/ansible/roles/mu-compliance/files/U_MS_Windows_Server_2016_V2R1_STIG_SCAP_1-2_Benchmark.xml +15674 -0
  28. data/ansible/roles/mu-compliance/files/U_MS_Windows_Server_2019_V2R1_STIG_SCAP_1-2_Benchmark.xml +17553 -0
  29. data/ansible/roles/mu-compliance/handlers/main.yml +2 -0
  30. data/ansible/roles/mu-compliance/meta/main.yml +53 -0
  31. data/ansible/roles/mu-compliance/tasks/main.yml +45 -0
  32. data/ansible/roles/mu-compliance/tests/inventory +2 -0
  33. data/ansible/roles/mu-compliance/tests/test.yml +5 -0
  34. data/ansible/roles/mu-compliance/vars/main.yml +4 -0
  35. data/ansible/roles/mu-elastic/README.md +51 -0
  36. data/ansible/roles/mu-elastic/defaults/main.yml +2 -0
  37. data/ansible/roles/mu-elastic/files/jvm.options +93 -0
  38. data/ansible/roles/mu-elastic/handlers/main.yml +10 -0
  39. data/ansible/roles/mu-elastic/meta/main.yml +52 -0
  40. data/ansible/roles/mu-elastic/tasks/main.yml +186 -0
  41. data/ansible/roles/mu-elastic/templates/elasticsearch.yml.j2 +110 -0
  42. data/ansible/roles/mu-elastic/templates/kibana.yml.j2 +131 -0
  43. data/ansible/roles/mu-elastic/templates/password_set.expect.j2 +19 -0
  44. data/ansible/roles/mu-elastic/tests/inventory +2 -0
  45. data/ansible/roles/mu-elastic/tests/test.yml +5 -0
  46. data/ansible/roles/mu-elastic/vars/main.yml +2 -0
  47. data/ansible/roles/mu-logstash/README.md +51 -0
  48. data/ansible/roles/mu-logstash/defaults/main.yml +2 -0
  49. data/ansible/roles/mu-logstash/files/02-beats-input.conf +5 -0
  50. data/ansible/roles/mu-logstash/files/10-rails-filter.conf +16 -0
  51. data/ansible/roles/mu-logstash/files/jvm.options +84 -0
  52. data/ansible/roles/mu-logstash/files/logstash.yml +304 -0
  53. data/ansible/roles/mu-logstash/handlers/main.yml +20 -0
  54. data/ansible/roles/mu-logstash/meta/main.yml +52 -0
  55. data/ansible/roles/mu-logstash/tasks/main.yml +254 -0
  56. data/ansible/roles/mu-logstash/templates/20-cloudtrail.conf.j2 +28 -0
  57. data/ansible/roles/mu-logstash/templates/30-elasticsearch-output.conf.j2 +19 -0
  58. data/ansible/roles/mu-logstash/templates/apm-server.yml.j2 +33 -0
  59. data/ansible/roles/mu-logstash/templates/heartbeat.yml.j2 +29 -0
  60. data/ansible/roles/mu-logstash/templates/nginx/apm.conf.j2 +25 -0
  61. data/ansible/roles/mu-logstash/templates/nginx/default.conf.j2 +56 -0
  62. data/ansible/roles/mu-logstash/templates/nginx/elastic.conf.j2 +27 -0
  63. data/ansible/roles/mu-logstash/tests/inventory +2 -0
  64. data/ansible/roles/mu-logstash/tests/test.yml +5 -0
  65. data/ansible/roles/mu-logstash/vars/main.yml +2 -0
  66. data/ansible/roles/mu-rdp/README.md +33 -0
  67. data/ansible/roles/mu-rdp/meta/main.yml +53 -0
  68. data/ansible/roles/mu-rdp/tasks/main.yml +9 -0
  69. data/ansible/roles/mu-rdp/tests/inventory +2 -0
  70. data/ansible/roles/mu-rdp/tests/test.yml +5 -0
  71. data/ansible/roles/mu-windows/tasks/main.yml +3 -0
  72. data/bin/mu-ansible-secret +1 -1
  73. data/bin/mu-aws-setup +4 -3
  74. data/bin/mu-azure-setup +5 -5
  75. data/bin/mu-configure +25 -17
  76. data/bin/mu-firewall-allow-clients +1 -0
  77. data/bin/mu-gcp-setup +3 -3
  78. data/bin/mu-load-config.rb +1 -0
  79. data/bin/mu-node-manage +66 -33
  80. data/bin/mu-self-update +2 -2
  81. data/bin/mu-upload-chef-artifacts +6 -1
  82. data/bin/mu-user-manage +1 -1
  83. data/cloud-mu.gemspec +25 -23
  84. data/cookbooks/firewall/CHANGELOG.md +417 -224
  85. data/cookbooks/firewall/LICENSE +202 -0
  86. data/cookbooks/firewall/README.md +153 -126
  87. data/cookbooks/firewall/TODO.md +6 -0
  88. data/cookbooks/firewall/attributes/firewalld.rb +7 -0
  89. data/cookbooks/firewall/attributes/iptables.rb +3 -3
  90. data/cookbooks/firewall/chefignore +115 -0
  91. data/cookbooks/firewall/libraries/helpers.rb +5 -0
  92. data/cookbooks/firewall/libraries/helpers_firewalld.rb +1 -1
  93. data/cookbooks/firewall/libraries/helpers_firewalld_dbus.rb +72 -0
  94. data/cookbooks/firewall/libraries/helpers_iptables.rb +3 -3
  95. data/cookbooks/firewall/libraries/helpers_nftables.rb +170 -0
  96. data/cookbooks/firewall/libraries/helpers_ufw.rb +7 -0
  97. data/cookbooks/firewall/libraries/helpers_windows.rb +8 -9
  98. data/cookbooks/firewall/libraries/provider_firewall_firewalld.rb +9 -9
  99. data/cookbooks/firewall/libraries/provider_firewall_iptables.rb +7 -7
  100. data/cookbooks/firewall/libraries/provider_firewall_iptables_ubuntu.rb +12 -8
  101. data/cookbooks/firewall/libraries/provider_firewall_iptables_ubuntu1404.rb +13 -9
  102. data/cookbooks/firewall/libraries/provider_firewall_rule.rb +1 -1
  103. data/cookbooks/firewall/libraries/provider_firewall_ufw.rb +5 -5
  104. data/cookbooks/firewall/libraries/provider_firewall_windows.rb +4 -4
  105. data/cookbooks/firewall/libraries/resource_firewall_rule.rb +3 -3
  106. data/cookbooks/firewall/metadata.json +40 -1
  107. data/cookbooks/firewall/metadata.rb +15 -0
  108. data/cookbooks/firewall/recipes/default.rb +7 -7
  109. data/cookbooks/firewall/recipes/disable_firewall.rb +1 -1
  110. data/cookbooks/firewall/recipes/firewalld.rb +87 -0
  111. data/cookbooks/firewall/renovate.json +18 -0
  112. data/cookbooks/firewall/resources/firewalld.rb +28 -0
  113. data/cookbooks/firewall/resources/firewalld_config.rb +39 -0
  114. data/cookbooks/firewall/resources/firewalld_helpers.rb +106 -0
  115. data/cookbooks/firewall/resources/firewalld_icmptype.rb +88 -0
  116. data/cookbooks/firewall/resources/firewalld_ipset.rb +104 -0
  117. data/cookbooks/firewall/resources/firewalld_policy.rb +115 -0
  118. data/cookbooks/firewall/resources/firewalld_service.rb +98 -0
  119. data/cookbooks/firewall/resources/firewalld_zone.rb +118 -0
  120. data/cookbooks/firewall/resources/nftables.rb +71 -0
  121. data/cookbooks/firewall/resources/nftables_rule.rb +113 -0
  122. data/cookbooks/mu-activedirectory/Berksfile +1 -1
  123. data/cookbooks/mu-activedirectory/metadata.rb +1 -1
  124. data/cookbooks/mu-firewall/metadata.rb +2 -2
  125. data/cookbooks/mu-master/Berksfile +4 -3
  126. data/cookbooks/mu-master/attributes/default.rb +5 -2
  127. data/cookbooks/mu-master/files/default/check_elastic.sh +761 -0
  128. data/cookbooks/mu-master/files/default/check_kibana.rb +45 -0
  129. data/cookbooks/mu-master/libraries/mu.rb +24 -0
  130. data/cookbooks/mu-master/metadata.rb +5 -5
  131. data/cookbooks/mu-master/recipes/default.rb +31 -20
  132. data/cookbooks/mu-master/recipes/firewall-holes.rb +5 -0
  133. data/cookbooks/mu-master/recipes/init.rb +58 -19
  134. data/cookbooks/mu-master/recipes/update_nagios_only.rb +251 -178
  135. data/cookbooks/mu-master/templates/default/nagios.conf.erb +5 -11
  136. data/cookbooks/mu-master/templates/default/web_app.conf.erb +3 -0
  137. data/cookbooks/mu-php54/Berksfile +1 -1
  138. data/cookbooks/mu-php54/metadata.rb +2 -2
  139. data/cookbooks/mu-tools/Berksfile +2 -3
  140. data/cookbooks/mu-tools/attributes/default.rb +3 -4
  141. data/cookbooks/mu-tools/files/amazon/etc/bashrc +90 -0
  142. data/cookbooks/mu-tools/files/amazon/etc/login.defs +292 -0
  143. data/cookbooks/mu-tools/files/amazon/etc/profile +77 -0
  144. data/cookbooks/mu-tools/files/amazon/etc/security/limits.conf +63 -0
  145. data/cookbooks/mu-tools/files/amazon/etc/sysconfig/init +19 -0
  146. data/cookbooks/mu-tools/files/amazon/etc/sysctl.conf +82 -0
  147. data/cookbooks/mu-tools/files/amazon-2023/etc/login.defs +294 -0
  148. data/cookbooks/mu-tools/files/default/logrotate.conf +35 -0
  149. data/cookbooks/mu-tools/files/default/nrpe_conf_d.pp +0 -0
  150. data/cookbooks/mu-tools/libraries/helper.rb +21 -9
  151. data/cookbooks/mu-tools/metadata.rb +4 -4
  152. data/cookbooks/mu-tools/recipes/apply_security.rb +3 -2
  153. data/cookbooks/mu-tools/recipes/aws_api.rb +23 -5
  154. data/cookbooks/mu-tools/recipes/base_repositories.rb +4 -1
  155. data/cookbooks/mu-tools/recipes/gcloud.rb +56 -56
  156. data/cookbooks/mu-tools/recipes/nagios.rb +1 -1
  157. data/cookbooks/mu-tools/recipes/nrpe.rb +20 -2
  158. data/cookbooks/mu-tools/recipes/rsyslog.rb +12 -1
  159. data/cookbooks/mu-tools/recipes/set_local_fw.rb +1 -1
  160. data/data_bags/nagios_services/apm_backend_connect.json +5 -0
  161. data/data_bags/nagios_services/apm_listen.json +5 -0
  162. data/data_bags/nagios_services/elastic_shards.json +5 -0
  163. data/data_bags/nagios_services/logstash.json +5 -0
  164. data/data_bags/nagios_services/rhel7_updates.json +8 -0
  165. data/extras/image-generators/AWS/centos7.yaml +1 -0
  166. data/extras/image-generators/AWS/rhel7.yaml +21 -0
  167. data/extras/image-generators/AWS/win2k12r2.yaml +1 -0
  168. data/extras/image-generators/AWS/win2k16.yaml +1 -0
  169. data/extras/image-generators/AWS/win2k19.yaml +1 -0
  170. data/extras/list-stock-amis +0 -0
  171. data/extras/ruby_rpm/muby.spec +8 -5
  172. data/extras/vault_tools/export_vaults.sh +1 -1
  173. data/extras/vault_tools/recreate_vaults.sh +0 -0
  174. data/extras/vault_tools/test_vaults.sh +0 -0
  175. data/install/deprecated-bash-library.sh +1 -1
  176. data/install/installer +4 -2
  177. data/modules/mommacat.ru +3 -1
  178. data/modules/mu/adoption.rb +1 -1
  179. data/modules/mu/cloud/dnszone.rb +2 -2
  180. data/modules/mu/cloud/machine_images.rb +26 -25
  181. data/modules/mu/cloud/resource_base.rb +213 -182
  182. data/modules/mu/cloud/server_pool.rb +1 -1
  183. data/modules/mu/cloud/ssh_sessions.rb +7 -5
  184. data/modules/mu/cloud/wrappers.rb +2 -2
  185. data/modules/mu/cloud.rb +1 -1
  186. data/modules/mu/config/bucket.rb +1 -1
  187. data/modules/mu/config/function.rb +6 -1
  188. data/modules/mu/config/loadbalancer.rb +24 -2
  189. data/modules/mu/config/ref.rb +12 -0
  190. data/modules/mu/config/role.rb +1 -1
  191. data/modules/mu/config/schema_helpers.rb +42 -9
  192. data/modules/mu/config/server.rb +43 -27
  193. data/modules/mu/config/tail.rb +19 -10
  194. data/modules/mu/config.rb +6 -5
  195. data/modules/mu/defaults/AWS.yaml +78 -114
  196. data/modules/mu/deploy.rb +9 -2
  197. data/modules/mu/groomer.rb +12 -4
  198. data/modules/mu/groomers/ansible.rb +104 -20
  199. data/modules/mu/groomers/chef.rb +15 -6
  200. data/modules/mu/master.rb +9 -4
  201. data/modules/mu/mommacat/daemon.rb +4 -2
  202. data/modules/mu/mommacat/naming.rb +1 -2
  203. data/modules/mu/mommacat/storage.rb +7 -2
  204. data/modules/mu/mommacat.rb +33 -6
  205. data/modules/mu/providers/aws/database.rb +161 -8
  206. data/modules/mu/providers/aws/dnszone.rb +11 -6
  207. data/modules/mu/providers/aws/endpoint.rb +81 -6
  208. data/modules/mu/providers/aws/firewall_rule.rb +254 -172
  209. data/modules/mu/providers/aws/function.rb +65 -3
  210. data/modules/mu/providers/aws/loadbalancer.rb +39 -28
  211. data/modules/mu/providers/aws/log.rb +2 -1
  212. data/modules/mu/providers/aws/role.rb +25 -7
  213. data/modules/mu/providers/aws/server.rb +36 -12
  214. data/modules/mu/providers/aws/server_pool.rb +237 -127
  215. data/modules/mu/providers/aws/storage_pool.rb +7 -1
  216. data/modules/mu/providers/aws/user.rb +1 -1
  217. data/modules/mu/providers/aws/userdata/linux.erb +6 -2
  218. data/modules/mu/providers/aws/userdata/windows.erb +7 -5
  219. data/modules/mu/providers/aws/vpc.rb +49 -25
  220. data/modules/mu/providers/aws.rb +13 -8
  221. data/modules/mu/providers/azure/container_cluster.rb +1 -1
  222. data/modules/mu/providers/azure/loadbalancer.rb +2 -2
  223. data/modules/mu/providers/azure/server.rb +5 -2
  224. data/modules/mu/providers/azure/userdata/linux.erb +1 -1
  225. data/modules/mu/providers/azure.rb +11 -8
  226. data/modules/mu/providers/cloudformation/dnszone.rb +1 -1
  227. data/modules/mu/providers/google/container_cluster.rb +15 -2
  228. data/modules/mu/providers/google/folder.rb +2 -1
  229. data/modules/mu/providers/google/function.rb +130 -4
  230. data/modules/mu/providers/google/habitat.rb +2 -1
  231. data/modules/mu/providers/google/loadbalancer.rb +407 -160
  232. data/modules/mu/providers/google/role.rb +16 -3
  233. data/modules/mu/providers/google/server.rb +5 -1
  234. data/modules/mu/providers/google/user.rb +25 -18
  235. data/modules/mu/providers/google/userdata/linux.erb +1 -1
  236. data/modules/mu/providers/google/vpc.rb +53 -7
  237. data/modules/mu/providers/google.rb +39 -39
  238. data/modules/mu.rb +8 -8
  239. data/modules/tests/elk.yaml +46 -0
  240. data/test/mu-master-test/controls/all_in_one.rb +1 -1
  241. metadata +207 -112
  242. data/cookbooks/firewall/CONTRIBUTING.md +0 -2
  243. data/cookbooks/firewall/MAINTAINERS.md +0 -19
  244. data/cookbooks/firewall/libraries/matchers.rb +0 -30
  245. data/extras/image-generators/AWS/rhel71.yaml +0 -17
@@ -19,6 +19,7 @@ module MU
19
19
  class Groomer
20
20
  # Support for Ansible as a host configuration management layer.
21
21
  class Ansible
22
+ require 'open3'
22
23
 
23
24
  # Failure to load or create a deploy
24
25
  class NoAnsibleExecError < MuError;
@@ -77,7 +78,7 @@ module MU
77
78
  # @param data [Hash]: Data to save
78
79
  # @param permissions [Boolean]: If true, save the secret under the current active deploy (if any), rather than in the global location for this user
79
80
  # @param deploy_dir [String]: If permissions is +true+, save the secret here
80
- def self.saveSecret(vault: nil, item: nil, data: nil, permissions: false, deploy_dir: nil)
81
+ def self.saveSecret(vault: nil, item: nil, data: nil, permissions: false, deploy_dir: nil, quiet: false)
81
82
 
82
83
  if vault.nil? or vault.empty? or item.nil? or item.empty?
83
84
  raise MuError, "Must call saveSecret with vault and item names"
@@ -86,6 +87,7 @@ module MU
86
87
  raise MuError, "Ansible vault/item names cannot include forward slashes"
87
88
  end
88
89
  pwfile = vaultPasswordFile
90
+ vault_cmd = %Q{#{ansibleExecDir}/ansible-vault}
89
91
 
90
92
  dir = if permissions
91
93
  if deploy_dir
@@ -104,7 +106,7 @@ module MU
104
106
  FileUtils.mkdir_p(dir, mode: 0700)
105
107
  end
106
108
 
107
- if File.exist?(path)
109
+ if File.exist?(path) and !quiet
108
110
  MU.log "Overwriting existing vault #{vault} item #{item}"
109
111
  end
110
112
 
@@ -112,14 +114,36 @@ module MU
112
114
  f.write data.to_yaml
113
115
  }
114
116
 
115
- cmd = %Q{#{ansibleExecDir}/ansible-vault encrypt #{path} --vault-password-file #{pwfile}}
116
- MU.log cmd
117
+ cmd = %Q{#{vault_cmd} encrypt #{path} --vault-password-file #{pwfile}}
118
+ MU.log cmd if !quiet
117
119
  raise MuError, "Failed Ansible command: #{cmd}" if !system(cmd)
120
+
121
+ # If we're stashing things under a deploy, go ahead and munge them into
122
+ # variables that actual Ansible tasks can get at
123
+ if permissions
124
+ encrypted_string = File.read(path).chomp
125
+ dir = (deploy_dir ? deploy_dir : MU.mommacat.deploy_dir)+"/ansible"
126
+ FileUtils.mkdir_p(dir, mode: 0700) if !Dir.exist?(dir)
127
+ FileUtils.mkdir_p(dir+"/vars", mode: 0700) if !Dir.exist?(dir+"/vars")
128
+ vars_file = "#{dir}/vars/#{vault}.yml"
129
+
130
+ vars = if File.exist?(vars_file)
131
+ YAML.load(File.read(vars_file))
132
+ else
133
+ {}
134
+ end
135
+ vars[item] = encrypted_string
136
+ File.open(vars_file, File::CREAT|File::RDWR|File::TRUNC, 0600) { |f|
137
+ f.flock(File::LOCK_EX)
138
+ f.puts vars.to_yaml
139
+ f.flock(File::LOCK_UN)
140
+ }
141
+ end
118
142
  end
119
143
 
120
144
  # see {MU::Groomer::Ansible.saveSecret}
121
- def saveSecret(vault: @server.mu_name, item: nil, data: nil, permissions: true)
122
- self.class.saveSecret(vault: vault, item: item, data: data, permissions: permissions, deploy_dir: @server.deploy.deploy_dir)
145
+ def saveSecret(vault: @server.mu_name, item: nil, data: nil, permissions: true, quiet: false)
146
+ self.class.saveSecret(vault: vault, item: item, data: data, permissions: permissions, deploy_dir: @server.deploy.deploy_dir, quiet: quiet)
123
147
  end
124
148
 
125
149
  # Retrieve sensitive data, which hopefully we're storing and retrieving
@@ -128,7 +152,7 @@ module MU
128
152
  # @param item [String]: The item within the repository to retrieve
129
153
  # @param field [String]: OPTIONAL - A specific field within the item to return.
130
154
  # @return [Hash]
131
- def self.getSecret(vault: nil, item: nil, field: nil, deploy_dir: nil)
155
+ def self.getSecret(vault: nil, item: nil, field: nil, deploy_dir: nil, quiet: false, cmd_only: false)
132
156
  if vault.nil? or vault.empty?
133
157
  raise MuError, "Must call getSecret with at least a vault name"
134
158
  end
@@ -137,7 +161,7 @@ module MU
137
161
  dir = nil
138
162
  try = [secret_dir+"/"+vault]
139
163
  try << deploy_dir+"/ansible/vaults/"+vault if deploy_dir
140
- try << MU.mommacat.deploy_dir+"/ansible/vaults/"+vault if MU.mommacat.deploy_dir
164
+ try << MU.mommacat.deploy_dir+"/ansible/vaults/"+vault if MU.mommacat and MU.mommacat.deploy_dir
141
165
  try.each { |maybe_dir|
142
166
  if Dir.exist?(maybe_dir) and (item.nil? or File.exist?(maybe_dir+"/"+item))
143
167
  dir = maybe_dir
@@ -155,7 +179,8 @@ module MU
155
179
  raise MuNoSuchSecret, "No such item #{item} in vault #{vault}"
156
180
  end
157
181
  cmd = %Q{#{ansibleExecDir}/ansible-vault view #{itempath} --vault-password-file #{pwfile}}
158
- MU.log cmd
182
+ return cmd if cmd_only
183
+ MU.log cmd if !quiet
159
184
  a = `#{cmd}`
160
185
  # If we happen to have stored recognizeable JSON or YAML, return it
161
186
  # as parsed, which is a behavior we're used to from Chef vault.
@@ -187,8 +212,8 @@ module MU
187
212
  end
188
213
 
189
214
  # see {MU::Groomer::Ansible.getSecret}
190
- def getSecret(vault: nil, item: nil, field: nil)
191
- self.class.getSecret(vault: vault, item: item, field: field, deploy_dir: @server.deploy.deploy_dir)
215
+ def getSecret(vault: @server.mu_name, item: nil, field: nil, quiet: false, cmd_only: false)
216
+ self.class.getSecret(vault: vault, item: item, field: field, deploy_dir: @server.deploy.deploy_dir, quiet: quiet, cmd_only: cmd_only)
192
217
  end
193
218
 
194
219
  # Delete a Ansible data bag / Vault
@@ -259,6 +284,16 @@ module MU
259
284
 
260
285
  cmd = %Q{cd #{@ansible_path} && echo "#{purpose}" && #{@ansible_execs}/ansible-playbook -i hosts #{playbook} --limit=#{@server.windows? ? @server.canonicalIP : @server.mu_name} --vault-password-file #{pwfile} --timeout=30 --vault-password-file #{@ansible_path}/.vault_pw -u #{ssh_user}}
261
286
 
287
+ if @server.config['vault_access']
288
+ @server.config['vault_access'].each { |entry|
289
+ vault = entry['vault'] || @server.deploy.deploy_id
290
+ begin
291
+ MU.log "To retrieve secret #{vault}:#{entry['item']} - "+getSecret(vault: vault, item: entry['item'], cmd_only: true), MU::SUMMARY
292
+ rescue MuNoSuchSecret
293
+ end
294
+ }
295
+ end
296
+
262
297
  retries = 0
263
298
  begin
264
299
  MU.log cmd
@@ -315,8 +350,13 @@ module MU
315
350
  play["become"] = "yes"
316
351
  end
317
352
 
318
- if @server.config['run_list'] and !@server.config['run_list'].empty?
319
- play["roles"] = @server.config['run_list']
353
+ if @server.windows?
354
+ play["roles"] = ["mu-windows"]
355
+ else
356
+ play["roles"] = ["mu-base"]
357
+ end
358
+ if @server.config['run_list']
359
+ play["roles"].concat(@server.config['run_list'])
320
360
  end
321
361
 
322
362
  if @server.config['ansible_vars']
@@ -326,6 +366,7 @@ module MU
326
366
  if @server.windows?
327
367
  play["vars"] ||= {}
328
368
  play["vars"]["ansible_connection"] = "winrm"
369
+ play["vars"]['ansible_python_interpreter'] = "c:/bin/python/python310/python.exe"
329
370
  play["vars"]["ansible_winrm_scheme"] = "https"
330
371
  play["vars"]["ansible_winrm_transport"] = "ntlm"
331
372
  play["vars"]["ansible_winrm_server_cert_validation"] = "ignore" # XXX this sucks; use Mu_CA.pem if we can get it to work
@@ -355,18 +396,43 @@ module MU
355
396
  allvars = {
356
397
  "mu_deployment" => MU::Config.stripConfig(@server.deploy.deployment),
357
398
  "mu_service_name" => @config["name"],
399
+ "mu_name" => @server.mu_name,
400
+ "mu_deploy_id" => @server.deploy.deploy_id,
358
401
  "mu_canonical_ip" => @server.canonicalIP,
359
402
  "mu_admin_email" => $MU_CFG['mu_admin_email'],
360
- "mu_environment" => MU.environment.downcase
403
+ "mu_environment" => MU.environment.downcase,
404
+ "mu_vaults" => {}
361
405
  }
362
406
  allvars['mu_deployment']['ssh_public_key'] = @server.deploy.ssh_public_key
363
407
 
408
+ vaultdir = @ansible_path+"/vaults"
409
+ if Dir.exist?(vaultdir)
410
+ Dir.entries(vaultdir).each { |v|
411
+ next if !File.directory?(vaultdir+"/"+v)
412
+ next if [".", ".."].include?(v)
413
+ Dir.entries(vaultdir+"/"+v).each { |i|
414
+ next if File.directory?(vaultdir+"/"+v+"/"+i)
415
+ value = getSecret(vault: v, item: i, quiet: true)
416
+ next if !value # ignore corrupted data
417
+
418
+ # Ansible struggles to actually use this. The only thing that
419
+ # seems to work is writing it (decrypted) to a tmp file on the
420
+ # target host then reading that back, which is both ugly and
421
+ # insecure. None of these workarounds seem to do the thing:
422
+ # https://github.com/ansible/ansible/issues/24425
423
+ allvars["mu_vaults"][v] ||= {}
424
+ allvars["mu_vaults"][v].merge!(YAML.load(self.class.encryptString(value.to_yaml, i)))
425
+ }
426
+ }
427
+ end
428
+
364
429
  if @server.config['cloud'] == "AWS"
365
430
  allvars["ec2"] = MU.structToHash(@server.cloud_desc, stringify_keys: true)
366
431
  end
367
432
 
368
433
  if @server.windows?
369
434
  allvars['windows_admin_username'] = @config['windows_admin_username']
435
+ allvars['ansible_python_interpreter'] = "c:/bin/python/python310/python.exe"
370
436
  end
371
437
 
372
438
  if !@server.cloud.nil?
@@ -380,6 +446,9 @@ module MU
380
446
  }
381
447
 
382
448
  groupvars = allvars.dup
449
+ if @server.windows? and @server.mu_windows_name
450
+ groupvars['mu_windows_name'] = @server.mu_windows_name
451
+ end
383
452
  if @server.deploy.original_config.has_key?('parameters')
384
453
  groupvars["mu_parameters"] = @server.deploy.original_config['parameters']
385
454
  end
@@ -433,17 +502,23 @@ module MU
433
502
  found
434
503
  end
435
504
 
436
- # Encrypt a string using +ansible-vault encrypt_string+ and print the
437
- # the results to +STDOUT+.
438
- # @param name [String]: The variable name to use for the string's YAML key
505
+ # Encrypt a string using +ansible-vault encrypt_string+ and return +STDOUT+
439
506
  # @param string [String]: The string to encrypt
440
- def self.encryptString(name, string)
507
+ # @param name [String]: A name to use for the string's YAML key
508
+ def self.encryptString(string, name = nil)
441
509
  pwfile = vaultPasswordFile
442
510
  cmd = %Q{#{ansibleExecDir}/ansible-vault}
443
- if !system(cmd, "encrypt_string", string, "--name", name, "--vault-password-file", pwfile)
511
+
512
+ stdout, status = if name
513
+ Open3.capture2(cmd, "encrypt_string", string, "--name", name, "--vault-password-file", pwfile)
514
+ else
515
+ Open3.capture2(cmd, "encrypt_string", string, "--vault-password-file", pwfile)
516
+ end
517
+
518
+ if !status.success?
444
519
  raise MuError, "Failed Ansible command: #{cmd} encrypt_string <redacted> --name #{name} --vault-password-file"
445
520
  end
446
- output
521
+ stdout.strip
447
522
  end
448
523
 
449
524
  # Hunt down and return a path for a Python executable
@@ -630,6 +705,14 @@ module MU
630
705
  File.symlink(MU.myRoot+"/ansible/roles/"+role, roledir+"/"+role)
631
706
  }
632
707
 
708
+ coldir = "#{Etc.getpwuid(Process.uid).dir}/.ansible/collections/ansible_collections"
709
+ ["ansible.windows", "community.general.gem"].each { |coll|
710
+ %x{#{@ansible_execs}/ansible-galaxy collection list -p "#{coldir}"}
711
+ if $? != 0
712
+ system(%Q{#{@ansible_execs}/ansible-galaxy}, "collection", "install", coll, "-p", coldir)
713
+ end
714
+ }
715
+
633
716
  if @server.config['run_list']
634
717
  @server.config['run_list'].each { |role|
635
718
  found = false
@@ -655,6 +738,7 @@ module MU
655
738
  end
656
739
  }
657
740
  end
741
+
658
742
  end
659
743
 
660
744
  # Upload the certificate to a Chef Vault for this node
@@ -58,6 +58,9 @@ module MU
58
58
  require 'chef/knife/ssh'
59
59
  require 'mu/monkey_patches/chef_knife_ssh'
60
60
  require 'chef/knife/bootstrap'
61
+ require 'chef/knife/bootstrap/train_connector'
62
+ require 'chef/knife/bootstrap/chef_vault_handler'
63
+ require 'chef/knife/bootstrap/client_builder'
61
64
  require 'chef/knife/node_delete'
62
65
  require 'chef/knife/client_delete'
63
66
  require 'chef/knife/data_bag_delete'
@@ -96,11 +99,11 @@ module MU
96
99
  }
97
100
  end
98
101
 
99
- @knife = "cd #{MU.myRoot} && env -i HOME=#{Etc.getpwnam(MU.mu_user).dir} PATH=/opt/chef/embedded/bin:/usr/bin:/usr/sbin knife"
102
+ @@knife = "cd #{MU.myRoot} && env -i HOME=#{Etc.getpwnam(MU.mu_user).dir} PATH=/usr/local/ruby-current/bin:/opt/chef/embedded/bin:/usr/bin:/usr/sbin knife"
100
103
  # The canonical path to invoke Chef's *knife* utility with a clean environment.
101
104
  # @return [String]
102
- def self.knife;
103
- @knife;
105
+ def self.knife
106
+ @@knife
104
107
  end
105
108
 
106
109
  attr_reader :knife
@@ -218,7 +221,7 @@ module MU
218
221
  end
219
222
 
220
223
  # see {MU::Groomer::Chef.getSecret}
221
- def getSecret(vault: nil, item: nil, field: nil)
224
+ def getSecret(vault: @server.mu_name, item: nil, field: nil)
222
225
  self.class.getSecret(vault: vault, item: item, field: field)
223
226
  end
224
227
 
@@ -618,8 +621,10 @@ module MU
618
621
  kb.name_args = "#{canonical_addr}"
619
622
  kb.config[:distro] = 'chef-full'
620
623
  kb.config[:ssh_user] = ssh_user
624
+ kb.config[:ssh_verify_host_key] = :accept_new
621
625
  kb.config[:forward_agent] = ssh_user
622
626
  kb.config[:identity_file] = "#{Etc.getpwuid(Process.uid).dir}/.ssh/#{ssh_key_name}"
627
+ kb.config[:ssh_identity_file] = "#{Etc.getpwuid(Process.uid).dir}/.ssh/#{ssh_key_name}"
623
628
  else
624
629
  kb = ::Chef::Knife::BootstrapWindowsWinrm.new([@server.mu_name])
625
630
  kb.name_args = [@server.mu_name]
@@ -628,6 +633,7 @@ module MU
628
633
  kb.config[:winrm_port] = 5986
629
634
  kb.config[:session_timeout] = timeout
630
635
  kb.config[:operation_timeout] = timeout
636
+ # kb.config[:bootstrap_curl_options] = ""
631
637
  if retries % 2 == 0
632
638
  kb.config[:host] = canonical_addr
633
639
  kb.config[:winrm_authentication_protocol] = :basic
@@ -658,7 +664,9 @@ module MU
658
664
  kb.config[:json_attribs] = JSON.generate(json_attribs) if json_attribs.size > 1
659
665
  kb.config[:run_list] = run_list
660
666
  kb.config[:chef_node_name] = @server.mu_name
667
+ kb.config[:bootstrap_product] = "chef"
661
668
  kb.config[:bootstrap_version] = MU.chefVersion
669
+ kb.config[:channel] = "stable"
662
670
  # XXX key off of MU verbosity level
663
671
  kb.config[:log_level] = :debug
664
672
  # kb.config[:ssh_gateway] = "#{nat_ssh_user}@#{nat_ssh_host}" if !nat_ssh_host.nil? # Breaking bootsrap
@@ -898,7 +906,7 @@ retry
898
906
  vaults_to_clean.each { |vault|
899
907
  MU::MommaCat.lock("vault-#{vault['vault']}", false, true)
900
908
  MU.log "Purging unknown clients from #{vault['vault']} #{vault['item']}", MU::DEBUG
901
- output = %x{#{@knife} data bag show "#{vault['vault']}" "#{vault['item']}_keys" --format json}
909
+ output = %x{#{knife} data bag show "#{vault['vault']}" "#{vault['item']}_keys" --format json}
902
910
  # This is an ugly workaround for --clean-unknown-clients, which in
903
911
  # fact cleans known clients.
904
912
  if output
@@ -941,7 +949,7 @@ retry
941
949
  MU::MommaCat.lock("vault-#{vault}", false, true)
942
950
  MU.log "Granting #{host} access to #{vault} #{item}"
943
951
  begin
944
- ::Chef::Knife.run(['vault', 'update', vault, item, "--search", "name:#{host}"])
952
+ ::Chef::Knife.run(['vault', 'update', vault, item, "--clients", "#{host}"])
945
953
  rescue StandardError => e
946
954
  MU.log e.inspect, MU::ERR, details: caller
947
955
  end
@@ -1087,6 +1095,7 @@ retry
1087
1095
  def grantSecretAccess(vault, item)
1088
1096
  return if @secrets_granted["#{vault}:#{item}"] == item
1089
1097
  self.class.grantSecretAccess(@server.mu_name, vault, item)
1098
+ MU.log %Q{To retrieve secret #{vault}:#{item} - #{self.class.knife} vault show "#{vault}" "#{item}"}, MU::SUMMARY
1090
1099
  @secrets_granted["#{vault}:#{item}"] = item
1091
1100
  end
1092
1101
 
data/modules/mu/master.rb CHANGED
@@ -202,6 +202,7 @@ module MU
202
202
  else
203
203
  device.dup
204
204
  end
205
+
205
206
  alias_device = cryptfile ? "/dev/mapper/"+path.gsub(/[^0-9a-z_\-]/i, "_") : realdevice
206
207
 
207
208
  if !File.exist?(realdevice)
@@ -212,7 +213,7 @@ module MU
212
213
  cloud_id: MU.myInstanceId,
213
214
  kitten_cfg: {}
214
215
  )
215
- dummy_svr.addVolume(device, size)
216
+ dummy_svr.addVolume(dev: device, size: size)
216
217
  MU::Cloud::AWS::Server.tagVolumes(
217
218
  MU.myInstanceId,
218
219
  device: device,
@@ -228,7 +229,7 @@ module MU
228
229
  cloud_id: MU.myInstanceId,
229
230
  kitten_cfg: { 'project' => MU::Cloud::Google.myProject, 'availability_zone' => MU.myAZ }
230
231
  )
231
- dummy_svr.addVolume(device, size) # This will tag itself sensibly
232
+ dummy_svr.addVolume(dev: device, size: size) # This will tag itself sensibly
232
233
  else
233
234
  raise MuError, "Not in a familiar cloud, so I don't know how to create volumes for myself"
234
235
  end
@@ -271,14 +272,16 @@ module MU
271
272
  end
272
273
 
273
274
  %x{/usr/sbin/xfs_admin -l "#{alias_device}" > /dev/null 2>&1}
275
+
274
276
  if $?.exitstatus != 0
275
277
  MU.log "Formatting #{alias_device}", MU::NOTICE
276
278
  %x{/sbin/mkfs.xfs "#{alias_device}"}
277
279
  %x{/usr/sbin/xfs_admin -L "#{path.gsub(/[^0-9a-z_\-]/i, "_")}" "#{alias_device}"}
278
280
  end
279
281
  Dir.mkdir(path, 0700) if !Dir.exist?(path) # XXX recursive
282
+
280
283
  %x{/usr/sbin/xfs_info "#{alias_device}" > /dev/null 2>&1}
281
- if $?.exitstatus != 0
284
+ if $?.exitstatus == 0 and !File.open("/etc/mtab").read.match(/ #{path} /)
282
285
  MU.log "Mounting #{alias_device} to #{path}"
283
286
  %x{/bin/mount "#{alias_device}" "#{path}"}
284
287
  end
@@ -797,6 +800,7 @@ module MU
797
800
  nagios_threads = []
798
801
  nagios_threads << Thread.new {
799
802
  MU.dupGlobals(parent_thread_id)
803
+ Thread.current.thread_variable_set("syncMonitoringConfig", "<main>")
800
804
  realhome = Etc.getpwnam("nagios").dir
801
805
  [NAGIOS_HOME, "#{NAGIOS_HOME}/.ssh"].each { |dir|
802
806
  Dir.mkdir(dir, 0711) if !Dir.exist?(dir)
@@ -839,6 +843,7 @@ module MU
839
843
  MU.dupGlobals(parent_thread_id)
840
844
  threads << Thread.new {
841
845
  MU::MommaCat.setThreadContext(deploy)
846
+ Thread.current.thread_variable_set("syncMonitoringConfig",server.mu_name)
842
847
  MU.log "Adding #{server.mu_name} to #{NAGIOS_HOME}/.ssh/config", MU::DEBUG
843
848
  MU::Master.addHostToSSHConfig(
844
849
  server,
@@ -941,7 +946,7 @@ module MU
941
946
  return true if l =~ /^\/dev\/nvme\d/
942
947
  }
943
948
  else
944
- return true if File.exists?("/dev/nvme0n1")
949
+ return true if File.exist?("/dev/nvme0n1")
945
950
  end
946
951
  false
947
952
  end
@@ -213,6 +213,7 @@ module MU
213
213
  need_reload = false
214
214
  @cleanup_threads << Thread.new {
215
215
  MU.dupGlobals(parent_thread_id)
216
+ Thread.current.thread_variable_set("cleanTerminatedInstances", deploy_id)
216
217
  deploy = MU::MommaCat.getLitter(deploy_id, set_context_to_me: true)
217
218
  purged_this_deploy = 0
218
219
  MU.log "#{deploy_id} has some kittens in it", loglevel, details: deploy.kittens.keys
@@ -225,7 +226,8 @@ module MU
225
226
  servers.each_pair { |mu_name, server|
226
227
  server.describe
227
228
  if !server.cloud_id
228
- MU.log "Checking for presence of #{mu_name}, but unable to fetch its cloud_id", MU::WARN, details: server
229
+ MU.log "Checking for presence of instance '#{mu_name}', but unable to fetch its cloud_id", MU::WARN, server.class.name
230
+ pp servers.keys
229
231
  elsif !server.active?
230
232
  next if File.exist?(deploy_dir(deploy_id)+"/.cleanup-"+server.cloud_id)
231
233
  deletia << mu_name
@@ -313,7 +315,7 @@ module MU
313
315
  return 0
314
316
  end
315
317
 
316
- File.unlink(daemonPidFile) if File.exists?(daemonPidFile)
318
+ File.unlink(daemonPidFile) if File.exist?(daemonPidFile)
317
319
  MU.log "Starting Momma Cat on port #{MU.mommaCatPort}, logging to #{daemonLogFile}, PID file #{daemonPidFile}"
318
320
  origdir = Dir.getwd
319
321
  Dir.chdir(MU.myRoot+"/modules")
@@ -305,9 +305,8 @@ module MU
305
305
  zones = MU::Cloud::DNSZone.find(cloud_id: "platform-mu")
306
306
  mu_zone = zones.values.first if !zones.nil?
307
307
  end
308
-
309
308
  if !mu_zone.nil?
310
- MU::Cloud::DNSZone.genericMuDNSEntry(name: node.gsub(/[^a-z0-9!"\#$%&'\(\)\*\+,\-\/:;<=>\?@\[\]\^_`{\|}~\.]/, '-').gsub(/--|^-/, ''), target: server.canonicalIP, cloudclass: MU::Cloud::Server, sync_wait: sync_wait)
309
+ MU::Cloud::DNSZone.genericMuDNSEntry(name: node.gsub(/[^a-z0-9!"\#$%&'\(\)\*\+,\-\/:;<=>\?@\[\]\^_`{\|}~\.]/i, '-').gsub(/--|^-/, ''), target: server.canonicalIP, cloudclass: MU::Cloud::Server, sync_wait: sync_wait)
311
310
  else
312
311
  MU::Master.addInstanceToEtcHosts(server.canonicalIP, node)
313
312
  end
@@ -179,6 +179,7 @@ module MU
179
179
  # return [false, nil]
180
180
  def self.lock(id, nonblock = false, global = false, retries: 0, deploy_id: MU.deploy_id)
181
181
  raise MuError, "Can't pass a nil id to MU::MommaCat.lock" if id.nil?
182
+ called_by = caller[0]
182
183
 
183
184
  if !global
184
185
  lockdir = "#{deploy_dir(deploy_id)}/locks"
@@ -200,6 +201,10 @@ module MU
200
201
  @locks[Thread.current.object_id][id] = File.open("#{lockdir}/#{id}.lock", File::CREAT|File::RDWR, 0600)
201
202
  }
202
203
 
204
+ thr_to_s = Proc.new { |t|
205
+ "#{t.object_id} (#{t.thread_variables.map { |v| "#{v.to_s}: #{t.thread_variable_get(v).to_s}" }.join(", ")})"
206
+ }
207
+
203
208
  MU.log "Getting a lock on #{lockdir}/#{id}.lock (thread #{Thread.current.object_id})...", MU::DEBUG, details: caller
204
209
  show_relevant = Proc.new {
205
210
  @lock_semaphore.synchronize {
@@ -208,7 +213,7 @@ module MU
208
213
  if lockid == id
209
214
  thread = Thread.list.select { |t| t.object_id == thread_id }.first
210
215
  if thread.object_id != Thread.current.object_id
211
- MU.log "#{thread_id} sitting on #{id} (#{thread.thread_variables.map { |v| "#{v.to_s}: #{thread.thread_variable_get(v).to_s}" }.join(", ")})", MU::WARN, thread.backtrace
216
+ MU.log "Thread #{thr_to_s.call(thread)} sitting on #{id}, which is needed by #{thr_to_s.call(Thread.current)} at #{called_by}", MU::WARN, thread.backtrace
212
217
  end
213
218
  end
214
219
  }
@@ -585,7 +590,7 @@ module MU
585
590
  orig_cfg = findResourceConfig(type, res_name)
586
591
 
587
592
  if orig_cfg.nil?
588
- MU.log "Failed to locate original config for #{attrs[:cfg_name]} #{res_name} in #{@deploy_id}", MU::WARN if !["firewall_rules", "databases", "storage_pools", "cache_clusters", "alarms"].include?(type) # XXX shaddap
593
+ MU.log "Failed to locate original config for #{attrs[:cfg_name]} #{res_name}, seen in cached deployment.json for #{@deploy_id}", MU::DEBUG
589
594
  next
590
595
  end
591
596
 
@@ -150,6 +150,7 @@ module MU
150
150
  @deploy_id = deploy_id
151
151
  @mu_user = mu_user.dup
152
152
  @no_artifacts = no_artifacts
153
+ @ssh_key_generated = false
153
154
 
154
155
  # Make sure mu_user and chef_user are sane.
155
156
  if @mu_user == "root"
@@ -167,7 +168,6 @@ module MU
167
168
  @need_deploy_flush = false
168
169
  @node_cert_semaphore = Mutex.new
169
170
  @deployment = deployment_data
170
-
171
171
  @deployment['mu_public_ip'] = MU.mu_public_ip
172
172
  @private_key = nil
173
173
  @public_key = nil
@@ -175,6 +175,7 @@ module MU
175
175
  @secrets['instance_secret'] = Hash.new
176
176
  @secrets['windows_admin_password'] = Hash.new
177
177
  @ssh_key_name = ssh_key_name
178
+ @ssh_key_name ||= "deploy-#{@deploy_id}"
178
179
  @ssh_private_key = ssh_private_key
179
180
  @ssh_public_key = ssh_public_key
180
181
  @clouds = {}
@@ -195,6 +196,7 @@ module MU
195
196
  setDeploySecret
196
197
  MU::MommaCat.setThreadContext(self) if set_context_to_me
197
198
  save!
199
+ generatePasswords
198
200
  end
199
201
 
200
202
  @appname ||= MU.appname
@@ -202,6 +204,7 @@ module MU
202
204
  @environment ||= MU.environment
203
205
 
204
206
  loadDeploy(set_context_to_me: set_context_to_me)
207
+ @deployment['mu_all_ips'] ||= [MU.mu_public_ip, MU.my_private_ip].uniq
205
208
  if !deploy_secret.nil? and !authKey(deploy_secret)
206
209
  raise DeployInitializeError, "Client request did not include a valid deploy authorization secret. Verify that userdata runs correctly?"
207
210
  end
@@ -224,6 +227,29 @@ module MU
224
227
  # if !@@litter_semaphore.owned?
225
228
  end # end of initialize()
226
229
 
230
+ def generatePasswords
231
+ return if !@original_config['generate_passwords']
232
+
233
+ @original_config['generate_passwords'].each { |pw|
234
+ password = MU.generatePassword(safe_pattern: pw['safe_chars'], length: pw['minlength'])
235
+ MU.supportedGroomers.each { |g|
236
+ groomclass = MU.loadGroomer(g)
237
+ begin
238
+ groomclass.getSecret(vault: @deploy_id,
239
+ item: pw['itemname'],
240
+ field: 'password')
241
+ rescue MU::Groomer::MuNoSuchSecret
242
+ pwdata = { "password" => password }
243
+ pwdata["username"] = pw["username"] if pw["username"]
244
+ groomclass.saveSecret(vault: @deploy_id,
245
+ item: pw['itemname'],
246
+ data: pwdata,
247
+ permissions: (g == "Ansible"))
248
+ end
249
+ }
250
+ }
251
+ end
252
+
227
253
  # List all the cloud providers declared by resources in our deploy.
228
254
  def cloudsUsed
229
255
  seen = []
@@ -490,7 +516,7 @@ module MU
490
516
  # Return the parts and pieces of this deploy's node ssh key set. Generate
491
517
  # or load if that hasn't been done already.
492
518
  def SSHKey
493
- return [@ssh_key_name, @ssh_private_key, @ssh_public_key] if !@ssh_key_name.nil?
519
+ return [@ssh_key_name, @ssh_private_key, @ssh_public_key] if @ssh_key_generated
494
520
  if numKittens(types: ["Server", "ServerPool", "ContainerCluster"]) == 0
495
521
  return []
496
522
  end
@@ -535,6 +561,7 @@ module MU
535
561
  }
536
562
  end
537
563
 
564
+ @ssh_key_generated = true
538
565
  return [@ssh_key_name, @ssh_private_key, @ssh_public_key]
539
566
  end
540
567
 
@@ -549,8 +576,8 @@ module MU
549
576
  # @param triggering_node [MU::Cloud]: A cloud object calling this notify, usually on behalf of itself
550
577
  # @param remove [Boolean]: Remove this resource from the deploy structure, instead of adding it.
551
578
  # @return [void]
552
- def notify(type, key, data, mu_name: nil, remove: false, triggering_node: nil, delayed_save: false)
553
- no_write = (@no_artifacts or !caller.grep(/\/mommacat\.rb:\d+:in `notify'/).empty?)
579
+ def notify(type, key, data, mu_name: nil, remove: false, triggering_node: nil, delayed_save: false, no_write: nil)
580
+ no_write ||= (@no_artifacts or !caller.grep(/\/mommacat\.rb:\d+:in `notify'/).empty?)
554
581
 
555
582
  begin
556
583
  if !no_write
@@ -831,7 +858,7 @@ MAIL_HEAD_END
831
858
  next if sibling.config.has_key?("groom") and !sibling.config["groom"]
832
859
  threads << Thread.new {
833
860
  Thread.abort_on_exception = true
834
- Thread.current.thread_variable_set("name", "sync-"+sibling.mu_name.downcase)
861
+ Thread.current.thread_variable_set("syncLitterThread", sibling.mu_name)
835
862
  MU.setVar("syncLitterThread", true)
836
863
  begin
837
864
  sibling.groomer.saveDeployData
@@ -874,7 +901,7 @@ MAIL_HEAD_END
874
901
  sans << resource.mu_name.downcase if resource.mu_name and resource.mu_name != cert_cn
875
902
  # XXX were there other names we wanted to include?
876
903
  key = MU::Master::SSL.getKey(cert_cn, keysize: keysize)
877
- cert, pfx_cert = MU::Master::SSL.getCert(cert_cn, "/CN=#{cert_cn}/O=Mu/C=US", sans: sans, pfx: is_windows)
904
+ cert, pfx_cert = MU::Master::SSL.getCert(cert_cn, "/CN=#{cert_cn}/O=Mu/C=US", sans: sans, pfx: true)
878
905
  results[cert_cn] = [key, cert]
879
906
 
880
907
  winrm_cert = nil