Skip to content

Commit 8dbd8ea

Browse files
committed
adding oci-apigw-display-httprequest-info-python
1 parent c700d1e commit 8dbd8ea

File tree

9 files changed

+380
-0
lines changed

9 files changed

+380
-0
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.DS_Store
2+
__pycache__
3+
test.py
Lines changed: 271 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
# Function that returns the HTTP request information when called through API Gateway
2+
This function returns the HTTP request information when called through API Gateway.
3+
4+
As you make your way through this tutorial, look out for this icon ![user input icon](./images/userinput.png).
5+
Whenever you see it, it's time for you to perform an action.
6+
7+
8+
## Prerequisites
9+
Before you deploy this sample function, make sure you have run step A, B and C of the [Oracle Functions Quick Start Guide for Cloud Shell](https://www.oracle.com/webfolder/technetwork/tutorials/infographics/oci_functions_cloudshell_quickview/functions_quickview_top/functions_quickview/index.html)
10+
* A - Set up your tenancy
11+
* B - Create application
12+
* C - Set up your Cloud Shell dev environment
13+
14+
15+
## List Applications
16+
Assuming your have successfully completed the prerequisites, you should see your
17+
application in the list of applications.
18+
```
19+
fn ls apps
20+
```
21+
22+
23+
## Review and customize the function
24+
Review the following files in the current folder:
25+
* the code of the function, [func.py](./func.py)
26+
* its dependencies, [requirements.txt](./requirements.txt)
27+
* the function metadata, [func.yaml](./func.yaml)
28+
29+
30+
## Deploy the function
31+
In Cloud Shell, run the *fn deploy* command to build the function and its dependencies as a Docker image,
32+
push the image to OCIR, and deploy the function to Oracle Functions in your application.
33+
34+
![user input icon](./images/userinput.png)
35+
```
36+
fn -v deploy --app <app-name>
37+
```
38+
39+
40+
## Create the API Gateway
41+
The functions is meant to be invoked through API Gateway.
42+
43+
![user input icon](./images/userinput.png)
44+
45+
On the OCI console, navigate to *Developer Services* > *API Gateway*. Click on *Create Gateway*. Provide a name, set the type to "Public", select a compartment, a VCN, a public subnet, and click *Create*.
46+
47+
![APIGW create](./images/apigw-create.png)
48+
49+
Once created, click on your gateway. Under *Resources*, select *Deployments* and click *Create Deployment*. Provide a name, a path prefix ("/v1" for example), click *Next*. Provide a name to the route ("/display-httprequest-info" for example), select methods "GET" and "POST", select type "Oracle Functions", select the Application for your function, and select your function you deployed in the previous step.
50+
51+
![APIGW deployment create](./images/apigw-deployment-create.png)
52+
53+
Click *Next* and finally, click *Save Changes*.
54+
55+
Note the endpoint of your API Gateway deployment.
56+
57+
![APIGW deployment endpoint](./images/apigw-deployment-endpoint.png)
58+
59+
60+
## Create or Update your Dynamic Group for API Gateway
61+
In order to invoke functions, your API Gateway must be part of a dynamic group.
62+
63+
When specifying the *Matching Rules*, we suggest matching all functions in a compartment with:
64+
```
65+
ALL {resource.type = 'ApiGateway', resource.compartment.id = 'ocid1.compartment.oc1..aaaaaxxxxx'}
66+
```
67+
68+
69+
## Create or Update IAM Policies for API Gateway
70+
Create a new policy that allows the API Gateway dynamic group to invoke functions. We will grant `use` access to `functions-family` in the compartment.
71+
72+
![user input icon](./images/userinput.png)
73+
74+
Your policy should look something like this:
75+
```
76+
Allow dynamic-group <dynamic-group-name> to use functions-family in compartment <compartment-name>
77+
```
78+
79+
For more information on how to create policies, check the [documentation](https://docs.cloud.oracle.com/iaas/Content/Identity/Concepts/policysyntax.htm).
80+
81+
82+
## Set the function configuration values
83+
The function returns the configuration values you set.
84+
85+
![user input icon](../images/userinput.png)
86+
87+
Use the *fn CLI* to set the config value:
88+
```
89+
fn config function <app-name> <function-name> <configkey> <configvalue>
90+
```
91+
e.g.
92+
```
93+
fn config function myapp oci-apigw-display-httprequest-info-python configkey1 "value1"
94+
```
95+
96+
97+
## Invoke the function
98+
The function returns the information of the HTTP request through API Gateway.
99+
100+
![user input icon](./images/userinput.png)
101+
102+
Set the Environment variable "APIGW_ENDPOINT" to the value of the endpoint of your API Gateway deployment, e.g.
103+
```
104+
export APIGW_ENDPOINT=https://xxxxx.apigateway.us-phoenix-1.oci.customer-oci.com/v1
105+
```
106+
107+
Use the curl command to make the HTTP request. You can optionally specify a request header just to see it returned by the function. You may want to pipe the curl command to `jq` to get a nicer output.
108+
```
109+
curl --header "X-MyHeader1: headerValue" $APIGW_ENDPOINT/display-httprequest-info | jq .
110+
```
111+
112+
Upon success, curl should return something similar to:
113+
```
114+
{
115+
"Headers": {
116+
"host": [
117+
"localhost",
118+
"xxxxx.apigateway.us-phoenix-1.oci.customer-oci.com"
119+
],
120+
"user-agent": [
121+
"lua-resty-http/0.14 (Lua) ngx_lua/10015",
122+
"curl/7.64.1"
123+
],
124+
"transfer-encoding": "chunked",
125+
"content-type": [
126+
"application/octet-stream",
127+
"application/octet-stream"
128+
],
129+
"date": "Tue, 23 Jun 2020 01:09:41 GMT",
130+
"fn-call-id": "xxxxxxxxx",
131+
"fn-deadline": "2020-06-23T01:10:21Z",
132+
"accept": "*/*",
133+
"forwarded": "for=x.x.x.x",
134+
"x-forwarded-for": "x.x.x.x",
135+
"x-myheader1": "headerValue",
136+
"x-real-ip": "x.x.x.x",
137+
"fn-http-method": "GET",
138+
"fn-http-request-url": "/v1/display-httprequest-info",
139+
"fn-intent": "httprequest",
140+
"fn-invoke-type": "sync",
141+
"oci-subject-id": "ocid1.apigateway.oc1.phx.xxxxx",
142+
"oci-subject-tenancy-id": "ocid1.tenancy.oc1..xxxxx",
143+
"oci-subject-type": "resource",
144+
"opc-request-id": "xxxxxxxxx",
145+
"x-content-sha256": "xxxxxxxxx",
146+
"accept-encoding": "gzip"
147+
},
148+
"Configuration": {
149+
"PATH": "/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
150+
"HOSTNAME": "xxxxxxxxx",
151+
"FN_FN_ID": "ocid1.fnfunc.oc1.phx.xxxxx",
152+
"FN_MEMORY": "256",
153+
"FN_TYPE": "sync",
154+
"configkey1": "value1",
155+
"FN_LISTENER": "unix:/tmp/iofs/lsnr.sock",
156+
"FN_FORMAT": "http-stream",
157+
"FN_APP_ID": "ocid1.fnapp.oc1.phx.xxxxx",
158+
"FN_CPUS": "100m",
159+
"OCI_RESOURCE_PRINCIPAL_RPST": "/.oci-credentials/rpst",
160+
"OCI_RESOURCE_PRINCIPAL_PRIVATE_PEM": "/.oci-credentials/private.pem",
161+
"OCI_RESOURCE_PRINCIPAL_VERSION": "2.2",
162+
"OCI_RESOURCE_PRINCIPAL_REGION": "us-phoenix-1",
163+
"OCI_REGION_METADATA": "{\"realmDomainComponent\":\"oraclecloud.com\",\"realmKey\":\"ocX\",\"regionIdentifier\":\"xx-xxxxx-x\",\"regionKey\":\"XXX\"}",
164+
"LANG": "C.UTF-8",
165+
"GPG_KEY": "xxxxxxxxx",
166+
"PYTHON_VERSION": "3.6.10",
167+
"PYTHON_PIP_VERSION": "20.1.1",
168+
"PYTHON_GET_PIP_URL": "https://github.com/pypa/get-pip/raw/eff16c878c7fd6b688b9b4c4267695cf1a0bf01b/get-pip.py",
169+
"PYTHON_GET_PIP_SHA256": "xxxxxxxxx",
170+
"PYTHONPATH": "/function:/python",
171+
"HOME": "/home/fn"
172+
},
173+
"Request body": {},
174+
"Request URL": "/v1/display-httprequest-info",
175+
"Query String": {},
176+
"Request Method": "GET",
177+
"AppID": "ocid1.fnapp.oc1.phx.xxxxx",
178+
"FnID": "ocid1.fnfunc.oc1.phx.xxxxx",
179+
"CallID": "xxxxxxxxx",
180+
"Format": "http-stream",
181+
"Deadline": "2020-06-23T01:10:21Z"
182+
}
183+
```
184+
185+
Now, use the "POST" method so you can specify a request payload, and specify some query string parameters:
186+
```
187+
curl -X POST --header "X-MyHeader1: headerValue" -d '{"key1":"value"}' "$APIGW_ENDPOINT/display-httprequest-info?key1=value1&key2=value2" | jq .
188+
```
189+
190+
Upon success, curl should return something similar to:
191+
```
192+
{
193+
"Headers": {
194+
"host": [
195+
"localhost",
196+
"xxxxx.apigateway.us-phoenix-1.oci.customer-oci.com"
197+
],
198+
"user-agent": [
199+
"lua-resty-http/0.14 (Lua) ngx_lua/10015",
200+
"curl/7.64.1"
201+
],
202+
"transfer-encoding": "chunked",
203+
"content-type": [
204+
"application/x-www-form-urlencoded",
205+
"application/x-www-form-urlencoded"
206+
],
207+
"date": "Tue, 23 Jun 2020 17:58:40 GMT",
208+
"fn-call-id": "xxxxxxxxx",
209+
"fn-deadline": "2020-06-23T17:59:10Z",
210+
"accept": "*/*",
211+
"content-length": "16",
212+
"forwarded": "for=x.x.x.x",
213+
"x-forwarded-for": "x.x.x.x",
214+
"x-myheader1": "headerValue",
215+
"x-real-ip": "x.x.x.x",
216+
"fn-http-method": "POST",
217+
"fn-http-request-url": "/v1/display-httprequest-info?key1=value1&key2=value2",
218+
"fn-intent": "httprequest",
219+
"fn-invoke-type": "sync",
220+
"oci-subject-id": "ocid1.apigateway.oc1.phx.xxxxx",
221+
"oci-subject-tenancy-id": "ocid1.tenancy.oc1..xxxxx",
222+
"oci-subject-type": "resource",
223+
"opc-request-id": "xxxxxxxxx",
224+
"x-content-sha256": "xxxxxxxxx",
225+
"accept-encoding": "gzip"
226+
},
227+
"Configuration": {
228+
"PATH": "/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
229+
"HOSTNAME": "xxxxxxxxx",
230+
"FN_LISTENER": "unix:/tmp/iofs/lsnr.sock",
231+
"FN_FORMAT": "http-stream",
232+
"FN_APP_ID": "ocid1.fnapp.oc1.phx.xxxxx",
233+
"FN_CPUS": "100m",
234+
"FN_FN_ID": "ocid1.fnfunc.oc1.phx.xxxxx",
235+
"FN_MEMORY": "256",
236+
"FN_TYPE": "sync",
237+
"configkey1": "value1",
238+
"OCI_RESOURCE_PRINCIPAL_RPST": "/.oci-credentials/rpst",
239+
"OCI_RESOURCE_PRINCIPAL_PRIVATE_PEM": "/.oci-credentials/private.pem",
240+
"OCI_RESOURCE_PRINCIPAL_VERSION": "2.2",
241+
"OCI_RESOURCE_PRINCIPAL_REGION": "us-phoenix-1",
242+
"OCI_REGION_METADATA": "{\"realmDomainComponent\":\"oraclecloud.com\",\"realmKey\":\"ocX\",\"regionIdentifier\":\"xx-xxxxx-x\",\"regionKey\":\"XXX\"}",
243+
"LANG": "C.UTF-8",
244+
"GPG_KEY": "xxxxxxxxx",
245+
"PYTHON_VERSION": "3.6.10",
246+
"PYTHON_PIP_VERSION": "20.1.1",
247+
"PYTHON_GET_PIP_URL": "https://github.com/pypa/get-pip/raw/eff16c878c7fd6b688b9b4c4267695cf1a0bf01b/get-pip.py",
248+
"PYTHON_GET_PIP_SHA256": "xxxxxxxxx",
249+
"PYTHONPATH": "/function:/python",
250+
"HOME": "/home/fn"
251+
},
252+
"Request body": {
253+
"key1": "value"
254+
},
255+
"Request URL": "/v1/display-httprequest-info?key1=value1&key2=value2",
256+
"Query String": {
257+
"key1": [
258+
"value1"
259+
],
260+
"key2": [
261+
"value2"
262+
]
263+
},
264+
"Request Method": "POST",
265+
"AppID": "ocid1.fnapp.oc1.phx.xxxxx",
266+
"FnID": "ocid1.fnfunc.oc1.phx.xxxxx",
267+
"CallID": "xxxxxxxxx",
268+
"Format": "http-stream",
269+
"Deadline": "2020-06-23T17:59:10Z"
270+
}
271+
```
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
#
2+
# oci-apigw-display-httprequest-info-python version 1.0.
3+
#
4+
# Copyright (c) 2020 Oracle, Inc.
5+
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
6+
#
7+
8+
import io
9+
import json
10+
import oci
11+
import logging
12+
from urllib.parse import urlparse, parse_qs
13+
14+
from fdk import response
15+
16+
17+
def handler(ctx, data: io.BytesIO=None):
18+
logging.getLogger().info("function handler start")
19+
20+
resp = {}
21+
22+
# retrieving the request headers
23+
headers = ctx.Headers()
24+
logging.getLogger().info("Headers: " + json.dumps(headers))
25+
resp["Headers"] = headers
26+
27+
# retrieving the function configuration
28+
resp["Configuration"] = dict(ctx.Config())
29+
logging.getLogger().info("Configuration: " + json.dumps(resp["Configuration"]))
30+
31+
# retrieving the request body, e.g. {"key1":"value"}
32+
#requestbody_bytes = data.getvalue()
33+
#if requestbody_bytes==b'':
34+
# logging.getLogger().info("No request body")
35+
# requestbody = {}
36+
#else:
37+
# requestbody = json.loads(requestbody_bytes)
38+
# logging.getLogger().info()
39+
try:
40+
requestbody_str = data.getvalue().decode('UTF-8')
41+
if requestbody_str:
42+
resp["Request body"] = json.loads(requestbody_str)
43+
else:
44+
resp["Request body"] = {}
45+
except Exception as ex:
46+
print('ERROR: The request body is not JSON', ex, flush=True)
47+
raise
48+
49+
# retrieving the request URL, e.g. "/v1/display-uri-info"
50+
requesturl = ctx.RequestURL()
51+
logging.getLogger().info("Request URL: " + json.dumps(requesturl))
52+
resp["Request URL"] = requesturl
53+
54+
# retrieving query string from the request URL, e.g. {"param1":["value"]}
55+
parsed_url = urlparse(requesturl)
56+
resp["Query String"] = parse_qs(parsed_url.query)
57+
logging.getLogger().info("Query string: " + json.dumps(resp["Query String"]))
58+
59+
# retrieving the request method, e.g. "POST", "GET"...
60+
method = ctx.Method()
61+
if method:
62+
logging.getLogger().info("Request Method: " + method)
63+
resp["Request Method"] = method
64+
else:
65+
logging.getLogger().info("No Request Method")
66+
resp["Request Method"] = None
67+
68+
# retrieving the Application ID, e.g. "ocid1.fnapp.oc1.phx.aaaaxxxx"
69+
appid = ctx.AppID()
70+
logging.getLogger().info("AppID: " + appid)
71+
resp["AppID"] = appid
72+
73+
# retrieving the Function ID, e.g. "ocid1.fnfunc.oc1.phx.aaaaxxxxx"
74+
fnid = ctx.FnID()
75+
logging.getLogger().info("FnID: " + fnid)
76+
resp["FnID"] = fnid
77+
78+
# retrieving the Function call ID, e.g. "01E9FE6JBW1BT0C68ZJ003KR1Q"
79+
callid = ctx.CallID()
80+
logging.getLogger().info("CallID: " + callid)
81+
resp["CallID"] = callid
82+
83+
# retrieving the Function format, e.g. "http-stream"
84+
fnformat = ctx.Format()
85+
logging.getLogger().info("Format: " + fnformat)
86+
resp["Format"] = fnformat
87+
88+
# retrieving the Function deadline, e.g. "2020-05-29T05:24:46Z"
89+
deadline = ctx.Deadline()
90+
logging.getLogger().info("Deadline: " + deadline)
91+
resp["Deadline"] = deadline
92+
93+
logging.getLogger().info("function handler end")
94+
return response.Response(
95+
ctx,
96+
response_data=json.dumps(resp),
97+
headers={"Content-Type": "application/json"}
98+
)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
schema_version: 20180708
2+
name: oci-apigw-display-httprequest-info-python
3+
version: 0.0.8
4+
runtime: python
5+
entrypoint: /python/bin/fdk /function/func.py handler
6+
memory: 256
Loading
Loading
Loading
Loading
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
fdk
2+
oci

0 commit comments

Comments
 (0)