Create Google Cloud Function using API in Python

前端 未结 1 1183
有刺的猬
有刺的猬 2020-12-11 10:30

I\'m working on a project with Python(3.6) & Django(1.10) in which I need to create a function at Google cloud using API request.

How can upload code in

相关标签:
1条回答
  • 2020-12-11 10:37

    In the request body you have a dictionary "CloudFunction" inside the request. The content of "CloudFunction" should be directly in request.

    request_body = {
        "name": parent + '/functions/' + name,
        "entryPoint": entry_point,
        "sourceUploadUrl": upload_url,
        "httpsTrigger": {}
    }
    

    I recomend using "Try this API" to discover the structure of projects.locations.functions.create .

    "sourceArchiveUrl" and "sourceUploadUrl" can't appear together. This is explained in Resorce Cloud Function:

    // Union field source_code can be only one of the following:
    "sourceArchiveUrl": string,
    "sourceRepository": { object(SourceRepository) },
    "sourceUploadUrl": string,
    // End of list of possible types for union field source_code.
    

    In the rest of the answer I assume that you want to use "sourceUploadUrl". It requires you to pass it a URL returned to you by .generateUploadUrl(...).execute(). See documentation:

    sourceUploadUrl -> string

    The Google Cloud Storage signed URL used for source uploading, generated by [google.cloud.functions.v1.GenerateUploadUrl][]

    But before passing it you need to upload a zip file to this URL:

    curl -X PUT "${URL}" -H 'content-type:application/zip' -H 'x-goog-content-length-range: 0,104857600'  -T test.zip
    

    or in python:

        headers = {
            'content-type':'application/zip',
            'x-goog-content-length-range':'0,104857600'
        }
        print(requests.put(upload_url, headers=headers, data=data))
    

    This is the trickiest part:

    • the case matters and it should be lowercase. Because the signature is calculated from a hash (here)

    • you need 'content-type':'application/zip'. I deduced this one logically, because documentation doesn't mention it. (here)

    • x-goog-content-length-range: min,max is obligatory for all PUT requests for cloud storage and is assumed implicitly in this case. More on it here

    • 104857600, the max in previous entry, is a magical number which I didn't found mentioned anywhere.

    where data is a FileLikeObject.

    I also assume that you want to use the httpsTrigger. For a cloud function you can only choose one trigger field. Here it's said that trigger is a Union field. For httpsTrigger however that you can just leave it to be an empty dictionary, as its content do not affect the outcome. As of now.

    request_body = {
        "name": parent + '/functions/' + name,
        "entryPoint": entry_point,
        "sourceUploadUrl": upload_url,
        "httpsTrigger": {}
    }
    

    You can safely use 'v1' instead of 'v1beta2' for .create().

    Here is a full working example. It would be to complicated if I presented it to you as part of your code, but you can easily integrate it.

    import pprint
    import zipfile
    import requests
    from tempfile import TemporaryFile
    from googleapiclient import discovery
    
    project_id = 'your_project_id'
    region = 'us-central1'
    parent = 'projects/{}/locations/{}'.format(project_id, region)
    print(parent)
    name = 'ExampleFunctionFibonacci'
    entry_point = "fibonacci"
    
    service = discovery.build('cloudfunctions', 'v1')
    CloudFunctionsAPI = service.projects().locations().functions()
    upload_url = CloudFunctionsAPI.generateUploadUrl(parent=parent, body={}).execute()['uploadUrl']
    print(upload_url)
    
    
    payload = """/**
     * Responds to any HTTP request that can provide a "message" field in the body.
     *
     * @param {Object} req Cloud Function request context.
     * @param {Object} res Cloud Function response context.
     */
    exports.""" + entry_point + """= function """ + entry_point + """ (req, res) {
      if (req.body.message === undefined) {
        // This is an error case, as "message" is required
        res.status(400).send('No message defined!');
      } else {
        // Everything is ok
        console.log(req.body.message);
        res.status(200).end();
      }
    };"""
    
    
    with TemporaryFile() as data:
        with zipfile.ZipFile(data, 'w', zipfile.ZIP_DEFLATED) as archive:
            archive.writestr('function.js', payload)
    
        data.seek(0)
        headers = {
            'content-type':'application/zip',
            'x-goog-content-length-range':'0,104857600'
        }
        print(requests.put(upload_url, headers=headers, data=data))
    
    # Prepare Request Body
    # https://cloud.google.com/functions/docs/reference/rest/v1/projects.locations.functions#resource-cloudfunction
    
    request_body = {
        "name": parent + '/functions/' + name,
        "entryPoint": entry_point,
        "sourceUploadUrl": upload_url,
        "httpsTrigger": {},
        "runtime": 'nodejs8'
    }
    
    print('https://{}-{}.cloudfunctions.net/{}'.format(region,project_id,name))
    response = CloudFunctionsAPI.create(location=parent, body=request_body).execute()
    
    pprint.pprint(response)
    

    Open and upload a zip file like following:

    file_name = os.path.join(IGui.settings.BASE_DIR, 'media/archives/', func_obj.sourceFile.name)
    headers = {
        'content-type': 'application/zip',
        'x-goog-content-length-range': '0,104857600'
    }
    
    with open(file_name, 'rb') as data:
        print(requests.put(upload_url, headers=headers, data=data))
    
    0 讨论(0)
提交回复
热议问题