modules/mu/providers/google/function.rb in cloud-mu-3.4.0 vs modules/mu/providers/google/function.rb in cloud-mu-3.5.0

- old
+ new

@@ -117,10 +117,13 @@ end # Called automatically by {MU::Deploy#createResources} def groom desc = {} + + func_obj = buildDesc + labels = Hash[@tags.keys.map { |k| [k.downcase, @tags[k].downcase.gsub(/[^-_a-z0-9]/, '-')] } ] labels["name"] = MU::Cloud::Google.nameStr(@mu_name) @@ -138,10 +141,14 @@ need_update = true end if cloud_desc.available_memory_mb != @config['memory'] need_update = true end + if cloud_desc.service_account_email != func_obj.service_account_email + need_update = true + end + if @config['environment_variable'] @config['environment_variable'].each { |var| if !cloud_desc.environment_variables or cloud_desc.environment_variables[var["key"].to_s] != var["value"].to_s need_update = true @@ -159,40 +166,56 @@ current = Dir.mktmpdir(@mu_name+"-current") { |dir| MU::Cloud::Google::Function.downloadPackage(@cloud_id, dir+"/current.zip", credentials: @credentials) File.read("#{dir}/current.zip") } - new = if @config['code']['zip_file'] + tempfile = nil + new = if @config['code']['zip_file'] or @config['code']['path'] + if @config['code']['path'] + tempfile = Tempfile.new(["function", ".zip"]) + MU.log "#{@mu_name} using code at #{@config['code']['path']}" + MU::Master.zipDir(@config['code']['path'], tempfile.path) + @config['code']['zip_file'] = tempfile.path + else + MU.log "#{@mu_name} using code packaged at #{@config['code']['zip_file']}" + end +# @code_sha256 = Base64.encode64(Digest::SHA256.digest(zip)).chomp File.read(@config['code']['zip_file']) elsif @config['code']['gs_url'] @config['code']['gs_url'].match(/^gs:\/\/([^\/]+)\/(.*)/) bucket = Regexp.last_match[1] path = Regexp.last_match[2] Dir.mktmpdir(@mu_name+"-new") { |dir| MU::Cloud::Google.storage(credentials: @credentials).get_object(bucket, path, download_dest: dir+"/new.zip") File.read(dir+"/new.zip") } end + if @config['code']['gs_url'] and (@config['code']['gs_url'] != cloud_desc.source_archive_url or current != new) need_update = true - elsif @config['code']['zip_file'] and current != new + elsif (@config['code']['zip_file'] or @config['code']['path']) and current != new need_update = true - desc[:source_archive_url] = MU::Cloud::Google::Function.uploadPackage(@config['code']['zip_file'], @mu_name+"-cloudfunction.zip", credentials: @credentials) end + if @config['vpc_connector'] + if cloud_desc.vpc_connector != @config['vpc_connector'] or + cloud_desc.vpc_connector_egress_settings != (@config['vpc_connector_allow_all_egress'] ? "ALL_TRAFFIC" : "PRIVATE_RANGES_ONLY") + need_update = true + end + end + if need_update - func_obj = buildDesc - MU.log "Updating Cloud Function #{@mu_name}", MU::NOTICE, details: func_obj + MU.log "Updating Cloud Function #{@cloud_id}", MU::NOTICE, details: func_obj begin -# MU::Cloud::Google.function(credentials: @credentials).patch_project_location_function( -# @cloud_id, -# func_obj -# ) - rescue ::Google::Apis::ClientError - MU.log "Error updating Cloud Function #{@mu_name}.", MU::ERR + MU::Cloud::Google.function(credentials: @credentials).patch_project_location_function( + @cloud_id, + func_obj + ) + rescue ::Google::Apis::ClientError => e + MU.log "Error updating Cloud Function #{@mu_name}.", MU::ERR, e.message if desc[:source_archive_url] main_file = nil HELLO_WORLDS.each_pair { |runtime, code| if @config['runtime'].match(/^#{Regexp.quote(runtime)}/) main_file = code.keys.first @@ -205,10 +228,15 @@ end # service_account_email: sa.kitten.cloud_desc.email, # labels: labels, + if tempfile + tempfile.close + tempfile.unlink + end + end # Return the metadata for this project's configuration # @return [Hash] def notify @@ -352,10 +380,11 @@ # @param config [MU::Config]: The calling MU::Config object # @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource def self.schema(config) toplevel_required = ["runtime"] schema = { + "roles" => MU::Cloud.resourceClass("Google", "User").schema(config)[1]["roles"], "triggers" => { "type" => "array", "items" => { "type" => "object", "description" => "Trigger for Cloud Function", @@ -446,10 +475,11 @@ bucket = MU::Cloud::Google.adminBucketName(credentials) obj_obj = MU::Cloud::Google.storage(:Object).new( content_type: "application/zip", name: filename ) + MU::Cloud::Google.storage(credentials: credentials).insert_object( bucket, obj_obj, upload_source: zipfile ) @@ -485,11 +515,11 @@ elsif function['runtime'] == "nodejs" function['runtime'] = "nodejs8" end # XXX list_project_locations - if !function['code'] or (!function['code']['zip_file'] and !function['code']['gs_url']) + if !function['code'] or (!function['code']['zip_file'] and !function['code']['gs_url'] and !function['code']['path']) MU.log "Must specify a code source in Cloud Function #{function['name']}", MU::ERR ok = false elsif function['code']['zip_file'] z = Zip::File.open(function['code']['zip_file']) if function['runtime'].match(/^python/) @@ -555,37 +585,29 @@ ] labels["name"] = MU::Cloud::Google.nameStr(@mu_name) location = "projects/"+@config['project']+"/locations/"+@config['region'] sa = nil - retries = 0 - begin - sa_ref = MU::Config::Ref.get(@config['service_account']) - sa = @deploy.findLitterMate(name: sa_ref.name, type: "users") - if !sa or !sa.cloud_desc - sleep 10 - end - rescue ::Google::Apis::ClientError => e - if e.message.match(/notFound:/) - sleep 10 - retries += 1 - retry - end - end while !sa or !sa.cloud_desc and retries < 5 + need_sa = Proc.new { + !sa or !sa.kitten or !sa.kitten.cloud_desc + } + MU.retrier(loop_if: need_sa, wait: 10, max: 6) { |retries, _wait| + sa = MU::Config::Ref.get(@config['service_account']) + } - if !sa or !sa.cloud_desc + if need_sa.call() raise MuError, "Failed to get service account cloud id from #{@config['service_account'].to_s}" end desc = { name: location+"/functions/"+@mu_name.downcase, runtime: @config['runtime'], timeout: @config['timeout'].to_s+"s", # entry_point: "hello_world", entry_point: @config['handler'], description: @deploy.deploy_id, - service_account_email: sa.cloud_desc.email, + service_account_email: sa.kitten.cloud_desc.email, labels: labels, available_memory_mb: @config['memory'] } # XXX This network argument is deprecated in favor of using VPC @@ -594,11 +616,10 @@ # can't do anything except pass their ids into Cloud Functions or # AppEngine and hope for the best. if @config['vpc_connector'] desc[:vpc_connector] = @config['vpc_connector'] desc[:vpc_connector_egress_settings] = @config['vpc_connector_allow_all_egress'] ? "ALL_TRAFFIC" : "PRIVATE_RANGES_ONLY" - pp desc elsif @vpc desc[:network] = @vpc.url.sub(/^.*?\/projects\//, 'projects/') end if @config['triggers'] @@ -625,11 +646,25 @@ # break # end # } if @config['code']['gs_url'] desc[:source_archive_url] = @config['code']['gs_url'] - elsif @config['code']['zip_file'] + elsif @config['code']['zip_file'] or @config['code']['path'] + tempfile = nil + if @config['code']['path'] + tempfile = Tempfile.new(["function", ".zip"]) + MU.log "#{@mu_name} using code at #{@config['code']['path']}" + MU::Master.zipDir(@config['code']['path'], tempfile.path) + @config['code']['zip_file'] = tempfile.path + else + MU.log "#{@mu_name} using code packaged at #{@config['code']['zip_file']}" + end desc[:source_archive_url] = MU::Cloud::Google::Function.uploadPackage(@config['code']['zip_file'], @mu_name+"-cloudfunction.zip", credentials: @credentials) + + if tempfile + tempfile.close + tempfile.unlink + end end # Dir.mktmpdir(@mu_name) { |dir| # hello_code.each_pair { |file, contents| # f = File.open(dir+"/"+file, "w")