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
@@ -25,14 +25,7 @@ module MU
25
25
  @config["groomer"] = MU::Config.defaultGroomer unless @config["groomer"]
26
26
  @groomclass = MU::Groomer.loadGroomer(@config["groomer"])
27
27
 
28
- @mu_name ||=
29
- if @config and @config['engine'] and @config["engine"].match(/^sqlserver/)
30
- @deploy.getResourceName(@config["name"], max_length: 15)
31
- else
32
- @deploy.getResourceName(@config["name"], max_length: 63)
33
- end
34
-
35
- @mu_name.gsub(/(--|-$)/i, "").gsub(/(_)/, "-").gsub!(/^[^a-z]/i, "")
28
+ @mu_name ||= @deploy.getResourceName(@config["name"], max_length: 63)
36
29
  end
37
30
 
38
31
  # Called automatically by {MU::Deploy#createResources}
@@ -68,8 +61,7 @@ module MU
68
61
  # Locate an existing Database or Databases and return an array containing matching GCP resource descriptors for those that match.
69
62
  # @return [Array<Hash<String,OpenStruct>>]: The cloud provider's complete descriptions of matching Databases
70
63
  def self.find(**args)
71
- args[:project] ||= args[:habitat]
72
- args[:project] ||= MU::Cloud::Google.defaultProject(args[:credentials])
64
+ args = MU::Cloud::Google.findLocationArgs(args)
73
65
  end
74
66
 
75
67
  # Called automatically by {MU::Deploy#createResources}
@@ -109,21 +101,21 @@ module MU
109
101
  # @param region [String]: The cloud provider region in which to operate
110
102
  # @return [void]
111
103
  def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
112
- flags["project"] ||= MU::Cloud::Google.defaultProject(credentials)
113
- skipsnapshots||= flags["skipsnapshots"]
114
- # instances = MU::Cloud::Google.sql(credentials: credentials).list_instances(flags['project'], filter: %Q{userLabels.mu-id:"#{MU.deploy_id.downcase}"})
104
+ flags["habitat"] ||= MU::Cloud::Google.defaultProject(credentials)
105
+
106
+ # instances = MU::Cloud::Google.sql(credentials: credentials).list_instances(flags['habitat'], filter: %Q{userLabels.mu-id:"#{MU.deploy_id.downcase}"})
115
107
  # if instances and instances.items
116
108
  # instances.items.each { |instance|
117
109
  # MU.log "Deleting Cloud SQL instance #{instance.name}"
118
- # MU::Cloud::Google.sql(credentials: credentials).delete_instance(flags['project'], instance.name) if !noop
110
+ # MU::Cloud::Google.sql(credentials: credentials).delete_instance(flags['habitat'], instance.name) if !noop
119
111
  # }
120
112
  # end
121
113
  end
122
114
 
123
115
  # Cloud-specific configuration properties.
124
- # @param config [MU::Config]: The calling MU::Config object
116
+ # @param _config [MU::Config]: The calling MU::Config object
125
117
  # @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource
126
- def self.schema(config)
118
+ def self.schema(_config)
127
119
  toplevel_required = []
128
120
  schema = {}
129
121
  [toplevel_required, schema]
@@ -131,9 +123,9 @@ module MU
131
123
 
132
124
  # Cloud-specific pre-processing of {MU::Config::BasketofKittens::databases}, bare and unvalidated.
133
125
  # @param db [Hash]: The resource to process and validate
134
- # @param configurator [MU::Config]: The overall deployment configurator of which this resource is a member
126
+ # @param _configurator [MU::Config]: The overall deployment configurator of which this resource is a member
135
127
  # @return [Boolean]: True if validation succeeded, False otherwise
136
- def self.validateConfig(db, configurator)
128
+ def self.validateConfig(db, _configurator)
137
129
  ok = true
138
130
 
139
131
  if db["create_cluster"]
@@ -144,8 +136,6 @@ module MU
144
136
  ok
145
137
  end
146
138
 
147
- private
148
-
149
139
  end #class
150
140
  end #class
151
141
  end
@@ -172,8 +172,7 @@ end
172
172
  # @param args [Hash]: Hash of named arguments passed via Ruby's double-splat
173
173
  # @return [Hash<String,OpenStruct>]: The cloud provider's complete descriptions of matching resources
174
174
  def self.find(**args)
175
- args[:project] ||= args[:habitat]
176
- args[:project] ||= MU::Cloud::Google.defaultProject(args[:credentials])
175
+ args = MU::Cloud::Google.findLocationArgs(args)
177
176
 
178
177
  found = {}
179
178
  resp = begin
