cloud-mu 2.1.0beta → 3.0.0beta

Sign up to get free protection for your applications and to get access to all the features.
Files changed (291) hide show
  1. checksums.yaml +5 -5
  2. data/Berksfile +4 -5
  3. data/Berksfile.lock +179 -0
  4. data/README.md +1 -6
  5. data/ansible/roles/geerlingguy.firewall/templates/firewall.bash.j2 +0 -0
  6. data/ansible/roles/mu-installer/README.md +33 -0
  7. data/ansible/roles/mu-installer/defaults/main.yml +2 -0
  8. data/ansible/roles/mu-installer/handlers/main.yml +2 -0
  9. data/ansible/roles/mu-installer/meta/main.yml +60 -0
  10. data/ansible/roles/mu-installer/tasks/main.yml +13 -0
  11. data/ansible/roles/mu-installer/tests/inventory +2 -0
  12. data/ansible/roles/mu-installer/tests/test.yml +5 -0
  13. data/ansible/roles/mu-installer/vars/main.yml +2 -0
  14. data/bin/mu-adopt +125 -0
  15. data/bin/mu-aws-setup +4 -4
  16. data/bin/mu-azure-setup +265 -0
  17. data/bin/mu-azure-tests +43 -0
  18. data/bin/mu-cleanup +20 -8
  19. data/bin/mu-configure +224 -98
  20. data/bin/mu-deploy +8 -3
  21. data/bin/mu-gcp-setup +16 -8
  22. data/bin/mu-gen-docs +92 -8
  23. data/bin/mu-load-config.rb +52 -12
  24. data/bin/mu-momma-cat +36 -0
  25. data/bin/mu-node-manage +34 -27
  26. data/bin/mu-self-update +2 -2
  27. data/bin/mu-ssh +12 -8
  28. data/bin/mu-upload-chef-artifacts +11 -4
  29. data/bin/mu-user-manage +3 -0
  30. data/cloud-mu.gemspec +8 -11
  31. data/cookbooks/firewall/libraries/helpers_iptables.rb +2 -2
  32. data/cookbooks/firewall/metadata.json +1 -1
  33. data/cookbooks/firewall/recipes/default.rb +5 -9
  34. data/cookbooks/mu-firewall/attributes/default.rb +2 -0
  35. data/cookbooks/mu-firewall/metadata.rb +1 -1
  36. data/cookbooks/mu-glusterfs/templates/default/mu-gluster-client.erb +0 -0
  37. data/cookbooks/mu-master/Berksfile +2 -2
  38. data/cookbooks/mu-master/files/default/check_mem.pl +0 -0
  39. data/cookbooks/mu-master/files/default/cloudamatic.png +0 -0
  40. data/cookbooks/mu-master/metadata.rb +5 -4
  41. data/cookbooks/mu-master/recipes/389ds.rb +1 -1
  42. data/cookbooks/mu-master/recipes/basepackages.rb +30 -10
  43. data/cookbooks/mu-master/recipes/default.rb +59 -7
  44. data/cookbooks/mu-master/recipes/firewall-holes.rb +1 -1
  45. data/cookbooks/mu-master/recipes/init.rb +65 -47
  46. data/cookbooks/mu-master/recipes/{eks-kubectl.rb → kubectl.rb} +4 -10
  47. data/cookbooks/mu-master/recipes/sssd.rb +2 -1
  48. data/cookbooks/mu-master/recipes/update_nagios_only.rb +6 -6
  49. data/cookbooks/mu-master/templates/default/web_app.conf.erb +2 -2
  50. data/cookbooks/mu-master/templates/mods/ldap.conf.erb +4 -0
  51. data/cookbooks/mu-php54/Berksfile +1 -2
  52. data/cookbooks/mu-php54/metadata.rb +4 -5
  53. data/cookbooks/mu-php54/recipes/default.rb +1 -1
  54. data/cookbooks/mu-splunk/templates/default/splunk-init.erb +0 -0
  55. data/cookbooks/mu-tools/Berksfile +3 -2
  56. data/cookbooks/mu-tools/files/default/Mu_CA.pem +33 -0
  57. data/cookbooks/mu-tools/libraries/helper.rb +20 -8
  58. data/cookbooks/mu-tools/metadata.rb +5 -2
  59. data/cookbooks/mu-tools/recipes/apply_security.rb +2 -3
  60. data/cookbooks/mu-tools/recipes/eks.rb +1 -1
  61. data/cookbooks/mu-tools/recipes/gcloud.rb +5 -30
  62. data/cookbooks/mu-tools/recipes/nagios.rb +1 -1
  63. data/cookbooks/mu-tools/recipes/rsyslog.rb +1 -0
  64. data/cookbooks/mu-tools/recipes/selinux.rb +19 -0
  65. data/cookbooks/mu-tools/recipes/split_var_partitions.rb +0 -1
  66. data/cookbooks/mu-tools/recipes/windows-client.rb +256 -122
  67. data/cookbooks/mu-tools/resources/disk.rb +3 -1
  68. data/cookbooks/mu-tools/templates/amazon/sshd_config.erb +1 -1
  69. data/cookbooks/mu-tools/templates/default/etc_hosts.erb +1 -1
  70. data/cookbooks/mu-tools/templates/default/{kubeconfig.erb → kubeconfig-eks.erb} +0 -0
  71. data/cookbooks/mu-tools/templates/default/kubeconfig-gke.erb +27 -0
  72. data/cookbooks/mu-tools/templates/windows-10/sshd_config.erb +137 -0
  73. data/cookbooks/mu-utility/recipes/nat.rb +4 -0
  74. data/extras/alpha.png +0 -0
  75. data/extras/beta.png +0 -0
  76. data/extras/clean-stock-amis +2 -2
  77. data/extras/generate-stock-images +131 -0
  78. data/extras/git-fix-permissions-hook +0 -0
  79. data/extras/image-generators/AWS/centos6.yaml +17 -0
  80. data/extras/image-generators/{aws → AWS}/centos7-govcloud.yaml +0 -0
  81. data/extras/image-generators/{aws → AWS}/centos7.yaml +0 -0
  82. data/extras/image-generators/{aws → AWS}/rhel7.yaml +0 -0
  83. data/extras/image-generators/{aws → AWS}/win2k12.yaml +0 -0
  84. data/extras/image-generators/{aws → AWS}/win2k16.yaml +0 -0
  85. data/extras/image-generators/{aws → AWS}/windows.yaml +0 -0
  86. data/extras/image-generators/{gcp → Google}/centos6.yaml +1 -0
  87. data/extras/image-generators/Google/centos7.yaml +18 -0
  88. data/extras/python_rpm/build.sh +0 -0
  89. data/extras/release.png +0 -0
  90. data/extras/ruby_rpm/build.sh +0 -0
  91. data/extras/ruby_rpm/muby.spec +1 -1
  92. data/install/README.md +43 -5
  93. data/install/deprecated-bash-library.sh +0 -0
  94. data/install/installer +1 -1
  95. data/install/jenkinskeys.rb +0 -0
  96. data/install/mu-master.yaml +55 -0
  97. data/modules/mommacat.ru +41 -7
  98. data/modules/mu.rb +444 -149
  99. data/modules/mu/adoption.rb +500 -0
  100. data/modules/mu/cleanup.rb +235 -158
  101. data/modules/mu/cloud.rb +675 -138
  102. data/modules/mu/clouds/aws.rb +156 -24
  103. data/modules/mu/clouds/aws/alarm.rb +4 -14
  104. data/modules/mu/clouds/aws/bucket.rb +60 -18
  105. data/modules/mu/clouds/aws/cache_cluster.rb +8 -20
  106. data/modules/mu/clouds/aws/collection.rb +12 -22
  107. data/modules/mu/clouds/aws/container_cluster.rb +209 -118
  108. data/modules/mu/clouds/aws/database.rb +120 -45
  109. data/modules/mu/clouds/aws/dnszone.rb +7 -18
  110. data/modules/mu/clouds/aws/endpoint.rb +5 -15
  111. data/modules/mu/clouds/aws/firewall_rule.rb +144 -72
  112. data/modules/mu/clouds/aws/folder.rb +4 -11
  113. data/modules/mu/clouds/aws/function.rb +6 -16
  114. data/modules/mu/clouds/aws/group.rb +4 -12
  115. data/modules/mu/clouds/aws/habitat.rb +11 -13
  116. data/modules/mu/clouds/aws/loadbalancer.rb +40 -28
  117. data/modules/mu/clouds/aws/log.rb +5 -13
  118. data/modules/mu/clouds/aws/msg_queue.rb +9 -24
  119. data/modules/mu/clouds/aws/nosqldb.rb +4 -12
  120. data/modules/mu/clouds/aws/notifier.rb +6 -13
  121. data/modules/mu/clouds/aws/role.rb +69 -40
  122. data/modules/mu/clouds/aws/search_domain.rb +17 -20
  123. data/modules/mu/clouds/aws/server.rb +184 -94
  124. data/modules/mu/clouds/aws/server_pool.rb +33 -38
  125. data/modules/mu/clouds/aws/storage_pool.rb +5 -12
  126. data/modules/mu/clouds/aws/user.rb +59 -33
  127. data/modules/mu/clouds/aws/userdata/linux.erb +18 -30
  128. data/modules/mu/clouds/aws/userdata/windows.erb +9 -9
  129. data/modules/mu/clouds/aws/vpc.rb +214 -145
  130. data/modules/mu/clouds/azure.rb +978 -44
  131. data/modules/mu/clouds/azure/container_cluster.rb +413 -0
  132. data/modules/mu/clouds/azure/firewall_rule.rb +500 -0
  133. data/modules/mu/clouds/azure/habitat.rb +167 -0
  134. data/modules/mu/clouds/azure/loadbalancer.rb +205 -0
  135. data/modules/mu/clouds/azure/role.rb +211 -0
  136. data/modules/mu/clouds/azure/server.rb +810 -0
  137. data/modules/mu/clouds/azure/user.rb +257 -0
  138. data/modules/mu/clouds/azure/userdata/README.md +4 -0
  139. data/modules/mu/clouds/azure/userdata/linux.erb +137 -0
  140. data/modules/mu/clouds/azure/userdata/windows.erb +275 -0
  141. data/modules/mu/clouds/azure/vpc.rb +782 -0
  142. data/modules/mu/clouds/cloudformation.rb +12 -9
  143. data/modules/mu/clouds/cloudformation/firewall_rule.rb +5 -13
  144. data/modules/mu/clouds/cloudformation/server.rb +10 -1
  145. data/modules/mu/clouds/cloudformation/server_pool.rb +1 -0
  146. data/modules/mu/clouds/cloudformation/vpc.rb +0 -2
  147. data/modules/mu/clouds/google.rb +554 -117
  148. data/modules/mu/clouds/google/bucket.rb +173 -32
  149. data/modules/mu/clouds/google/container_cluster.rb +1112 -157
  150. data/modules/mu/clouds/google/database.rb +24 -47
  151. data/modules/mu/clouds/google/firewall_rule.rb +344 -89
  152. data/modules/mu/clouds/google/folder.rb +156 -79
  153. data/modules/mu/clouds/google/group.rb +272 -82
  154. data/modules/mu/clouds/google/habitat.rb +177 -52
  155. data/modules/mu/clouds/google/loadbalancer.rb +9 -34
  156. data/modules/mu/clouds/google/role.rb +1211 -0
  157. data/modules/mu/clouds/google/server.rb +491 -227
  158. data/modules/mu/clouds/google/server_pool.rb +233 -48
  159. data/modules/mu/clouds/google/user.rb +479 -125
  160. data/modules/mu/clouds/google/userdata/linux.erb +3 -3
  161. data/modules/mu/clouds/google/userdata/windows.erb +9 -9
  162. data/modules/mu/clouds/google/vpc.rb +381 -223
  163. data/modules/mu/config.rb +689 -214
  164. data/modules/mu/config/bucket.rb +1 -1
  165. data/modules/mu/config/cache_cluster.rb +1 -1
  166. data/modules/mu/config/cache_cluster.yml +0 -4
  167. data/modules/mu/config/container_cluster.rb +18 -9
  168. data/modules/mu/config/database.rb +6 -23
  169. data/modules/mu/config/firewall_rule.rb +9 -15
  170. data/modules/mu/config/folder.rb +22 -21
  171. data/modules/mu/config/habitat.rb +22 -21
  172. data/modules/mu/config/loadbalancer.rb +2 -2
  173. data/modules/mu/config/role.rb +9 -40
  174. data/modules/mu/config/server.rb +26 -5
  175. data/modules/mu/config/server_pool.rb +1 -1
  176. data/modules/mu/config/storage_pool.rb +2 -2
  177. data/modules/mu/config/user.rb +4 -0
  178. data/modules/mu/config/vpc.rb +350 -110
  179. data/modules/mu/defaults/{amazon_images.yaml → AWS.yaml} +37 -39
  180. data/modules/mu/defaults/Azure.yaml +17 -0
  181. data/modules/mu/defaults/Google.yaml +24 -0
  182. data/modules/mu/defaults/README.md +1 -1
  183. data/modules/mu/deploy.rb +168 -125
  184. data/modules/mu/groomer.rb +2 -1
  185. data/modules/mu/groomers/ansible.rb +104 -32
  186. data/modules/mu/groomers/chef.rb +96 -44
  187. data/modules/mu/kittens.rb +20602 -0
  188. data/modules/mu/logger.rb +38 -11
  189. data/modules/mu/master.rb +90 -8
  190. data/modules/mu/master/chef.rb +2 -3
  191. data/modules/mu/master/ldap.rb +0 -1
  192. data/modules/mu/master/ssl.rb +250 -0
  193. data/modules/mu/mommacat.rb +917 -513
  194. data/modules/scratchpad.erb +1 -1
  195. data/modules/tests/super_complex_bok.yml +0 -0
  196. data/modules/tests/super_simple_bok.yml +0 -0
  197. data/roles/mu-master.json +2 -1
  198. data/spec/azure_creds +5 -0
  199. data/spec/mu.yaml +56 -0
  200. data/spec/mu/clouds/azure_spec.rb +164 -27
  201. data/spec/spec_helper.rb +5 -0
  202. data/test/clean_up.py +0 -0
  203. data/test/exec_inspec.py +0 -0
  204. data/test/exec_mu_install.py +0 -0
  205. data/test/exec_retry.py +0 -0
  206. data/test/smoke_test.rb +0 -0
  207. metadata +90 -118
  208. data/cookbooks/mu-jenkins/Berksfile +0 -14
  209. data/cookbooks/mu-jenkins/CHANGELOG.md +0 -13
  210. data/cookbooks/mu-jenkins/LICENSE +0 -37
  211. data/cookbooks/mu-jenkins/README.md +0 -105
  212. data/cookbooks/mu-jenkins/attributes/default.rb +0 -42
  213. data/cookbooks/mu-jenkins/files/default/cleanup_deploy_config.xml +0 -73
  214. data/cookbooks/mu-jenkins/files/default/deploy_config.xml +0 -44
  215. data/cookbooks/mu-jenkins/metadata.rb +0 -21
  216. data/cookbooks/mu-jenkins/recipes/default.rb +0 -195
  217. data/cookbooks/mu-jenkins/recipes/node-ssh-config.rb +0 -54
  218. data/cookbooks/mu-jenkins/recipes/public_key.rb +0 -24
  219. data/cookbooks/mu-jenkins/templates/default/example_job.config.xml.erb +0 -24
  220. data/cookbooks/mu-jenkins/templates/default/org.jvnet.hudson.plugins.SSHBuildWrapper.xml.erb +0 -14
  221. data/cookbooks/mu-jenkins/templates/default/ssh_config.erb +0 -6
  222. data/cookbooks/nagios/Berksfile +0 -11
  223. data/cookbooks/nagios/CHANGELOG.md +0 -589
  224. data/cookbooks/nagios/CONTRIBUTING.md +0 -11
  225. data/cookbooks/nagios/LICENSE +0 -37
  226. data/cookbooks/nagios/README.md +0 -328
  227. data/cookbooks/nagios/TESTING.md +0 -2
  228. data/cookbooks/nagios/attributes/config.rb +0 -171
  229. data/cookbooks/nagios/attributes/default.rb +0 -228
  230. data/cookbooks/nagios/chefignore +0 -102
  231. data/cookbooks/nagios/definitions/command.rb +0 -33
  232. data/cookbooks/nagios/definitions/contact.rb +0 -33
  233. data/cookbooks/nagios/definitions/contactgroup.rb +0 -33
  234. data/cookbooks/nagios/definitions/host.rb +0 -33
  235. data/cookbooks/nagios/definitions/hostdependency.rb +0 -33
  236. data/cookbooks/nagios/definitions/hostescalation.rb +0 -34
  237. data/cookbooks/nagios/definitions/hostgroup.rb +0 -33
  238. data/cookbooks/nagios/definitions/nagios_conf.rb +0 -38
  239. data/cookbooks/nagios/definitions/resource.rb +0 -33
  240. data/cookbooks/nagios/definitions/service.rb +0 -33
  241. data/cookbooks/nagios/definitions/servicedependency.rb +0 -33
  242. data/cookbooks/nagios/definitions/serviceescalation.rb +0 -34
  243. data/cookbooks/nagios/definitions/servicegroup.rb +0 -33
  244. data/cookbooks/nagios/definitions/timeperiod.rb +0 -33
  245. data/cookbooks/nagios/libraries/base.rb +0 -314
  246. data/cookbooks/nagios/libraries/command.rb +0 -91
  247. data/cookbooks/nagios/libraries/contact.rb +0 -230
  248. data/cookbooks/nagios/libraries/contactgroup.rb +0 -112
  249. data/cookbooks/nagios/libraries/custom_option.rb +0 -36
  250. data/cookbooks/nagios/libraries/data_bag_helper.rb +0 -23
  251. data/cookbooks/nagios/libraries/default.rb +0 -90
  252. data/cookbooks/nagios/libraries/host.rb +0 -412
  253. data/cookbooks/nagios/libraries/hostdependency.rb +0 -181
  254. data/cookbooks/nagios/libraries/hostescalation.rb +0 -173
  255. data/cookbooks/nagios/libraries/hostgroup.rb +0 -119
  256. data/cookbooks/nagios/libraries/nagios.rb +0 -282
  257. data/cookbooks/nagios/libraries/resource.rb +0 -59
  258. data/cookbooks/nagios/libraries/service.rb +0 -455
  259. data/cookbooks/nagios/libraries/servicedependency.rb +0 -215
  260. data/cookbooks/nagios/libraries/serviceescalation.rb +0 -195
  261. data/cookbooks/nagios/libraries/servicegroup.rb +0 -144
  262. data/cookbooks/nagios/libraries/timeperiod.rb +0 -160
  263. data/cookbooks/nagios/libraries/users_helper.rb +0 -54
  264. data/cookbooks/nagios/metadata.rb +0 -25
  265. data/cookbooks/nagios/recipes/_load_databag_config.rb +0 -153
  266. data/cookbooks/nagios/recipes/_load_default_config.rb +0 -241
  267. data/cookbooks/nagios/recipes/apache.rb +0 -48
  268. data/cookbooks/nagios/recipes/default.rb +0 -204
  269. data/cookbooks/nagios/recipes/nginx.rb +0 -82
  270. data/cookbooks/nagios/recipes/pagerduty.rb +0 -143
  271. data/cookbooks/nagios/recipes/server_package.rb +0 -40
  272. data/cookbooks/nagios/recipes/server_source.rb +0 -164
  273. data/cookbooks/nagios/templates/default/apache2.conf.erb +0 -96
  274. data/cookbooks/nagios/templates/default/cgi.cfg.erb +0 -266
  275. data/cookbooks/nagios/templates/default/commands.cfg.erb +0 -13
  276. data/cookbooks/nagios/templates/default/contacts.cfg.erb +0 -37
  277. data/cookbooks/nagios/templates/default/hostgroups.cfg.erb +0 -25
  278. data/cookbooks/nagios/templates/default/hosts.cfg.erb +0 -15
  279. data/cookbooks/nagios/templates/default/htpasswd.users.erb +0 -6
  280. data/cookbooks/nagios/templates/default/nagios.cfg.erb +0 -22
  281. data/cookbooks/nagios/templates/default/nginx.conf.erb +0 -62
  282. data/cookbooks/nagios/templates/default/pagerduty.cgi.erb +0 -185
  283. data/cookbooks/nagios/templates/default/resource.cfg.erb +0 -27
  284. data/cookbooks/nagios/templates/default/servicedependencies.cfg.erb +0 -15
  285. data/cookbooks/nagios/templates/default/servicegroups.cfg.erb +0 -14
  286. data/cookbooks/nagios/templates/default/services.cfg.erb +0 -14
  287. data/cookbooks/nagios/templates/default/templates.cfg.erb +0 -31
  288. data/cookbooks/nagios/templates/default/timeperiods.cfg.erb +0 -13
  289. data/extras/image-generators/aws/centos6.yaml +0 -18
  290. data/modules/mu/defaults/google_images.yaml +0 -16
  291. data/roles/mu-master-jenkins.json +0 -24
