From a5e8b800e161e64bf56f7855e44da833fc13d551 Mon Sep 17 00:00:00 2001 From: Deepak Devadathan Date: Mon, 12 Sep 2022 00:35:21 +0000 Subject: [PATCH 1/6] Added compute control dotnet function Signed-off-by: Deepak Devadathan --- .../Common/ComputeClient.cs | 29 ++++++ .../ControlInstance.cs | 56 +++++++++++ .../ControlInstance.csproj | 18 ++++ .../Controller/ComputeController.cs | 94 +++++++++++++++++++ samples/oci-compute-control-dotnet/Dockerfile | 11 +++ .../oci-compute-control-dotnet/Function.sln | 17 ++++ .../Models/InputMessage.cs | 14 +++ samples/oci-compute-control-dotnet/func.yaml | 8 ++ 8 files changed, 247 insertions(+) create mode 100644 samples/oci-compute-control-dotnet/Common/ComputeClient.cs create mode 100644 samples/oci-compute-control-dotnet/ControlInstance.cs create mode 100644 samples/oci-compute-control-dotnet/ControlInstance.csproj create mode 100644 samples/oci-compute-control-dotnet/Controller/ComputeController.cs create mode 100644 samples/oci-compute-control-dotnet/Dockerfile create mode 100644 samples/oci-compute-control-dotnet/Function.sln create mode 100644 samples/oci-compute-control-dotnet/Models/InputMessage.cs create mode 100644 samples/oci-compute-control-dotnet/func.yaml diff --git a/samples/oci-compute-control-dotnet/Common/ComputeClient.cs b/samples/oci-compute-control-dotnet/Common/ComputeClient.cs new file mode 100644 index 0000000..29d99e6 --- /dev/null +++ b/samples/oci-compute-control-dotnet/Common/ComputeClient.cs @@ -0,0 +1,29 @@ + +using System; +using System.Threading.Tasks; +using System.Text; + +using Oci.Common; +using Oci.Common.Auth; +using Oci.CoreService; + + +namespace ControlInstance +{ + public class ComputeClientHelper + { + public static ComputeClient GetComputeClient() + { + try{ + + return new ComputeClient(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 ComputeClient(new InstancePrincipalsAuthenticationDetailsProvider(), new ClientConfiguration()); + } + } + + } +} diff --git a/samples/oci-compute-control-dotnet/ControlInstance.cs b/samples/oci-compute-control-dotnet/ControlInstance.cs new file mode 100644 index 0000000..550b4ad --- /dev/null +++ b/samples/oci-compute-control-dotnet/ControlInstance.cs @@ -0,0 +1,56 @@ +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.CoreService; + +namespace ControlInstance +{ + class Function + { + public string function_handler(InputMessage input) + { + string command; + string instance_ocid; + Dictionary output = new Dictionary(); + try{ + command=input.command.ToLower(); + instance_ocid=input.instance_ocid; + ComputeClient client = ComputeClientHelper.GetComputeClient(); + if (command=="status") + { + Task instance_state = ComputeController.GetComputeStatus(client,instance_ocid); + output.Add("result", instance_state.Result); + } + else if (command=="start") + { + Task instance_state = ComputeController.StartCompute(client,instance_ocid); + output.Add("result", instance_state.Result); + } + else if (command=="stop") + { + Task instance_state = ComputeController.StopCompute(client,instance_ocid); + output.Add("result", instance_state.Result); + } + else + { + output.Add("result", "Invalid Command"); + } + + return JsonSerializer.Serialize(output); + + } + catch(Exception ex){ + Console.WriteLine($"Invalid Payload: {ex.Message}"); + output.Add("result", "Invalid Payload"); + return JsonSerializer.Serialize(output); + } + } + + static void Main(string[] args) { Fdk.Handle(args[0]); } + + } +} diff --git a/samples/oci-compute-control-dotnet/ControlInstance.csproj b/samples/oci-compute-control-dotnet/ControlInstance.csproj new file mode 100644 index 0000000..6b4798f --- /dev/null +++ b/samples/oci-compute-control-dotnet/ControlInstance.csproj @@ -0,0 +1,18 @@ + + + + Exe + netcoreapp3.1 + + + + + + + + + + + + + diff --git a/samples/oci-compute-control-dotnet/Controller/ComputeController.cs b/samples/oci-compute-control-dotnet/Controller/ComputeController.cs new file mode 100644 index 0000000..880485b --- /dev/null +++ b/samples/oci-compute-control-dotnet/Controller/ComputeController.cs @@ -0,0 +1,94 @@ + +using System; +using System.Threading.Tasks; +using System.Text; +using Oci.Common.Model; +using Oci.Common; +using Oci.Common.Auth; +using Oci.CoreService; +using Oci.CoreService.Models; +using Oci.CoreService.Requests; +using Oci.CoreService.Responses; + +namespace ControlInstance +{ + public class ComputeController + { + public static async Task GetComputeStatus(ComputeClient client,string instance_ocid) + { + try + { + var getInstanceRequest = new Oci.CoreService.Requests.GetInstanceRequest + { + InstanceId = instance_ocid + }; + + var getInstancesResponse = await client.GetInstance(getInstanceRequest); + return getInstancesResponse.Instance.LifecycleState.ToString(); + } + catch (OciException ex) + { + return ex.ServiceCode; + } + } + + public static async Task StartCompute(ComputeClient client,string instance_ocid) + { + Console.WriteLine($"Starting Instance Id: {instance_ocid}"); + try + { + if (GetComputeStatus(client,instance_ocid).Result == "Stopped" ) + { + var instanceActionRequest = new Oci.CoreService.Requests.InstanceActionRequest + { + InstanceId = instance_ocid, + Action = "START", + }; + + var getInstancesResponse = await client.InstanceAction(instanceActionRequest); + Console.WriteLine($"Start Response Code : {getInstancesResponse.Instance.LifecycleState.ToString()}"); + return GetComputeStatus(client,instance_ocid).Result; + } + else + { + Console.WriteLine($"Instance Is Already Running"); + return "Instance Is Already Running"; + } + } + catch (OciException ex) + { + return ex.Message; + } + } + + public static async Task StopCompute(ComputeClient client,string instance_ocid) + { + Console.WriteLine($"Stopping Instance Id: {instance_ocid}"); + try + { + if (GetComputeStatus(client,instance_ocid).Result == "Running" ) + { + var instanceActionRequest = new Oci.CoreService.Requests.InstanceActionRequest + { + InstanceId = instance_ocid, + Action = "STOP", + }; + + var getInstancesResponse = await client.InstanceAction(instanceActionRequest); + Console.WriteLine($"Stop Response Code : {getInstancesResponse.Instance.LifecycleState.ToString()}"); + return GetComputeStatus(client,instance_ocid).Result; + } + else + { + Console.WriteLine($"Instance Is Already Stopped"); + return "Instance Is Already Stopped"; + } + } + catch (OciException ex) + { + return ex.Message; + } + } + + } +} diff --git a/samples/oci-compute-control-dotnet/Dockerfile b/samples/oci-compute-control-dotnet/Dockerfile new file mode 100644 index 0000000..a8be4cd --- /dev/null +++ b/samples/oci-compute-control-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 ControlInstance.csproj +RUN dotnet build ControlInstance.csproj -c Release +RUN dotnet publish ControlInstance.csproj -c Release -o out +FROM fnproject/dotnet:3.1-1.0.4 +WORKDIR /function +COPY --from=build-stage /function/out/ /function/ +ENTRYPOINT ["dotnet", "ControlInstance.dll"] +CMD ["ControlInstance:Function:function_handler"] \ No newline at end of file diff --git a/samples/oci-compute-control-dotnet/Function.sln b/samples/oci-compute-control-dotnet/Function.sln new file mode 100644 index 0000000..f87916a --- /dev/null +++ b/samples/oci-compute-control-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-compute-control-dotnet/Models/InputMessage.cs b/samples/oci-compute-control-dotnet/Models/InputMessage.cs new file mode 100644 index 0000000..89a9d2a --- /dev/null +++ b/samples/oci-compute-control-dotnet/Models/InputMessage.cs @@ -0,0 +1,14 @@ +using System; + +namespace ControlInstance +{ + + class InputMessage + { + public string command { get; set; } + + public string instance_ocid { get; set; } + + } + +} diff --git a/samples/oci-compute-control-dotnet/func.yaml b/samples/oci-compute-control-dotnet/func.yaml new file mode 100644 index 0000000..46cf06a --- /dev/null +++ b/samples/oci-compute-control-dotnet/func.yaml @@ -0,0 +1,8 @@ +schema_version: 20180708 +name: oci-compute-control-dotnet +version: 0.0.2 +runtime: dotnet3.1 +build_image: fnproject/dotnet:3.1-1.0.4-dev +run_image: fnproject/dotnet:3.1-1.0.4 +cmd: ControlInstance:Function:function_handler +entrypoint: dotnet ControlInstance.dll From e166def3ccf67afcb2f651220e9e47f5788b0ab0 Mon Sep 17 00:00:00 2001 From: Deepak Devadathan Date: Mon, 12 Sep 2022 00:41:14 +0000 Subject: [PATCH 2/6] added function readme Signed-off-by: Deepak Devadathan --- samples/oci-compute-control-dotnet/README.md | 111 ++++++++++++++++++ .../images/userinput.png | Bin 0 -> 3030 bytes 2 files changed, 111 insertions(+) create mode 100644 samples/oci-compute-control-dotnet/README.md create mode 100644 samples/oci-compute-control-dotnet/images/userinput.png diff --git a/samples/oci-compute-control-dotnet/README.md b/samples/oci-compute-control-dotnet/README.md new file mode 100644 index 0000000..a582790 --- /dev/null +++ b/samples/oci-compute-control-dotnet/README.md @@ -0,0 +1,111 @@ +# Function that controls a Compute instance + +This function uses Resource Principals to securely authorize a function to make +API calls to OCI services using the [OCI Dotnet SDK](https://docs.oracle.com/iaas/tools/dotnet/latest/api/index.html). +It returns a list of all instances within the compartment that calls the function. + +The function calls the following OCI Dotnet SDK classes: +* [ResourcePrincipalAuthenticationDetailsProvider](https://docs.oracle.com/en-us/iaas/tools/dotnet/latest/api/Oci.Common.Auth.ResourcePrincipalAuthenticationDetailsProvider.html) to authenticate +* [ComputeClient](https://docs.oracle.com/en-us/iaas/tools/dotnet/latest/api/Oci.CoreService.ComputeClient.html) to interact with Compute + +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 steps 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 you 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'} +``` + + +## Create or Update IAM Policies + +Create a new policy that allows the dynamic group to `inspect instances` in +the functions related compartment. + +![user input icon](./images/userinput.png) + +Your policy should look something like this: +``` +Allow dynamic-group to inspect instances in compartment +``` +e.g. +``` +Allow dynamic-group demo-func-dyn-group to inspect instances in compartment demo-func-compartment +``` + +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: +- [ControlInstance.csproj](./ControlInstance.csproj) specifies all the dependencies for your function +- [func.yaml](./func.yaml) that contains metadata about your function and declares properties +- [ControlInstance.cs](./ControlInstance.cs) which contains the Dotnet code + +The name of your function *oci-compute-control-dotnet* is specified in [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 the specified Docker registry, and deploy the function to Oracle Functions +in the application created earlier: + +![user input icon](./images/userinput.png) +``` +fn -v deploy --app +``` +e.g. +``` +fn -v deploy --app myapp +``` + + +## Test + +Use the *fn* CLI to invoke your function with your app name and the compartment OCID: + +![user input icon](./images/userinput.png) +``` +echo '{"command":"", "instance_ocid":""}' | fn invoke +``` +e.g. +``` +echo '{"command":"stop", "instance_ocid":"ocid1.fnfunc.oc1.iad.aaaaaxxxxx"}' | fn invoke myapp oci-compute-control-dotnet +``` +The supported values for command are "status", "start" and "stop". + + +## 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-compute-control-dotnet/images/userinput.png b/samples/oci-compute-control-dotnet/images/userinput.png new file mode 100644 index 0000000000000000000000000000000000000000..ce6a2028d7a713959f0b61bb99fd1793e4dfdb14 GIT binary patch literal 3030 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 Date: Mon, 12 Sep 2022 00:43:24 +0000 Subject: [PATCH 3/6] Updated readme index for comput control dotnet Signed-off-by: Deepak Devadathan --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6417241..35fd804 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ This repository provides examples demonstrating how to use Oracle Functions. |------------------------------------------------------|:------:|:----:|:----:| | Hello World |[sample](./samples/helloworld)|[sample](./samples/helloworld)|[sample](./samples/helloworld)| | List OCI Compute instances |[sample](./samples/oci-list-instances-python)|[sample](./samples/oci-list-instances-java)|[sample](./samples/oci-list-instances-dotnet)| -| Control OCI Compute instances (start/stop/status) |[sample](./samples/oci-compute-control-python)| +| Control OCI Compute instances (start/stop/status) |[sample](./samples/oci-compute-control-python)||[sample](./samples/oci-compute-control-dotnet)| | List OCI compartments |[sample](./samples/oci-list-compartments-python)| | List objects in OCI Object Storage |[sample](./samples/oci-objectstorage-list-objects-python)|[sample](./samples/oci-objectstorage-list-objects-java)| | Read an object in OCI Object Storage |[sample](./samples/oci-objectstorage-get-object-python)|[sample](./samples/oci-objectstorage-get-object-java)| From 308537e24b7b12352463e4717e8f10e74e1d505c Mon Sep 17 00:00:00 2001 From: Deepak Devadathan Date: Wed, 28 Sep 2022 01:53:13 +0000 Subject: [PATCH 4/6] Added dotnet function for listing compartments in a tenancy Signed-off-by: Deepak Devadathan --- .../Common/IdentityClient.cs | 30 ++++++ .../Controller/GetComparments.cs | 61 ++++++++++++ .../oci-list-compartments-dotnet/Dockerfile | 11 +++ .../oci-list-compartments-dotnet/Function.sln | 17 ++++ .../ListCompartment.cs | 42 ++++++++ .../ListCompartment.csproj | 18 ++++ .../Models/CompartmentDetails.cs | 14 +++ .../Models/InputMessage.cs | 12 +++ .../oci-list-compartments-dotnet/README.md | 91 ++++++++++++++++++ .../oci-list-compartments-dotnet/func.yaml | 8 ++ .../images/userinput.png | Bin 0 -> 3030 bytes 11 files changed, 304 insertions(+) create mode 100644 samples/oci-list-compartments-dotnet/Common/IdentityClient.cs create mode 100644 samples/oci-list-compartments-dotnet/Controller/GetComparments.cs create mode 100644 samples/oci-list-compartments-dotnet/Dockerfile create mode 100644 samples/oci-list-compartments-dotnet/Function.sln create mode 100644 samples/oci-list-compartments-dotnet/ListCompartment.cs create mode 100644 samples/oci-list-compartments-dotnet/ListCompartment.csproj create mode 100644 samples/oci-list-compartments-dotnet/Models/CompartmentDetails.cs create mode 100644 samples/oci-list-compartments-dotnet/Models/InputMessage.cs create mode 100644 samples/oci-list-compartments-dotnet/README.md create mode 100644 samples/oci-list-compartments-dotnet/func.yaml create mode 100644 samples/oci-list-compartments-dotnet/images/userinput.png diff --git a/samples/oci-list-compartments-dotnet/Common/IdentityClient.cs b/samples/oci-list-compartments-dotnet/Common/IdentityClient.cs new file mode 100644 index 0000000..bc9a45f --- /dev/null +++ b/samples/oci-list-compartments-dotnet/Common/IdentityClient.cs @@ -0,0 +1,30 @@ + +using System; +using System.Threading.Tasks; +using System.Text; + +using Oci.Common; +using Oci.Common.Auth; +using Oci.IdentityService; + + +namespace ListCompartment +{ + public class IdentityClientHelper + { + public static IdentityClient GetIdentityClient() + { + try + { + return new IdentityClient(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 IdentityClient(new InstancePrincipalsAuthenticationDetailsProvider(), new ClientConfiguration()); + } + } + + } +} diff --git a/samples/oci-list-compartments-dotnet/Controller/GetComparments.cs b/samples/oci-list-compartments-dotnet/Controller/GetComparments.cs new file mode 100644 index 0000000..78a547e --- /dev/null +++ b/samples/oci-list-compartments-dotnet/Controller/GetComparments.cs @@ -0,0 +1,61 @@ + +using System; +using System.Threading.Tasks; +using System.Text; +using System.Collections.Generic; +using Oci.Common.Model; +using Oci.Common; +using Oci.Common.Auth; +using Oci.IdentityService; +using Oci.IdentityService.Models; +using Oci.IdentityService.Requests; +using Oci.IdentityService.Responses; + + +namespace ListCompartment +{ + public class ListComparmentHelper + { + public static async Task> GetComparmentList(IdentityClient client, string parent_compartment_ocid) + + { + string nextpage = ""; + List comp_list = new List(); + while (true) + { + try + { + + var listCompartmentsRequest = new Oci.IdentityService.Requests.ListCompartmentsRequest + { + CompartmentId = parent_compartment_ocid, + AccessLevel = Oci.IdentityService.Requests.ListCompartmentsRequest.AccessLevelEnum.Any, + CompartmentIdInSubtree = true, + Page = nextpage, + Limit = 1000, + SortBy = Oci.IdentityService.Requests.ListCompartmentsRequest.SortByEnum.Name, + SortOrder = Oci.IdentityService.Requests.ListCompartmentsRequest.SortOrderEnum.Asc, + LifecycleState = Oci.IdentityService.Models.Compartment.LifecycleStateEnum.Active + }; + + var response = await client.ListCompartments(listCompartmentsRequest); + nextpage = response.OpcNextPage; + comp_list.AddRange(response.Items); + if (string.IsNullOrEmpty(nextpage)) + { + break; + } + } + + catch (OciException ex) + { + Console.WriteLine("Unable To Get Compartment List: {0}", ex.Message); + return new List(); + } + } + return comp_list; + } + + + } +} diff --git a/samples/oci-list-compartments-dotnet/Dockerfile b/samples/oci-list-compartments-dotnet/Dockerfile new file mode 100644 index 0000000..2ecd429 --- /dev/null +++ b/samples/oci-list-compartments-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 ListCompartment.csproj +RUN dotnet build ListCompartment.csproj -c Release +RUN dotnet publish ListCompartment.csproj -c Release -o out +FROM fnproject/dotnet:3.1-1.0.4 +WORKDIR /function +COPY --from=build-stage /function/out/ /function/ +ENTRYPOINT ["dotnet", "ListCompartment.dll"] +CMD ["ListCompartment:Function:function_handler"] \ No newline at end of file diff --git a/samples/oci-list-compartments-dotnet/Function.sln b/samples/oci-list-compartments-dotnet/Function.sln new file mode 100644 index 0000000..f87916a --- /dev/null +++ b/samples/oci-list-compartments-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-list-compartments-dotnet/ListCompartment.cs b/samples/oci-list-compartments-dotnet/ListCompartment.cs new file mode 100644 index 0000000..5121321 --- /dev/null +++ b/samples/oci-list-compartments-dotnet/ListCompartment.cs @@ -0,0 +1,42 @@ +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.IdentityService; +using Oci.IdentityService.Models; + +namespace ListCompartment +{ + class Function + { + public string function_handler(InputMessage input) + { + + Dictionary> output = new Dictionary>(); + var compartment_details_list = new List(); + string parent_compartment_ocid; + parent_compartment_ocid = input.compartment_ocid; + Console.WriteLine($"Getting Compartment tree for parent ocid : {parent_compartment_ocid}"); + IdentityClient client = IdentityClientHelper.GetIdentityClient(); + Task> compartment_list = ListComparmentHelper.GetComparmentList(client, parent_compartment_ocid); + + foreach (Compartment comp in compartment_list.Result) + { + var compartment_detail = new CompartmentDetails(); + compartment_detail.name = comp.Name; + compartment_detail.ocid = comp.Id; + compartment_details_list.Add(compartment_detail); + } + + output.Add("results", compartment_details_list); + return JsonSerializer.Serialize(output); + + } + + static void Main(string[] args) { Fdk.Handle(args[0]); } + + } +} diff --git a/samples/oci-list-compartments-dotnet/ListCompartment.csproj b/samples/oci-list-compartments-dotnet/ListCompartment.csproj new file mode 100644 index 0000000..6b4798f --- /dev/null +++ b/samples/oci-list-compartments-dotnet/ListCompartment.csproj @@ -0,0 +1,18 @@ + + + + Exe + netcoreapp3.1 + + + + + + + + + + + + + diff --git a/samples/oci-list-compartments-dotnet/Models/CompartmentDetails.cs b/samples/oci-list-compartments-dotnet/Models/CompartmentDetails.cs new file mode 100644 index 0000000..1787324 --- /dev/null +++ b/samples/oci-list-compartments-dotnet/Models/CompartmentDetails.cs @@ -0,0 +1,14 @@ +using System; + +namespace ListCompartment +{ + + class CompartmentDetails + { + public string name { get; set; } + + public string ocid { get; set; } + + } + +} diff --git a/samples/oci-list-compartments-dotnet/Models/InputMessage.cs b/samples/oci-list-compartments-dotnet/Models/InputMessage.cs new file mode 100644 index 0000000..46a19d3 --- /dev/null +++ b/samples/oci-list-compartments-dotnet/Models/InputMessage.cs @@ -0,0 +1,12 @@ +using System; + +namespace ListCompartment +{ + + class InputMessage + { + public string compartment_ocid { get; set; } + + } + +} diff --git a/samples/oci-list-compartments-dotnet/README.md b/samples/oci-list-compartments-dotnet/README.md new file mode 100644 index 0000000..2cf0000 --- /dev/null +++ b/samples/oci-list-compartments-dotnet/README.md @@ -0,0 +1,91 @@ +# Function that returns the list of compartments in a user's tenancy + +This function uses Resource Principals to securely authorize a function to make +API calls to OCI services using the [OCI Dotnet SDK](https://docs.oracle.com/en-us/iaas/tools/dotnet/latest/api/index.html). +It returns a list of all compartments within the tenancy. + +The function calls the following OCI Dotnet SDK classes: +* [Resource Principals](https://docs.oracle.com/en-us/iaas/tools/dotnet/latest/api/Oci.Common.Auth.ResourcePrincipalAuthenticationDetailsProvider.html) to authenticate +* [Identity Client](https://docs.oracle.com/en-us/iaas/tools/dotnet/latest/api/Oci.IdentityService.IdentityClient.html) to interact with Identity and Access Management + +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 steps 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 you 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'} +``` + + +## Create or Update Policies +This function does not require any particular IAM policy. + + +## Review and customize the function +Review the following files in the current folder: +- [ListCompartment.csproj](./ListCompartment.csproj) which specifies all the dependencies for your function +- [func.yaml](./func.yaml) which contains metadata about your function and declares properties +- [ListCompartment.cs](./ListCompartment.cs) which is your actual Dotnet function + +The name of your function *oci-list-compartments-dotnet* is specified in [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 the specified Docker registry, and deploy the function to Oracle Functions +in the application created earlier: + +![user input icon](./images/userinput.png) +``` +fn -v deploy --app +``` +e.g. +``` +fn -v deploy --app myapp +``` + + +## Test +![user input icon](./images/userinput.png) +``` +echo '{"compartment_ocid":""}' |fn invoke +``` +e.g. +``` +echo '{"compartment_ocid":""}' | fn invoke myapp oci-list-compartments-python +``` +You should see all the compartments in your tenancy listed in the terminal. + + +## 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-list-compartments-dotnet/func.yaml b/samples/oci-list-compartments-dotnet/func.yaml new file mode 100644 index 0000000..aeb2dad --- /dev/null +++ b/samples/oci-list-compartments-dotnet/func.yaml @@ -0,0 +1,8 @@ +schema_version: 20180708 +name: oci-list-compartment-dotnet +version: 0.0.48 +runtime: dotnet3.1 +build_image: fnproject/dotnet:3.1-1.0.4-dev +run_image: fnproject/dotnet:3.1-1.0.4 +cmd: ListCompartment:Function:function_handler +entrypoint: dotnet ListCompartment.dll diff --git a/samples/oci-list-compartments-dotnet/images/userinput.png b/samples/oci-list-compartments-dotnet/images/userinput.png new file mode 100644 index 0000000000000000000000000000000000000000..ce6a2028d7a713959f0b61bb99fd1793e4dfdb14 GIT binary patch literal 3030 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 Date: Wed, 28 Sep 2022 01:55:25 +0000 Subject: [PATCH 5/6] corrected readme Signed-off-by: Deepak Devadathan --- samples/oci-list-compartments-dotnet/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/oci-list-compartments-dotnet/README.md b/samples/oci-list-compartments-dotnet/README.md index 2cf0000..ea46884 100644 --- a/samples/oci-list-compartments-dotnet/README.md +++ b/samples/oci-list-compartments-dotnet/README.md @@ -79,7 +79,7 @@ echo '{"compartment_ocid":""}' |fn invoke "}' | fn invoke myapp oci-list-compartments-python +echo '{"compartment_ocid":""}' | fn invoke myapp oci-list-compartments-dotnet ``` You should see all the compartments in your tenancy listed in the terminal. From 08391dc278168e718e185799f20c4355365e386c Mon Sep 17 00:00:00 2001 From: Deepak Devadathan Date: Wed, 28 Sep 2022 01:56:33 +0000 Subject: [PATCH 6/6] updated index readme Signed-off-by: Deepak Devadathan --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 35fd804..43f5f5d 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ This repository provides examples demonstrating how to use Oracle Functions. | Hello World |[sample](./samples/helloworld)|[sample](./samples/helloworld)|[sample](./samples/helloworld)| | List OCI Compute instances |[sample](./samples/oci-list-instances-python)|[sample](./samples/oci-list-instances-java)|[sample](./samples/oci-list-instances-dotnet)| | Control OCI Compute instances (start/stop/status) |[sample](./samples/oci-compute-control-python)||[sample](./samples/oci-compute-control-dotnet)| -| List OCI compartments |[sample](./samples/oci-list-compartments-python)| +| List OCI compartments |[sample](./samples/oci-list-compartments-python)||[sample](./samples/oci-list-compartments-dotnet)| | List objects in OCI Object Storage |[sample](./samples/oci-objectstorage-list-objects-python)|[sample](./samples/oci-objectstorage-list-objects-java)| | Read an object in OCI Object Storage |[sample](./samples/oci-objectstorage-get-object-python)|[sample](./samples/oci-objectstorage-get-object-java)| | Create an object in OCI Object Storage |[sample](./samples/oci-objectstorage-put-object-python)|[sample](./samples/oci-objectstorage-put-object-java)|