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
@@ -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