@@ -207,15 +206,19 @@ end
207
206
  # Remove all security groups (firewall rulesets) associated with the currently loaded deployment.
208
207
  # @param noop [Boolean]: If true, will only print what would be done
209
208
  # @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
210
- # @param region [String]: The cloud provider region
211
209
  # @return [void]
212
- def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
213
- flags["project"] ||= MU::Cloud::Google.defaultProject(credentials)
214
- return if !MU::Cloud::Google::Habitat.isLive?(flags["project"], credentials)
210
+ def self.cleanup(noop: false, ignoremaster: false, credentials: nil, flags: {})
211
+ flags["habitat"] ||= MU::Cloud::Google.defaultProject(credentials)
212
+ return if !MU::Cloud.resourceClass("Google", "Habitat").isLive?(flags["habitat"], credentials)
213
+ filter = %Q{(labels.mu-id = "#{MU.deploy_id.downcase}")}
214
+ if !ignoremaster and MU.mu_public_ip
215
+ filter += %Q{ AND (labels.mu-master-ip = "#{MU.mu_public_ip.gsub(/\./, "_")}")}
216
+ end
217
+ MU.log "Placeholder: Google FirewallRule artifacts do not support labels, so ignoremaster cleanup flag has no effect", MU::DEBUG, details: filter
215
218
 
216
219
  MU::Cloud::Google.compute(credentials: credentials).delete(
217
220
  "firewall",
218
- flags["project"],
221
+ flags["habitat"],
219
222
  nil,
220
223
  noop
221
224
  )
@@ -224,7 +227,7 @@ end
224
227
  # Reverse-map our cloud description into a runnable config hash.
225
228
  # We assume that any values we have in +@config+ are placeholders, and
226
229
  # calculate our own accordingly based on what's live in the cloud.
227
- def toKitten(rootparent: nil, billing: nil, habitats: nil)
230
+ def toKitten(**_args)
228
231
 
229
232
  if cloud_desc.name.match(/^[a-f0-9]+$/)
230
233
  gke_ish = true
@@ -362,9 +365,9 @@ end
362
365
  end
363
366
 
364
367
  # Cloud-specific configuration properties.
365
- # @param config [MU::Config]: The calling MU::Config object
368
+ # @param _config [MU::Config]: The calling MU::Config object
366
369
  # @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource
367
- def self.schema(config = nil)
370
+ def self.schema(_config = nil)
368
371
  toplevel_required = []
