Skip to content

dotnet function for query adb using oracle client #14

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ This repository provides examples demonstrating how to use Oracle Functions.
| Display an OCI Cloud Event |[sample](./samples/oci-event-display-python)||[sample](./samples/oci-event-display-dotnet)|
| Invoke another Function using the OCI SDK |[sample](./samples/oci-invoke-function-python)||[sample](./samples/oci-invoke-function-dotnet)|
| Run a SQL statement against Autonomous DB using ORDS | [sample](./samples/oci-adb-ords-runsql-python) ||[sample](./samples/oci-adb-ords-runsql-dotnet)|
| Run a SQL statement against Autonomous DB using DB Client |[sample](./samples/oci-adb-client-runsql-python)||
| Run a SQL statement against Autonomous DB using DB Client |[sample](./samples/oci-adb-client-runsql-python)|| [sample](./samples/oci-adb-client-runsql-dotnet)
| Publish a notification using ONS |[sample](./samples/oci-ons-publish-python)|
| Send an email using Email Delivery Service |[sample](./samples/oci-email-send-python)|
| Decrypt cipher using Vault keys |[sample](./samples/oci-vault-decrypt-python)||[sample](./samples/oci-vault-decrypt-dotnet)|
Expand Down
29 changes: 29 additions & 0 deletions samples/oci-adb-client-runsql-dotnet/Common/DBClientHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@

using System;
using System.Threading.Tasks;
using System.Text;

using Oci.Common;
using Oci.Common.Auth;
using Oci.DatabaseService;

