cloud-mu 3.1.2 → 3.2.0

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 (201) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +15 -3
  3. data/ansible/roles/mu-windows/README.md +33 -0
  4. data/ansible/roles/mu-windows/defaults/main.yml +2 -0
  5. data/ansible/roles/mu-windows/files/LaunchConfig.json +9 -0
  6. data/ansible/roles/mu-windows/files/config.xml +76 -0
  7. data/ansible/roles/mu-windows/handlers/main.yml +2 -0
  8. data/ansible/roles/mu-windows/meta/main.yml +53 -0
  9. data/ansible/roles/mu-windows/tasks/main.yml +36 -0
  10. data/ansible/roles/mu-windows/tests/inventory +2 -0
  11. data/ansible/roles/mu-windows/tests/test.yml +5 -0
  12. data/ansible/roles/mu-windows/vars/main.yml +2 -0
  13. data/bin/mu-adopt +10 -13
  14. data/bin/mu-azure-tests +57 -0
  15. data/bin/mu-cleanup +2 -4
  16. data/bin/mu-configure +52 -0
  17. data/bin/mu-deploy +3 -3
  18. data/bin/mu-findstray-tests +25 -0
  19. data/bin/mu-gen-docs +2 -4
  20. data/bin/mu-load-config.rb +2 -3
  21. data/bin/mu-node-manage +15 -16
  22. data/bin/mu-run-tests +135 -37
  23. data/cloud-mu.gemspec +22 -20
  24. data/cookbooks/mu-activedirectory/resources/domain.rb +4 -4
  25. data/cookbooks/mu-activedirectory/resources/domain_controller.rb +4 -4
  26. data/cookbooks/mu-tools/libraries/helper.rb +3 -2
  27. data/cookbooks/mu-tools/libraries/monkey.rb +35 -0
  28. data/cookbooks/mu-tools/recipes/apply_security.rb +14 -14
  29. data/cookbooks/mu-tools/recipes/aws_api.rb +9 -0
  30. data/cookbooks/mu-tools/recipes/eks.rb +2 -2
  31. data/cookbooks/mu-tools/recipes/google_api.rb +2 -2
  32. data/cookbooks/mu-tools/recipes/selinux.rb +2 -1
  33. data/cookbooks/mu-tools/recipes/windows-client.rb +163 -164
  34. data/cookbooks/mu-tools/resources/disk.rb +1 -1
  35. data/cookbooks/mu-tools/resources/windows_users.rb +44 -43
  36. data/extras/clean-stock-amis +25 -19
  37. data/extras/generate-stock-images +1 -0
  38. data/extras/image-generators/AWS/win2k12.yaml +18 -13
  39. data/extras/image-generators/AWS/win2k16.yaml +18 -13
  40. data/extras/image-generators/AWS/win2k19.yaml +21 -0
  41. data/extras/image-generators/Google/centos6.yaml +1 -0
  42. data/extras/image-generators/Google/centos7.yaml +1 -1
  43. data/modules/mommacat.ru +6 -16
  44. data/modules/mu.rb +165 -111
  45. data/modules/mu/adoption.rb +401 -68
  46. data/modules/mu/cleanup.rb +199 -306
  47. data/modules/mu/cloud.rb +100 -1632
  48. data/modules/mu/cloud/database.rb +49 -0
  49. data/modules/mu/cloud/dnszone.rb +46 -0
  50. data/modules/mu/cloud/machine_images.rb +212 -0
  51. data/modules/mu/cloud/providers.rb +81 -0
  52. data/modules/mu/cloud/resource_base.rb +920 -0
  53. data/modules/mu/cloud/server.rb +40 -0
  54. data/modules/mu/cloud/server_pool.rb +1 -0
  55. data/modules/mu/cloud/ssh_sessions.rb +228 -0
  56. data/modules/mu/cloud/winrm_sessions.rb +237 -0
  57. data/modules/mu/cloud/wrappers.rb +165 -0
  58. data/modules/mu/config.rb +171 -1767
  59. data/modules/mu/config/alarm.rb +2 -6
  60. data/modules/mu/config/bucket.rb +4 -4
  61. data/modules/mu/config/cache_cluster.rb +1 -1
  62. data/modules/mu/config/collection.rb +4 -4
  63. data/modules/mu/config/container_cluster.rb +9 -4
  64. data/modules/mu/config/database.rb +83 -104
  65. data/modules/mu/config/database.yml +1 -2
  66. data/modules/mu/config/dnszone.rb +6 -6
  67. data/modules/mu/config/doc_helpers.rb +516 -0
  68. data/modules/mu/config/endpoint.rb +4 -4
  69. data/modules/mu/config/firewall_rule.rb +103 -4
  70. data/modules/mu/config/folder.rb +4 -4
  71. data/modules/mu/config/function.rb +3 -3
  72. data/modules/mu/config/group.rb +4 -4
  73. data/modules/mu/config/habitat.rb +4 -4
  74. data/modules/mu/config/loadbalancer.rb +60 -14
  75. data/modules/mu/config/log.rb +4 -4
  76. data/modules/mu/config/msg_queue.rb +4 -4
  77. data/modules/mu/config/nosqldb.rb +4 -4
  78. data/modules/mu/config/notifier.rb +3 -3
  79. data/modules/mu/config/ref.rb +365 -0
  80. data/modules/mu/config/role.rb +4 -4
  81. data/modules/mu/config/schema_helpers.rb +509 -0
  82. data/modules/mu/config/search_domain.rb +4 -4
  83. data/modules/mu/config/server.rb +97 -70
  84. data/modules/mu/config/server.yml +1 -0
  85. data/modules/mu/config/server_pool.rb +5 -9
  86. data/modules/mu/config/storage_pool.rb +1 -1
  87. data/modules/mu/config/tail.rb +200 -0
  88. data/modules/mu/config/user.rb +4 -4
  89. data/modules/mu/config/vpc.rb +70 -27
  90. data/modules/mu/config/vpc.yml +0 -1
  91. data/modules/mu/defaults/AWS.yaml +83 -60
  92. data/modules/mu/defaults/Azure.yaml +1 -0
  93. data/modules/mu/defaults/Google.yaml +3 -2
  94. data/modules/mu/deploy.rb +30 -26
  95. data/modules/mu/groomer.rb +17 -2
  96. data/modules/mu/groomers/ansible.rb +188 -41
  97. data/modules/mu/groomers/chef.rb +116 -55
  98. data/modules/mu/logger.rb +127 -148
  99. data/modules/mu/master.rb +389 -2
  100. data/modules/mu/master/chef.rb +3 -4
  101. data/modules/mu/master/ldap.rb +3 -3
  102. data/modules/mu/master/ssl.rb +12 -3
  103. data/modules/mu/mommacat.rb +217 -2612
  104. data/modules/mu/mommacat/daemon.rb +397 -0
  105. data/modules/mu/mommacat/naming.rb +473 -0
  106. data/modules/mu/mommacat/search.rb +495 -0
  107. data/modules/mu/mommacat/storage.rb +722 -0
  108. data/modules/mu/{clouds → providers}/README.md +1 -1
  109. data/modules/mu/{clouds → providers}/aws.rb +271 -112
  110. data/modules/mu/{clouds → providers}/aws/alarm.rb +5 -3
  111. data/modules/mu/{clouds → providers}/aws/bucket.rb +26 -22
  112. data/modules/mu/{clouds → providers}/aws/cache_cluster.rb +33 -67
  113. data/modules/mu/{clouds → providers}/aws/collection.rb +24 -23
  114. data/modules/mu/{clouds → providers}/aws/container_cluster.rb +681 -721
  115. data/modules/mu/providers/aws/database.rb +1744 -0
  116. data/modules/mu/{clouds → providers}/aws/dnszone.rb +64 -63
  117. data/modules/mu/{clouds → providers}/aws/endpoint.rb +22 -27
  118. data/modules/mu/{clouds → providers}/aws/firewall_rule.rb +214 -244
  119. data/modules/mu/{clouds → providers}/aws/folder.rb +7 -7
  120. data/modules/mu/{clouds → providers}/aws/function.rb +17 -22
  121. data/modules/mu/{clouds → providers}/aws/group.rb +23 -23
  122. data/modules/mu/{clouds → providers}/aws/habitat.rb +17 -14
  123. data/modules/mu/{clouds → providers}/aws/loadbalancer.rb +57 -48
  124. data/modules/mu/{clouds → providers}/aws/log.rb +15 -12
  125. data/modules/mu/{clouds → providers}/aws/msg_queue.rb +17 -16
  126. data/modules/mu/{clouds → providers}/aws/nosqldb.rb +18 -11
  127. data/modules/mu/{clouds → providers}/aws/notifier.rb +11 -6
  128. data/modules/mu/{clouds → providers}/aws/role.rb +112 -86
  129. data/modules/mu/{clouds → providers}/aws/search_domain.rb +39 -33
  130. data/modules/mu/{clouds → providers}/aws/server.rb +835 -1133
  131. data/modules/mu/{clouds → providers}/aws/server_pool.rb +56 -60
  132. data/modules/mu/{clouds → providers}/aws/storage_pool.rb +24 -42
  133. data/modules/mu/{clouds → providers}/aws/user.rb +21 -22
  134. data/modules/mu/{clouds → providers}/aws/userdata/README.md +0 -0
  135. data/modules/mu/{clouds → providers}/aws/userdata/linux.erb +0 -0
  136. data/modules/mu/{clouds → providers}/aws/userdata/windows.erb +2 -1
  137. data/modules/mu/{clouds → providers}/aws/vpc.rb +523 -929
  138. data/modules/mu/providers/aws/vpc_subnet.rb +286 -0
  139. data/modules/mu/{clouds → providers}/azure.rb +29 -9
  140. data/modules/mu/{clouds → providers}/azure/container_cluster.rb +3 -8
  141. data/modules/mu/{clouds → providers}/azure/firewall_rule.rb +18 -11
  142. data/modules/mu/{clouds → providers}/azure/habitat.rb +8 -6
  143. data/modules/mu/{clouds → providers}/azure/loadbalancer.rb +5 -5
  144. data/modules/mu/{clouds → providers}/azure/role.rb +8 -10
  145. data/modules/mu/{clouds → providers}/azure/server.rb +95 -48
  146. data/modules/mu/{clouds → providers}/azure/user.rb +6 -8
  147. data/modules/mu/{clouds → providers}/azure/userdata/README.md +0 -0
  148. data/modules/mu/{clouds → providers}/azure/userdata/linux.erb +0 -0
  149. data/modules/mu/{clouds → providers}/azure/userdata/windows.erb +0 -0
  150. data/modules/mu/{clouds → providers}/azure/vpc.rb +16 -21
  151. data/modules/mu/{clouds → providers}/cloudformation.rb +18 -7
  152. data/modules/mu/{clouds → providers}/cloudformation/alarm.rb +3 -3
  153. data/modules/mu/{clouds → providers}/cloudformation/cache_cluster.rb +3 -3
  154. data/modules/mu/{clouds → providers}/cloudformation/collection.rb +3 -3
  155. data/modules/mu/{clouds → providers}/cloudformation/database.rb +6 -17
  156. data/modules/mu/{clouds → providers}/cloudformation/dnszone.rb +3 -3
  157. data/modules/mu/{clouds → providers}/cloudformation/firewall_rule.rb +3 -3
  158. data/modules/mu/{clouds → providers}/cloudformation/loadbalancer.rb +3 -3
  159. data/modules/mu/{clouds → providers}/cloudformation/log.rb +3 -3
  160. data/modules/mu/{clouds → providers}/cloudformation/server.rb +7 -7
  161. data/modules/mu/{clouds → providers}/cloudformation/server_pool.rb +5 -5
  162. data/modules/mu/{clouds → providers}/cloudformation/vpc.rb +5 -7
  163. data/modules/mu/{clouds → providers}/docker.rb +0 -0
  164. data/modules/mu/{clouds → providers}/google.rb +67 -30
  165. data/modules/mu/{clouds → providers}/google/bucket.rb +13 -15
  166. data/modules/mu/{clouds → providers}/google/container_cluster.rb +84 -77
  167. data/modules/mu/{clouds → providers}/google/database.rb +10 -20
  168. data/modules/mu/{clouds → providers}/google/firewall_rule.rb +15 -14
  169. data/modules/mu/{clouds → providers}/google/folder.rb +20 -17
  170. data/modules/mu/{clouds → providers}/google/function.rb +139 -167
  171. data/modules/mu/{clouds → providers}/google/group.rb +29 -34
  172. data/modules/mu/{clouds → providers}/google/habitat.rb +21 -22
  173. data/modules/mu/{clouds → providers}/google/loadbalancer.rb +18 -20
  174. data/modules/mu/{clouds → providers}/google/role.rb +92 -58
  175. data/modules/mu/{clouds → providers}/google/server.rb +242 -155
  176. data/modules/mu/{clouds → providers}/google/server_pool.rb +25 -44
  177. data/modules/mu/{clouds → providers}/google/user.rb +95 -31
  178. data/modules/mu/{clouds → providers}/google/userdata/README.md +0 -0
  179. data/modules/mu/{clouds → providers}/google/userdata/linux.erb +0 -0
  180. data/modules/mu/{clouds → providers}/google/userdata/windows.erb +0 -0
  181. data/modules/mu/{clouds → providers}/google/vpc.rb +103 -79
  182. data/modules/tests/bucket.yml +4 -0
  183. data/modules/tests/centos6.yaml +11 -0
  184. data/modules/tests/centos7.yaml +11 -0
  185. data/modules/tests/centos8.yaml +12 -0
  186. data/modules/tests/ecs.yaml +23 -0
  187. data/modules/tests/includes-and-params.yaml +2 -1
  188. data/modules/tests/rds.yaml +108 -0
  189. data/modules/tests/regrooms/aws-iam.yaml +201 -0
  190. data/modules/tests/regrooms/bucket.yml +19 -0
  191. data/modules/tests/regrooms/rds.yaml +123 -0
  192. data/modules/tests/server-with-scrub-muisms.yaml +1 -0
  193. data/modules/tests/super_simple_bok.yml +1 -3
  194. data/modules/tests/win2k12.yaml +17 -5
  195. data/modules/tests/win2k16.yaml +25 -0
  196. data/modules/tests/win2k19.yaml +25 -0
  197. data/requirements.txt +1 -0
  198. data/spec/mu/clouds/azure_spec.rb +2 -2
  199. metadata +232 -154
  200. data/extras/image-generators/AWS/windows.yaml +0 -18
  201. data/modules/mu/clouds/aws/database.rb +0 -1985