369
372
  schema = {
370
373
  "rules" => {
@@ -437,7 +440,7 @@ end
437
440
  elsif acl['vpc']['habitat'] and acl['vpc']['habitat']['name']
438
441
  acl['vpc']['project'] = acl['vpc']['habitat']['name']
439
442
  end
440
- correct_vpc = MU::Cloud::Google::VPC.pickVPC(
443
+ correct_vpc = MU::Cloud.resourceClass("Google", "VPC").pickVPC(
441
444
  acl['vpc'],
442
445
  acl,
443
446
  "firewall_rule",
@@ -523,7 +526,7 @@ end
523
526
  end
524
527
  }
525
528
 
526
- rules_by_class.reject! { |k, v| v.size == 0 }
529
+ rules_by_class.reject! { |_k, v| v.size == 0 }
527
530
 
528
531
  # Generate other firewall rule objects to cover the other behaviors
529
532
  # we've requested, if indeed we've done so.
@@ -543,8 +546,6 @@ end
543
546
  ok
544
547
  end
545
548
 
546
- private
547
-
548
549
  end #class
549
550
  end #class
550
551
  end
@@ -48,7 +48,7 @@ module MU
48
48
  folder_obj = MU::Cloud::Google.folder(:Folder).new(params)
49
49
 
50
50
  MU.log "Creating folder #{name_string} under #{parent}", details: folder_obj
51
- resp = MU::Cloud::Google.folder(credentials: @config['credentials']).create_folder(folder_obj, parent: parent)
51
+ MU::Cloud::Google.folder(credentials: @config['credentials']).create_folder(folder_obj, parent: parent)
52
52
 
53
53
  # Wait for list_folders output to be consistent (for the folder we
54
54
  # just created to show up)
@@ -125,10 +125,12 @@ module MU
125
125
  nil
126
126
  end
127
127
 
128
+ @cached_cloud_desc = nil
128
129
  # Return the cloud descriptor for the Folder
129
130
  # @return [Google::Apis::Core::Hashable]
130
- def cloud_desc
131
- @cached_cloud_desc ||= MU::Cloud::Google::Folder.find(cloud_id: @cloud_id, credentials: @config['credentials']).values.first
131
+ def cloud_desc(use_cache: true)
132
+ return @cached_cloud_desc if @cached_cloud_desc and use_cache
133
+ @cached_cloud_desc = MU::Cloud::Google::Folder.find(cloud_id: @cloud_id, credentials: @config['credentials']).values.first
132
134
  @habitat_id ||= @cached_cloud_desc.parent.sub(/^(folders|organizations)\//, "")
133
135
  @cached_cloud_desc
134
136
  end
@@ -136,7 +138,7 @@ module MU
136
138
  # Return the metadata for this folders's configuration
137
139
  # @return [Hash]
138
140
  def notify
139
- desc = MU.structToHash(MU::Cloud::Google.folder(credentials: @config['credentials']).get_folder("folders/"+@cloud_id))
141
+ desc = MU.structToHash(cloud_desc)
140
142
  desc["mu_name"] = @mu_name
141
143
  desc["parent"] = @parent
142
144
  desc["cloud_id"] = @cloud_id
@@ -160,7 +162,12 @@ module MU
160
162
  # @param noop [Boolean]: If true, will only print what would be done
161
163
  # @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
162
164
  # @return [void]
163
- def self.cleanup(noop: false, ignoremaster: false, credentials: nil, flags: {}, region: MU.myRegion)
165
+ def self.cleanup(noop: false, ignoremaster: false, credentials: nil, flags: {})
166
+ filter = %Q{(labels.mu-id = "#{MU.deploy_id.downcase}")}
167
+ if !ignoremaster and MU.mu_public_ip
168
+ filter += %Q{ AND (labels.mu-master-ip = "#{MU.mu_public_ip.gsub(/\./, "_")}")}
169
+ end
170
+ MU.log "Placeholder: Google Folder artifacts do not support labels, so ignoremaster cleanup flag has no effect", MU::DEBUG, details: filter
164
171
  # We can't label GCP folders, and their names are too short to encode
165
172
  # Mu deploy IDs, so all we can do is rely on flags['known'] passed in
166
173
  # from cleanup, which relies on our metadata to know what's ours.
@@ -229,10 +236,10 @@ module MU
229
236
  # @return [Hash<String,OpenStruct>]: The cloud provider's complete descriptions of matching resources
230
237
  def self.find(**args)
231
238
  found = {}
232
-
233
239
  # Recursively search a GCP folder hierarchy for a folder matching our
234
240
  # supplied name or identifier.
235
241
  def self.find_matching_folder(parent, name: nil, id: nil, credentials: nil)
242
+
236
243
  resp = MU::Cloud::Google.folder(credentials: credentials).list_folders(parent: parent)
237
244
  if resp and resp.folders
238
245
  resp.folders.each { |f|
@@ -271,6 +278,7 @@ module MU
271
278
  end
272
279
  else
273
280
  resp = MU::Cloud::Google.folder(credentials: args[:credentials]).list_folders(parent: parent)
281
+
274
282
  if resp and resp.folders
275
283
  resp.folders.each { |folder|
276
284
  next if folder.lifecycle_state == "DELETE_REQUESTED"
@@ -293,7 +301,7 @@ module MU
293
301
  # Reverse-map our cloud description into a runnable config hash.
294
302
  # We assume that any values we have in +@config+ are placeholders, and
295
303
  # calculate our own accordingly based on what's live in the cloud.
296
- def toKitten(rootparent: nil, billing: nil, habitats: nil)
304
+ def toKitten(**args)
297
305
  bok = {
298
306
  "cloud" => "Google",
299
307
  "credentials" => @config['credentials']
@@ -303,16 +311,15 @@ module MU
303
311
  bok['cloud_id'] = cloud_desc.name
304
312
  bok['name'] = cloud_desc.display_name#+bok['cloud_id'] # only way to guarantee uniqueness
305
313
  if cloud_desc.parent.match(/^folders\/(.*)/)
306
- MU.log bok['display_name']+" generating reference", MU::NOTICE, details: cloud_desc.parent
307
314
  bok['parent'] = MU::Config::Ref.get(
308
315
  id: cloud_desc.parent,
309
316
  cloud: "Google",
310
317
  credentials: @config['credentials'],
311
318
  type: "folders"
312
319
  )
313
- elsif rootparent
320
+ elsif args[:rootparent]
314
321
  bok['parent'] = {
315
- 'id' => rootparent.is_a?(String) ? rootparent : rootparent.cloud_desc.name
322
+ 'id' => args[:rootparent].is_a?(String) ? args[:rootparent] : args[:rootparent].cloud_desc.name
316
323
  }
317
324
  else
318
325
  bok['parent'] = { 'id' => cloud_desc.parent }
@@ -322,9 +329,9 @@ MU.log bok['display_name']+" generating reference", MU::NOTICE, details: cloud_d
322
329
  end
323
330
 
324
331
  # Cloud-specific configuration properties.
325
- # @param config [MU::Config]: The calling MU::Config object
332
+ # @param _config [MU::Config]: The calling MU::Config object
326
333
  # @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource
327
- def self.schema(config)
334
+ def self.schema(_config)
328
335
  toplevel_required = []
329
336
  schema = {
330
337
  "display_name" => {
@@ -348,11 +355,7 @@ MU.log bok['display_name']+" generating reference", MU::NOTICE, details: cloud_d
348
355
  end
349
356
 
350
357
  if folder['parent'] and folder['parent']['name'] and !folder['parent']['deploy_id'] and configurator.haveLitterMate?(folder['parent']['name'], "folders")
351
- folder["dependencies"] ||= []
352
- folder["dependencies"] << {
353
- "type" => "folder",
354
- "name" => folder['parent']['name']
355
- }
358
+ MU::Config.addDependency(folder, folder['parent']['name'], "folder")
356
359
  end
357
360
 
358
361
  ok
@@ -108,98 +108,9 @@ module example.com/cloudfunction
108
108
 
109
109
  # Called automatically by {MU::Deploy#createResources}
110
110
  def create
111
- labels = Hash[@tags.keys.map { |k|
112
- [k.downcase, @tags[k].downcase.gsub(/[^-_a-z0-9]/, '-')] }
113
- ]
114
- labels["name"] = MU::Cloud::Google.nameStr(@mu_name)
115
111
 
116
112
  location = "projects/"+@config['project']+"/locations/"+@config['region']
117
- sa = nil
118
- retries = 0
119
- begin
120
- sa_ref = MU::Config::Ref.get(@config['service_account'])
121
- sa = @deploy.findLitterMate(name: sa_ref.name, type: "users")
122
- if !sa or !sa.cloud_desc
123
- sleep 10
124
- end
125
- rescue ::Google::Apis::ClientError => e
126
- if e.message.match(/notFound:/)
127
- sleep 10
128
- retries += 1
129
- retry
130
- end
131
- end while !sa or !sa.cloud_desc and retries < 5
132
-
133
- if !sa or !sa.cloud_desc
134
- raise MuError, "Failed to get service account cloud id from #{@config['service_account'].to_s}"
135
- end
136
-
137
- desc = {
138
- name: location+"/functions/"+@mu_name.downcase,
139
- runtime: @config['runtime'],
140
- timeout: @config['timeout'].to_s+"s",
141
- # entry_point: "hello_world",
142
- entry_point: @config['handler'],
143
- description: @deploy.deploy_id,
144
- service_account_email: sa.cloud_desc.email,
145
- labels: labels,
146
- available_memory_mb: @config['memory']
147
- }
148
-
149
- # XXX This network argument is deprecated in favor of using VPC
150
- # Connectors. Which would be fine, except there's no API support for
151
- # interacting with VPC Connectors. Can't create them, can't list them,
152
- # can't do anything except pass their ids into Cloud Functions or
153
- # AppEngine and hope for the best.
154
- if @config['vpc_connector']
155
- desc[:vpc_connector] = @config['vpc_connector']
156
- elsif @vpc
157
- desc[:network] = @vpc.url.sub(/^.*?\/projects\//, 'projects/')
158
- end
159
-
160
- if @config['triggers']
161
- desc[:event_trigger] = MU::Cloud::Google.function(:EventTrigger).new(
162
- event_type: @config['triggers'].first['event'],
163
- resource: @config['triggers'].first['resource']
164
- )
165
- else
166
- desc[:https_trigger] = MU::Cloud::Google.function(:HttpsTrigger).new
167
- end
168
-
169
-
170
- if @config['environment_variable']
171
- @config['environment_variable'].each { |var|
172
- desc[:environment_variables] ||= {}
173
- desc[:environment_variables][var["key"].to_s] = var["value"].to_s
174
- }
175
- end
176
-
177
- # hello_code = nil
178
- # HELLO_WORLDS.each_pair { |runtime, code|
179
- # if @config['runtime'].match(/^#{Regexp.quote(runtime)}/)
180
- # hello_code = code
181
- # break
182
- # end
183
- # }
184
- if @config['code']['gs_url']
185
- desc[:source_archive_url] = @config['code']['gs_url']
186
- elsif @config['code']['zip_file']
187
- desc[:source_archive_url] = MU::Cloud::Google::Function.uploadPackage(@config['code']['zip_file'], @mu_name+"-cloudfunction.zip", credentials: @credentials)
188
- end
189
-
190
- # Dir.mktmpdir(@mu_name) { |dir|
191
- # hello_code.each_pair { |file, contents|
192
- # f = File.open(dir+"/"+file, "w")
193
- # f.puts contents
194
- # f.close
195
- # Zip::File.open(dir+"/function.zip", Zip::File::CREATE) { |z|
196
- # z.add(file, dir+"/"+file)
197
- # }
198
- # }
199
- # desc[:source_archive_url] = MU::Cloud::Google::Function.uploadPackage(dir+"/function.zip", @mu_name+"-cloudfunction.zip", credentials: @credentials)
200
- # }
201
-
202
- func_obj = MU::Cloud::Google.function(:CloudFunction).new(desc)
113
+ func_obj = buildDesc
203
114
  MU.log "Creating Cloud Function #{@mu_name} in #{location}", details: func_obj
204
115
  resp = MU::Cloud::Google.function(credentials: @credentials).create_project_location_function(location, func_obj)
205
116
  @cloud_id = resp.name
@@ -214,27 +125,26 @@ module example.com/cloudfunction
214
125
  labels["name"] = MU::Cloud::Google.nameStr(@mu_name)
215
126
 
216
127
  if cloud_desc.labels != labels
217
- desc[:labels] = labels
128
+ need_update = true
218
129
  end
219
130
 
220
131
  if cloud_desc.runtime != @config['runtime']
221
- desc[:runtime] = @config['runtime']
132
+ need_update = true
222
133
  end
223
134
  if cloud_desc.timeout != @config['timeout'].to_s+"s"
224
- desc[:timeout] = @config['timeout'].to_s+"s"
135
+ need_update = true
225
136
  end
226
137
  if cloud_desc.entry_point != @config['handler']
227
- desc[:entry_point] = @config['handler']
138
+ need_update = true
228
139
  end
229
140
  if cloud_desc.available_memory_mb != @config['memory']
230
- desc[:available_memory_mb] = @config['memory']
141
+ need_update = true
231
142
  end
232
143
  if @config['environment_variable']
233
144
  @config['environment_variable'].each { |var|
234
145
  if !cloud_desc.environment_variables or
235
146
  cloud_desc.environment_variables[var["key"].to_s] != var["value"].to_s
236
- desc[:environment_variables] ||= {}
237
- desc[:environment_variables][var["key"].to_s] = var["value"].to_s
147
+ need_update = true
238
148
  end
239
149
  }
240
150
  end
@@ -242,10 +152,7 @@ module example.com/cloudfunction
242
152
  if !cloud_desc.event_trigger or
243
153
  cloud_desc.event_trigger.event_type != @config['triggers'].first['event'] or
244
154
  cloud_desc.event_trigger.resource != @config['triggers'].first['resource']
245
- desc[:event_trigger] = MU::Cloud::Google.function(:EventTrigger).new(
246
- event_type: @config['triggers'].first['event'],
247
- resource: @config['triggers'].first['resource']
248
- )
155
+ need_update = true
249
156
  end
250
157
  end
251
158
 
@@ -254,7 +161,6 @@ module example.com/cloudfunction
254
161
  File.read("#{dir}/current.zip")
255
162
  }
256
163
 
257
- source_url = nil
258
164
  new = if @config['code']['zip_file']
259
165
  File.read(@config['code']['zip_file'])
260
166
  elsif @config['code']['gs_url']
@@ -269,37 +175,21 @@ module example.com/cloudfunction
269
175
  if @config['code']['gs_url'] and
270
176
  (@config['code']['gs_url'] != cloud_desc.source_archive_url or
271
177
  current != new)
272
- desc[:source_archive_url] = @config['code']['gs_url']
178
+ need_update = true
273
179
  elsif @config['code']['zip_file'] and current != new
180
+ need_update = true
274
181
  desc[:source_archive_url] = MU::Cloud::Google::Function.uploadPackage(@config['code']['zip_file'], @mu_name+"-cloudfunction.zip", credentials: @credentials)
275
182
  end
276
183
 
277
- if desc.size > 0
278
- # A trigger and some code must always be specified, apparently. The
279
- # endpoint hangs indefinitely if either is missing. Charming.
280
- if !desc[:https_trigger] and !desc[:event_trigger]
281
- if cloud_desc.https_trigger
282
- desc[:https_trigger] = MU::Cloud::Google.function(:HttpsTrigger).new
283
- else
284
- desc[:event_trigger] = cloud_desc.event_trigger
285
- end
286
- end
287
- if !desc[:source_archive_url] and !desc[:source_upload_url]
288
- if cloud_desc.source_archive_url
289
- desc[:source_archive_url] = cloud_desc.source_archive_url
290
- else
291
- desc[:source_upload_url] = cloud_desc.source_upload_url
292
- end
293
- end
294
-
295
- func_obj = MU::Cloud::Google.function(:CloudFunction).new(desc)
184
+ if need_update
185
+ func_obj = buildDesc
296
186
  MU.log "Updating Cloud Function #{@mu_name}", MU::NOTICE, details: func_obj
297
187
  begin
298
- MU::Cloud::Google.function(credentials: @credentials).patch_project_location_function(
299
- @cloud_id,
300
- func_obj
301
- )
302
- rescue ::Google::Apis::ClientError => e
188
+ # MU::Cloud::Google.function(credentials: @credentials).patch_project_location_function(
189
+ # @cloud_id,
190
+ # func_obj
191
+ # )
192
+ rescue ::Google::Apis::ClientError
303
193
  MU.log "Error updating Cloud Function #{@mu_name}.", MU::ERR
304
194
  if desc[:source_archive_url]
305
195
  main_file = nil
@@ -344,13 +234,13 @@ module example.com/cloudfunction
344
234
  # @param region [String]: The cloud provider region
345
235
  # @return [void]
346
236
  def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
347
- flags["project"] ||= MU::Cloud::Google.defaultProject(credentials)
348
- return if !MU::Cloud::Google::Habitat.isLive?(flags["project"], credentials)
237
+ flags["habitat"] ||= MU::Cloud::Google.defaultProject(credentials)
238
+ return if !MU::Cloud.resourceClass("Google", "Habitat").isLive?(flags["habitat"], credentials)
349
239
  # Make sure we catch regional *and* zone functions
350
- found = MU::Cloud::Google::Function.find(credentials: credentials, region: region, project: flags["project"])
240
+ found = MU::Cloud::Google::Function.find(credentials: credentials, region: region, project: flags["habitat"])
351
241
  found.each_pair { |cloud_id, desc|
352
242
  if (desc.description and desc.description == MU.deploy_id) or
353
- (desc.labels and desc.labels["mu-id"] == MU.deploy_id.downcase) or
243
+ (desc.labels and desc.labels["mu-id"] == MU.deploy_id.downcase and (ignoremaster or desc.labels["mu-master-ip"] == MU.mu_public_ip.gsub(/\./, "_"))) or
354
244
  (flags["known"] and flags["known"].include?(cloud_id))
355
245
  MU.log "Deleting Cloud Function #{desc.name}"
356
246
  if !noop
@@ -364,9 +254,7 @@ module example.com/cloudfunction
364
254
  # Locate an existing project
365
255
  # @return [Hash<OpenStruct>]: The cloud provider's complete descriptions of matching project
366
256
  def self.find(**args)
367
- args[:project] ||= args[:habitat]
368
- args[:project] ||= MU::Cloud::Google.defaultProject(args[:credentials])
369
- location = args[:region] || args[:availability_zone] || "-"
257
+ args = MU::Cloud::Google.findLocationArgs(args)
370
258
 
371
259
  found = {}
372
260
 
@@ -379,7 +267,7 @@ module example.com/cloudfunction
379
267
  found[args[:cloud_id]] = resp if resp
380
268
  else
381
269
  resp = begin
382
- MU::Cloud::Google.function(credentials: args[:credentials]).list_project_location_functions("projects/#{args[:project]}/locations/#{location}")
270
+ MU::Cloud::Google.function(credentials: args[:credentials]).list_project_location_functions("projects/#{args[:project]}/locations/#{args[:location]}")
383
271
  rescue ::Google::Apis::ClientError => e
384
272
  raise e if !e.message.match(/forbidden:/)
385
273
  end
@@ -397,7 +285,7 @@ module example.com/cloudfunction
397
285
  # Reverse-map our cloud description into a runnable config hash.
398
286
  # We assume that any values we have in +@config+ are placeholders, and
399
287
  # calculate our own accordingly based on what's live in the cloud.
400
- def toKitten(rootparent: nil, billing: nil, habitats: nil)
288
+ def toKitten(**_args)
401
289
  bok = {
402
290
  "cloud" => "Google",
403
291
  "cloud_id" => @cloud_id,
@@ -452,7 +340,7 @@ module example.com/cloudfunction
452
340
  end
453
341
 
454
342
  codefile = bok["project"]+"_"+bok["region"]+"_"+bok["name"]+".zip"
455
- MU::Cloud::Google::Function.downloadPackage(@cloud_id, codefile, credentials: @config['credentials'])
343
+ return nil if !MU::Cloud::Google::Function.downloadPackage(@cloud_id, codefile, credentials: @config['credentials'])
456
344
  bok['code'] = {
457
345
  'zip_file' => codefile
458
346
  }
@@ -460,7 +348,6 @@ module example.com/cloudfunction
460
348
  bok
461
349
  end
462
350
 
463
-
464
351
  # Cloud-specific configuration properties.
465
352
  # @param config [MU::Config]: The calling MU::Config object
466
353
  # @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource
@@ -486,7 +373,7 @@ module example.com/cloudfunction
486
373
  }
487
374
  }
488
375
  },
489
- "service_account" => MU::Cloud::Google::Server.schema(config)[1]["service_account"],
376
+ "service_account" => MU::Cloud.resourceClass("Google", "Server").schema(config)[1]["service_account"],
490
377
  "runtime" => {
491
378
  "type" => "string",
492
379
  "enum" => %w{nodejs go python nodejs8 nodejs10 python37 go111 go113},
@@ -495,8 +382,14 @@ module example.com/cloudfunction
495
382
  "type" => "string",
496
383
  "description" => "+DEPRECATED+ VPC Connector to attach, of the form +projects/my-project/locations/some-region/connectors/my-connector+. This option will be removed once proper google-cloud-sdk support for VPC Connectors becomes available, at which point we will piggyback on the normal +vpc+ stanza and resolve connectors as needed."
497
384
  },
385
+ "vpc_connector_allow_all_egress" => {
386
+ "type" => "boolean",
387
+ "default" => false,
388
+ "description" => "+DEPRECATED+ Allow VPC connector egress traffic to any IP range, instead of just private IPs. This option will be removed once proper google-cloud-sdk support for VPC Connectors becomes available, at which point we will piggyback on the normal +vpc+ stanza and resolve connectors as needed."
389
+ },
498
390
  "code" => {
499
391
  "type" => "object",
392
+ "description" => "Zipped deployment package to upload to our function.",
500
393
  "properties" => {
501
394
  "gs_url" => {
502
395
  "type" => "string",
@@ -523,8 +416,13 @@ module example.com/cloudfunction
523
416
  cloud_desc.source_archive_url.match(/^gs:\/\/([^\/]+)\/(.*)/)
524
417
  bucket = Regexp.last_match[1]
525
418
  path = Regexp.last_match[2]
526
- current = nil
527
- MU::Cloud::Google.storage(credentials: credentials).get_object(bucket, path, download_dest: zipfile)
419
+
420
+ begin
421
+ MU::Cloud::Google.storage(credentials: credentials).get_object(bucket, path, download_dest: zipfile)
422
+ rescue ::Google::Apis::ClientError => e
423
+ MU.log "Couldn't retrieve gs://#{bucket}/#{path} for #{function_id}", MU::WARN, details: e.inspect
424
+ return false
425
+ end
528
426
  elsif cloud_desc.source_upload_url
529
427
  resp = MU::Cloud::Google.function(credentials: credentials).generate_function_download_url(
530
428
  function_id
@@ -535,6 +433,7 @@ module example.com/cloudfunction
535
433
  f.close
536
434
  end
537
435
  end
436
+ true
538
437
  end
539
438
 
540
439
  # Upload a zipfile to our admin Cloud Storage bucket, for use by
@@ -625,32 +524,7 @@ module example.com/cloudfunction
625
524
  ok = false
626
525
  end
627
526
  else
628
- user = {
629
- "name" => function['name'],
630
- "cloud" => "Google",
631
- "project" => function["project"],
632
- "credentials" => function["credentials"],
633
- "type" => "service"
634
- }
635
- if user["name"].length < 6
636
- user["name"] += Password.pronounceable(6)
637
- end
638
- if function['roles']
639
- user['roles'] = function['roles'].dup
640
- end
641
- configurator.insertKitten(user, "users", true)
642
- function['dependencies'] ||= []
643
- function['service_account'] = MU::Config::Ref.get(
644
- type: "users",
645
- cloud: "Google",
646
- name: user["name"],
647
- project: user["project"],
648
- credentials: user["credentials"]
649
- )
650
- function['dependencies'] << {
651
- "type" => "user",
652
- "name" => user["name"]
653
- }
527
+ function = MU::Cloud.resourceClass("Google", "User").genericServiceAccount(function, configurator)
654
528
  end
655
529
 
656
530
  # siblings = configurator.haveLitterMate?(nil, "vpcs", has_multiple: true)
@@ -673,6 +547,104 @@ module example.com/cloudfunction
673
547
  ok
674
548
  end
675
549
 
550
+ private
551
+
552
+ def buildDesc
553
+ labels = Hash[@tags.keys.map { |k|
554
+ [k.downcase, @tags[k].downcase.gsub(/[^-_a-z0-9]/, '-')] }
555
+ ]
556
+ labels["name"] = MU::Cloud::Google.nameStr(@mu_name)
557
+
558
+ location = "projects/"+@config['project']+"/locations/"+@config['region']
559
+ sa = nil
560
+ retries = 0
561
+ begin
562
+ sa_ref = MU::Config::Ref.get(@config['service_account'])
563
+ sa = @deploy.findLitterMate(name: sa_ref.name, type: "users")
564
+ if !sa or !sa.cloud_desc
565
+ sleep 10
566
+ end
567
+ rescue ::Google::Apis::ClientError => e
568
+ if e.message.match(/notFound:/)
569
+ sleep 10
570
+ retries += 1
571
+ retry
572
+ end
573
+ end while !sa or !sa.cloud_desc and retries < 5
574
+
575
+ if !sa or !sa.cloud_desc
576
+ raise MuError, "Failed to get service account cloud id from #{@config['service_account'].to_s}"
577
+ end
578
+
579
+ desc = {
580
+ name: location+"/functions/"+@mu_name.downcase,
581
+ runtime: @config['runtime'],
582
+ timeout: @config['timeout'].to_s+"s",
583
+ # entry_point: "hello_world",
584
+ entry_point: @config['handler'],
585
+ description: @deploy.deploy_id,
586
+ service_account_email: sa.cloud_desc.email,
587
+ labels: labels,
588
+ available_memory_mb: @config['memory']
589
+ }
590
+
591
+ # XXX This network argument is deprecated in favor of using VPC
592
+ # Connectors. Which would be fine, except there's no API support for
593
+ # interacting with VPC Connectors. Can't create them, can't list them,
594
+ # can't do anything except pass their ids into Cloud Functions or
595
+ # AppEngine and hope for the best.
596
+ if @config['vpc_connector']
597
+ desc[:vpc_connector] = @config['vpc_connector']
598
+ desc[:vpc_connector_egress_settings] = @config['vpc_connector_allow_all_egress'] ? "ALL_TRAFFIC" : "PRIVATE_RANGES_ONLY"
599
+ pp desc
600
+ elsif @vpc
601
+ desc[:network] = @vpc.url.sub(/^.*?\/projects\//, 'projects/')
602
+ end
603
+
604
+ if @config['triggers']
605
+ desc[:event_trigger] = MU::Cloud::Google.function(:EventTrigger).new(
606
+ event_type: @config['triggers'].first['event'],
607
+ resource: @config['triggers'].first['resource']
608
+ )
609
+ else
610
+ desc[:https_trigger] = MU::Cloud::Google.function(:HttpsTrigger).new
611
+ end
612
+
613
+
614
+ if @config['environment_variable']
615
+ @config['environment_variable'].each { |var|
616
+ desc[:environment_variables] ||= {}
617
+ desc[:environment_variables][var["key"].to_s] = var["value"].to_s
618
+ }
619
+ end
620
+
621
+ # hello_code = nil
622
+ # HELLO_WORLDS.each_pair { |runtime, code|
623
+ # if @config['runtime'].match(/^#{Regexp.quote(runtime)}/)
624
+ # hello_code = code
625
+ # break
626
+ # end
627
+ # }
628
+ if @config['code']['gs_url']
629
+ desc[:source_archive_url] = @config['code']['gs_url']
630
+ elsif @config['code']['zip_file']
631
+ desc[:source_archive_url] = MU::Cloud::Google::Function.uploadPackage(@config['code']['zip_file'], @mu_name+"-cloudfunction.zip", credentials: @credentials)
632
+ end
633
+
634
+ # Dir.mktmpdir(@mu_name) { |dir|
635
+ # hello_code.each_pair { |file, contents|
636
+ # f = File.open(dir+"/"+file, "w")
637
+ # f.puts contents
638
+ # f.close
639
+ # Zip::File.open(dir+"/function.zip", Zip::File::CREATE) { |z|
640
+ # z.add(file, dir+"/"+file)
641
+ # }
642
+ # }
643
+ # desc[:source_archive_url] = MU::Cloud::Google::Function.uploadPackage(dir+"/function.zip", @mu_name+"-cloudfunction.zip", credentials: @credentials)
644
+ # }
645
+ MU::Cloud::Google.function(:CloudFunction).new(desc)
646
+ end
647
+
676
648
  end
677
649
  end
678
650
  end