cloud-mu 3.1.2 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
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