@@ -0,0 +1,495 @@
1
+ # Copyright:: Copyright (c) 2020 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
+ # MommaCat is in charge of managing metadata about resources we've created,
18
+ # as well as orchestrating amongst them and bootstrapping nodes outside of
19
+ # the normal synchronous deploy sequence invoked by *mu-deploy*.
20
+ class MommaCat
21
+
22
+ @@desc_semaphore = Mutex.new
23
+
24
+ # A search which returned multiple matches, but is not allowed to
25
+ class MultipleMatches < MuError
26
+ def initialize(message = nil)
27
+ super(message, silent: true)
28
+ end
29
+ end
30
+
31
+ # Locate a resource that's either a member of another deployment, or of no
32
+ # deployment at all, and return a {MU::Cloud} object for it.
33
+ # @param cloud [String]: The Cloud provider to use.
34
+ # @param type [String]: The resource type. Can be the full class name, symbolic name, or Basket of Kittens configuration shorthand for the resource type.
35
+ # @param deploy_id [String]: The identifier of an outside deploy to search.
36
+ # @param name [String]: The name of the resource as defined in its 'name' Basket of Kittens field, typically used in conjunction with deploy_id.
37
+ # @param mu_name [String]: The fully-resolved and deployed name of the resource, typically used in conjunction with deploy_id.
38
+ # @param cloud_id [String]: A cloud provider identifier for this resource.
39
+ # @param region [String]: The cloud provider region
40
+ # @param tag_key [String]: A cloud provider tag to help identify the resource, used in conjunction with tag_value.
41
+ # @param tag_value [String]: A cloud provider tag to help identify the resource, used in conjunction with tag_key.
42
+ # @param allow_multi [Boolean]: Permit an array of matching resources to be returned (if applicable) instead of just one.
43
+ # @param dummy_ok [Boolean]: Permit return of a faked {MU::Cloud} object if we don't have enough information to identify a real live one.
44
+ # @return [Array<MU::Cloud>]
45
+ def self.findStray(cloud, type,
46
+ dummy_ok: false,
47
+ no_deploy_search: false,
48
+ allow_multi: false,
49
+ deploy_id: nil,
50
+ name: nil,
51
+ mu_name: nil,
52
+ cloud_id: nil,
53
+ credentials: nil,
54
+ region: nil,
55
+ tag_key: nil,
56
+ tag_value: nil,
57
+ calling_deploy: MU.mommacat,
58
+ habitats: [],
59
+ **flags
60
+ )
61
+ _shortclass, _cfg_name, type, _classname, _attrs = MU::Cloud.getResourceNames(type, true)
62
+
63
+ cloudclass = MU::Cloud.cloudClass(cloud)
64
+ return nil if cloudclass.virtual?
65
+
66
+ if (tag_key and !tag_value) or (!tag_key and tag_value)
67
+ raise MuError, "Can't call findStray with only one of tag_key and tag_value set, must be both or neither"
68
+ end
69
+
70
+ credlist = credentials ? [credentials] : cloudclass.listCredentials
71
+
72
+ # Help ourselves by making more refined parameters out of mu_name, if
73
+ # they weren't passed explicitly
74
+ if mu_name
75
+ # We can extract a deploy_id from mu_name if we don't have one already
76
+ deploy_id ||= mu_name.sub(/^(\w+-\w+-\d{10}-[A-Z]{2})-/, '\1')
77
+ if !tag_key and !tag_value
78
+ tag_key = "Name"
79
+ tag_value = mu_name
80
+ end
81
+ end
82
+
83
+ # See if the thing we're looking for is a member of the deploy that's
84
+ # asking after it.
85
+ if !deploy_id.nil? and !calling_deploy.nil? and
86
+ calling_deploy.deploy_id == deploy_id and (!name.nil? or !mu_name.nil?)
87
+ kitten = calling_deploy.findLitterMate(type: type, name: name, mu_name: mu_name, cloud_id: cloud_id, credentials: credentials)
88
+ return [kitten] if !kitten.nil?
89
+ end
90
+
91
+ # See if we have it in deployment metadata generally
92
+ kittens = {}
93
+ if !no_deploy_search and (deploy_id or name or mu_name or cloud_id)
94
+ kittens = search_my_deploys(type, deploy_id: deploy_id, name: name, mu_name: mu_name, cloud_id: cloud_id, credentials: credentials)
95
+ return kittens.values if kittens.size == 1
96
+
97
+ # We can't refine any further by asking the cloud provider...
98
+ if kittens.size > 1 and !allow_multi and
99
+ !cloud_id and !tag_key and !tag_value
100
+ raise MultipleMatches, "Multiple matches in MU::MommaCat.findStray where none allowed from #{cloud}, #{type}, name: #{name}, mu_name: #{mu_name}, cloud_id: #{cloud_id}, credentials: #{credentials}, habitats: #{habitats} (#{caller(1..1)})"
101
+ end
102
+ end
103
+
104
+ if !cloud_id and !(tag_key and tag_value) and (name or mu_name or deploy_id)
105
+ return kittens.values
106
+ end
107
+ matches = []
108
+
109
+ credlist.each { |creds|
110
+ # next if region and region.is_a?(Array) and !region.empty? and !region.include?(r)
111
+ cloud_descs = search_cloud_provider(type, cloud, habitats, region, cloud_id: cloud_id, tag_key: tag_key, tag_value: tag_value, credentials: creds, flags: flags)
112
+
113
+ cloud_descs.each_pair.each { |p, regions|
114
+ regions.each_pair.each { |r, results|
115
+ results.each_pair { |kitten_cloud_id, descriptor|
116
+ # We already have a MU::Cloud object for this guy, use it
117
+ if kittens.has_key?(kitten_cloud_id)
118
+ matches << kittens[kitten_cloud_id]
119
+ elsif dummy_ok and kittens.empty?
120
+ # XXX this is why this was threaded
121
+ matches << generate_dummy_object(type, cloud, name, mu_name, kitten_cloud_id, descriptor, r, p, tag_value, calling_deploy, creds)
122
+ end
123
+ }
124
+ }
125
+ }
126
+ }
127
+
128
+ matches
129
+ end
130
+
131
+ @object_load_fails = false
132
+
133
+ # Return the resource object of another member of this deployment
134
+ # @param type [String,Symbol]: The type of resource
135
+ # @param name [String]: The name of the resource as defined in its 'name' Basket of Kittens field
136
+ # @param mu_name [String]: The fully-resolved and deployed name of the resource
137
+ # @param cloud_id [String]: The cloud provider's unique identifier for this resource
138
+ # @param created_only [Boolean]: Only return the littermate if its cloud_id method returns a value
139
+ # @param return_all [Boolean]: Return a Hash of matching objects indexed by their mu_name, instead of a single match. Only valid for resource types where has_multiples is true.
140
+ # @return [MU::Cloud]
141
+ def findLitterMate(type: nil, name: nil, mu_name: nil, cloud_id: nil, created_only: false, return_all: false, credentials: nil, habitat: nil, debug: false, **flags)
142
+ _shortclass, _cfg_name, type, _classname, attrs = MU::Cloud.getResourceNames(type)
143
+
144
+ # If we specified a habitat, which we may also have done by its shorthand
145
+ # sibling name, or a Ref. Convert to something we can use.
146
+ habitat = resolve_habitat(habitat, credentials: credentials)
147
+
148
+ nofilter = (mu_name.nil? and cloud_id.nil? and credentials.nil?)
149
+
150
+ does_match = Proc.new { |obj|
151
+
152
+ (!created_only or !obj.cloud_id.nil?) and (nofilter or (
153
+ (mu_name and obj.mu_name and mu_name.to_s == obj.mu_name) or
154
+ (cloud_id and obj.cloud_id and cloud_id.to_s == obj.cloud_id.to_s) or
155
+ (credentials and obj.credentials and credentials.to_s == obj.credentials.to_s) and
156
+ !(
157
+ (mu_name and obj.mu_name and mu_name.to_s != obj.mu_name) or
158
+ (cloud_id and obj.cloud_id and cloud_id.to_s != obj.cloud_id.to_s) or
159
+ (credentials and obj.credentials and credentials.to_s != obj.credentials.to_s)
160
+ )
161
+ ))
162
+ }
163
+
164
+ @kitten_semaphore.synchronize {
165
+
166
+ if !@kittens.has_key?(type)
167
+ return nil if !@original_config or @original_config[type].nil? or @original_config[type].empty?
168
+ begin
169
+ loadObjects(false)
170
+ rescue ThreadError => e
171
+ if e.message !~ /deadlock/
172
+ raise e
173
+ end
174
+ end
175
+ if @object_load_fails or !@kittens[type]
176
+ MU.log "#{@deploy_id}'s original config has #{@original_config[type].size == 1 ? "a" : @original_config[type].size.to_s} #{type}, but loadObjects could not populate anything from deployment metadata", MU::ERR if !@object_load_fails
177
+ @object_load_fails = true
178
+ return nil
179
+ end
180
+ end
181
+ matches = {}
182
+ @kittens[type].each { |habitat_group, sib_classes|
183
+ next if habitat and habitat_group and habitat_group != habitat
184
+ sib_classes.each_pair { |sib_class, cloud_objs|
185
+
186
+ if attrs[:has_multiples]
187
+ next if !name.nil? and name != sib_class or cloud_objs.empty?
188
+ if !name.nil?
189
+ if return_all
190
+ matches.merge!(cloud_objs.clone)
191
+ next
192
+ elsif cloud_objs.size == 1 and does_match.call(cloud_objs.values.first)
193
+ return cloud_objs.values.first
194
+ end
195
+ end
196
+
197
+ cloud_objs.each_value { |obj|
198
+ if does_match.call(obj)
199
+ if return_all
200
+ matches.merge!(cloud_objs.clone)
201
+ else
202
+ return obj.clone
203
+ end
204
+ end
205
+ }
206
+ # has_multiples is false, "cloud_objs" is actually a singular object
207
+ elsif (name.nil? and does_match.call(cloud_objs)) or [sib_class, cloud_objs.virtual_name(name)].include?(name.to_s)
208
+ matches[cloud_objs.config['name']] = cloud_objs.clone
209
+ end
210
+ }
211
+ }
212
+
213
+ return matches if return_all and matches.size >= 1
214
+
215
+ return matches.values.first if matches.size == 1
216
+
217
+ }
218
+
219
+ return nil
220
+ end
221
+
222
+
223
+ private
224
+
225
+ def resolve_habitat(habitat, credentials: nil, debug: false)
226
+ return nil if habitat.nil?
227
+ if habitat.is_a?(MU::Config::Ref) and habitat.id
228
+ return habitat.id
229
+ else
230
+ realhabitat = findLitterMate(type: "habitat", name: habitat, credentials: credentials)
231
+ if realhabitat and realhabitat.mu_name
232
+ return realhabitat.cloud_id
233
+ elsif debug
234
+ MU.log "Failed to resolve habitat name #{habitat}", MU::WARN
235
+ end
236
+ end
237
+ end
238
+
239
+ def self.generate_dummy_object(type, cloud, name, mu_name, cloud_id, desc, region, habitat, tag_value, calling_deploy, credentials)
240
+ resourceclass = MU::Cloud.resourceClass(cloud, type)
241
+
242
+ use_name = if (name.nil? or name.empty?)
243
+ if !mu_name.nil?
244
+ mu_name
245
+ else
246
+ guessName(desc, resourceclass, cloud_id: cloud_id, tag_value: tag_value)
247
+ end
248
+ else
249
+ name
250
+ end
251
+
252
+ if use_name.nil?
253
+ return
254
+ end
255
+
256
+ cfg = {
257
+ "name" => use_name,
258
+ "cloud" => cloud,
259
+ "credentials" => credentials
260
+ }
261
+ if !region.nil? and !resourceclass.isGlobal?
262
+ cfg["region"] = region
263
+ end
264
+
265
+ if resourceclass.canLiveIn.include?(:Habitat) and habitat
266
+ cfg["project"] = habitat
267
+ end
268
+
269
+ # If we can at least find the config from the deploy this will
270
+ # belong with, use that, even if it's an ungroomed resource.
271
+ if !calling_deploy.nil? and
272
+ !calling_deploy.original_config.nil? and
273
+ !calling_deploy.original_config[type+"s"].nil?
274
+ calling_deploy.original_config[type+"s"].each { |s|
275
+ if s["name"] == use_name
276
+ cfg = s.dup
277
+ break
278
+ end
279
+ }
280
+
281
+ return resourceclass.new(mommacat: calling_deploy, kitten_cfg: cfg, cloud_id: cloud_id)
282
+ else
283
+ if !@@dummy_cache[type] or !@@dummy_cache[type][cfg.to_s]
284
+ newobj = resourceclass.new(mu_name: use_name, kitten_cfg: cfg, cloud_id: cloud_id, from_cloud_desc: desc)
285
+ @@desc_semaphore.synchronize {
286
+ @@dummy_cache[type] ||= {}
287
+ @@dummy_cache[type][cfg.to_s] = newobj
288
+ }
289
+ end
290
+ return @@dummy_cache[type][cfg.to_s]
291
+ end
292
+ end
293
+ private_class_method :generate_dummy_object
294
+
295
+ def self.search_cloud_provider(type, cloud, habitats, region, cloud_id: nil, tag_key: nil, tag_value: nil, credentials: nil, flags: nil)
296
+ cloudclass = MU::Cloud.cloudClass(cloud)
297
+ resourceclass = MU::Cloud.resourceClass(cloud, type)
298
+
299
+ # Decide what regions we'll search, if applicable for this resource
300
+ # type.
301
+ regions = if resourceclass.isGlobal?
302
+ [nil]
303
+ else
304
+ if region
305
+ if region.is_a?(Array) and !region.empty?
306
+ region
307
+ else
308
+ [region]
309
+ end
310
+ else
311
+ cloudclass.listRegions(credentials: credentials)
312
+ end
313
+ end
314
+
315
+ # Decide what habitats (accounts/projects/subscriptions) we'll
316
+ # search, if applicable for this resource type.
317
+ habitats ||= []
318
+ if habitats.empty?
319
+ if resourceclass.canLiveIn.include?(nil)
320
+ habitats << nil
321
+ end
322
+ if resourceclass.canLiveIn.include?(:Habitat)
323
+ habitats.concat(cloudclass.listHabitats(credentials, use_cache: false))
324
+ end
325
+ end
326
+ habitats << nil if habitats.empty?
327
+ habitats.uniq!
328
+
329
+ cloud_descs = {}
330
+
331
+ thread_waiter = Proc.new { |threads, threshold|
332
+ begin
333
+ threads.each { |t| t.join(0.1) }
334
+ threads.reject! { |t| t.nil? or !t.alive? or !t.status }
335
+ sleep 1 if threads.size > threshold
336
+ end while threads.size > threshold
337
+ }
338
+
339
+ habitat_threads = []
340
+ found_the_thing = false
341
+ habitats.each { |hab|
342
+ break if found_the_thing
343
+ thread_waiter.call(habitat_threads, 5)
344
+
345
+ habitat_threads << Thread.new(hab) { |habitat|
346
+ cloud_descs[habitat] = {}
347
+ region_threads = []
348
+ regions.each { |reg|
349
+ break if found_the_thing
350
+ region_threads << Thread.new(reg) { |r|
351
+ found = resourceclass.find(cloud_id: cloud_id, region: r, tag_key: tag_key, tag_value: tag_value, credentials: credentials, habitat: habitat, flags: flags)
352
+
353
+ if found
354
+ @@desc_semaphore.synchronize {
355
+ cloud_descs[habitat][r] = found
356
+ }
357
+ end
358
+ # Stop if you found the thing by a specific cloud_id
359
+ if cloud_id and found and !found.empty?
360
+ found_the_thing = true
361
+ end
362
+ }
363
+ }
364
+ thread_waiter.call(region_threads, 0)
365
+ }
366
+ }
367
+ thread_waiter.call(habitat_threads, 0)
368
+
369
+ cloud_descs
370
+ end
371
+ private_class_method :search_cloud_provider
372
+
373
+ def self.search_my_deploys(type, deploy_id: nil, name: nil, mu_name: nil, cloud_id: nil, credentials: nil)
374
+ kittens = {}
375
+ _shortclass, _cfg_name, type, _classname, attrs = MU::Cloud.getResourceNames(type, true)
376
+
377
+ # Check our in-memory cache of live deploys before resorting to
378
+ # metadata
379
+ littercache = nil
380
+ # Sometimes we're called inside a locked thread, sometimes not. Deal
381
+ # with locking gracefully.
382
+ begin
383
+ @@litter_semaphore.synchronize {
384
+ littercache = @@litters.dup
385
+ }
386
+ rescue ThreadError => e
387
+ raise e if !e.message.match(/recursive locking/)
388
+ littercache = @@litters.dup
389
+ end
390
+
391
+ # First, see what we have in deploys that already happen to be loaded in
392
+ # memory.
393
+ littercache.each_pair { |cur_deploy, momma|
394
+ next if deploy_id and deploy_id != cur_deploy
395
+
396
+ @@deploy_struct_semaphore.synchronize {
397
+ @deploy_cache[deploy_id] = {
398
+ "mtime" => Time.now,
399
+ "data" => momma.deployment
400
+ }
401
+ }
402
+
403
+ straykitten = momma.findLitterMate(type: type, cloud_id: cloud_id, name: name, mu_name: mu_name, credentials: credentials, created_only: true)
404
+ if straykitten
405
+ MU.log "Found matching kitten #{straykitten.mu_name} in-memory - #{sprintf("%.2fs", (Time.now-start))}", MU::DEBUG
406
+ # Peace out if we found the exact resource we want
407
+ if cloud_id and straykitten.cloud_id.to_s == cloud_id.to_s
408
+ return { straykitten.cloud_id => straykitten }
409
+ elsif mu_name and straykitten.mu_name == mu_name
410
+ return { straykitten.cloud_id => straykitten }
411
+ else
412
+ kittens[straykitten.cloud_id] ||= straykitten
413
+ end
414
+ end
415
+ }
416
+
417
+ # Now go rifle metadata from any other deploys we have on disk, if they
418
+ # weren't already there in memory.
419
+ cacheDeployMetadata(deploy_id) # freshen up @@deploy_cache
420
+ mu_descs = {}
421
+ if deploy_id.nil?
422
+ @@deploy_cache.each_key { |deploy|
423
+ next if littercache[deploy]
424
+ next if !@@deploy_cache[deploy].has_key?('data')
425
+ next if !@@deploy_cache[deploy]['data'].has_key?(type)
426
+ if !name.nil?
427
+ next if @@deploy_cache[deploy]['data'][type][name].nil?
428
+ mu_descs[deploy] ||= []
429
+ mu_descs[deploy] << @@deploy_cache[deploy]['data'][type][name].dup
430
+ else
431
+ mu_descs[deploy] ||= []
432
+ mu_descs[deploy].concat(@@deploy_cache[deploy]['data'][type].values)
433
+ end
434
+ }
435
+ elsif !@@deploy_cache[deploy_id].nil?
436
+ if !@@deploy_cache[deploy_id]['data'].nil? and
437
+ !@@deploy_cache[deploy_id]['data'][type].nil?
438
+ if !name.nil? and !@@deploy_cache[deploy_id]['data'][type][name].nil?
439
+ mu_descs[deploy_id] ||= []
440
+ mu_descs[deploy_id] << @@deploy_cache[deploy_id]['data'][type][name].dup
441
+ else
442
+ mu_descs[deploy_id] = @@deploy_cache[deploy_id]['data'][type].values
443
+ end
444
+ end
445
+ end
446
+
447
+ mu_descs.each_pair { |deploy, matches|
448
+ next if matches.nil? or matches.size == 0
449
+ momma = MU::MommaCat.getLitter(deploy)
450
+
451
+ # If we found exactly one match in this deploy, use its metadata to
452
+ # guess at resource names we weren't told.
453
+ straykitten = if matches.size > 1 and cloud_id
454
+ momma.findLitterMate(type: type, cloud_id: cloud_id, credentials: credentials, created_only: true)
455
+ elsif matches.size == 1 and (!attrs[:has_multiples] or matches.first.size == 1) and name.nil? and mu_name.nil?
456
+ actual_data = attrs[:has_multiples] ? matches.first.values.first : matches.first
457
+ if cloud_id.nil?
458
+ momma.findLitterMate(type: type, name: (actual_data["name"] || actual_data["MU_NODE_CLASS"]), cloud_id: actual_data["cloud_id"], credentials: credentials)
459
+ else
460
+ momma.findLitterMate(type: type, name: (actual_data["name"] || actual_data["MU_NODE_CLASS"]), cloud_id: cloud_id, credentials: credentials)
461
+ end
462
+ else
463
+ # There's more than one of this type of resource in the target
464
+ # deploy, so see if findLitterMate can narrow it down for us
465
+ momma.findLitterMate(type: type, name: name, mu_name: mu_name, cloud_id: cloud_id, credentials: credentials)
466
+ end
467
+
468
+ next if straykitten.nil?
469
+ straykitten.intoDeploy(momma)
470
+
471
+ if straykitten.cloud_id.nil?
472
+ MU.log "findStray: kitten #{straykitten.mu_name} came back with nil cloud_id", MU::WARN
473
+ next
474
+ end
475
+ next if cloud_id and straykitten.cloud_id.to_s != cloud_id.to_s
476
+
477
+ # Peace out if we found the exact resource we want
478
+ if (cloud_id and straykitten.cloud_id.to_s == cloud_id.to_s) or
479
+ (mu_descs.size == 1 and matches.size == 1) or
480
+ (credentials and straykitten.credentials == credentials)
481
+ # XXX strictly speaking this last check is only valid if findStray is searching
482
+ # exactly one set of credentials
483
+
484
+ return { straykitten.cloud_id => straykitten }
485
+ end
486
+
487
+ kittens[straykitten.cloud_id] ||= straykitten
488
+ }
489
+
490
+ kittens
491
+ end
492
+ private_class_method :search_my_deploys
493
+
494
+ end #class
495
+ end #module