Skip to content

Commit 19e55cd

Browse files
authored
Merge pull request #7 from ddevadat/dotnet-samples
added copy object dotnet function
2 parents 6d68d86 + d860a79 commit 19e55cd

File tree

13 files changed

+375
-1
lines changed

13 files changed

+375
-1
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +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)|[sample](./samples/oci-objectstorage-get-object-dotnet)|
2424
| Create an object in OCI Object Storage |[sample](./samples/oci-objectstorage-put-object-python)|[sample](./samples/oci-objectstorage-put-object-java)|[sample](./samples/oci-objectstorage-put-object-dotnet)|
2525
| Create a PAR in OCI Object Storage |[sample](./samples/oci-objectstorage-create-par-python)||[sample](./samples/oci-objectstorage-create-par-dotnet)|
26-
| Copy object from one OCI Object Storage bucket to another |[sample](./samples/oci-objectstorage-copy-objects-python)||
26+
| Copy object from one OCI Object Storage bucket to another |[sample](./samples/oci-objectstorage-copy-objects-python)||[sample](./samples/oci-objectstorage-copy-objects-dotnet)|
2727
| Display an OCI Cloud Event |[sample](./samples/oci-event-display-python)|
2828
| Invoke another Function using the OCI SDK |[sample](./samples/oci-invoke-function-python)|||
2929
| Run a SQL statement against Autonomous DB using ORDS | [sample](./samples/oci-adb-ords-runsql-python) |
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
2+
using System;
3+
using System.Threading.Tasks;
4+
using System.Text;
5+
6+
using Oci.Common;
7+
using Oci.Common.Auth;
8+
using Oci.ObjectstorageService;
9+
10+
11+
namespace CopyObjects
12+
{
13+
public class ObjectStorageClientHelper
14+
{
15+
public static ObjectStorageClient GetObjectStorageClient()
16+
{
17+
try
18+
{
19+
return new ObjectStorageClient(ResourcePrincipalAuthenticationDetailsProvider.GetProvider(), new ClientConfiguration());
20+
}
21+
catch (Exception ex)
22+
{
23+
Console.WriteLine("Unable To Create Resource Principal Provider: {0}", ex.Message);
24+
Console.WriteLine("Defaulting to Instance Provider");
25+
return new ObjectStorageClient(new InstancePrincipalsAuthenticationDetailsProvider(), new ClientConfiguration());
26+
}
27+
}
28+
29+
}
30+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
2+
using System;
3+
using System.Threading.Tasks;
4+
using System.Text;
5+
using System.Collections.Generic;
6+
using System.IO;
7+
using Oci.Common.Model;
8+
using Oci.Common;
9+
using Oci.Common.Auth;
10+
using Oci.ObjectstorageService;
11+
using Oci.ObjectstorageService.Models;
12+
using Oci.ObjectstorageService.Requests;
13+
using Oci.ObjectstorageService.Responses;
14+
15+
16+
namespace CopyObjects
17+
{
18+
public class CopyObjectsHelper
19+
{
20+
public static async Task<string> CopyObject(ObjectStorageClient client, string src_bucketName, string dest_bucketName, string namespaceName, string objectName)
21+
22+
{
23+
24+
try
25+
{
26+
27+
var copyObjectDetails = new Oci.ObjectstorageService.Models.CopyObjectDetails
28+
{
29+
DestinationBucket = dest_bucketName,
30+
DestinationNamespace = namespaceName,
31+
SourceObjectName = objectName,
32+
DestinationObjectName = objectName,
33+
DestinationRegion = Environment.GetEnvironmentVariable("REGION"),
34+
};
35+
36+
var copyObjectRequest = new Oci.ObjectstorageService.Requests.CopyObjectRequest
37+
{
38+
NamespaceName = namespaceName,
39+
BucketName = src_bucketName,
40+
CopyObjectDetails = copyObjectDetails,
41+
};
42+
43+
var response = await client.CopyObject(copyObjectRequest);
44+
var opcWorkRequestIdValue = response.OpcWorkRequestId;
45+
46+
return opcWorkRequestIdValue;
47+
48+
}
49+
50+
catch (OciException ex)
51+
{
52+
Console.WriteLine("Unable To Put Object : {0}", ex.Message);
53+
return "Failed " + ex.Message;
54+
}
55+
56+
}
57+
58+
59+
}
60+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
using Fnproject.Fn.Fdk;
2+
using System.Runtime.CompilerServices;
3+
using System.Collections.Generic;
4+
using System;
5+
using System.Text;
6+
using System.Text.Json;
7+
using System.Threading.Tasks;
8+
using Newtonsoft.Json;
9+
using Oci.ObjectstorageService;
10+
using Oci.ObjectstorageService.Models;
11+
12+
namespace CopyObjects
13+
{
14+
class Function
15+
{
16+
public string function_handler(String input)
17+
{
18+
19+
Dictionary<string, List<ObjectDetails>> output = new Dictionary<string, List<ObjectDetails>>();
20+
var object_details_list = new List<ObjectDetails>();
21+
22+
dynamic event_json = JsonConvert.DeserializeObject(input);
23+
24+
string src_bucketName = event_json.data.additionalDetails["bucketName"];
25+
string dest_bucketName = event_json.data.additionalDetails["bucketName"] + "_IMMUTABLE";
26+
string namespaceName = event_json.data.additionalDetails["namespace"];
27+
string objectName = event_json.data.resourceName;
28+
29+
ObjectStorageClient client = ObjectStorageClientHelper.GetObjectStorageClient();
30+
Task<string> object_str = CopyObjectsHelper.CopyObject(client, src_bucketName, dest_bucketName, namespaceName, objectName);
31+
var object_detail = new ObjectDetails();
32+
object_detail.result = object_str.Result;
33+
object_details_list.Add(object_detail);
34+
35+
output.Add("results", object_details_list);
36+
return System.Text.Json.JsonSerializer.Serialize(output);
37+
38+
}
39+
40+
static void Main(string[] args) { Fdk.Handle(args[0]); }
41+
42+
}
43+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>netcoreapp3.1</TargetFramework>
6+
</PropertyGroup>
7+
8+
<ItemGroup>
9+
<PackageReference Include="Fnproject.Fn.Fdk" Version="1.0.4" />
10+
</ItemGroup>
11+
12+
<ItemGroup>
13+
<PackageReference Include="OCI.DotNetSDK.Common" Version="42.1.0" />
14+
<PackageReference Include="OCI.DotNetSDK.Objectstorage" Version="42.1.0" />
15+
<PackageReference Include="Newtonsoft.Json" Version="13.0.2-beta1" />
16+
</ItemGroup>
17+
18+
</Project>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
FROM fnproject/dotnet:3.1-1.0.4-dev as build-stage
2+
WORKDIR /function
3+
COPY . .
4+
RUN dotnet sln add CopyObjects.csproj
5+
RUN dotnet build CopyObjects.csproj -c Release
6+
RUN dotnet publish CopyObjects.csproj -c Release -o out
7+
FROM fnproject/dotnet:3.1-1.0.4
8+
WORKDIR /function
9+
COPY --from=build-stage /function/out/ /function/
10+
ENTRYPOINT ["dotnet", "CopyObjects.dll"]
11+
CMD ["CopyObjects:Function:function_handler"]
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
Microsoft Visual Studio Solution File, Format Version 12.00
2+
# Visual Studio 15
3+
VisualStudioVersion = 15.0.26124.0
4+
MinimumVisualStudioVersion = 15.0.26124.0
5+
Global
6+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
7+
Debug|Any CPU = Debug|Any CPU
8+
Debug|x64 = Debug|x64
9+
Debug|x86 = Debug|x86
10+
Release|Any CPU = Release|Any CPU
11+
Release|x64 = Release|x64
12+
Release|x86 = Release|x86
13+
EndGlobalSection
14+
GlobalSection(SolutionProperties) = preSolution
15+
HideSolutionNode = FALSE
16+
EndGlobalSection
17+
EndGlobal
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using System;
2+
3+
namespace CopyObjects
4+
{
5+
6+
class InputMessage
7+
{
8+
public string objectName { get; set; }
9+
public string bucketName { get; set; }
10+
public string namespaceName { get; set; }
11+
12+
public string content { get; set; }
13+
14+
}
15+
16+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using System;
2+
3+
namespace CopyObjects
4+
{
5+
6+
class ObjectDetails
7+
{
8+
9+
public string result { get; set; }
10+
11+
12+
}
13+
14+
}
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
# Function that copies an object in an OCI Object Storage bucket to another bucket using the OCI Dotnet 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+
This function uses Resource Principals to securely authorize a function to make
6+
API calls to OCI services using the [OCI Dotnet SDK](https://docs.oracle.com/en-us/iaas/tools/dotnet/latest/api/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 Dotnet SDK classes:
11+
* [Resource Principals](https://docs.oracle.com/en-us/iaas/tools/dotnet/latest/api/Oci.Common.Auth.ResourcePrincipalAuthenticationDetailsProvider.html) to authenticate
12+
* [Object Storage Client](https://docs.oracle.com/en-us/iaas/tools/dotnet/latest/api/Oci.ObjectstorageService.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+
- [CopyObjects.csproj](./CopyObjects.csproj) specifies all the dependencies for your function
81+
- [func.yaml](./func.yaml) that contains metadata about your function and declares properties
82+
- [CopyObjects.cs](./CopyObjects.cs) which is your actual Python function
83+
84+
The name of your function *oci-objectstorage-copy-objects-dotnet* 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+
## Set the function configuration values
104+
The function requires the config value *REGION* to be set.
105+
106+
![user input icon](./images/userinput.png)
107+
108+
Use the *fn* CLI to set the config value:
109+
```
110+
fn config function <app-name> <function-name> REGION <region>
111+
```
112+
e.g.
113+
```
114+
fn config function myapp oci-objectstorage-create-par-dotnet REGION 'eu-frankfurt-1'
115+
```
116+
117+
## Create Object Store Buckets
118+
119+
![user input icon](./images/userinput.png)
120+
121+
From the OCI Console > Storage > Object Storage > Create Bucket with bucket name = "TEST" and enable "Emit Object Events"
122+
123+
From the OCI Console > Storage > Object Storage > Create Bucket with bucket name = "TEST_IMMUTABLE" and apply a retention policy
124+
125+
## Create an Event Rule on Bucket
126+
127+
![user input icon](./images/userinput.png)
128+
129+
From the OCI Console > Observability & Management > Event Service > Create Rule:
130+
131+
Display Name: IMMUTABLE-OBJECT_STORE
132+
Rule Conditions:
133+
Event Type: Object Storage: Object - Create; Object - Update
134+
Attribute: bucketName: TEST
135+
Actions (<app-name> as per the `fn -v deploy --app <app-name>`) :
136+
Function: (root): <app-name>
137+
138+
![event](./images/create_rule.png)
139+
140+
## Test
141+
142+
![user input icon](./images/userinput.png)
143+
144+
From the OCI Console > Storage > Object Storage > TEST
145+
146+
Objects -> Upload; Drop file to upload
147+
148+
From the OCI Console > Storage > Object Storage > TEST_IMMUTABLE
149+
150+
__The file uploaded to the TEST bucket should now be present in the TEST_IMMUTABLE bucket.__
151+
152+
153+
## Monitoring Functions
154+
155+
Learn how to configure basic observability for your function using metrics, alarms and email alerts:
156+
* [Basic Guidance for Monitoring your Functions](../basic-observability/functions.md)
157+
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-dotnet
3+
version: 0.0.84
4+
runtime: dotnet3.1
5+
build_image: fnproject/dotnet:3.1-1.0.4-dev
6+
run_image: fnproject/dotnet:3.1-1.0.4
7+
cmd: CopyObjects:Function:function_handler
8+
entrypoint: dotnet CopyObjects.dll
Loading
Loading

0 commit comments

Comments
 (0)