diff --git a/README.md b/README.md index 742c4e1..c9295e9 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ This repository provides examples demonstrating how to use Oracle Functions. | List objects in OCI Object Storage |[sample](./samples/oci-objectstorage-list-objects-python)|[sample](./samples/oci-objectstorage-list-objects-java)|[sample](./samples/oci-objectstorage-list-objects-dotnet)| | 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)| | 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)| -| Create a PAR in OCI Object Storage |[sample](./samples/oci-objectstorage-create-par-python)|| +| Create a PAR in OCI Object Storage |[sample](./samples/oci-objectstorage-create-par-python)||[sample](./samples/oci-objectstorage-create-par-dotnet)| | Copy object from one OCI Object Storage bucket to another |[sample](./samples/oci-objectstorage-copy-objects-python)|| | Display an OCI Cloud Event |[sample](./samples/oci-event-display-python)| | Invoke another Function using the OCI SDK |[sample](./samples/oci-invoke-function-python)||| diff --git a/samples/oci-objectstorage-create-par-dotnet/Common/ObjectStorageClient.cs b/samples/oci-objectstorage-create-par-dotnet/Common/ObjectStorageClient.cs new file mode 100644 index 0000000..0beeed9 --- /dev/null +++ b/samples/oci-objectstorage-create-par-dotnet/Common/ObjectStorageClient.cs @@ -0,0 +1,30 @@ + +using System; +using System.Threading.Tasks; +using System.Text; + +using Oci.Common; +using Oci.Common.Auth; +using Oci.ObjectstorageService; + + +namespace CreatePAR +{ + public class ObjectStorageClientHelper + { + public static ObjectStorageClient GetObjectStorageClient() + { + try + { + return new ObjectStorageClient(ResourcePrincipalAuthenticationDetailsProvider.GetProvider(), new ClientConfiguration()); + } + catch (Exception ex) + { + Console.WriteLine("Unable To Create Resource Principal Provider: {0}", ex.Message); + Console.WriteLine("Defaulting to Instance Provider"); + return new ObjectStorageClient(new InstancePrincipalsAuthenticationDetailsProvider(), new ClientConfiguration()); + } + } + + } +} diff --git a/samples/oci-objectstorage-create-par-dotnet/Controller/CreatePARHelper.cs b/samples/oci-objectstorage-create-par-dotnet/Controller/CreatePARHelper.cs new file mode 100644 index 0000000..2acd09e --- /dev/null +++ b/samples/oci-objectstorage-create-par-dotnet/Controller/CreatePARHelper.cs @@ -0,0 +1,60 @@ + +using System; +using System.Threading.Tasks; +using System.Text; +using System.Collections.Generic; +using System.IO; +using Oci.Common.Model; +using Oci.Common; +using Oci.Common.Auth; +using Oci.ObjectstorageService; +using Oci.ObjectstorageService.Models; +using Oci.ObjectstorageService.Requests; +using Oci.ObjectstorageService.Responses; + + +namespace CreatePAR +{ + public class CreatePARHelper + { + + public static async Task CreatePAR(ObjectStorageClient client, string bucketName, string namespaceName, string parName, int lifetime, string region) + + { + + try + { + DateTime currentTime = DateTime.Now; + DateTime parexpiry = currentTime.AddMinutes(lifetime); + string object_storage_endpoint = "https://objectstorage." + region + ".oraclecloud.com"; + var createPreauthenticatedRequestDetails = new Oci.ObjectstorageService.Models.CreatePreauthenticatedRequestDetails + { + Name = parName, + BucketListingAction = Oci.ObjectstorageService.Models.PreauthenticatedRequest.BucketListingActionEnum.ListObjects, + AccessType = Oci.ObjectstorageService.Models.CreatePreauthenticatedRequestDetails.AccessTypeEnum.AnyObjectWrite, + TimeExpires = parexpiry + }; + var createPreauthenticatedRequestRequest = new Oci.ObjectstorageService.Requests.CreatePreauthenticatedRequestRequest + { + NamespaceName = namespaceName, + BucketName = bucketName, + CreatePreauthenticatedRequestDetails = createPreauthenticatedRequestDetails, + }; + + var response = await client.CreatePreauthenticatedRequest(createPreauthenticatedRequestRequest); + return object_storage_endpoint + response.PreauthenticatedRequest.AccessUri; + + + } + + catch (OciException ex) + { + Console.WriteLine("Unable To Put Object : {0}", ex.Message); + return "Failed " + ex.Message; + } + + } + + + } +} diff --git a/samples/oci-objectstorage-create-par-dotnet/CreatePAR.cs b/samples/oci-objectstorage-create-par-dotnet/CreatePAR.cs new file mode 100644 index 0000000..c9bf4eb --- /dev/null +++ b/samples/oci-objectstorage-create-par-dotnet/CreatePAR.cs @@ -0,0 +1,41 @@ +using Fnproject.Fn.Fdk; +using System.Runtime.CompilerServices; +using System.Collections.Generic; +using System; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; +using Oci.ObjectstorageService; +using Oci.ObjectstorageService.Models; + +namespace CreatePAR +{ + class Function + { + public string function_handler(InputMessage input) + { + + Dictionary> output = new Dictionary>(); + var object_details_list = new List(); + string parName = input.PARName; + string bucketName = Environment.GetEnvironmentVariable("BUCKET_NAME"); + string namespaceName = Environment.GetEnvironmentVariable("NAMESPACE"); + int lifetime = Int32.Parse(Environment.GetEnvironmentVariable("LIFETIME")); + string region = Environment.GetEnvironmentVariable("REGION"); + ObjectStorageClient client = ObjectStorageClientHelper.GetObjectStorageClient(); + Task object_str = CreatePARHelper.CreatePAR(client, bucketName, namespaceName, parName, lifetime, region); + var object_detail = new ObjectDetails(); + object_detail.parname = parName; + object_detail.bucketname = bucketName; + object_detail.parurl = object_str.Result; + object_details_list.Add(object_detail); + + output.Add("results", object_details_list); + return JsonSerializer.Serialize(output); + + } + + static void Main(string[] args) { Fdk.Handle(args[0]); } + + } +} diff --git a/samples/oci-objectstorage-create-par-dotnet/CreatePAR.csproj b/samples/oci-objectstorage-create-par-dotnet/CreatePAR.csproj new file mode 100644 index 0000000..84b6070 --- /dev/null +++ b/samples/oci-objectstorage-create-par-dotnet/CreatePAR.csproj @@ -0,0 +1,17 @@ + + + + Exe + netcoreapp3.1 + + + + + + + + + + + + diff --git a/samples/oci-objectstorage-create-par-dotnet/Dockerfile b/samples/oci-objectstorage-create-par-dotnet/Dockerfile new file mode 100644 index 0000000..9e25431 --- /dev/null +++ b/samples/oci-objectstorage-create-par-dotnet/Dockerfile @@ -0,0 +1,11 @@ +FROM fnproject/dotnet:3.1-1.0.4-dev as build-stage +WORKDIR /function +COPY . . +RUN dotnet sln add CreatePAR.csproj +RUN dotnet build CreatePAR.csproj -c Release +RUN dotnet publish CreatePAR.csproj -c Release -o out +FROM fnproject/dotnet:3.1-1.0.4 +WORKDIR /function +COPY --from=build-stage /function/out/ /function/ +ENTRYPOINT ["dotnet", "CreatePAR.dll"] +CMD ["CreatePAR:Function:function_handler"] \ No newline at end of file diff --git a/samples/oci-objectstorage-create-par-dotnet/Function.sln b/samples/oci-objectstorage-create-par-dotnet/Function.sln new file mode 100644 index 0000000..f87916a --- /dev/null +++ b/samples/oci-objectstorage-create-par-dotnet/Function.sln @@ -0,0 +1,17 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26124.0 +MinimumVisualStudioVersion = 15.0.26124.0 +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/samples/oci-objectstorage-create-par-dotnet/Models/InputMessage.cs b/samples/oci-objectstorage-create-par-dotnet/Models/InputMessage.cs new file mode 100644 index 0000000..14f0668 --- /dev/null +++ b/samples/oci-objectstorage-create-par-dotnet/Models/InputMessage.cs @@ -0,0 +1,12 @@ +using System; + +namespace CreatePAR +{ + + class InputMessage + { + public string PARName { get; set; } + + } + +} diff --git a/samples/oci-objectstorage-create-par-dotnet/Models/ObjectDetails.cs b/samples/oci-objectstorage-create-par-dotnet/Models/ObjectDetails.cs new file mode 100644 index 0000000..51663bd --- /dev/null +++ b/samples/oci-objectstorage-create-par-dotnet/Models/ObjectDetails.cs @@ -0,0 +1,16 @@ +using System; + +namespace CreatePAR +{ + + class ObjectDetails + { + public string parname { get; set; } + + public string bucketname { get; set; } + public string parurl { get; set; } + + + } + +} diff --git a/samples/oci-objectstorage-create-par-dotnet/README.md b/samples/oci-objectstorage-create-par-dotnet/README.md new file mode 100644 index 0000000..05acd1f --- /dev/null +++ b/samples/oci-objectstorage-create-par-dotnet/README.md @@ -0,0 +1,103 @@ +# Function that creates a PAR +This function creates a PAR (Pre-Authenticated Request) for a bucket in Object Storage. + +As you make your way through this tutorial, look out for this icon ![user input icon](./images/userinput.png). +Whenever you see it, it's time for you to perform an action. + + +## Prerequisites +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) +* A - Set up your tenancy +* B - Create application +* C - Set up your Cloud Shell dev environment + + +## List Applications +Assuming your have successfully completed the prerequisites, you should see your +application in the list of applications. +``` +fn ls apps +``` + + +## Create or Update your Dynamic Group +In order to use other OCI Services, your function must be part of a dynamic group. For information on how to create a dynamic group, refer to the [documentation](https://docs.cloud.oracle.com/iaas/Content/Identity/Tasks/managingdynamicgroups.htm#To). + +When specifying the *Matching Rules*, we suggest matching all functions in a compartment with: +``` +ALL {resource.type = 'fnfunc', resource.compartment.id = 'ocid1.compartment.oc1..aaaaaxxxxx'} +``` +Please check the [Accessing Other Oracle Cloud Infrastructure Resources from Running Functions](https://docs.cloud.oracle.com/en-us/iaas/Content/Functions/Tasks/functionsaccessingociresources.htm) for other *Matching Rules* options. + + +## Create or Update IAM Policies +Create a new policy that allows the dynamic group to manage compute instances. We will grant `manage` access to a specific `bucket` and `objects` in that bucket for a given compartment. + +![user input icon](./images/userinput.png) + +Your policy should look something like this: +``` +Allow dynamic-group to manage buckets in compartment where target.bucket.name= +Allow dynamic-group to manage objects in compartment where target.bucket.name= +``` +For more information on how to create policies, go [here](https://docs.cloud.oracle.com/iaas/Content/Identity/Concepts/policysyntax.htm). + + +## Review and customize your function +Review the following files in the current folder: +* the code of the function, [CreatePAR.cs](./CreatePAR.cs) +* its dependencies, [CreatePAR.proj](./CreatePAR.proj) +* the function metadata, [func.yaml](./func.yaml) + + +## Deploy the function +In Cloud Shell, run the *fn deploy* command to build the function and its dependencies as a Docker image, +push the image to OCIR, and deploy the function to Oracle Functions in your application. + +![user input icon](./images/userinput.png) +``` +fn -v deploy --app +``` + + +## Set the function configuration values +The function requires the config value *bucket-name* and *lifetime* to be set. + +![user input icon](./images/userinput.png) + +Use the *fn* CLI to set the config value: +``` +fn config function BUCKET_NAME +fn config function NAMESPACE +fn config function LIFETIME +fn config function REGION +``` +e.g. +``` +fn config function myapp oci-objectstorage-create-par-dotnet BUCKET_NAME 'my-bucket' +fn config function myapp oci-objectstorage-create-par-dotnet NAMESPACE 'samplenamespace' +fn config function myapp oci-objectstorage-create-par-dotnet LIFETIME '30' +fn config function myapp oci-objectstorage-create-par-dotnet REGION 'ap-osaka-1' +``` + +## Invoke the function +The function requires the name of the PAR in the payload to be invoked. + +![user input icon](./images/userinput.png) +``` + +echo '{"PAR name": }' | fn invoke oci-objectstorage-create-par-dotnet +``` +e.g.: +``` +echo '{"PAR name": "myPAR" }' | fn invoke myapp oci-objectstorage-create-par-dotnet +``` + +Upon success, the function returns the PAR URL. + + +## Monitoring Functions + +Learn how to configure basic observability for your function using metrics, alarms and email alerts: +* [Basic Guidance for Monitoring your Functions](../basic-observability/functions.md) + diff --git a/samples/oci-objectstorage-create-par-dotnet/func.yaml b/samples/oci-objectstorage-create-par-dotnet/func.yaml new file mode 100644 index 0000000..fe298ea --- /dev/null +++ b/samples/oci-objectstorage-create-par-dotnet/func.yaml @@ -0,0 +1,8 @@ +schema_version: 20180708 +name: oci-objectstorage-create-par-dotnet +version: 0.0.79 +runtime: dotnet3.1 +build_image: fnproject/dotnet:3.1-1.0.4-dev +run_image: fnproject/dotnet:3.1-1.0.4 +cmd: CreatePAR:Function:function_handler +entrypoint: dotnet CreatePAR.dll diff --git a/samples/oci-objectstorage-create-par-dotnet/images/userinput.png b/samples/oci-objectstorage-create-par-dotnet/images/userinput.png new file mode 100644 index 0000000..ce6a202 Binary files /dev/null and b/samples/oci-objectstorage-create-par-dotnet/images/userinput.png differ