namespace RunSQL
{
public class DBClientHelper
{
public static DatabaseClient GetDBClient()
{
try
{
return new DatabaseClient(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 DatabaseClient(new InstancePrincipalsAuthenticationDetailsProvider(), new ClientConfiguration());
}
}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@

using System;
using System.Linq;
using System.Threading.Tasks;
using System.Text;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using Oci.Common.Model;
using Oci.Common;
using Oci.Common.Auth;
using Oci.DatabaseService;
using Oci.DatabaseService.Models;
using Oci.DatabaseService.Requests;
using Oci.DatabaseService.Responses;


namespace RunSQL
{
public class GenerateDBWalletHelper
{

public static string RandomString(int length)
{
const string pool = "abcdefghijklmnopqrstuvwxyz0123456789#%^$@";
Random random = new Random();
var chars = Enumerable.Range(0, length)
.Select(x => pool[random.Next(0, pool.Length)]);
return new string(chars.ToArray());
}

public static string GenerateWalletPassword(int length)
{
Random ran = new Random();
String b = "abcdefghijklmnopqrstuvwxyz0123456789";
String sc = "!@#$%^&*~";
String random = "";
for (int i = 0; i < length; i++)
{
int a = ran.Next(b.Length);
random = random + b.ElementAt(a);
}
for (int j = 0; j < 2; j++)
{
int sz = ran.Next(sc.Length);
random = random + sc.ElementAt(sz);
}
return random;
}
public static async Task<string> GenWallet(DatabaseClient client, string adb_ocid, string extractPath)

{

try
{
var wallet_password = GenerateWalletPassword(10);

Console.WriteLine("Inside GenWallet Method");
var generateAutonomousDatabaseWalletDetails = new Oci.DatabaseService.Models.GenerateAutonomousDatabaseWalletDetails
{
GenerateType = Oci.DatabaseService.Models.GenerateAutonomousDatabaseWalletDetails.GenerateTypeEnum.Single,
Password = wallet_password
};

var generateAutonomousDatabaseWalletRequest = new Oci.DatabaseService.Requests.GenerateAutonomousDatabaseWalletRequest
{
AutonomousDatabaseId = adb_ocid,
GenerateAutonomousDatabaseWalletDetails = generateAutonomousDatabaseWalletDetails,
};

var response = await client.GenerateAutonomousDatabaseWallet(generateAutonomousDatabaseWalletRequest);

using (var memoryStream = new MemoryStream())
{

response.InputStream.CopyTo(memoryStream);
Console.WriteLine("Generating zip file...");
var fileName = $"gen_wallet.zip";
string zipPath = Path.Combine(extractPath + "/" + fileName);
Console.WriteLine("Wallet location : {0}", zipPath);
using (var fs = new FileStream(zipPath, FileMode.Create, FileAccess.Write))
{
memoryStream.WriteTo(fs);
}
Console.WriteLine("extracting : {0} to {1}", zipPath, extractPath);

using (ZipArchive source = ZipFile.Open(zipPath, ZipArchiveMode.Read, null))
{
foreach (ZipArchiveEntry entry in source.Entries)
{
string fullPath = Path.GetFullPath(Path.Combine(extractPath, entry.FullName));

if (Path.GetFileName(fullPath).Length != 0)
{
entry.ExtractToFile(fullPath, true);
}
}
}

}
return "success";


}

catch (OciException ex)
{
Console.WriteLine("Unable To Generate wallet : {0}", ex.Message);
return "Failed " + ex.Message;
}

}


}
}
12 changes: 12 additions & 0 deletions samples/oci-adb-client-runsql-dotnet/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
FROM fnproject/dotnet:3.1-1.0.4-dev as build-stage
WORKDIR /function
COPY . .
RUN dotnet sln add RunSQL.csproj
RUN dotnet build RunSQL.csproj -c Release
RUN dotnet publish RunSQL.csproj -c Release -o out
FROM fnproject/dotnet:3.1-1.0.4
WORKDIR /function
COPY --from=build-stage /function/out/ /function/
ENV TNS_ADMIN=/tmp
ENTRYPOINT ["dotnet", "RunSQL.dll"]
CMD ["RunSQL:Function:function_handler"]
17 changes: 17 additions & 0 deletions samples/oci-adb-client-runsql-dotnet/Function.sln
Original file line number Diff line number Diff line change
@@ -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
13 changes: 13 additions & 0 deletions samples/oci-adb-client-runsql-dotnet/Models/InputMessage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System;

namespace RunSQL
{

class InputMessage
{
public string sql { get; set; }


}

}
18 changes: 18 additions & 0 deletions samples/oci-adb-client-runsql-dotnet/Models/OutputMessage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
// using System.Collections;
// using System.Collections.Specialized;

namespace RunSQL
{

class OutputDetails
{
public string sql { get; set; }

public List<Dictionary<string, string>> result { get; set; }

}


}
153 changes: 153 additions & 0 deletions samples/oci-adb-client-runsql-dotnet/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
# Execute a SQL statement against Autonomous Database using the Oracle client
This function connects to Oracle Autonomous Database (either Transaction Processing or Data Warehouse) using the Oracle Client and execute a SQL statement.

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.


## Review and customize the function
Review the following files in the current folder:
* the code of the function, [RunSQL.cs](./RunSQL.cs)
* its dependencies, [RunSQL.csproj](./RunSQL.csproj)
* 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 <app-name>
```


## Create an Autonomous Database
Use an existing Autonomous Database (either Transaction Processing or Datawarehouse) or create a new one as follows.

![user input icon](./images/userinput.png)

On the OCI console, navigate to *Autonomous Transaction Processing* or *Autonomous Data Warehouse* and click *Create Autonomous Database*. In the Create Autonomous Database dialog, enter the following:
- Display Name
- Compartment
- Database Name
- Infrastructure Type: Shared
- Admin password
- License type

![ADB create](./images/ADB-create.png)
For more information, go to https://docs.cloud.oracle.com/iaas/Content/Database/Tasks/adbcreating.htm


## Database Wallet and IAM Policies
The Database wallet is not part of the Docker image because it is not secure. The function downloads the wallet while it is executed.
The wallet can be retrieved from Object Storage or directly from Autonomous Database.

![user input icon](./images/userinput.png)

If you choose to retrieve the wallet from Object Storage, first download the wallet from Autonomous Database. Navigate to *Autonomous Transaction Processing* or *Autonomous Data Warehouse*, click on your database abd click on *DB Connection*. On the Pop-up window, click *Download Wallet*.

![Download Wallet](./images/Download_wallet.png)

Create a bucket in Object Storage and upload the wallet there. Note the name of the bucket and the wallet object name.
Create an IAM policy that allows the dynamic group to read objects in the bucket. We will grant `read` access to `objects` in your bucket in the compartment.

![user input icon](./images/userinput.png)

Your policy should look something like this:
```
Allow dynamic-group <dynamic-group-name> to read objects in compartment <compartment-name> where target.bucket.name='<bucket-name>'
```

If you choose to retrieve the wallet from Autonomous Database directly during the execution of the function, note the OCID of the Autonomous Database and create an IAM policy that allows the dynamic group to use the autonomous Database with the specific permission 'AUTONOMOUS_DATABASE_CONTENT_READ'.
```
Allow dynamic-group <dynamic-group-name> to use autonomous-databases in compartment <compartment-name> where request.permission='AUTONOMOUS_DATABASE_CONTENT_READ'
```

For more information on how to create policies, check the [documentation](https://docs.cloud.oracle.com/iaas/Content/Identity/Concepts/policysyntax.htm).


## Set the function configuration values
The function requires several config value to be set.

![user input icon](./images/userinput.png)

Use the *fn CLI* to set the config value:
```
fn config function <app-name> <function-name> DBSVC <DB-service-name>
fn config function <app-name> <function-name> DBUSER <DB-username>
fn config function <app-name> <function-name> DBPWD_CYPHER <DB-encrypted-password>
```
Additionally, the DB wallet should be downloaded from the autonomous DB, specify the Autonomouns Database OCID:

```
fn config function <app-name> <function name> ADB_OCID <Autonomous-DB-OCID>
```
e.g. with a DB wallet in a bucket:
```
fn config function myapp oci-adb-client-runsql-dotnet DBSVC "gregadw_high"
fn config function myapp oci-adb-client-runsql-dotnet DBUSER "admin"
fn config function myapp oci-adb-client-runsql-dotnet DBPWD_CYPHER "dfgjksadhfg4526897dfgkj"
fn config function myapp oci-adb-client-runsql-dotnet ADB_OCID "db-wallets"

```


## Invoke the function
![user input icon](./images/userinput.png)
```

echo '{"sql":"<sql statement>"}' | fn invoke <app-name> oci-adb-client-runsql-dotnet
```
e.g.:
```
echo '{"sql":"select sysdate from dual"}' | fn invoke myapp oci-adb-client-runsql-dotnet
```

Upon success, the function returns a JSON object similar to this:
```
{
"output": [
{
"sql": "select sysdate from dual",
"result": [
{
"SYSDATE": "10/27/2022 03:02:38"
}
]
}
]
}
```


## 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)

Loading