简体   繁体   English

在 Python 中使用 API 创建 Google Cloud Function

[英]Create Google Cloud Function using API in Python

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.我正在使用 Python(3.6) 和 Django(1.10) 开发一个项目,在该项目中我需要使用 API 请求在 Google 云上创建一个函数。

How can upload code in the form of a zip archive while creating that function?在创建该函数时,如何以 zip 存档的形式上传代码?

Here's what I have tried:这是我尝试过的:

From views.py :从 views.py :

    def post(self, request, *args, **kwargs):
    if request.method == 'POST':
        post_data = request.POST.copy()
        post_data.update({'user': request.user.pk})
        form = forms.SlsForm(post_data, request.FILES)
        print('get post request')
        if form.is_valid():
            func_obj = form
            func_obj.user = request.user
            func_obj.project = form.cleaned_data['project']
            func_obj.fname = form.cleaned_data['fname']
            func_obj.fmemory = form.cleaned_data['fmemory']
            func_obj.entryPoint = form.cleaned_data['entryPoint']
            func_obj.sourceFile = form.cleaned_data['sourceFile']
            func_obj.sc_github = form.cleaned_data['sc_github']
            func_obj.sc_inline_index = form.cleaned_data['sc_inline_index']
            func_obj.sc_inline_package = form.cleaned_data['sc_inline_package']
            func_obj.bucket = form.cleaned_data['bucket']
            func_obj.save()
            service = discovery.build('cloudfunctions', 'v1', http=views.getauth(), cache_discovery=False)
            requ = service.projects().locations().functions().generateUploadUrl(parent='projects/' + func_obj.project + '/locations/us-central1', body={})
            resp = requ.execute()
            print(resp)
            try:
                auth = views.getauth()
                # Prepare Request Body
                req_body = {
                    "CloudFunction": {
                        "name": func_obj.fname,
                        "entryPoint": func_obj.entryPoint,
                        "timeout": '60s',
                        "availableMemoryMb": func_obj.fmemory,
                        "sourceArchiveUrl": func_obj.sc_github,
                    },
                    "sourceUploadUrl": func_obj.bucket,
                }
                service = discovery.build('cloudfunctions', 'v1beta2', http=auth, cachce_dicovery=False)
                func_req = service.projects().locations().functions().create(location='projects/' + func_obj.project
                                                                                      + '/locations/-',
                                                                             body=req_body)
                func_res = func_req.execute()
                print(func_res)
                return HttpResponse('Submitted',)
            except:
                return HttpResponse(status=500)

        return HttpResponse('Sent!')

Updated Code below:更新代码如下:

            if form.is_valid():
            func_obj = form
            func_obj.user = request.user
            func_obj.project = form.cleaned_data['project']
            func_obj.fname = form.cleaned_data['fname']
            func_obj.fmemory = form.cleaned_data['fmemory']
            func_obj.entryPoint = form.cleaned_data['entryPoint']
            func_obj.sourceFile = form.cleaned_data['sourceFile']
            func_obj.sc_github = form.cleaned_data['sc_github']
            func_obj.sc_inline_index = form.cleaned_data['sc_inline_index']
            func_obj.sc_inline_package = form.cleaned_data['sc_inline_package']
            func_obj.bucket = form.cleaned_data['bucket']
            func_obj.save()

            #######################################################################
            # FIRST APPROACH FOR FUNCTION CREATION USING STORAGE BUCKET
            #######################################################################

            file_name = os.path.join(IGui.settings.BASE_DIR, 'media/archives/', func_obj.sourceFile.name)
            print(file_name)

            service = discovery.build('cloudfunctions', 'v1')
            func_api = service.projects().locations().functions()
            url_svc_req = func_api.generateUploadUrl(parent='projects/'
                                                            + func_obj.project
                                                            + '/locations/us-central1',
                                                     body={})
            url_svc_res = url_svc_req.execute()
            print(url_svc_res)

            upload_url = url_svc_res['uploadUrl']
            print(upload_url)
            headers = {
                'content-type': 'application/zip',
                'x-goog-content-length-range': '0,104857600'
            }
            print(requests.put(upload_url, headers=headers, data=func_obj.sourceFile.name))
            auth = views.getauth()
            # Prepare Request Body
            name = "projects/{}/locations/us-central1/functions/{}".format(func_obj.project, func_obj.fname,)
            print(name)
            req_body = {
              "name": name,
              "entryPoint": func_obj.entryPoint,
              "timeout": "3.5s",
              "availableMemoryMb": func_obj.fmemory,
              "sourceUploadUrl": upload_url,
              "httpsTrigger": {},
            }
            service = discovery.build('cloudfunctions', 'v1')
            func_api = service.projects().locations().functions()

            response = func_api.create(location='projects/' + func_obj.project + '/locations/us-central1',
                                                body=req_body).execute()

            pprint.pprint(response)

