Skip to content

Commit 95dcbdb

Browse files
authored
Merge pull request #2 from ddevadat/dotnet-samples
Dotnet samples for list compartment
2 parents 36af33d + 08391dc commit 95dcbdb

22 files changed

+664
-2
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ This repository provides examples demonstrating how to use Oracle Functions.
1717
|------------------------------------------------------|:------:|:----:|:----:|
1818
| Hello World |[sample](./samples/helloworld)|[sample](./samples/helloworld)|[sample](./samples/helloworld)|
1919
| List OCI Compute instances |[sample](./samples/oci-list-instances-python)|[sample](./samples/oci-list-instances-java)|[sample](./samples/oci-list-instances-dotnet)|
20-
| Control OCI Compute instances (start/stop/status) |[sample](./samples/oci-compute-control-python)|
21-
| List OCI compartments |[sample](./samples/oci-list-compartments-python)|
20+
| Control OCI Compute instances (start/stop/status) |[sample](./samples/oci-compute-control-python)||[sample](./samples/oci-compute-control-dotnet)|
21+
| List OCI compartments |[sample](./samples/oci-list-compartments-python)||[sample](./samples/oci-list-compartments-dotnet)|
2222
| List objects in OCI Object Storage |[sample](./samples/oci-objectstorage-list-objects-python)|[sample](./samples/oci-objectstorage-list-objects-java)|
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)|
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
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.CoreService;
9+
10+
11+
namespace ControlInstance
12+
{
13+
public class ComputeClientHelper
14+
{
15+
public static ComputeClient GetComputeClient()
16+
{
17+
try{
18+
19+
return new ComputeClient(ResourcePrincipalAuthenticationDetailsProvider.GetProvider(), new ClientConfiguration());
20+
}
21+
catch(Exception ex) {
22+
Console.WriteLine("Unable To Create Resource Principal Provider: {0}", ex.Message);
23+
Console.WriteLine("Defaulting to Instance Provider");
24+
return new ComputeClient(new InstancePrincipalsAuthenticationDetailsProvider(), new ClientConfiguration());
25+
}
26+
}
27+
28+
}
29+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
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 Oci.CoreService;
9+
10+
namespace ControlInstance
11+
{
12+
class Function
13+
{
14+
public string function_handler(InputMessage input)
15+
{
16+
string command;
17+
string instance_ocid;
18+
Dictionary<string, string> output = new Dictionary<string, string>();
19+
try{
20+
command=input.command.ToLower();
21+
instance_ocid=input.instance_ocid;
22+
ComputeClient client = ComputeClientHelper.GetComputeClient();
23+
if (command=="status")
24+
{
25+
Task<string> instance_state = ComputeController.GetComputeStatus(client,instance_ocid);
26+
output.Add("result", instance_state.Result);
27+
}
28+
else if (command=="start")
29+
{
30+
Task<string> instance_state = ComputeController.StartCompute(client,instance_ocid);
31+
output.Add("result", instance_state.Result);
32+
}
33+
else if (command=="stop")
34+
{
35+
Task<string> instance_state = ComputeController.StopCompute(client,instance_ocid);
36+
output.Add("result", instance_state.Result);
37+
}
38+
else
39+
{
40+
output.Add("result", "Invalid Command");
41+
}
42+
43+
return JsonSerializer.Serialize(output);
44+
45+
}
46+
catch(Exception ex){
47+
Console.WriteLine($"Invalid Payload: {ex.Message}");
48+
output.Add("result", "Invalid Payload");
49+
return JsonSerializer.Serialize(output);
50+
}
51+
}
52+
53+
static void Main(string[] args) { Fdk.Handle(args[0]); }
54+
55+
}
56+
}
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.Core" Version="42.1.0" />
15+
<PackageReference Include="OCI.DotNetSDK.Identity" Version="42.1.0" />
16+
</ItemGroup>
17+
18+
</Project>
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
2+
using System;
3+
using System.Threading.Tasks;
4+
using System.Text;
5+
using Oci.Common.Model;
6+
using Oci.Common;
7+
using Oci.Common.Auth;
8+
using Oci.CoreService;
9+
using Oci.CoreService.Models;
10+
using Oci.CoreService.Requests;
11+
using Oci.CoreService.Responses;
12+
13+
namespace ControlInstance
14+
{
15+
public class ComputeController
16+
{
17+
public static async Task<string> GetComputeStatus(ComputeClient client,string instance_ocid)
18+
{
19+
try
20+
{
21+
var getInstanceRequest = new Oci.CoreService.Requests.GetInstanceRequest
22+
{
23+
InstanceId = instance_ocid
24+
};
25+
26+
var getInstancesResponse = await client.GetInstance(getInstanceRequest);
27+
return getInstancesResponse.Instance.LifecycleState.ToString();
28+
}
29+
catch (OciException ex)
30+
{
31+
return ex.ServiceCode;
32+
}
33+
}
34+
35+
public static async Task<string> StartCompute(ComputeClient client,string instance_ocid)
36+
{
37+
Console.WriteLine($"Starting Instance Id: {instance_ocid}");
38+
try
39+
{
40+
if (GetComputeStatus(client,instance_ocid).Result == "Stopped" )
41+
{
42+
var instanceActionRequest = new Oci.CoreService.Requests.InstanceActionRequest
43+
{
44+
InstanceId = instance_ocid,
45+
Action = "START",
46+
};
47+
48+
var getInstancesResponse = await client.InstanceAction(instanceActionRequest);
49+
Console.WriteLine($"Start Response Code : {getInstancesResponse.Instance.LifecycleState.ToString()}");
50+
return GetComputeStatus(client,instance_ocid).Result;
51+
}
52+
else
53+
{
54+
Console.WriteLine($"Instance Is Already Running");
55+
return "Instance Is Already Running";
56+
}
57+
}
58+
catch (OciException ex)
59+
{
60+
return ex.Message;
61+
}
62+
}
63+
64+
public static async Task<string> StopCompute(ComputeClient client,string instance_ocid)
65+
{
66+
Console.WriteLine($"Stopping Instance Id: {instance_ocid}");
67+
try
68+
{
69+
if (GetComputeStatus(client,instance_ocid).Result == "Running" )
70+
{
71+
var instanceActionRequest = new Oci.CoreService.Requests.InstanceActionRequest
72+
{
73+
InstanceId = instance_ocid,
74+
Action = "STOP",
75+
};
76+
77+
var getInstancesResponse = await client.InstanceAction(instanceActionRequest);
78+
Console.WriteLine($"Stop Response Code : {getInstancesResponse.Instance.LifecycleState.ToString()}");
79+
return GetComputeStatus(client,instance_ocid).Result;
80+
}
81+
else
82+
{
83+
Console.WriteLine($"Instance Is Already Stopped");
84+
return "Instance Is Already Stopped";
85+
}
86+
}
87+
catch (OciException ex)
88+
{
89+
return ex.Message;
90+
}
91+
}
92+
93+
}
94+
}
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 ControlInstance.csproj
5+
RUN dotnet build ControlInstance.csproj -c Release
6+
RUN dotnet publish ControlInstance.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", "ControlInstance.dll"]
11+
CMD ["ControlInstance: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: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using System;
2+
3+
namespace ControlInstance
4+
{
5+
6+
class InputMessage
7+
{
8+
public string command { get; set; }
9+
10+
public string instance_ocid { get; set; }
11+
12+
}
13+
14+
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# Function that controls a Compute instance
2+
3+
This function uses Resource Principals to securely authorize a function to make
4+
API calls to OCI services using the [OCI Dotnet SDK](https://docs.oracle.com/iaas/tools/dotnet/latest/api/index.html).
5+
It returns a list of all instances within the compartment that calls the function.
6+
7+
The function calls the following OCI Dotnet SDK classes:
8+
* [ResourcePrincipalAuthenticationDetailsProvider](https://docs.oracle.com/en-us/iaas/tools/dotnet/latest/api/Oci.Common.Auth.ResourcePrincipalAuthenticationDetailsProvider.html) to authenticate
9+
* [ComputeClient](https://docs.oracle.com/en-us/iaas/tools/dotnet/latest/api/Oci.CoreService.ComputeClient.html) to interact with Compute
10+
11+
As you make your way through this tutorial, look out for this icon ![user input icon](./images/userinput.png).
12+
Whenever you see it, it's time for you to perform an action.
13+
14+
15+
## Prerequisites
16+
17+
Before you deploy this sample function, make sure you have run steps A, B
18+
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)
19+
* A - Set up your tenancy
20+
* B - Create application
21+
* C - Set up your Cloud Shell dev environment
22+
23+
24+
## List Applications
25+
26+
Assuming you have successfully completed the prerequisites, you should see your
27+
application in the list of applications.
28+
29+
```
30+
fn ls apps
31+
```
32+
33+
34+
## Create or Update your Dynamic Group
35+
36+
In order to use other OCI Services, your function must be part of a dynamic
37+
group. For information on how to create a dynamic group, refer to the
38+
[documentation](https://docs.cloud.oracle.com/iaas/Content/Identity/Tasks/managingdynamicgroups.htm#To).
39+
40+
When specifying the *Matching Rules*, we suggest matching all functions in a compartment with:
41+
42+
```
43+
ALL {resource.type = 'fnfunc', resource.compartment.id = 'ocid1.compartment.oc1..aaaaaxxxxx'}
44+
```
45+
46+
47+
## Create or Update IAM Policies
48+
49+
Create a new policy that allows the dynamic group to `inspect instances` in
50+
the functions related compartment.
51+
52+
![user input icon](./images/userinput.png)
53+
54+
Your policy should look something like this:
55+
```
56+
Allow dynamic-group <dynamic-group-name> to inspect instances in compartment <compartment-name>
57+
```
58+
e.g.
59+
```
60+
Allow dynamic-group demo-func-dyn-group to inspect instances in compartment demo-func-compartment
61+
```
62+
63+
For more information on how to create policies, go [here](https://docs.cloud.oracle.com/iaas/Content/Identity/Concepts/policysyntax.htm).
64+
65+
66+
## Review and customize your function
67+
68+
Review the following files in the current folder:
69+
- [ControlInstance.csproj](./ControlInstance.csproj) specifies all the dependencies for your function
70+
- [func.yaml](./func.yaml) that contains metadata about your function and declares properties
71+
- [ControlInstance.cs](./ControlInstance.cs) which contains the Dotnet code
72+
73+
The name of your function *oci-compute-control-dotnet* is specified in [func.yaml](./func.yaml).
74+
75+
76+
## Deploy the function
77+
78+
In Cloud Shell, run the *fn deploy* command to build the function and its dependencies as a Docker image,
79+
push the image to the specified Docker registry, and deploy the function to Oracle Functions
80+
in the application created earlier:
81+
82+
![user input icon](./images/userinput.png)
83+
```
84+
fn -v deploy --app <app-name>
85+
```
86+
e.g.
87+
```
88+
fn -v deploy --app myapp
89+
```
90+
91+
92+
## Test
93+
94+
Use the *fn* CLI to invoke your function with your app name and the compartment OCID:
95+
96+
![user input icon](./images/userinput.png)
97+
```
98+
echo '{"command":"<command>", "instance_ocid":"<instance-ocid>"}' | fn invoke <app-name> <function-name>
99+
```
100+
e.g.
101+
```
102+
echo '{"command":"stop", "instance_ocid":"ocid1.fnfunc.oc1.iad.aaaaaxxxxx"}' | fn invoke myapp oci-compute-control-dotnet
103+
```
104+
The supported values for command are "status", "start" and "stop".
105+
106+
107+
## Monitoring Functions
108+
109+
Learn how to configure basic observability for your function using metrics, alarms and email alerts:
110+
* [Basic Guidance for Monitoring your Functions](../basic-observability/functions.md)
111+
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-compute-control-dotnet
3+
version: 0.0.2
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: ControlInstance:Function:function_handler
8+
entrypoint: dotnet ControlInstance.dll
Loading

0 commit comments

Comments
 (0)