@@ -0,0 +1,500 @@
1
+ # Copyright:: Copyright (c) 2019 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
+ module MU
16
+
17
+ # Scrape cloud providers for existing resources, and reverse-engineer them
18
+ # into runnable {MU::Config} descriptors and/or {MU::MommaCat} deploy objects.
19
+ class Adoption
20
+
21
+ attr_reader :found
22
+
23
+ # Error class for objects which fail to fully resolve (e.g. references to
24
+ # other objects which are not found)
25
+ class Incomplete < MU::MuNonFatal; end
26
+
27
+ # Presets methods we use to clump discovered resources into discrete deploys
28
+ GROUPMODES = {
29
+ :logical => "Group resources in logical layers (folders and habitats together, users/roles/groups together, network resources together, etc)",
30
+ :omnibus => "Jam everything into one monolothic configuration"
31
+ }
32
+
33
+ def initialize(clouds: MU::Cloud.supportedClouds, types: MU::Cloud.resource_types.keys, parent: nil, billing: nil, sources: nil, credentials: nil, group_by: :logical, savedeploys: true, diff: false, habitats: [])
34
+ @scraped = {}
35
+ @clouds = clouds
36
+ @types = types
37
+ @parent = parent
38
+ @boks = {}
39
+ @billing = billing
40
+ @reference_map = {}
41
+ @sources = sources
42
+ @target_creds = credentials
43
+ @group_by = group_by
44
+ @savedeploys = savedeploys
45
+ @diff = diff
46
+ @habitats = habitats
47
+ @habitats ||= []
48
+ end
49
+
50
+ # Walk cloud providers with available credentials to discover resources
51
+ def scrapeClouds()
52
+ @default_parent = nil
53
+
54
+ @clouds.each { |cloud|
55
+ cloudclass = Object.const_get("MU").const_get("Cloud").const_get(cloud)
56
+ next if cloudclass.listCredentials.nil?
57
+
58
+ if cloud == "Google" and !@parent and @target_creds
59
+ dest_org = MU::Cloud::Google.getOrg(@target_creds)
60
+ if dest_org
61
+ @default_parent = dest_org.name
62
+ end
63
+ end
64
+
65
+ cloudclass.listCredentials.each { |credset|
66
+ next if @sources and !@sources.include?(credset)
67
+
68
+ if @parent
69
+ # TODO handle different inputs (cloud_id, etc)
70
+ # TODO do something about vague matches
71
+ found = MU::MommaCat.findStray(
72
+ cloud,
73
+ "folders",
74
+ flags: { "display_name" => @parent },
75
+ credentials: credset,
76
+ allow_multi: false,
77
+ dummy_ok: true,
78
+ debug: false
79
+ )
80
+ if found and found.size == 1
81
+ @default_parent = found.first
82
+ end
83
+ end
84
+
85
+ @types.each { |type|
86
+ begin
87
+ resclass = Object.const_get("MU").const_get("Cloud").const_get(cloud).const_get(type)
88
+ rescue ::MU::Cloud::MuCloudResourceNotImplemented
89
+ next
90
+ end
91
+ if !resclass.instance_methods.include?(:toKitten)
92
+ MU.log "Skipping MU::Cloud::#{cloud}::#{type} (resource has not implemented #toKitten)", MU::WARN
93
+ next
94
+ end
95
+ MU.log "Scraping #{cloud}/#{credset} for #{resclass.cfg_plural}"
96
+
97
+ found = MU::MommaCat.findStray(
98
+ cloud,
99
+ type,
100
+ credentials: credset,
101
+ allow_multi: true,
102
+ habitats: @habitats.dup,
103
+ dummy_ok: true,
104
+ debug: false,
105
+ flags: { "skip_provider_owned" => true }
106
+ )
107
+
108
+
109
+ if found and found.size > 0
110
+ MU.log "Found #{found.size.to_s} raw #{resclass.cfg_plural} in #{cloud}"
111
+ @scraped[type] ||= {}
112
+ found.each { |obj|
113
+ # XXX apply any filters (e.g. MU-ID tags)
114
+ @scraped[type][obj.cloud_id] = obj
115
+ }
116
+ end
117
+
118
+ }
119
+ }
120
+ }
121
+
122
+ if @parent and !@default_parent
123
+ MU.log "Failed to locate a folder that resembles #{@parent}", MU::ERR
124
+ end
125
+ MU.log "Scraping complete"
126
+ end
127
+
128
+ # Generate a {MU::Config} (Basket of Kittens) hash using our discovered
129
+ # cloud objects.
130
+ # @return [Hash]
131
+ def generateBaskets(prefix: "")
132
+ groupings = {
133
+ "" => MU::Cloud.resource_types.values.map { |v| v[:cfg_plural] }
134
+ }
135
+
136
+ # XXX as soon as we come up with a method that isn't about what resource
137
+ # type you are, this code will stop making sense
138
+ if @group_by == :logical
139
+ groupings = {
140
+ "spaces" => ["folders", "habitats"],
141
+ "people" => ["users", "groups", "roles"],
142
+ "network" => ["vpcs", "firewall_rules", "dnszones"],
143
+ "storage" => ["storage_pools", "buckets"],
144
+ }
145
+ # "the movie star/and the rest"
146
+ groupings["services"] = MU::Cloud.resource_types.values.map { |v| v[:cfg_plural] } - groupings.values.flatten
147
+ elsif @group_by == :omnibus
148
+ prefix = "mu" if prefix.empty? # so that appnames aren't ever empty
149
+ end
150
+
151
+ groupings.each_pair { |appname, types|
152
+ bok = { "appname" => prefix+appname }
153
+ if @target_creds
154
+ bok["credentials"] = @target_creds
155
+ end
156
+
157
+ count = 0
158
+ allowed_types = @types.map { |t| MU::Cloud.resource_types[t][:cfg_plural] }
159
+ next if (types & allowed_types).size == 0
160
+ origin = {
161
+ "appname" => bok['appname'],
162
+ "types" => (types & allowed_types).sort,
163
+ "habitats" => @habitats.sort,
164
+ "group_by" => @group_by.to_s
165
+ }
166
+
167
+ deploy = MU::MommaCat.findMatchingDeploy(origin)
168
+ if @diff and !deploy
169
+ MU.log "--diff was set but I failed to find a deploy like me to compare to", MU::ERR, details: origin
170
+ exit 1
171
+ end
172
+
173
+ threads = []
174
+ @clouds.each { |cloud|
175
+ @scraped.each_pair { |type, resources|
176
+ res_class = begin
177
+ MU::Cloud.loadCloudType(cloud, type)
178
+ rescue MU::Cloud::MuCloudResourceNotImplemented => e
179
+ # XXX I don't think this can actually happen
180
+ next
181
+ end
182
+ next if !types.include?(res_class.cfg_plural)
183
+
184
+ bok[res_class.cfg_plural] ||= []
185
+
186
+ class_semaphore = Mutex.new
187
+
188
+ Thread.abort_on_exception = true
189
+ resources.each_pair { |cloud_id_thr, obj_thr|
190
+ threads << Thread.new(cloud_id_thr, obj_thr) { |cloud_id, obj|
191
+
192
+ kitten_cfg = obj.toKitten(rootparent: @default_parent, billing: @billing, habitats: @habitats)
193
+ if kitten_cfg
194
+ print "."
195
+ kitten_cfg.delete("credentials") if @target_creds
196
+ class_semaphore.synchronize {
197
+ bok[res_class.cfg_plural] << kitten_cfg
198
+ }
199
+ count += 1
200
+ end
201
+ }
202
+
203
+ }
204
+
205
+ threads.each { |t|
206
+ t.join
207
+ }
208
+ puts ""
209
+ bok[res_class.cfg_plural].sort! { |a, b|
210
+ strs = [a, b].map { |x|
211
+ if x['cloud_id']
212
+ x['cloud_id']
213
+ elsif x['parent'] and ['parent'].respond_to?(:id) and kitten_cfg['parent'].id
214
+ x['name']+x['parent'].id
215
+ elsif x['project']
216
+ x['name']+x['project']
217
+ else
218
+ x['name']
219
+ end
220
+ }
221
+ strs[0] <=> strs[1]
222
+ }
223
+
224
+ # If we've got duplicate names in here, try to deal with it
225
+ bok[res_class.cfg_plural].each { |kitten_cfg|
226
+ bok[res_class.cfg_plural].each { |sibling|
227
+ next if kitten_cfg == sibling
228
+ if sibling['name'] == kitten_cfg['name']
229
+ MU.log "#{res_class.cfg_name} name #{sibling['name']} unavailable, will attempt to rename duplicate object", MU::DEBUG, details: kitten_cfg
230
+ if kitten_cfg['parent'] and kitten_cfg['parent'].respond_to?(:id) and kitten_cfg['parent'].id
231
+ kitten_cfg['name'] = kitten_cfg['name']+kitten_cfg['parent'].id
232
+ elsif kitten_cfg['project']
233
+ kitten_cfg['name'] = kitten_cfg['name']+kitten_cfg['project']
234
+ elsif kitten_cfg['cloud_id']
235
+ kitten_cfg['name'] = kitten_cfg['name']+kitten_cfg['cloud_id'].gsub(/[^a-z0-9]/i, "-")
236
+ else
237
+ raise MU::Config::DuplicateNameError, "Saw duplicate #{res_class.cfg_name} name #{sibling['name']} and couldn't come up with a good way to differentiate them"
238
+ end
239
+ MU.log "De-duplication: Renamed #{res_class.cfg_name} name '#{sibling['name']}' => '#{kitten_cfg['name']}'", MU::NOTICE
240
+ break
241
+ end
242
+ }
243
+ }
244
+ }
245
+ }
246
+
247
+ # No matching resources isn't necessarily an error
248
+ next if count == 0 or bok.nil?
249
+
250
+ # Now walk through all of the Refs in these objects, resolve them, and minimize
251
+ # their config footprint
252
+ MU.log "Minimizing footprint of #{count.to_s} found resources", MU::DEBUG
253
+ @boks[bok['appname']] = vacuum(bok, origin: origin, save: @savedeploys)
254
+
255
+ if @diff and !deploy
256
+ MU.log "diff flag set, but no comparable deploy provided for #{bok['appname']}", MU::ERR
257
+ exit 1
258
+ end
259
+
260
+ if deploy and @diff
261
+ prevcfg = MU::Config.manxify(vacuum(deploy.original_config, deploy: deploy))
262
+ if !prevcfg
263
+ MU.log "#{deploy.deploy_id} didn't have a working original config for me to compare", MU::ERR
264
+ exit 1
265
+ end
266
+ newcfg = MU::Config.manxify(@boks[bok['appname']])
267
+
268
+ prevcfg.diff(newcfg)
269
+ exit
270
+ end
271
+ }
272
+ @boks
273
+ end
274
+
275
+ private
276
+
277
+ # Recursively walk through a BoK hash, validate all {MU::Config::Ref}
278
+ # objects, convert them to hashes, and pare them down to the minimal
279
+ # representation (remove extraneous attributes that match the parent
280
+ # object).
281
+ # Do the same for our main objects: if they all use the same credentials,
282
+ # for example, remove the explicit +credentials+ attributes and set that
283
+ # value globally, once.
284
+ def vacuum(bok, origin: nil, save: false, deploy: nil)
285
+ deploy ||= generateStubDeploy(bok)
286
+
287
+ globals = {
288
+ 'cloud' => {},
289
+ 'credentials' => {},
290
+ 'region' => {},
291
+ 'billing_acct' => {},
292
+ 'us_only' => {},
293
+ }
294
+ clouds = {}
295
+ credentials = {}
296
+ regions = {}
297
+ MU::Cloud.resource_types.each_pair { |typename, attrs|
298
+ if bok[attrs[:cfg_plural]]
299
+ processed = []
300
+ bok[attrs[:cfg_plural]].each { |resource|
301
+ globals.each_pair { |field, counts|
302
+ if resource[field]
303
+ counts[resource[field]] ||= 0
304
+ counts[resource[field]] += 1
305
+ end
306
+ }
307
+ obj = deploy.findLitterMate(type: attrs[:cfg_plural], name: resource['name'])
308
+ begin
309
+ processed << resolveReferences(resource, deploy, obj)
310
+ rescue Incomplete
311
+ end
312
+ resource.delete("cloud_id")
313
+ }
314
+ deploy.original_config[attrs[:cfg_plural]] = processed
315
+ bok[attrs[:cfg_plural]] = processed
316
+ end
317
+ }
318
+
319
+ # Pare out global values like +cloud+ or +region+ that appear to be
320
+ # universal in the deploy we're creating.
321
+ def scrub_globals(h, field)
322
+ if h.is_a?(Hash)
323
+ newhash = {}
324
+ h.each_pair { |k, v|
325
+ next if k == field
326
+ newhash[k] = scrub_globals(v, field)
327
+ }
328
+ h = newhash
329
+ elsif h.is_a?(Array)
330
+ newarr = []
331
+ h.each { |v|
332
+ newarr << scrub_globals(v, field)
333
+ }
334
+ h = newarr
335
+ end
336
+
337
+ h
338
+ end
339
+
340
+ globals.each_pair { |field, counts|
341
+ next if counts.size != 1
342
+ bok[field] = counts.keys.first
343
+ MU.log "Setting global default #{field} to #{bok[field]} (#{deploy.deploy_id})", MU::DEBUG
344
+ MU::Cloud.resource_types.each_pair { |typename, attrs|
345
+ if bok[attrs[:cfg_plural]]
346
+ new_resources = []
347
+ bok[attrs[:cfg_plural]].each { |resource|
348
+ new_resources << scrub_globals(resource, field)
349
+ }
350
+ bok[attrs[:cfg_plural]] = new_resources
351
+ end
352
+ }
353
+ }
354
+
355
+ if save
356
+ MU.log "Committing adopted deployment to #{MU.dataDir}/deployments/#{deploy.deploy_id}", MU::NOTICE, details: origin
357
+ deploy.save!(force: true, origin: origin)
358
+ end
359
+
360
+ bok
361
+ end
362
+
363
+ def resolveReferences(cfg, deploy, parent)
364
+ if cfg.is_a?(MU::Config::Ref)
365
+ hashcfg = cfg.to_h
366
+ if cfg.kitten(deploy)
367
+ littermate = deploy.findLitterMate(type: cfg.type, name: cfg.name, cloud_id: cfg.id, habitat: cfg.habitat)
368
+ if littermate and littermate.config['name']
369
+ hashcfg['name'] = littermate.config['name']
370
+ hashcfg.delete("id") if hashcfg["name"]
371
+ hashcfg
372
+ elsif cfg.deploy_id and cfg.name and @savedeploys
373
+ hashcfg.delete("id") if hashcfg["name"]
374
+ hashcfg
375
+ elsif cfg.id
376
+ littermate = deploy.findLitterMate(type: cfg.type, cloud_id: cfg.id, habitat: cfg.habitat)
377
+ if littermate and littermate.config['name']
378
+ hashcfg['name'] = littermate.config['name']
379
+ hashcfg.delete("id") if hashcfg["name"]
380
+ elsif !@savedeploys
381
+ hashcfg.delete("deploy_id")
382
+ hashcfg.delete("name")
383
+ else
384
+ hashcfg.delete("name") if cfg.id and !cfg.deploy_id
385
+ end
386
+ end
387
+ elsif hashcfg["id"] # reference to raw cloud ids is reasonable
388
+ hashcfg.delete("deploy_id")
389
+ hashcfg.delete("name")
390
+ else
391
+ pp parent.cloud_desc
392
+ raise Incomplete, "Failed to resolve reference on behalf of #{parent}"
393
+ end
394
+ hashcfg.delete("deploy_id") if hashcfg['deploy_id'] == deploy.deploy_id
395
+ cfg = hashcfg
396
+ elsif cfg.is_a?(Hash)
397
+ deletia = []
398
+ cfg.each_pair { |key, value|
399
+ begin
400
+ cfg[key] = resolveReferences(value, deploy, parent)
401
+ rescue Incomplete
402
+ MU.log "Dropping unresolved key #{key}", MU::WARN, details: cfg
403
+ deletia << key
404
+ end
405
+ }
406
+ deletia.each { |key|
407
+ cfg.delete(key)
408
+ }
409
+ cfg = nil if cfg.empty? and deletia.size > 0
410
+ elsif cfg.is_a?(Array)
411
+ new_array = []
412
+ cfg.each { |value|
413
+ begin
414
+ new_item = resolveReferences(value, deploy, parent)
415
+ if !new_item
416
+ MU.log "Dropping unresolved value", MU::WARN, details: value
417
+ else
418
+ new_array << new_item
419
+ end
420
+ rescue Incomplete
421
+ MU.log "Dropping unresolved value", MU::WARN, details: value
422
+ end
423
+ }
424
+ cfg = new_array
425
+ end
426
+
427
+ cfg
428
+ end
429
+
430
+ # @return [MU::MommaCat]
431
+ def generateStubDeploy(bok)
432
+ # hashify Ref objects before passing into here... or do we...?
433
+
434
+ time = Time.new
435
+ timestamp = time.strftime("%Y%m%d%H").to_s;
436
+ timestamp.freeze
437
+
438
+ retries = 0
439
+ deploy_id = nil
440
+ seed = nil
441
+ begin
442
+ raise MuError, "Failed to allocate an unused MU-ID after #{retries} tries!" if retries > 70
443
+ seedsize = 1 + (retries/10).abs
444
+ seed = (0...seedsize+1).map { ('a'..'z').to_a[rand(26)] }.join
445
+ deploy_id = bok['appname'].upcase + "-ADOPT-" + timestamp + "-" + seed.upcase
446
+ end while MU::MommaCat.deploy_exists?(deploy_id) or seed == "mu" or seed[0] == seed[1]
447
+
448
+ MU.setVar("deploy_id", deploy_id)
449
+ MU.setVar("appname", bok['appname'].upcase)
450
+ MU.setVar("environment", "ADOPT")
451
+ MU.setVar("timestamp", timestamp)
452
+ MU.setVar("seed", seed)
453
+ MU.setVar("handle", MU::MommaCat.generateHandle(seed))
454
+
455
+ deploy = MU::MommaCat.new(
456
+ deploy_id,
457
+ create: true,
458
+ config: bok,
459
+ environment: "adopt",
460
+ appname: bok['appname'].upcase,
461
+ timestamp: timestamp,
462
+ nocleanup: true,
463
+ no_artifacts: !(@savedeploys),
464
+ set_context_to_me: true,
465
+ mu_user: MU.mu_user
466
+ )
467
+
468
+ MU::Cloud.resource_types.each_pair { |typename, attrs|
469
+ if bok[attrs[:cfg_plural]]
470
+ bok[attrs[:cfg_plural]].each { |kitten|
471
+
472
+ if !@scraped[typename][kitten['cloud_id']]
473
+ MU.log "No object in scraped tree for #{attrs[:cfg_name]} #{kitten['cloud_id']} (#{kitten['name']})", MU::ERR, details: kitten
474
+ next
475
+ end
476
+
477
+ MU.log "Inserting #{attrs[:cfg_name]} #{kitten['name']} (#{kitten['cloud_id']}) into stub deploy", MU::DEBUG, details: @scraped[typename][kitten['cloud_id']]
478
+
479
+ @scraped[typename][kitten['cloud_id']].config!(kitten)
480
+
481
+ deploy.addKitten(
482
+ attrs[:cfg_plural],
483
+ kitten['name'],
484
+ @scraped[typename][kitten['cloud_id']]
485
+ )
486
+ }
487
+ end
488
+ }
489
+
490
+ deploy
491
+ end
492
+
493
+ # Go through everything we've scraped and update our mappings of cloud ids
494
+ # and bare name fields, so that resources can reference one another
495
+ # portably by name.
496
+ def catalogResources
497
+ end
498
+
499
+ end
500
+ end