Now the function has been created successfully, but it fails because the source code doesn't upload to storage bucket, that's maybe something wrong at:现在函数已经创建成功,但是由于源代码没有上传到存储桶而失败,这可能是错误的:

upload_url = url_svc_res['uploadUrl']
            print(upload_url)
            headers = {
                'content-type': 'application/zip',
                'x-goog-content-length-range': '0,104857600'
            }
            print(requests.put(upload_url, headers=headers, data=func_obj.sourceFile.name))

In the request body you have a dictionary "CloudFunction" inside the request.在请求正文中,请求中有一个字典“CloudFunction”。 The content of "CloudFunction" should be directly in request. “CloudFunction”的内容应直接在请求中。

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 .我建议使用“尝试这个 API”来发现 projects.locations.functions.create 的结构。

"sourceArchiveUrl" and "sourceUploadUrl" can't appear together. "sourceArchiveUrl""sourceUploadUrl"不能一起出现。 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" .在其余的答案中,我假设您想使用"sourceUploadUrl" It requires you to pass it a URL returned to you by .generateUploadUrl(...).execute() .它要求您将.generateUploadUrl(...).execute()返回给您的 URL 传递给它。 See documentation :请参阅文档

sourceUploadUrl -> string sourceUploadUrl ->字符串

The Google Cloud Storage signed URL used for source uploading, generated by [google.cloud.functions.v1.用于源上传的 Google Cloud Storage 签名 URL,由 [google.cloud.functions.v1. GenerateUploadUrl ][]生成上传网址][]

But before passing it you need to upload a zip file to this URL:但在传递它之前,您需要将 zip 文件上传到此 URL:

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

or in python:或在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'.您需要“内容类型”:“应用程序/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. x-goog-content-length-range: min,max对于云存储的所有PUT请求都是必需的,在这种情况下是隐式假设的。 More on it here更多关于这里

  • 104857600, the max in previous entry, is a magical number which I didn't found mentioned anywhere. 104857600,上一个条目中的最大值,是一个神奇的数字,我在任何地方都没有发现它被提及。

where data is a FileLikeObject.其中data是一个 FileLikeObject。

I also assume that you want to use the httpsTrigger .我还假设您想使用httpsTrigger For a cloud function you can only choose one trigger field.对于云函数,您只能选择一个触发字段。 Here it's said that trigger is a Union field. 这里说 trigger 是一个 Union 字段。 For httpsTrigger however that you can just leave it to be an empty dictionary, as its content do not affect the outcome.但是,对于 httpsTrigger,您可以将其保留为空字典,因为其内容不会影响结果。 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() .对于.create()您可以安全地使用 'v1' 而不是 'v1beta2' 。

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:打开并上传一个 zip 文件,如下所示:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Google Cloud Scheduler API 创建云 Function - Google Cloud Scheduler API to create Cloud Function 将 Google Calendar API 与 Python 3.7 Google Cloud Function 结合使用 - Using Google Calendar API with a Python 3.7 Google Cloud Function 使用Google Cloud Python API客户端创建磁盘快照 - Create disk snapshot using google cloud python api client 使用 Google Cloud AppEngine 管理 API 通过 Python 创建请求? - Using Google Cloud AppEngine admin API to create request with Python? 使用 ZA7F5F35426B92741117231B5638 中的 API 更新 Google Cloud Function 的 label - Update the label of Google Cloud Function using API in Python 使用 Python 在云 Function 中创建表格 API 身份验证 - Create Sheets API Authentication in Cloud Function with Python 使用 Python 的 Google Cloud Billing API - Google Cloud Billing API using Python 使用谷歌云函数生成python脚本 - Using google cloud function to spawn a python script 第一步如何使用 Python API 客户端在 google cloud 上创建项目 - How can take the first step create a project on google cloud using Python API client GCP - 将数据从 REST API 插入/加载到 BigQuery,使用 Google Cloud Function 和 ZA7F5F35426B927824717BFCFC11 - GCP - Insert/Load Data to BigQuery from REST API using Google Cloud Function with Python
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM