From 9cf982d1f18bfadb97b9f6c15a1776fa3e7b3a9f Mon Sep 17 00:00:00 2001 From: karonganyong <15002917143@163.com> Date: Sat, 14 Sep 2019 18:46:32 +0800 Subject: [PATCH] release huaweicloud python sdk --- Notice.md | 194 ++++++++++++++++ PKG-INFO | 2 +- README.rst | 2 + examples/ecs/v1/cloudserver.py | 175 ++++++++++++++- examples/ecs/v1/flavor.py | 30 +++ examples/ecs/v1/quota.py | 26 +++ examples/fgs/v2/function.py | 238 ++++++++++++++++++++ examples/fgs/v2/triggers.py | 100 +++++++++ openstack/cloud_eye/v1/metric.py | 5 +- openstack/exceptions.py | 10 +- openstack/fgs/__init__.py | 0 openstack/fgs/fgs_service.py | 25 +++ openstack/fgs/v2/__init__.py | 0 openstack/fgs/v2/_proxy.py | 218 ++++++++++++++++++ openstack/fgs/v2/functions.py | 321 +++++++++++++++++++++++++++ openstack/fgs/v2/triggers.py | 86 +++++++ openstack/fgs/version.py | 32 +++ openstack/profile.py | 3 + openstack/service_endpoint.py | 3 + openstack/util/__init__.py | 0 openstack/util/ecs_metadata_utils.py | 84 +++++++ requirements.txt | 1 - 22 files changed, 1542 insertions(+), 13 deletions(-) create mode 100644 Notice.md create mode 100644 examples/ecs/v1/flavor.py create mode 100644 examples/ecs/v1/quota.py create mode 100644 examples/fgs/v2/function.py create mode 100644 examples/fgs/v2/triggers.py create mode 100644 openstack/fgs/__init__.py create mode 100644 openstack/fgs/fgs_service.py create mode 100644 openstack/fgs/v2/__init__.py create mode 100644 openstack/fgs/v2/_proxy.py create mode 100644 openstack/fgs/v2/functions.py create mode 100644 openstack/fgs/v2/triggers.py create mode 100644 openstack/fgs/version.py create mode 100644 openstack/util/__init__.py create mode 100644 openstack/util/ecs_metadata_utils.py diff --git a/Notice.md b/Notice.md new file mode 100644 index 0000000..ac0903c --- /dev/null +++ b/Notice.md @@ -0,0 +1,194 @@ +## OPEN SOURCE SOFTWARE NOTICE ## + +Please note we provide an open source software notice along with this product and/or this product firmware (in the following just “this product”). The open source software licenses are granted by the respective right holders. And the open source licenses prevail all other license information with regard to the respective open source software contained in the product, including but not limited to End User Software Licensing Agreement. This notice is provided on behalf of Huawei Technologies Co. Ltd. and any of its local subsidiaries which may have provided this product to you in your local country. + +## Warranty Disclaimer ## +THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. + +## Copyright Notice and License Texts + +- Software: oslo.utils 3.25 +- Copyright notice: +- Copyright (c) 2013 Hewlett-Packard Development Company, L.P. +- License: Apache License V2.0 + +- Software: keystoneauth1 2.18.0 +- Copyright notice: +- Copyright (c) 2009 Jacob Kaplan-Moss initial codebase (< v2.1) +- Copyright (c) 2011 Rackspace OpenStack extensions (>= v2.1) +- Copyright (c) 2011 Nebula, Inc Keystone refactor (>= v2.7) +- License: Apache License V2.0 + +- Software: openstacksdk 0.9.17 +- Copyright notice: +- Copyright 2010-2011 OpenStack Foundation +- Copyright (c) 2013 Hewlett-Packard Development Company, L.P. +- Copyright 2010 Jacob Kaplan-Moss +- Copyright 2011 Nebula, Inc. +- License: Apache License V2.0 + +Please see below + + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/PKG-INFO b/PKG-INFO index 2e2d5b7..d995afa 100644 --- a/PKG-INFO +++ b/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: huaweicloud-sdk-python -Version: 1.0.16 +Version: 1.0.17 Summary: An SDK for building applications to work with OpenStack Home-page: https://github.com/huaweicloud/huaweicloud-sdk-python Author: huawei diff --git a/README.rst b/README.rst index 29cb3d1..3a3e478 100644 --- a/README.rst +++ b/README.rst @@ -46,3 +46,5 @@ The following services' SDK are included. - SMN - RTS + +- FunctionGraph \ No newline at end of file diff --git a/examples/ecs/v1/cloudserver.py b/examples/ecs/v1/cloudserver.py index dd57300..fbc638c 100644 --- a/examples/ecs/v1/cloudserver.py +++ b/examples/ecs/v1/cloudserver.py @@ -3,23 +3,24 @@ from openstack import connection from openstack import utils -import os -import base64 - +import time utils.enable_logging(debug=True, stream=sys.stdout) # create connection username = "xxxxx" password = "xxxxx" -projectId = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # tenant ID -userDomainId = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # user account ID -auth_url = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # endpoint url +projectId = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # tenant ID +userDomainId = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # user account ID +auth_url = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # endpoint url conn = connection.Connection(auth_url=auth_url, user_domain_id=userDomainId, project_id=projectId, username=username, password=password) +TIMES = 60 +INTERVAL = 10 + # create server def create_server(): @@ -91,9 +92,171 @@ def config_autorecovery(server_id, autorecovery): conn.ecs.config_autorecovery(server_id, autorecovery) +# get list of servers +def servers(): + query = { + "name": "ecs", + "status": "ACTIVE", + "limit": 5, + "offset": 1, + } + servers = conn.ecs.servers(**query) + for server in servers: + print("count: ", server.count) + for each_server in server.servers: + print (each_server["id"], each_server["name"]) + + +# get detail of server +def get_server(server_id): + server = conn.ecs.get_server(server_id) + print(server) + print(server.name) + + +# batch stop server +def stop_server(): + data = { + "os-stop": { + "type": "SOFT", + "servers": [ + { + "id": "cd57e8fb-ce0c-45d8-b7c9-74910b29d734" + }, + { + "id": "559a6009-ef40-48bb-a551-fe5385b13266" + } + ] + } + } + action = conn.ecs.stop_server(**data) + print (action) + job = wait_for_job(TIMES, INTERVAL, action.job_id) + success_servers, failed_servers = get_servers_after_job(job) + print ("Stop success servers: ", success_servers) + print ("Stop failed servers: ", failed_servers) + + +# batch start server +def start_server(): + data = { + "os-start": { + "servers": [ + { + "id": "6e311c63-ae8a-4273-b04e-90aff7210213" + }, + { + "id": "851f66fd-a1ee-4e54-8bb3-af1655d89d86" + } + ] + } + } + action = conn.ecs.start_server(**data) + print(action) + job = wait_for_job(TIMES, INTERVAL, action.job_id) + success_servers, failed_servers = get_servers_after_job(job) + print ("Start success servers: ", success_servers) + print ("Start failed servers: ", failed_servers) + + +# batch reboot server +def reboot_server(): + data = { + "reboot": { + "type": "SOFT", + "servers": [ + { + "id": "cd57e8fb-ce0c-45d8-b7c9-74910b29d734" + }, + { + "id": "559a6009-ef40-48bb-a551-fe5385b13266" + } + ] + } + } + action = conn.ecs.reboot_server(**data) + print(action) + job = wait_for_job(TIMES, INTERVAL, action.job_id) + success_servers, failed_servers = get_servers_after_job(job) + print ("Reboot success servers: ", success_servers) + print ("Reboot failed servers: ", failed_servers) + + +# resize server +def resize_server(server_id): + data = { + "flavorRef": "s3.2xlarge.4", + } + server = conn.ecs.resize_server(server_id, **data) + job = wait_for_job(TIMES, INTERVAL, server.job_id) + print(job) + + +# batch delete server +def delete_server(): + data = { + "servers": [ + { + "id": "cd57e8fb-ce0c-45d8-b7c9-74910b29d734" + }, + { + "id": "559a6009-ef40-48bb-a551-fe5385b13266" + } + ], + "delete_publicip": True, + "delete_volume": True + } + action = conn.ecs.delete_server(**data) + print(action) + job = wait_for_job(TIMES, INTERVAL, action.job_id) + success_servers, failed_servers = get_servers_after_job(job) + print ("Delete success servers: ", success_servers) + print ("Delete failed servers: ", failed_servers) + + +# wait until job status becoming SUCCESS or FAIL +def wait_for_job(times, interval, job_id): + job_result = None + for index in range(times): + time.sleep(interval) + job = conn.ecs.get_job(job_id) + if job.status == "SUCCESS": + job_result = job + print("Get job success after %s tries" % index) + break + elif job.status == "FAIL": + job_result = job + print("Get job failed after %s tries" % index) + break + return job_result + + +# get success and failed server list after waiting job status +def get_servers_after_job(job): + sub_jobs = job.entities["sub_jobs"] + success_servers = [] + failed_servers = [] + + if len(sub_jobs) > 0: + for sub_job in sub_jobs: + if "server_id" in sub_job.get("entities"): + if sub_job["status"] == "SUCCESS": + success_servers.append(sub_job.get("entities").get("server_id")) + else: + failed_servers.append(sub_job.get("entities").get("server_id")) + return success_servers, failed_servers + + if __name__ == "__main__": server_id = "server_id" autorecovery = "true" get_autorecovery(server_id) config_autorecovery(server_id, autorecovery) create_server() + servers() + get_server(server_id) + stop_server() + start_server() + reboot_server() + resize_server(server_id) + delete_server() diff --git a/examples/ecs/v1/flavor.py b/examples/ecs/v1/flavor.py new file mode 100644 index 0000000..65b24dc --- /dev/null +++ b/examples/ecs/v1/flavor.py @@ -0,0 +1,30 @@ +# -*-coding:utf-8 -*- + +from openstack import connection + +# create connection +username = "xxxxxx" +password = "xxxxxx" +projectId = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx" # tenant ID +userDomainId = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx" # user account ID +auth_url = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx" # endpoint url +conn = connection.Connection(auth_url=auth_url, + user_domain_id=userDomainId, + project_id=projectId, + username=username, + password=password) + + +# get list of flavors +def flavors(): + query = { + "availability_zone": "kvmxen.dc1" + } + flavor_list = conn.ecs.flavors(**query) + for flavor in flavor_list: + print(flavor.name) + print(flavor) + + +if __name__ == "__main__": + flavors() diff --git a/examples/ecs/v1/quota.py b/examples/ecs/v1/quota.py new file mode 100644 index 0000000..67da8a4 --- /dev/null +++ b/examples/ecs/v1/quota.py @@ -0,0 +1,26 @@ +# -*-coding:utf-8 -*- + +from openstack import connection + +# create connection +username = "xxxxxx" +password = "xxxxxx" +projectId = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx" # tenant ID +userDomainId = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx" # user account ID +auth_url = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx" # endpoint url +conn = connection.Connection(auth_url=auth_url, + user_domain_id=userDomainId, + project_id=projectId, + username=username, + password=password) + + +def get_quotas(): + quota = conn.ecs.quotas() + print (quota) + print (quota.maxsecuritygrouprules) + + +if __name__ == "__main__": + get_quotas() + diff --git a/examples/fgs/v2/function.py b/examples/fgs/v2/function.py new file mode 100644 index 0000000..ead6a3d --- /dev/null +++ b/examples/fgs/v2/function.py @@ -0,0 +1,238 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +import os +from openstack import connection + +# setup endpoint override for cloud services +# "example" in the endpoint stands for "Region.Cloud" +os.environ.setdefault( + 'OS_FUNCTIONGRAPH_ENDPOINT_OVERRIDE', + 'https://functiongraph.cn-north-1.myhuaweicloud.com/v2/%(project_id)s' +) + +# create connection +username = "xxxxxx" +password = "xxxxxx" +projectId = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx" # tenant ID +userDomainId = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx" # user account ID +auth_url = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx" # iam url +conn = connection.Connection(auth_url=auth_url, + user_domain_id=userDomainId, + project_id=projectId, + username=username, + password=password) + + +# Querying a Function List +def get_function_list(): + function_list = conn.fgs.functions(marker=0,maxitems=400) + for data in function_list: + print(data) + return None + +#Creating a Function +def create_function(): + function_req = { + "func_name": "TestCreateFunctionInPythonSdk", + "runtime": "Python3.6", + "code_type": "inline", + "timeout":30, + "handler":"index.handler", + "package": "default", + "memory_size":128, + "func_code": { + "file": "aW1wb3J0IGpzb24KZGVmIGhhbmRsZXIgKGV2ZW50LCBjb250ZXh0KToKICAgIG91dHB1dCA9ICdIZWxsbyBtZXNzYWdlOiAnICsganNvbi5kdW1wcyhldmVudCkKICAgIHJldHVybiBvdXRwdXQ=" + } + } + function = conn.fgs.create_function(**function_req) + print(function) + return function + +# Querying the Metadata Information of a Function +def get_function_metadata(function_urn): + function = conn.fgs.get_function_metadata(function_urn) + print(function) + return function + +# Querying the Code of a Function +def get_function_code(function_urn): + function = conn.fgs.get_function_code(function_urn) + return function + +# Deleting a Function +def del_function(function_urn): + function = conn.fgs.delete_function(function_urn) + return function + +# Modifying the Code of a Function +def update_function_code(function_urn): + function_req={ + "code_filename": "index.zip", + "code_type": "inline", + "code_url": "", + "depend_list": [], + "dependency_pkg": "", + "func_code": { + "file": "UEsDBAoAAAAAAO5Qak5BtFZEugAAALoAAAAIAAAAaW5kZXgucHlpbXBvcnQganNvbgpkZWYgaGFuZGxlciAoZXZlbnQsIGNvbnRleHQpOgogICAgb3V0cHV0ID0gJ0hlbGxvIG1lc3NhZ2U6ICcgKyBqc29uLmR1bXBzKGV2ZW50KQogICAgcHJpbnQoIjIzMjM0MjQzNDM0MzQzNDM0MzQzNTQ1MzQzPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09IikKICAgIHJldHVybiBvdXRwdXRQSwECHgMKAAAAAADuUGpOQbRWRLoAAAC6AAAACAAAAAAAAAAAAAAAtIEAAAAAaW5kZXgucHlQSwUGAAAAAAEAAQA2AAAA4AAAAAAA", + "link": "" + } + } + function = conn.fgs.update_function_code(function_urn,**function_req) + return function + +# Modifying the Metadata Information of a Function +def update_function_conf(function_urn): + function_req={ + "app_xrole": "", + "description": "", + "func_name": "TestCreateFunctionInPythonSdk", + "depend_list": [], + "dependency_pkg": "", + "func_vpc": { + "subnet_id": "", + "vpc_id": "" + }, + "handler":"index.handler", + "initializer_handler": "", + "initializer_timeout": 0, + "memory_size": 256, + "runtime":"Python3.6", + "strategy_config":{ + "concurrency": -1 + }, + "timeout":300, + "user_data":"", + "xrole":"" + } + function = conn.fgs.update_function_metadata(function_urn,**function_req) + return function + +# Publishing a Function Version +def public_function_verion(function_urn): + function_req = { + "description": "test1.0.1↵函数服务发布版本1.0.1", + "version": "1.0.1" + } + function = conn.fgs.publish_function_version(function_urn,**function_req) + return function + +# Creating an Alias for a Function Version +def create_function_aliase(function_urn): + function_req = { + "additional_version_weights": { + "1.0.1":50 + }, + "description":"函数服务灰度版本别名", + "name":"latest-1_1", + "version": "latest" + } + function = conn.fgs.create_function_aliase(function_urn,**function_req) + return function + +# Modifying the Alias Information of a Function Version +def update_function_aliase(function_urn,alias_name): + function_req = { + "additional_version_weights": { + "1.0.1":80 + }, + "description":"函数服务灰度版本别名", + "version": "latest" + } + function = conn.fgs.update_function_aliase(function_urn,alias_name,**function_req) + return function + +# Querying the Alias Information of a Function Version +def get_function_aliase(function_urn,alias_name): + function = conn.fgs.get_function_aliase(function_urn,alias_name) + return function + +# Querying the Aliases of a Function's All Versions +def get_function_aliase_list(function_urn): + function_list = list(conn.fgs.function_aliases(function_urn)) + print(function_list) + return None + +# Deleting an Alias of a Function Version +def delete_function_aliase(function_urn,alias_name): + function = conn.fgs.delete_function_aliase(function_urn,alias_name) + return function + +# Executing a Function Synchronously +def execut_function_synchronously(function_urn): + function_req = { + "test1":"value1" + } + function = conn.fgs.execute_function_synchronously(function_urn,**function_req) + return function + +# Executing a Function Asynchronously +def execut_function_asynchronously(function_urn): + function_req = { + "test2":"value2" + } + function = conn.fgs.execute_function_asynchronously(function_urn,**function_req) + return function + +# Querying the Aliases of a Function's All Versions +def get_function_version(function_urn): + function_list = conn.fgs.get_function_version(function_urn=function_urn,marker=0,maxitems=400) + for data in function_list: + print(data) + return None + +if __name__ == "__main__": + #Querying a Function List + get_function_list() + + #Creating a Function + func = create_function() + if func.func_urn: + #Querying the Metadata Information of a Function + func_get_conf = get_function_metadata(func.func_urn) + print("func_get_conf:") + print(func_get_conf) + #Executing a Function Synchronously + execut_function_syn = execut_function_synchronously(func.func_urn) + print("execut_function_synchronously:") + print(execut_function_syn) + #Modifying the Code of a Function + func_update_conf = update_function_conf(func.func_urn) + print("func_update_conf:") + print(func_update_conf) + #Publishing a Function Version + func_public_version = public_function_verion(func.func_urn) + print("public_function_verion:") + print(func_public_version) + #Querying the Aliases of a Function's All Versions + get_function_version=get_function_version(func.func_urn) + print("get_function_version:") + print(get_function_version) + #Querying the Code of a Function + func_get_code = get_function_code(func.func_urn) + print("func_get_code:") + print(func_get_code) + #Modifying the Code of a Function + func_update_code = update_function_code(func.func_urn) + print("func_update_code:") + print(func_update_code) + #Creating an Alias for a Function Version + func_create_aliase = create_function_aliase(func.func_urn) + print("create_function_aliase:") + print(func_create_aliase) + #Modifying the Alias Information of a Function Version + func_update_aliase = update_function_aliase(func.func_urn,func_create_aliase.name) + print("update_function_aliase:") + print(func_update_aliase) + #Querying the Alias Information of a Function Version + get_function_aliase(func.func_urn,func_create_aliase.name) + #Querying the Aliases of a Function's All Versions + get_function_aliase_list(func.func_urn) + #Executing a Function Asynchronously + execut_func_asynchronously = execut_function_asynchronously(func.func_urn) + print("execut_function_asynchronously:") + print(execut_func_asynchronously) + #Deleting an Alias of a Function Version + delete_function_aliase(func.func_urn, func_create_aliase.name) + #Deleting a Function or Function Version + del_function(func.func_urn[:-7]) diff --git a/examples/fgs/v2/triggers.py b/examples/fgs/v2/triggers.py new file mode 100644 index 0000000..bcd5118 --- /dev/null +++ b/examples/fgs/v2/triggers.py @@ -0,0 +1,100 @@ +# -*-coding:utf-8 -*- +import os +from openstack import connection + +# setup endpoint override for cloud services +# "example" in the endpoint stands for "Region.Cloud" +os.environ.setdefault( + 'OS_FUNCTIONGRAPH_ENDPOINT_OVERRIDE', + 'https://functiongraph.cn-north-1.myhuaweicloud.com/v2/%(project_id)s' +) + +# create connection +username = "xxxxxx" +password = "xxxxxx" +projectId = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx" # tenant ID +userDomainId = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx" # user account ID +auth_url = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx" # iam url +conn = connection.Connection(auth_url=auth_url, + user_domain_id=userDomainId, + project_id=projectId, + username=username, + password=password) + +#create function +def create_function(): + function_req = { + "func_name": "TestCreateFunctionInPythonSdk", + "runtime": "Python3.6", + "code_type": "inline", + "timeout":30, + "handler":"index.handler", + "package": "default", + "memory_size":128, + "func_code": { + "file": "aW1wb3J0IGpzb24KZGVmIGhhbmRsZXIgKGV2ZW50LCBjb250ZXh0KToKICAgIG91dHB1dCA9ICdIZWxsbyBtZXNzYWdlOiAnICsganNvbi5kdW1wcyhldmVudCkKICAgIHJldHVybiBvdXRwdXQ=" + } + } + function = conn.fgs.creat_function(**function_req) + print(function) + return function + +#create trigger +def create_trigger(func_urn): + function_req = { + "trigger_type_code": "APIG", + "event_type_code": "APICreated", + "event_data": { + "group_id": "6a50c9199d7f4857818188aeb3c3dc0b", + "auth": "IAM", + "backend_type": "FUNCTION", + "env_id": "DEFAULT_ENVIRONMENT_RELEASE_ID", + "env_name": "RELEASE", + "func_info":{ + "timeout": 5000 + }, + "match_mode": "SWA", + "name": "TestCreateTriggerSdk", + "path": "/TestCreateFunctionInPythonSdk", + "protocol": "HTTPS", + "req_method": "ANY", + "sl_domain": "6f53d3cf3b804cc3a1ea312c36bbc8b5.apigw.southchina.huaweicloud.com", + "type": 1 + } + } + trigger = conn.fgs.create_trigger(func_urn,**function_req) + print(trigger) + return trigger + +#Get list of trigger +def get_trigger_list(func_urn): + trigger = list(conn.fgs.trigges(func_urn)) + print(trigger) + return None + +#Get a trigger +def get_trigger(func_urn,trigger_type_code,trigger_id): + trigger = conn.fgs.get_trigger(func_urn,trigger_type_code,trigger_id) + print(trigger) + return trigger + +#delete trigger by func_urn +def delete_all_trigger(func_urn): + trigger = conn.fgs.delete_all_triggers(func_urn) + return trigger + +#delete trigger +def delete_trigger(function_urn,trigger_type_code,trigger_id): + trigger = conn.fgs.delete_trigger(function_urn,trigger_type_code,trigger_id) + return trigger + + +if __name__ == "__main__": + #create function + func = create_function() + if func.func_urn: + #create trigger + trigger=create_trigger(func.func_urn) + get_trigger(func.func_urn, trigger.trigger_type_code, trigger.trigger_id) + delete_all_trigger(func.func_urn) + conn.fgs.delete_function(func.func_urn[:-7]) diff --git a/openstack/cloud_eye/v1/metric.py b/openstack/cloud_eye/v1/metric.py index 05249dd..f686e58 100644 --- a/openstack/cloud_eye/v1/metric.py +++ b/openstack/cloud_eye/v1/metric.py @@ -29,9 +29,8 @@ class Metric(resource.Resource): # capabilities allow_list = True - _query_mapping = QueryParameters('namespace', 'metric_name', 'dim.0', - 'dim.1', 'dim.2', 'order', 'limit', - marker=query_marker_key) + _query_mapping = QueryParameters('namespace', 'metric_name', 'start', + 'order', 'limit', marker=query_marker_key) #: Properties #: Metric Namespace diff --git a/openstack/exceptions.py b/openstack/exceptions.py index 17c1c8c..91c5a8a 100644 --- a/openstack/exceptions.py +++ b/openstack/exceptions.py @@ -37,13 +37,16 @@ import six -class MissingRequiredArgument(BaseException): + +class MissingRequiredArgument(Exception): message = "ClientException" + def __init__(self, message=None): self.message = message or self.message super(MissingRequiredArgument, self).__init__(self.message) -class SDKException(BaseException): + +class SDKException(Exception): """The base exception class for all exceptions this library raises.""" def __init__(self, message=None, cause=None): @@ -101,6 +104,7 @@ class NotFoundException(HttpException): """HTTP 404 Not Found.""" pass + class BadRequestException(HttpException): """HTTP 400 Bad Request.""" pass @@ -120,8 +124,10 @@ def __init__(self, resource, method): (method, resource.__module__, name)) super(MethodNotSupported, self).__init__(message=message) + class MicroversionNotSupported(SDKException): """The service does not support microversion.""" + def __init__(self, service_type, version): message = ('The %s service is not support microversion' % (service_type)) diff --git a/openstack/fgs/__init__.py b/openstack/fgs/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/openstack/fgs/fgs_service.py b/openstack/fgs/fgs_service.py new file mode 100644 index 0000000..72cf544 --- /dev/null +++ b/openstack/fgs/fgs_service.py @@ -0,0 +1,25 @@ +# -*- coding:utf-8 -*- +# Copyright 2019 Huawei Technologies Co.,Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. + +from openstack import service_filter + + +class FGSService(service_filter.ServiceFilter): + """The FunctionGraph service.""" + + valid_versions = [service_filter.ValidVersion('v2')] + + def __init__(self, version=None): + """Create a FunctionGraph service.""" + super(FGSService, self).__init__(service_type='fgsv2', version=version) diff --git a/openstack/fgs/v2/__init__.py b/openstack/fgs/v2/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/openstack/fgs/v2/_proxy.py b/openstack/fgs/v2/_proxy.py new file mode 100644 index 0000000..8973545 --- /dev/null +++ b/openstack/fgs/v2/_proxy.py @@ -0,0 +1,218 @@ +# -*- coding:utf-8 -*- +# Copyright 2019 Huawei Technologies Co.,Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. + +import copy +from openstack.fgs.v2 import functions as _function +from openstack.fgs.v2 import triggers as _trigger +from openstack import proxy2 + + +class Proxy(proxy2.BaseProxy): + def functions(self, **attrs): + """Querying a Function List""" + return self._list(_function.Function, paginated=True, **attrs) + + def get_function_metadata(self, function_urn): + """Querying the Metadata Information of a Function + :param function_urn: Uniform Resource Name (URN) used to uniquely identify a function. + :class:`~openstack.fgs.v2.functions.FunctionMetadata` + :returns: A generator of Function (:class:`~openstack.fgs.v2.functions.FunctionMetadata`) + instances + """ + return self._get(_function.FunctionMetadata, requires_id=False, function_urn=function_urn) + + def get_function_code(self, function_urn): + """Querying the Code of a Function + :param function_urn: Uniform Resource Name (URN) used to uniquely identify a function. + :class:`~openstack.fgs.v2.functions.FunctionCode` + :returns: A generator of Function (:class:`~openstack.fgs.v2.functions.FunctionCode`) + instances + """ + return self._get(_function.FunctionCode, requires_id=False, function_urn=function_urn) + + def create_function(self, **attrs): + """ + This API is used to create a function. + :param attrs: data to create function see more info from support website + :return: :class:`~openstack.fgs.v2.functions.Functions` + """ + return self._create(_function.Function, prepend_key=False, **attrs) + + def delete_function(self, function_urn): + """Deleting a Function or Function Version + :param function_urn: Uniform Resource Name (URN) used to uniquely identify a function. + :class:`~openstack.fgs.v2.functions.FunctionExpansion` + :returns: ``None`` + """ + return self._delete(_function.FunctionExpansion, function_urn=function_urn) + + def update_function_code(self, function_urn, **attrs): + """ + Modifying the Code of a Function + :param function_urn: Uniform Resource Name (URN) used to uniquely identify a function. + :param attrs: data to create function see more info from support website + :return: :class:`~openstack.fgs.v2.functions.FunctionCode` + """ + return self._update(_function.FunctionCode, function_urn=function_urn, **attrs) + + def update_function_metadata(self, function_urn, **attrs): + """ + Modifying the Metadata Information of a Function + :param function_urn: Uniform Resource Name (URN) used to uniquely identify a function. + :param attrs: data to create function see more info from support website + :return: :class:`~openstack.fgs.v2.functions.FunctionMetadata` + """ + return self._update(_function.FunctionMetadata, function_urn=function_urn, **attrs) + + def publish_function_version(self, function_urn, **attrs): + """ + Publishing a Function Version + :param function_urn: + :param attrs: data to create function see more info from support website + :return: :class:`~openstack.fgs.v2.functions.FunctionVersion` + """ + return self._create(_function.FunctionVersion, function_urn=function_urn, **attrs) + + def get_function_version(self, function_urn, **attrs): + """Querying the Versions of a Function + :param function_urn: Uniform Resource Name (URN) used to uniquely identify a function. + :class:`~openstack.fgs.v2.functions.FunctionVersion` + :param attrs: data to create function see more info from support website + :returns: A generator of Function (:class:`~openstack.fgs.v2.functions.FunctionVersion`) + instances + """ + return self._list(_function.FunctionVersion, paginated=True, function_urn=function_urn, **attrs) + + def create_function_aliase(self, function_urn, **attrs): + """ + Creating an Alias for a Function Version + :param function_urn: + :param attrs: data to create function see more info from support website + :return: :class:`~openstack.fgs.v2.functions.FunctionAliase` + """ + return self._create(_function.FunctionAliase, function_urn=function_urn, **attrs) + + def update_function_aliase(self, function_urn, alias_name, **attrs): + """ + Modifying the Alias Information of a Function Version + :param function_urn: Uniform Resource Name (URN) used to uniquely identify a function. + :param alias_name: The alias of function + :param attrs: data to create function see more info from support website + :return: :class:`~openstack.fgs.v2.functions.FunctionAliaseExpansion` + """ + return self._update(_function.FunctionAliaseExpansion, function_urn=function_urn, alias_name=alias_name, + **attrs) + + def delete_function_aliase(self, function_urn, alias_name): + """Deleting an Alias of a Function Version + :param function_urn: Uniform Resource Name (URN) used to uniquely identify a function. + :param alias_name: The alias of function + :class:`~openstack.fgs.v2.functions.FunctionAliaseExpansion` + :returns: ``None`` + """ + return self._delete(_function.FunctionAliaseExpansion, function_urn=function_urn, alias_name=alias_name) + + def get_function_aliase(self, function_urn, alias_name): + """ + Querying the Alias Information of a Function Version + :param function_urn: Uniform Resource Name (URN) used to uniquely identify a function. + :param alias_name: The alias of function + :return: :class:`~openstack.fgs.v2.functions.FunctionAliaseExpansion` + """ + return self._get(_function.FunctionAliaseExpansion, requires_id=False, function_urn=function_urn, + alias_name=alias_name) + + def function_aliases(self, function_urn, **function): + """ + Querying the Aliases of All Versions of a Function + :param function_urn: Uniform Resource Name (URN) used to uniquely identify a function. + :return: :class:`~openstack.fgs.v2.functions.FunctionAliase + """ + return self._list(_function.FunctionAliase, function_urn=function_urn, paginated=False, **function) + + def execute_function_synchronously(self, function_urn, **attrs): + """ + Executing a Function Synchronously + :param function_urn: Uniform Resource Name (URN) used to uniquely identify a function. + :param attrs: usedata + :return: :class:`~openstack.fgs.v2.functions.FunctionInvocations + """ + req_body = copy.deepcopy(attrs) + attrs["function_urn"] = function_urn + res = _function.FunctionInvocations.new(**attrs) + return res.create(self._session, prepend_key=False, **req_body) + + def execute_function_asynchronously(self, function_urn, **attrs): + """ + Executing a Function Asynchronously + :param function_urn: Uniform Resource Name (URN) used to uniquely identify a function. + :return: :class:`~openstack.fgs.v2.functions.FunctionInvocationsAsync + """ + req_body = copy.deepcopy(attrs) + attrs["function_urn"] = function_urn + res = _function.FunctionInvocationsAsync.new(**attrs) + return res.create(self._session, prepend_key=False, **req_body) + + def create_trigger(self, function_urn, **attrs): + """ + This API is used to create a trigger. + :param function_urn: + :param attrs: data to create trigger see more info from support website + :return: :class:`~openstack.fgs.v2.triggers.Trigger` + """ + return self._create(_trigger.Trigger, prepend_key=False, function_urn=function_urn, **attrs) + + def get_trigger(self, function_urn, trigger_type_code, trigger_id): + """ + Querying the Information About a Trigger + :param function_urn: Uniform Resource Name (URN) used to uniquely identify a function. + :param trigger_type_code: Trigger type. Options: SMN, DMS, OBS, DIS, APIG, TIMER, LTS, and CTS. + :param trigger_id: Trigger ID. + :return: :class:`~openstack.fgs.v2.triggers.TriggerExpansion` + """ + attrs = { + "function_urn": function_urn, + "tg_type": trigger_type_code, + "tg_id": trigger_id + } + return self._get(_trigger.TriggerExpansion, requires_id=False, **attrs) + + def triggers(self, function_urn, **attrs): + """ + Querying All Triggers of a Function + :param function_urn: Uniform Resource Name (URN) used to uniquely identify a function. + :return: :class:`~openstack.fgs.v2.triggers.Trigger` + """ + return self._list(_trigger.Trigger, function_urn=function_urn, paginated=False, **attrs) + + def delete_trigger(self, function_urn, trigger_type_code, trigger_id): + """Deleting a Trigger + :param function_urn: Uniform Resource Name (URN) used to uniquely identify a function. + :param trigger_type_code: Trigger type. Options: SMN, DMS, OBS, DIS, APIG, TIMER, LTS, and CTS. + :param trigger_id: Trigger ID. + :returns: ``None`` + """ + attrs = { + "function_urn": function_urn, + "tg_type": trigger_type_code, + "tg_id": trigger_id + } + return self._delete(_trigger.TriggerExpansion, **attrs) + + def delete_all_triggers(self, function_urn): + """Deleting All Triggers of a Function + :param function_urn: Uniform Resource Name (URN) used to uniquely identify a function. + :returns: ``None`` + """ + return self._delete(_trigger.Trigger, function_urn=function_urn) diff --git a/openstack/fgs/v2/functions.py b/openstack/fgs/v2/functions.py new file mode 100644 index 0000000..86cfe6d --- /dev/null +++ b/openstack/fgs/v2/functions.py @@ -0,0 +1,321 @@ +# -*- coding:utf-8 -*- +# Copyright 2019 Huawei Technologies Co.,Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. + +from openstack.fgs import fgs_service +from openstack import resource2 as resource +from openstack import exceptions + + +class Function(resource.Resource): + resources_key = 'functions' + base_path = '/fgs/functions' + service = fgs_service.FGSService() + + # capabilities + allow_create = True + allow_list = True + allow_get = False + allow_update = False + allow_delete = False + + # noinspection SpellCheckingInspection + _query_mapping = resource.QueryParameters("maxitems") + + #: Properties + #: Function name. + func_name = resource.Body('func_name') + #: Group to which the function belongs. This field is defined to group functions. + package = resource.Body('package') + #: Function code type + code_type = resource.Body('code_type') + # Address of the function code package in OBS when CodeType is set to obs, + # or blank when CodeType is set to another value. ; + code_url = resource.Body('code_url') + #: Description of the function. + description = resource.Body('description') + #: Name of the function file. + code_filename = resource.Body('code_filename') + #: Entry point of the function. + handler = resource.Body('handler') + #: Memory size (MB) allocated to the function. + memory_size = resource.Body('memory_size', type=int) + #: Environment for executing the function. + runtime = resource.Body('runtime') + #: Timeout duration (3s to 900s) for executing the function. + timeout = resource.Body('timeout', type=int) + #: Name/Value information defined for the function. + user_data = resource.Body('user_data') + #: Agency used by the function. + # noinspection SpellCheckingInspection,SpellCheckingInspection + xrole = resource.Body('xrole') + #: Agency used by the function. + # noinspection SpellCheckingInspection + app_xrole = resource.Body('app_xrole') + #: The url address of the third-party software zip package used by the function on the obs. + dependency_pkg = resource.Body('dependency_pkg') + #: Function code, need to be base64 encoded. + func_code = resource.Body('func_code') + #: URN of a function. + func_urn = resource.Body('func_urn') + + # name of tenant + user_domain = resource.Body("user_domain") + # project id of tenant + domain_id = resource.Body("domain_id") + # namespace of tenant + namespace = resource.Body("namespace") + # project name id of tenant + project_name = resource.Body("project_name") + # Cpu resource occupied by the function, the unit is millicore + cpu = resource.Body("cpu", type=int) + # Function size in bytes. + code_size = resource.Body("code_size") + #: Function digest . + digest = resource.Body("digest") + #: Function version . + version = resource.Body('version') + #: The internal ID of the function version. + image_name = resource.Body('image_name') + #: Function version description. + version_description = resource.Body('version_description') + #: Last update time of the function. + last_modified = resource.Body('last_modified') + #: Vpc configuration. + func_vpc = resource.Body('func_vpc') + #: Function enable flag + concurrency = resource.Body('concurrency') + #: Dependency package list + depend_list = resource.Body('depend_list') + #: Function policy configuration + strategy_config = resource.Body('strategy_config') + #: Function extension configuration + extend_config = resource.Body('extend_config') + #: Dependency code package + dependencies = resource.Body('dependencies') + #: Function initialization entry + initializer_handler = resource.Body('initializer_handler') + #: Function initialization time + initializer_timeout = resource.Body('initializer_timeout') + #: Function next_marker + next_marker = resource.Body('next_marker') + + def delete(self, session, params=None, has_body=False): + """Delete the remote resource based on this instance. + + :param session: The session to use for making this request. + :type session: :class:`~openstack.session.Session` + :param params: http params to be sent + :param bool has_body: should mapping response body to resource + + :return: This :class:`Resource` instance. + :raises: :exc:`~openstack.exceptions.MethodNotSupported` if + :data:`Resource.allow_update` is not set to ``True``. + """ + if not self.allow_delete: + raise exceptions.MethodNotSupported(self, "delete") + + request = self._prepare_request(requires_id=False) + + endpoint_override = self.service.get_endpoint_override() + response = session.delete(request.uri, endpoint_filter=self.service, + endpoint_override=endpoint_override, + headers={"Accept": ""}, + params=params) + + self._translate_response(response, has_body=has_body) + return self + + def update(self, session, prepend_key=True, has_body=True): + """Update the remote resource based on this instance. + + :param has_body: DELETE operations don't return a body, so only try to work + with a body when has_body is True. + :param session: The session to use for making this request. + :type session: :class:`~openstack.session.Session` + :param prepend_key: A boolean indicating whether the resource_key + should be prepended in a resource update request. + Default to True. + + :return: This :class:`Resource` instance. + :raises: :exc:`~openstack.exceptions.MethodNotSupported` if + :data:`Resource.allow_update` is not set to ``True``. + """ + # The id cannot be dirty for an update + # noinspection PyProtectedMember + self._body._dirty.discard("id") + id_mapping_name = self._body_mapping()["id"] + self._body._dirty.discard(id_mapping_name) + + # Only try to update if we actually have anything to update. + if not any([self._body.dirty, self._header.dirty]): + return self + + if not self.allow_update: + raise exceptions.MethodNotSupported(self, "update") + + request = self._prepare_request(requires_id=False, prepend_key=prepend_key) + + endpoint_override = self.service.get_endpoint_override() + if self.patch_update: + response = session.patch(request.uri, endpoint_filter=self.service, + endpoint_override=endpoint_override, + json=request.body, + headers=request.headers) + else: + response = session.put(request.uri, endpoint_filter=self.service, + endpoint_override=endpoint_override, + json=request.body, headers=request.headers) + + self._translate_response(response, has_body=has_body) + return self + + +class FunctionExpansion(Function): + base_path = '/fgs/functions/%(function_urn)s' + function_urn = resource.URI('function_urn') + + # capabilities + allow_create = False + allow_list = False + allow_delete = True + + +class FunctionInvocations(Function): + #: requestId for API2.0 + requestId = resource.Body('requestId') + #: requestId for API1.0 + request_id = resource.Body('request_id') + #: result of invocations + result = resource.Body('result') + #: log of invocations + log = resource.Body('log') + #: status of invocations + status = resource.Body('status') + + base_path = '/fgs/functions/%(function_urn)s/invocations' + function_urn = resource.URI('function_urn') + + # capabilities + allow_list = False + + def create(self, session, prepend_key=True, **attrs): + """Create a remote resource based on this instance. + + :param session: The session to use for making this request. + :type session: :class:`~openstack.session.Session` + :param prepend_key: A boolean indicating whether the resource_key + should be prepended in a resource creation + request. Default to True. + + :return: This :class:`Resource` instance. + :raises: :exc:`~openstack.exceptions.MethodNotSupported` if + :data:`Resource.allow_create` is not set to ``True``. + """ + if not self.allow_create: + raise exceptions.MethodNotSupported(self, "create") + + endpoint_override = self.service.get_endpoint_override() + + request = self._prepare_request(requires_id=False, + prepend_key=prepend_key) + request.body = attrs + request.headers = {"Accept": "*/*", + "Content-type": "application/json;charset=UTF-8", + "x-cf2-passthrough": "true", + "x-cff-log-type": "tail", + "x-cff-request-version": "v1" + } + response = session.post(request.uri, endpoint_filter=self.service, + endpoint_override=endpoint_override, + json=request.body, headers=request.headers) + + self._translate_response(response) + return self + + +class FunctionInvocationsAsync(FunctionInvocations): + base_path = '/fgs/functions/%(function_urn)s/invocations-async' + function_urn = resource.URI('function_urn') + + # capabilities + allow_list = False + + +class FunctionMetadata(Function): + base_path = '/fgs/functions/%(function_urn)s/config' + function_urn = resource.URI('function_urn') + + # capabilities + allow_create = False + allow_list = False + allow_get = True + allow_update = True + + +class FunctionCode(Function): + base_path = '/fgs/functions/%(function_urn)s/code' + function_urn = resource.URI('function_urn') + + # capabilities + allow_create = False + allow_list = False + allow_get = True + allow_update = True + + +class FunctionVersion(Function): + base_path = '/fgs/functions/%(function_urn)s/versions' + function_urn = resource.URI('function_urn') + resources_key = 'versions' + + # capabilities + put_create = False + + #: Function version . + version = resource.Body('version') + #: Function digest . + digest = resource.Body('digest') + #: Function next_marker + next_marker = resource.Body('next_marker') + + +class FunctionAliase(Function): + base_path = '/fgs/functions/%(function_urn)s/aliases' + function_urn = resource.URI('function_urn') + resources_key = None + + # capabilities + allow_get = True + put_create = False + + #: Function alias. + name = resource.Body('name') + #: Function version . + version = resource.Body('version') + #: Function alias_urn . + alias_urn = resource.Body('alias_urn') + #: Function additional_version_weights . + additional_version_weights = resource.Body('additional_version_weights') + + +class FunctionAliaseExpansion(FunctionAliase): + base_path = '/fgs/functions/%(function_urn)s/aliases/%(alias_name)s' + function_urn = resource.URI('function_urn') + alias_name = resource.URI('alias_name') + + # capabilities + allow_create = False + allow_list = False + allow_update = True + allow_delete = True diff --git a/openstack/fgs/v2/triggers.py b/openstack/fgs/v2/triggers.py new file mode 100644 index 0000000..60c2739 --- /dev/null +++ b/openstack/fgs/v2/triggers.py @@ -0,0 +1,86 @@ +# -*- coding:utf-8 -*- +# Copyright 2019 Huawei Technologies Co.,Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. + +from openstack.fgs import fgs_service +from openstack import resource2 as resource +from openstack import exceptions + + +class Trigger(resource.Resource): + """FGS reverse record resource""" + resources_key = 'triggers' + base_path = '/fgs/triggers/%(function_urn)s' + service = fgs_service.FGSService() + + function_urn = resource.URI('function_urn') + + # capabilities + allow_create = True + allow_get = False + allow_update = False + allow_list = True + allow_delete = True + + #: Trigger type. + trigger_type_code = resource.Body('trigger_type_code') + #: Event type. + event_type_code = resource.Body('event_type_code') + #: Event message. + event_data = resource.Body('event_data') + #: trigger_id. + trigger_id = resource.Body('trigger_id') + #: trigger_status. + trigger_status = resource.Body('trigger_status') + #: last_updated_time. + last_updated_time = resource.Body('last_updated_time') + #: created_time. + created_time = resource.Body('created_time') + + def delete(self, session, params=None, has_body=False): + """Delete the remote resource based on this instance. + + :param session: The session to use for making this request. + :type session: :class:`~openstack.session.Session` + :param params: http params to be sent + :param bool has_body: should mapping response body to resource + + :return: This :class:`Resource` instance. + :raises: :exc:`~openstack.exceptions.MethodNotSupported` if + :data:`Resource.allow_update` is not set to ``True``. + """ + if not self.allow_delete: + raise exceptions.MethodNotSupported(self, "delete") + + request = self._prepare_request(requires_id=False) + + endpoint_override = self.service.get_endpoint_override() + response = session.delete(request.uri, endpoint_filter=self.service, + endpoint_override=endpoint_override, + headers={"Accept": ""}, + params=params) + + self._translate_response(response, has_body=has_body) + return self + + +class TriggerExpansion(Trigger): + base_path = '/fgs/triggers/%(function_urn)s/%(tg_type)s/%(tg_id)s' + function_urn = resource.URI('function_urn') + tg_type = resource.URI('tg_type') + tg_id = resource.URI('tg_id') + + # capabilities + allow_create = False + allow_list = False + allow_get = True diff --git a/openstack/fgs/version.py b/openstack/fgs/version.py new file mode 100644 index 0000000..292e1e8 --- /dev/null +++ b/openstack/fgs/version.py @@ -0,0 +1,32 @@ +# -*- coding:utf-8 -*- +# Copyright 2019 Huawei Technologies Co.,Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. + +from openstack.fgs import fgs_service +from openstack import resource2 as resource + + +class Version(resource.Resource): + resource_key = 'version' + resources_key = 'versions' + base_path = '/' + service = fgs_service.FGSService( + version=fgs_service.FGSService.UNVERSIONED + ) + + # capabilities + allow_list = True + + # Properties + links = resource.Body('links') + status = resource.Body('status') diff --git a/openstack/profile.py b/openstack/profile.py index 0954fb2..a5cdcd7 100644 --- a/openstack/profile.py +++ b/openstack/profile.py @@ -112,6 +112,7 @@ # from openstack.telemetry.alarm import alarm_service # from openstack.telemetry import telemetry_service # from openstack.workflow import workflow_service +from openstack.fgs import fgs_service from openstack.iam import iam_service _logger = logging.getLogger(__name__) @@ -183,6 +184,8 @@ def __init__(self, plugins=None): # self._add_service(rds_os_service.RDSService(version="v1")) # self._add_service(telemetry_service.TelemetryService(version="v2")) # self._add_service(workflow_service.WorkflowService(version="v2")) + self._add_service(fgs_service.FGSService(version='v2')) + if plugins: for plugin in plugins: self._load_plugin(plugin) diff --git a/openstack/service_endpoint.py b/openstack/service_endpoint.py index d033cd7..85c6633 100644 --- a/openstack/service_endpoint.py +++ b/openstack/service_endpoint.py @@ -86,6 +86,9 @@ "DEH": { "public": "https://deh.%(region)s.%(domain)s/v1.0/%(project_id)s" }, + "FGSV2": { + "public": "https://functiongraph.%(region)s.%(domain)s/v2/%(project_id)s" + }, "IAM": { "public": "https://iam.%(region)s.%(domain)s/v3.0" } diff --git a/openstack/util/__init__.py b/openstack/util/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/openstack/util/ecs_metadata_utils.py b/openstack/util/ecs_metadata_utils.py new file mode 100644 index 0000000..835c905 --- /dev/null +++ b/openstack/util/ecs_metadata_utils.py @@ -0,0 +1,84 @@ +# -*- coding:utf-8 -*- +# Copyright 2019 Huawei Technologies Co.,Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from keystoneauth1 import session + +from openstack.resource2 import Body +from openstack.resource2 import Resource + +# Default root url for the openstack metadata apis. +OPENSTACK_METADATA_ROOT = "/openstack/latest" +# Default root url for the metadata apis compatible with EC2. +EC2_METADATA_ROOT = "/latest/meta-data" + +# Default endpoint for the ECS Instance Metadata Service. +ECS_METADATA_SERIVCE_URL = "http://169.254.169.254" + + +class ECSMetadataUtils(object): + """Utility class for retrieving ECS instance metadata. + + Examples: + ECSMetadataUtils.get_instance_type() + ECSMetadataUtils.get_security_key().security_token + """ + + @classmethod + def get_security_key(cls): + """Get the temporary security credentials of the instance. + + Returns the temporary security credentials (access, secret, + securitytoken, and expires_at) associated with the IAM roles on + the instance.""" + return cls.get_resource(SecurityKey, + OPENSTACK_METADATA_ROOT + "/securitykey") + + @classmethod + def get_instance_type(cls): + """Get the type of the instance.""" + return cls.get_resource(str.__class__, + EC2_METADATA_ROOT + "/instance-type") + + @classmethod + def get_resource(cls, resource_class, url): + """Get resource and return contents from metadata service. + :param resource_class: The type of resource to get. + :param url: URL of request. + """ + session_obj = session.Session() + resp = session_obj.get(url, endpoint_override=ECS_METADATA_SERIVCE_URL) + if issubclass(resource_class, Resource): + response_json = resp.json() + resource_json = Resource.find_value_by_accessor( + response_json, resource_class.resource_key) + resource = resource_class.existing(**resource_json) + else: + resource = resp.text + return resource + + +class SecurityKey(Resource): + """The temporary security credentials associated with the IAM role.""" + + resource_key = "credential" + + #: access of security key + access = Body('access') + #: secret of security key + secret = Body('secret') + #: security token of security key + security_token = Body('securitytoken') + #: expires_at of security key + expires_at = Body('expires_at') diff --git a/requirements.txt b/requirements.txt index 68c41d0..77c42ed 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,6 @@ # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. pbr!=2.1.0,>=2.0.0 # Apache-2.0 -jsonpatch>=1.1 # BSD six>=1.9.0 # MIT stevedore>=1.20.0 # Apache-2.0 keystoneauth1>=3.0.0,<=3.4.0 # Apache-2.0