Skip to content

Commit 29c490a

Browse files
authored
Merge pull request oracle-samples#42 from gotsysdba/master
Sample fn to copy objects from one bucket to another
2 parents a8038e7 + 25f467b commit 29c490a

File tree

7 files changed

+211
-0
lines changed

7 files changed

+211
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ This repository provides examples demonstrating how to use Oracle Functions.
2323
| Read an object in OCI Object Storage |[sample](./samples/oci-objectstorage-get-object-python)|[sample](./samples/oci-objectstorage-get-object-java)|
2424
| Create an object in OCI Object Storage |[sample](./samples/oci-objectstorage-put-object-python)|[sample](./samples/oci-objectstorage-put-object-java)|
2525
| Create a PAR in OCI Object Storage |[sample](./samples/oci-objectstorage-create-par-python)||
26+
| Copy object from one OCI Object Storage bucket to another |[sample](./samples/oci-objectstorage-copy-objects-python)||
2627
| Display an OCI Cloud Event |[sample](./samples/oci-event-display-python)|
2728
| Invoke another Function using the OCI SDK |[sample](./samples/oci-invoke-function-python)|||
2829
| Run a SQL statement against Autonomous DB using ORDS | [sample](./samples/oci-adb-ords-runsql-python) |
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
# Function that copies an object in an OCI Object Storage bucket to another bucket using the OCI Python SDK
2+
This function can be used to create *"Immutable Copies"* of objects in an OCI bucket by copying them, during creation/update, to another bucket with defined retention policies. This is especially useful when using the [Oracle Backup Cloud Service](https://docs.oracle.com/en/cloud/paas/db-backup-cloud/csdbb/oracle-database-backup-cloud-service.html) to ensure backups are maintained for a specified amount of time.
3+
4+
5+
The function uses Resource Principals to securely authorize a function to make
6+
API calls to OCI services using the [OCI Python SDK](https://oracle-cloud-infrastructure-python-sdk.readthedocs.io/en/latest/index.html).
7+
It creates an object in a bucket in Object Storage and returns a message with a status.
8+
9+
10+
The function calls the following OCI Python SDK classes:
11+
* [Resource Principals Signer](https://oracle-cloud-infrastructure-python-sdk.readthedocs.io/en/latest/api/signing.html#resource-principals-signer) to authenticate
12+
* [Object Storage Client](https://oracle-cloud-infrastructure-python-sdk.readthedocs.io/en/latest/api/object_storage/client/oci.object_storage.ObjectStorageClient.html) to interact with Object Storage
13+
14+
As you make your way through this tutorial, look out for this icon ![user input icon](./images/userinput.png).
15+
Whenever you see it, it's time for you to perform an action.
16+
17+
18+
## Prerequisites
19+
20+
1. Before you deploy this sample function, make sure you have run steps A, B
21+
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)
22+
* A - Set up your tenancy
23+
* B - Create application
24+
* C - Set up your Cloud Shell dev environment
25+
26+
2. Have your Oracle Object Storage Namespace available. This can be found by
27+
logging into your [cloud account](https://console.us-ashburn-1.oraclecloud.com/),
28+
under your user profile, click on your Tenancy. Your Object Storage Namespace
29+
is shown there.
30+
31+
32+
## List Applications
33+
34+
Assuming you have successfully completed the prerequisites, you should see your
35+
application in the list of applications.
36+
37+
```
38+
fn ls apps
39+
```
40+
41+
42+
## Create or Update your Dynamic Group
43+
44+
In order to use other OCI Services, your function must be part of a dynamic
45+
group. For information on how to create a dynamic group, refer to the
46+
[documentation](https://docs.cloud.oracle.com/iaas/Content/Identity/Tasks/managingdynamicgroups.htm#To).
47+
48+
When specifying the *Matching Rules*, we suggest matching all functions in a compartment with:
49+
50+
```
51+
ALL {resource.type = 'fnfunc', resource.compartment.id = 'ocid1.compartment.oc1..aaaaaxxxxx'}
52+
```
53+
54+
55+
## Create or Update IAM Policies
56+
57+
Create a new policy that allows the dynamic group to `manage objects` and `manage buckets` in the functions related compartment.
58+
59+
![user input icon](./images/userinput.png)
60+
61+
Your policy should look something like this:
62+
```
63+
Allow service objectstorage-<region> to manage object-family in compartment <compartment-name>
64+
Allow dynamic-group <dynamic-group-name> to manage objects in compartment <compartment-name>
65+
Allow dynamic-group <dynamic-group-name> to manage buckets in compartment <compartment-name>
66+
```
67+
e.g.
68+
```
69+
Allow service objectstorage-eu-frankfurt-1 to manage object-family in compartment demo-func-compartment
70+
Allow dynamic-group demo-func-dyn-group to manage objects in compartment demo-func-compartment
71+
Allow dynamic-group demo-func-dyn-group to manage buckets in compartment demo-func-compartment
72+
```
73+
For more information on how to create policies, go [here](https://docs.cloud.oracle.com/iaas/Content/Identity/Concepts/policysyntax.htm).
74+
75+
76+
## Review and customize the function
77+
78+
Review the following files in the current folder:
79+
80+
- [requirements.txt](./requirements.txt) specifies all the dependencies for your function
81+
- [func.yaml](./func.yaml) that contains metadata about your function and declares properties
82+
- [func.py](./func.py) which is your actual Python function
83+
84+
The name of your function *oci-objectstorage-copy-objects-python* is specified in [func.yaml](./func.yaml).
85+
86+
87+
## Deploy the function
88+
89+
In Cloud Shell, run the `fn deploy` command to build the function and its dependencies as a Docker image,
90+
push the image to the specified Docker registry, and deploy the function to Oracle Functions
91+
in the application created earlier:
92+
93+
![user input icon](./images/userinput.png)
94+
95+
```
96+
fn -v deploy --app <app-name>
97+
```
98+
e.g.
99+
```
100+
fn -v deploy --app myapp
101+
```
102+
103+
## Create Object Store Buckets
104+
105+
![user input icon](./images/userinput.png)
106+
107+
From the OCI Console > Storage > Object Storage > Create Bucket with bucket name = "TEST" and enable "Emit Object Events"
108+
109+
From the OCI Console > Storage > Object Storage > Create Bucket with bucket name = "TEST_IMMUTABLE" and apply a retention policy
110+
111+
## Create an Event Rule on Bucket
112+
113+
![user input icon](./images/userinput.png)
114+
115+
From the OCI Console > Observability & Management > Event Service > Create Rule:
116+
117+
Display Name: IMMUTABLE-OBJECT_STORE
118+
Rule Conditions:
119+
Event Type: Object Storage: Object - Create; Object - Update
120+
Attribute: bucketName: TEST
121+
Actions (<app-name> as per the `fn -v deploy --app <app-name>`) :
122+
Function: (root): <app-name>
123+
124+
![event](./images/create_rule.png)
125+
126+
## Test
127+
128+
![user input icon](./images/userinput.png)
129+
130+
From the OCI Console > Storage > Object Storage > TEST
131+
132+
Objects -> Upload; Drop file to upload
133+
134+
From the OCI Console > Storage > Object Storage > TEST_IMMUTABLE
135+
136+
__The file uploaded to the TEST bucket should now be present in the TEST_IMMUTABLE bucket.__
137+
138+
139+
## Monitoring Functions
140+
141+
Learn how to configure basic observability for your function using metrics, alarms and email alerts:
142+
* [Basic Guidance for Monitoring your Functions](../basic-observability/functions.md)
143+
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#
2+
# oci-objectstorage-copy-objects-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+
import io
8+
import json
9+
import logging
10+
11+
import oci.object_storage
12+
from fdk import response
13+
14+
def copy_object(signer, namespace, src_bucket, dst_bucket, object_name):
15+
try:
16+
objstore = oci.object_storage.ObjectStorageClient(config={}, signer=signer)
17+
objstore_composite_ops = oci.object_storage.ObjectStorageClientCompositeOperations(objstore)
18+
resp = objstore_composite_ops.copy_object_and_wait_for_state(
19+
namespace,
20+
src_bucket,
21+
oci.object_storage.models.CopyObjectDetails(
22+
destination_bucket=dst_bucket,
23+
destination_namespace=namespace,
24+
destination_object_name=object_name,
25+
destination_region=signer.region,
26+
source_object_name=object_name
27+
)
28+
)
29+
except (Exception, ValueError) as ex:
30+
logging.getLogger().error(str(ex))
31+
return {"response": str(ex)}
32+
33+
return {"response": str(response)}
34+
35+
36+
def handler(ctx, data: io.BytesIO=None):
37+
signer = oci.auth.signers.get_resource_principals_signer()
38+
resp = ""
39+
try:
40+
body = json.loads(data.getvalue())
41+
#logging.getLogger().info(json.dumps(body))
42+
namespace = body["data"]["additionalDetails"]["namespace"]
43+
src_bucket = body["data"]["additionalDetails"]["bucketName"]
44+
object_name = body["data"]["resourceName"]
45+
dst_bucket = body["data"]["additionalDetails"]["bucketName"]+"_IMMUTABLE"
46+
47+
logging.getLogger().info(f'Copying {object_name} from {src_bucket} to {dst_bucket}')
48+
49+
resp = copy_object(signer, namespace, src_bucket, dst_bucket, object_name)
50+
except (Exception, ValueError) as ex:
51+
logging.getLogger().error(str(ex))
52+
53+
return response.Response(
54+
ctx,
55+
response_data=json.dumps(resp),
56+
headers={"Content-Type": "application/json"}
57+
)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
schema_version: 20180708
2+
name: oci-objectstorage-copy-objects-python
3+
version: 0.0.1
4+
runtime: python
5+
build_image: fnproject/python:3.8-dev
6+
run_image: fnproject/python:3.8
7+
entrypoint: /python/bin/fdk /function/func.py handler
8+
memory: 256
Loading
Loading
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
fdk>=0.1.40
2+
oci>=2.49.1

0 commit comments

Comments
 (0)