From e12b0753a04a0c75eb503ea8b8acf46ab5efa2fb Mon Sep 17 00:00:00 2001 From: Mohit Mangal Date: Tue, 5 Oct 2021 16:23:02 +0530 Subject: [PATCH] Java, Ruby, Python and go samples to push to object storage with custom certs --- LICENSE.txt | 2 +- THIRD_PARTY_LICENSES.txt | 182 +++++++++++++++++- .../README.md | 120 ++++++++++++ .../func.go | 113 +++++++++++ .../func.yaml | 7 + .../go.mod | 8 + .../images/userinput.png | Bin 0 -> 3030 bytes .../README.md | 120 ++++++++++++ .../func.yaml | 8 + .../images/userinput.png | Bin 0 -> 3030 bytes .../pom.xml | 77 ++++++++ .../fn/ObjectStorageCustomCertPutObject.java | 145 ++++++++++++++ .../README.md | 114 +++++++++++ .../func.py | 52 +++++ .../func.yaml | 7 + .../images/userinput.png | Bin 0 -> 3030 bytes .../requirements.txt | 2 + .../Gemfile | 4 + .../README.md | 120 ++++++++++++ .../func.rb | 38 ++++ .../func.yaml | 8 + .../images/userinput.png | Bin 0 -> 3030 bytes 22 files changed, 1124 insertions(+), 3 deletions(-) create mode 100644 samples/oci-objectstorage-custom-cert-put-object-go/README.md create mode 100644 samples/oci-objectstorage-custom-cert-put-object-go/func.go create mode 100644 samples/oci-objectstorage-custom-cert-put-object-go/func.yaml create mode 100644 samples/oci-objectstorage-custom-cert-put-object-go/go.mod create mode 100644 samples/oci-objectstorage-custom-cert-put-object-go/images/userinput.png create mode 100644 samples/oci-objectstorage-custom-cert-put-object-java/README.md create mode 100755 samples/oci-objectstorage-custom-cert-put-object-java/func.yaml create mode 100644 samples/oci-objectstorage-custom-cert-put-object-java/images/userinput.png create mode 100644 samples/oci-objectstorage-custom-cert-put-object-java/pom.xml create mode 100755 samples/oci-objectstorage-custom-cert-put-object-java/src/main/java/com/example/fn/ObjectStorageCustomCertPutObject.java create mode 100644 samples/oci-objectstorage-custom-cert-put-object-python/README.md create mode 100644 samples/oci-objectstorage-custom-cert-put-object-python/func.py create mode 100644 samples/oci-objectstorage-custom-cert-put-object-python/func.yaml create mode 100644 samples/oci-objectstorage-custom-cert-put-object-python/images/userinput.png create mode 100644 samples/oci-objectstorage-custom-cert-put-object-python/requirements.txt create mode 100644 samples/oci-objectstorage-custom-cert-put-object-ruby/Gemfile create mode 100644 samples/oci-objectstorage-custom-cert-put-object-ruby/README.md create mode 100644 samples/oci-objectstorage-custom-cert-put-object-ruby/func.rb create mode 100644 samples/oci-objectstorage-custom-cert-put-object-ruby/func.yaml create mode 100644 samples/oci-objectstorage-custom-cert-put-object-ruby/images/userinput.png diff --git a/LICENSE.txt b/LICENSE.txt index 7ce682f..4ac08f5 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2020 Oracle and/or its affiliates. +Copyright (c) 2021 Oracle and/or its affiliates. The Universal Permissive License (UPL), Version 1.0 diff --git a/THIRD_PARTY_LICENSES.txt b/THIRD_PARTY_LICENSES.txt index 6963e4d..f8bc1e2 100644 --- a/THIRD_PARTY_LICENSES.txt +++ b/THIRD_PARTY_LICENSES.txt @@ -4,13 +4,13 @@ The following software (or subsets of the software) are dependencies that are us -------------------------------------------------------------------------------- -oci-java-sdk and oci-python-sdk are dual-licensed to you under the Universal Permissive License (UPL) 1.0 or Apache License 2.0. See below for license terms. You may choose either license. +oci-java-sdk, oci-python-sdk, oci-go-sdk and oci-ruby-sdk are dual-licensed to you under the Universal Permissive License (UPL) 1.0 or Apache License 2.0. See below for license terms. You may choose either license. Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. License: Copies of the Apache License V2 and the Universal Permissive License 1.0 are included at the end of this file. -------------------------------------------------------------------------------- -fdk-java and fdk-python are licensed under the Apache License, Version 2.0. +fdk-java,fdk-python, fdk-go and fdk-ruby are licensed under the Apache License, Version 2.0. License: A copy of the Apache License V2 is included at the end of this file. -------------------------------------------------------------------------------- @@ -579,10 +579,188 @@ py_zipkin Copyright (c) 2018, Yelp, Inc. All Rights reserved. Apache v2 License: Apache License 2.0, a copy of the license is included at the end of this file. +-------------------------------------------------------------------------------- + +mockito-core +Copyright (c) 2007 Mockito contributors + +This product includes software developed at +https://github.com/mockito/mockito. + +License +The MIT License + +Copyright (c) 2007 Mockito contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +-------------------------------------------------------------------------------- + +assertj-core + +This product includes software developed at https://github.com/assertj/assertj-core. + +License: Apache License 2.0, a copy of the license is included at the end of this file. -------------------------------------------------------------------------------- +Webrick +This product includes software developed at https://github.com/ruby/webrick. + +License: +Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. +-------------------------------------------------------------------------------- +Inifile +* MIT License Copyright (c) 2006 - 2014 +* License: MIT License +MIT License Copyright (c) 2006 - 2014 + +Copyright (c) 2011 Jeff Lindsay + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +* Source code: https://github.com/twp/inifile/ +* Project home: https://rubygems.org/gems/inifile +-------------------------------------------------------------------------------- +json +* License: Ruby License + +Ruby is copyrighted free software by Yukihiro Matsumoto . +You can redistribute it and/or modify it under either the terms of the +2-clause BSDL (see the file BSDL), or the conditions below: + + 1. You may make and give away verbatim copies of the source form of the + software without restriction, provided that you duplicate all of the + original copyright notices and associated disclaimers. + + 2. You may modify your copy of the software in any way, provided that + you do at least ONE of the following: + + a) place your modifications in the Public Domain or otherwise + make them Freely Available, such as by posting said + modifications to Usenet or an equivalent medium, or by allowing + the author to include your modifications in the software. + + b) use the modified software only within your corporation or + organization. + + c) give non-standard binaries non-standard names, with + instructions on where to get the original software distribution. + + d) make other distribution arrangements with the author. + + 3. You may distribute the software in object code or binary form, + provided that you do at least ONE of the following: + + a) distribute the binaries and library files of the software, + together with instructions (in the manual page or equivalent) + on where to get the original distribution. + + b) accompany the distribution with the machine-readable source of + the software. + + c) give non-standard binaries non-standard names, with + instructions on where to get the original software distribution. + + d) make other distribution arrangements with the author. + + 4. You may modify and include the part of the software into any other + software (possibly commercial). But some files in the distribution + are not written by the author, so that they are not under these terms. + + For the list of those files and their copying conditions, see the + file LEGAL. + + 5. The scripts and library files supplied as input to or produced as + output from the software do not automatically fall under the + copyright of the software, but belong to whomever generated them, + and may be sold commercially, and may be aggregated with this + software. + + 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE. +* Source code: https://github.com/flori/json/ +* Project home: http://flori.github.io/json/ +-------------------------------------------------------------------------------- +jwt +* Copyright (c) 2011 Jeff Lindsay +* License: MIT License +Copyright (c) 2011 Jeff Lindsay + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +* Source code: https://github.com/jwt/ruby-jwt +* Project home: https://github.com/jwt/ruby-jwt ================================================================================ Apache License diff --git a/samples/oci-objectstorage-custom-cert-put-object-go/README.md b/samples/oci-objectstorage-custom-cert-put-object-go/README.md new file mode 100644 index 0000000..b8e7247 --- /dev/null +++ b/samples/oci-objectstorage-custom-cert-put-object-go/README.md @@ -0,0 +1,120 @@ +# Function that creates an object in a bucket in Object Storage using the OCI Java SDK with custom certificate + +This function uses Resource Principals to securely authorize a function to make +API calls to OCI services using the [OCI Go SDK](hhttps://docs.oracle.com/en-us/iaas/tools/go/46.1.0/). +It creates an object in a bucket in Object Storage and returns a message with a status. + +The function calls the following OCI Go SDK classes: +* [ResourcePrincipalConfigurationProvider](https://docs.oracle.com/en-us/iaas/tools/go/47.1.0/common/auth/index.html#ResourcePrincipalConfigurationProvider) to authenticate +* [NewObjectStorageClientWithConfigurationProvider](https://docs.oracle.com/en-us/iaas/tools/go/47.1.0/objectstorage/index.html#NewObjectStorageClientWithConfigurationProvider) to interact with 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 + +1. 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 + +2. Have your Oracle Object Storage Namespace available. This can be found by +logging into your [cloud account](https://console.us-ashburn-1.oraclecloud.com/), +under your user profile, click on your Tenancy. Your Object Storage Namespace +is shown there. + + +## 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 `manage objects` in +the functions related compartment. + +![user input icon](./images/userinput.png) + +Your policy should look something like this: +``` +Allow dynamic-group to manage objects in compartment +``` +e.g. +``` +Allow dynamic-group demo-func-dyn-group to manage objects 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 the function + +Review the following files in the current folder: +- [go.mod](./go.mod) specifies all the dependencies for your function +- [func.yaml](./func.yaml) that contains metadata about your function and declares properties +- [func.go](./func.go) which contains the go code + +The name of your function 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 +``` + +## Create a bucket called "test" + +![user input icon](./images/userinput.png) + +From the OCI Console > Core Infrastructure > Object Storage > Create Bucket with bucket name = "test" + +## Test + +Use the *fn* CLI to invoke your function with your own bucket name and app name: + +![user input icon](./images/userinput.png) +``` +echo -n '{"name": "", "bucketName":"", "content": ""}' | fn invoke +``` +e.g. +``` +echo -n '{"name": "file1.txt", "bucketName":"mybucket", "content": "This file was created in OCI object storage bucket using Oracle Functions"}' | fn invoke myapp oci-objectstorage-custom-cert-put-object-go +``` +You should see a success message appear in your 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-objectstorage-custom-cert-put-object-go/func.go b/samples/oci-objectstorage-custom-cert-put-object-go/func.go new file mode 100644 index 0000000..cc4f1ed --- /dev/null +++ b/samples/oci-objectstorage-custom-cert-put-object-go/func.go @@ -0,0 +1,113 @@ +/* + oci-objectstorage-onsr-put-object-go version 1.0. + + Copyright (c) 2021 Oracle, Inc. All rights reserved. + Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. +*/ + +package main + +import ( + "context" + "crypto/tls" + "crypto/x509" + "encoding/json" + "io" + "io/ioutil" + "net/http" + "os" + "path" + + fdk "github.com/fnproject/fdk-go" + "github.com/oracle/oci-go-sdk/v37/common" + "github.com/oracle/oci-go-sdk/v37/common/auth" + "github.com/oracle/oci-go-sdk/v37/example/helpers" + "github.com/oracle/oci-go-sdk/v37/objectstorage" +) + +type ObjectStorage_Bucket struct { + Name string `json:"bucketName"` +} + +func main() { + fdk.Handle(fdk.HandlerFunc(myHandler)) +} + +func putObject(ctx context.Context, c objectstorage.ObjectStorageClient, namespace, bucketname, objectname string, contentLen int64, content io.ReadCloser, metadata map[string]string) error { + request := objectstorage.PutObjectRequest{ + NamespaceName: common.String(namespace), + BucketName: common.String(bucketname), + ObjectName: common.String(objectname), + ContentLength: common.Int64(contentLen), + PutObjectBody: content, + OpcMeta: metadata, + } + _, err := c.PutObject(ctx, request) + return err +} + +func fileExists(filename string) bool { + // fileExists checks if a file exists + info, err := os.Stat(filename) + if os.IsNotExist(err) { + return false + } + return !info.IsDir() +} + +func ObjectStorage_UploadFile(ctx context.Context, bname string) string { + // Get auth + provider, err := auth.ResourcePrincipalConfigurationProvider() + helpers.FatalIfError(err) + + client, client_err := objectstorage.NewObjectStorageClientWithConfigurationProvider(provider) + helpers.FatalIfError(client_err) + + // Use custom cert if it was mounted + cert_file_path := "/etc/oci-pki/customer/customer-cert.pem" + if fileExists(cert_file_path) { + cert, err := ioutil.ReadFile(cert_file_path) + helpers.FatalIfError(err) + + // Adding extra certs + pool := x509.NewCertPool() + pool.AppendCertsFromPEM([]byte(string(cert))) + + //install the certificates to the client + if h, ok := client.HTTPClient.(*http.Client); ok { + tr := &http.Transport{TLSClientConfig: &tls.Config{RootCAs: pool}} + h.Transport = tr + } else { + panic("the client dispatcher is not of http.Client type. can not patch the tls config") + } + } + request := objectstorage.GetNamespaceRequest{} + r, err := client.GetNamespace(ctx, request) + helpers.FatalIfError(err) + + namespace := *r.Value + + contentlen := 1024 * 1000 + filepath, filesize := helpers.WriteTempFileOfSize(int64(contentlen)) + filename := path.Base(filepath) + + file, e := os.Open(filepath) + defer file.Close() + helpers.FatalIfError(e) + + e = putObject(ctx, client, namespace, bname, filename, filesize, file, nil) + helpers.FatalIfError(e) + return filename +} + +func myHandler(ctx context.Context, in io.Reader, out io.Writer) { + bucket := &ObjectStorage_Bucket{Name: "bucketName"} + json.NewDecoder(in).Decode(bucket) + filename := ObjectStorage_UploadFile(ctx, bucket.Name) + msg := struct { + Msg string `json:"message"` + }{ + Msg: filename + " uploaded successfully in bucket " + bucket.Name, + } + json.NewEncoder(out).Encode(&msg) +} diff --git a/samples/oci-objectstorage-custom-cert-put-object-go/func.yaml b/samples/oci-objectstorage-custom-cert-put-object-go/func.yaml new file mode 100644 index 0000000..a955fb7 --- /dev/null +++ b/samples/oci-objectstorage-custom-cert-put-object-go/func.yaml @@ -0,0 +1,7 @@ +schema_version: 20180708 +name: oci-objectstorage-custom-cert-put-object-go +version: 0.0.1 +runtime: go +build_image: fnproject/go:1.15-dev +run_image: fnproject/go:1.15 +entrypoint: ./func diff --git a/samples/oci-objectstorage-custom-cert-put-object-go/go.mod b/samples/oci-objectstorage-custom-cert-put-object-go/go.mod new file mode 100644 index 0000000..c9885d9 --- /dev/null +++ b/samples/oci-objectstorage-custom-cert-put-object-go/go.mod @@ -0,0 +1,8 @@ +module func + +go 1.16 + +require ( + github.com/fnproject/fdk-go v0.0.8 + github.com/oracle/oci-go-sdk/v41 v41.2.0 +) diff --git a/samples/oci-objectstorage-custom-cert-put-object-go/images/userinput.png b/samples/oci-objectstorage-custom-cert-put-object-go/images/userinput.png new file mode 100644 index 0000000000000000000000000000000000000000..ce6a2028d7a713959f0b61bb99fd1793e4dfdb14 GIT binary patch literal 3030 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 to manage objects in compartment +``` +e.g. +``` +Allow dynamic-group demo-func-dyn-group to manage objects 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 the function + +Review the following files in the current folder: +- [pom.xml](./pom.xml) specifies all the dependencies for your function +- [func.yaml](./func.yaml) that contains metadata about your function and declares properties +- [src/main/java/com/example/fn/ObjectStoragePutObject.java](./src/main/java/com/example/fn/ObjectStoragePutObject.java) which contains the Java code + +The name of your function 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 +``` + +## Create a bucket called "test" + +![user input icon](./images/userinput.png) + +From the OCI Console > Core Infrastructure > Object Storage > Create Bucket with bucket name = "test" + +## Test + +Use the *fn* CLI to invoke your function with your own bucket name and app name: + +![user input icon](./images/userinput.png) +``` +echo -n '{"name": "", "bucketName":"", "content": ""}' | fn invoke +``` +e.g. +``` +echo -n '{"name": "file1.txt", "bucketName":"mybucket", "content": "This file was created in OCI object storage bucket using Oracle Functions"}' | fn invoke myapp oci-objectstorage-custom-cert-put-object-java +``` +You should see a success message appear in your 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-objectstorage-custom-cert-put-object-java/func.yaml b/samples/oci-objectstorage-custom-cert-put-object-java/func.yaml new file mode 100755 index 0000000..0546539 --- /dev/null +++ b/samples/oci-objectstorage-custom-cert-put-object-java/func.yaml @@ -0,0 +1,8 @@ +schema_version: 20180708 +name: oci-objectstorage-custom-cert-put-object-java +version: 0.0.1 +runtime: java +build_image: fnproject/fn-java-fdk-build:jdk11-1.0.130 +run_image: fnproject/fn-java-fdk:jre11-1.0.130 +cmd: com.example.fn.ObjectStorageCustomCertPutObject::handle +timeout: 300 diff --git a/samples/oci-objectstorage-custom-cert-put-object-java/images/userinput.png b/samples/oci-objectstorage-custom-cert-put-object-java/images/userinput.png new file mode 100644 index 0000000000000000000000000000000000000000..ce6a2028d7a713959f0b61bb99fd1793e4dfdb14 GIT binary patch literal 3030 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 + + 4.0.0 + + UTF-8 + 1.0.133 + + com.example.fn + oci-objectstorage-custom-cert-put-object-java + 1.0.0 + + + + + com.oracle.oci.sdk + oci-java-sdk-bom + 2.5.0 + pom + import + + + + + + + com.fnproject.fn + api + ${fdk.version} + + + com.fnproject.fn + testing-core + ${fdk.version} + test + + + com.fnproject.fn + testing-junit4 + ${fdk.version} + test + + + junit + junit + 4.13.2 + test + + + com.oracle.oci.sdk + oci-java-sdk-objectstorage + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.3 + + 11 + 11 + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.1 + + false + + + + + diff --git a/samples/oci-objectstorage-custom-cert-put-object-java/src/main/java/com/example/fn/ObjectStorageCustomCertPutObject.java b/samples/oci-objectstorage-custom-cert-put-object-java/src/main/java/com/example/fn/ObjectStorageCustomCertPutObject.java new file mode 100755 index 0000000..967db97 --- /dev/null +++ b/samples/oci-objectstorage-custom-cert-put-object-java/src/main/java/com/example/fn/ObjectStorageCustomCertPutObject.java @@ -0,0 +1,145 @@ +/* +** ObjectStorageCustomCertPutObject version 1.0. +** +** Copyright (c) 2021 Oracle, Inc. +** Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. +*/ + +package com.example.fn; + +import com.oracle.bmc.auth.ResourcePrincipalAuthenticationDetailsProvider; +import com.oracle.bmc.objectstorage.ObjectStorage; +import com.oracle.bmc.objectstorage.ObjectStorageClient; +import com.oracle.bmc.objectstorage.requests.GetNamespaceRequest; +import com.oracle.bmc.objectstorage.requests.PutObjectRequest; +import com.oracle.bmc.objectstorage.responses.PutObjectResponse; + +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; +import java.io.File; + +import java.security.KeyStore; +import java.security.cert.CertificateFactory; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.security.Key; +import java.io.IOException; +import java.io.InputStream; +import java.io.DataInputStream; +import java.security.cert.Certificate; +import java.util.Collection; + +public class ObjectStorageCustomCertPutObject { + + private ObjectStorage objStoreClient = null; + final ResourcePrincipalAuthenticationDetailsProvider provider + = ResourcePrincipalAuthenticationDetailsProvider.builder().build(); + + public ObjectStorageCustomCertPutObject() { + try { + //print env vars in Functions container + System.err.println("OCI_RESOURCE_PRINCIPAL_VERSION " + System.getenv("OCI_RESOURCE_PRINCIPAL_VERSION")); + System.err.println("OCI_RESOURCE_PRINCIPAL_REGION " + System.getenv("OCI_RESOURCE_PRINCIPAL_REGION")); + System.err.println("OCI_RESOURCE_PRINCIPAL_RPST " + System.getenv("OCI_RESOURCE_PRINCIPAL_RPST")); + System.err.println("OCI_RESOURCE_PRINCIPAL_PRIVATE_PEM " + System.getenv("OCI_RESOURCE_PRINCIPAL_PRIVATE_PEM")); + + // Adding certificates to trust store + // Adding certificates to trust store + String certificate_file_path = "/etc/oci-pki/customer/customer-cert.pem"; + String trust_store_path = "/tmp/keystore.jks"; + File cacertFile = new File(certificate_file_path); + if (cacertFile.exists()) { + createKeystoreWithCaBundle(certificate_file_path, trust_store_path); + System.setProperty("javax.net.ssl.trustStore", trust_store_path); + } + objStoreClient = new ObjectStorageClient(provider); + } catch (Throwable ex) { + System.err.println("Failed to instantiate ObjectStorage client - " + ex.getMessage()); + } + } + + private static void createKeystoreWithCaBundle(String caBundlePath, String trustStorePath) throws Exception { + KeyStore ks = KeyStore.getInstance("JKS"); + ks.load(null, null); + + // Now load our cert and add it to the keystore + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + + try (FileInputStream inputStream = new FileInputStream(caBundlePath)) { + Collection caCollection = cf.generateCertificates(inputStream); + int i = 0; + for (Certificate ca : caCollection) { + ks.setCertificateEntry("Trusted Cert " + i++, ca); + } + + FileOutputStream fos = new FileOutputStream(trustStorePath); + ks.store(fos,"changeit".toCharArray()); + } + } + + public static class ObjectInfo { + + private String name; + private String bucketName; + private String content; + + public String getBucketName() { + return bucketName; + } + + public void setBucketName(String bucketName) { + this.bucketName = bucketName; + } + + public ObjectInfo() { + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + } + + public String handle(ObjectInfo objectInfo) { + String result = "FAILED"; + + if (objStoreClient == null) { + System.err.println("There was a problem creating the ObjectStorage Client object. Please check logs"); + return result; + } + try { + GetNamespaceRequest request = GetNamespaceRequest.builder().build(); + String nameSpace = objStoreClient.getNamespace(request).getValue(); + String name = "cert_test"; + String content = "This is sample content"; + PutObjectRequest por = PutObjectRequest.builder() + .namespaceName(nameSpace) + .bucketName(objectInfo.bucketName) + .objectName(name) + .putObjectBody(new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8))) + .build(); + + PutObjectResponse poResp = objStoreClient.putObject(por); + result = "Successfully submitted Put request for object " + name + " in bucket " + objectInfo.bucketName + ". OPC reuquest ID is " + poResp.getOpcRequestId(); + System.err.println(result); + + } catch (Throwable e) { + System.err.println("Error storing object in bucket " + e.getMessage()); + result = "Error storing object in bucket " + e.getMessage(); + } + + return result; + } +} diff --git a/samples/oci-objectstorage-custom-cert-put-object-python/README.md b/samples/oci-objectstorage-custom-cert-put-object-python/README.md new file mode 100644 index 0000000..98188dd --- /dev/null +++ b/samples/oci-objectstorage-custom-cert-put-object-python/README.md @@ -0,0 +1,114 @@ +# Function that creates an object in a bucket in Object Storage using the OCI Python SDK with custom certificate + +This function uses Resource Principals to securely authorize a function to make +API calls to OCI services using the [OCI Python SDK](https://oracle-cloud-infrastructure-python-sdk.readthedocs.io/en/latest/index.html). +It creates an object in a bucket in Object Storage and returns a message with a status. + +The function calls the following OCI Python SDK classes: +* [Resource Principals Signer](https://oracle-cloud-infrastructure-python-sdk.readthedocs.io/en/latest/api/signing.html#resource-principals-signer) to authenticate +* [Object Storage Client](https://oracle-cloud-infrastructure-python-sdk.readthedocs.io/en/latest/api/object_storage/client/oci.object_storage.ObjectStorageClient.html) to interact with 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 + +1. 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 + +2. Have your Oracle Object Storage Namespace available. This can be found by +logging into your [cloud account](https://console.us-ashburn-1.oraclecloud.com/), +under your user profile, click on your Tenancy. Your Object Storage Namespace +is shown there. + + +## 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 `manage objects` in the functions related compartment. + +![user input icon](./images/userinput.png) + +Your policy should look something like this: +``` +Allow dynamic-group to manage objects in compartment +``` +e.g. +``` +Allow dynamic-group demo-func-dyn-group to manage objects 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 the function + +Review the following files in the current folder: + +- [requirements.txt](./requirements.txt) specifies all the dependencies for your function +- [func.yaml](./func.yaml) that contains metadata about your function and declares properties +- [func.py](./func.py) which is your actual Python function + +The name of your function 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 -n | fn invoke +``` +e.g. +``` +echo -n '{"objectName": "", "bucketName": "", "content": ""}' | fn invoke myapp oci-objectstorage-custom-cert-put-object-python +``` +You should see a success message appear 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-objectstorage-custom-cert-put-object-python/func.py b/samples/oci-objectstorage-custom-cert-put-object-python/func.py new file mode 100644 index 0000000..0644547 --- /dev/null +++ b/samples/oci-objectstorage-custom-cert-put-object-python/func.py @@ -0,0 +1,52 @@ +# +# oci-objectstorage-onsr-put-object-python version 1.0. +# +# Copyright (c) 2021 Oracle, Inc. +# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. +# + +import io +import os +import json +import sys +from fdk import response + +import oci.object_storage + +# Certs location +cert_file_path = "/etc/oci-pki/customer/customer-cert.pem" +# file to upload +file_to_upload = "cert_test" +file_to_upload_content = {"content":"This is test file"} + +def handler(ctx, data: io.BytesIO=None): + try: + body = json.loads(data.getvalue()) + bucketName = body["bucketName"] + except Exception: + error = """ + Input a JSON object in the format: '{"bucketName": "", + "content": "", "objectName": ""}' + """ + raise Exception(error) + signer = oci.auth.signers.get_resource_principals_signer() + client = oci.object_storage.ObjectStorageClient(config={}, signer=signer) + if os.path.exists(cert_file_path): + client.base_client.session.verify = cert_file_path + + resp = put_object(client, bucketName, file_to_upload, file_to_upload_content) + return response.Response( + ctx, + response_data=json.dumps(resp), + headers={"Content-Type": "application/json"} + ) + +def put_object(client, bucketName, objectName, content): + namespace = client.get_namespace().data + output="" + try: + object = client.put_object(namespace, bucketName, objectName, json.dumps(content)) + output = "Success: Put object '" + objectName + "' in bucket '" + bucketName + "'" + except Exception as e: + output = "Failed: " + str(e.message) + return { "state": output } diff --git a/samples/oci-objectstorage-custom-cert-put-object-python/func.yaml b/samples/oci-objectstorage-custom-cert-put-object-python/func.yaml new file mode 100644 index 0000000..beae1cb --- /dev/null +++ b/samples/oci-objectstorage-custom-cert-put-object-python/func.yaml @@ -0,0 +1,7 @@ +schema_version: 20180708 +name: oci-objectstorage-custom-cert-put-object-python +version: 0.0.1 +runtime: python +build_image: fnproject/python:3.8-dev +run_image: fnproject/python:3.8 +entrypoint: /python/bin/fdk /function/func.py handler diff --git a/samples/oci-objectstorage-custom-cert-put-object-python/images/userinput.png b/samples/oci-objectstorage-custom-cert-put-object-python/images/userinput.png new file mode 100644 index 0000000000000000000000000000000000000000..ce6a2028d7a713959f0b61bb99fd1793e4dfdb14 GIT binary patch literal 3030 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.1.35 +oci==2.43.0 diff --git a/samples/oci-objectstorage-custom-cert-put-object-ruby/Gemfile b/samples/oci-objectstorage-custom-cert-put-object-ruby/Gemfile new file mode 100644 index 0000000..428d2c0 --- /dev/null +++ b/samples/oci-objectstorage-custom-cert-put-object-ruby/Gemfile @@ -0,0 +1,4 @@ +source 'https://www.rubygems.org' do + gem 'fdk', '>= 0.0.26' + gem 'oci', '= 2.12.0' +end diff --git a/samples/oci-objectstorage-custom-cert-put-object-ruby/README.md b/samples/oci-objectstorage-custom-cert-put-object-ruby/README.md new file mode 100644 index 0000000..47f1344 --- /dev/null +++ b/samples/oci-objectstorage-custom-cert-put-object-ruby/README.md @@ -0,0 +1,120 @@ +# Function that creates an object in a bucket in Object Storage using the OCI Ruby SDK with custom certificate + +This function uses Resource Principals to securely authorize a function to make +API calls to OCI services using the [OCI Ruby SDK](https://docs.cloud.oracle.com/iaas/tools/ruby/latest/). +It creates an object in a bucket in Object Storage and returns a message with a status. + +The function calls the following OCI Ruby SDK classes: +* [resource_principals_signer](https://docs.oracle.com/en-us/iaas/tools/ruby/2.14.0/OCI/Auth/Signers/ResourcePrincipalsFederationSigner.html) to authenticate +* [ObjectStorageClient](https://docs.oracle.com/en-us/iaas/tools/ruby/2.15.0/OCI/ObjectStorage/ObjectStorageClient.html) to interact with 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 + +1. 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 + +2. Have your Oracle Object Storage Namespace available. This can be found by +logging into your [cloud account](https://console.us-ashburn-1.oraclecloud.com/), +under your user profile, click on your Tenancy. Your Object Storage Namespace +is shown there. + + +## 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 `manage objects` in +the functions related compartment. + +![user input icon](./images/userinput.png) + +Your policy should look something like this: +``` +Allow dynamic-group to manage objects in compartment +``` +e.g. +``` +Allow dynamic-group demo-func-dyn-group to manage objects 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 the function + +Review the following files in the current folder: +- [Gemfile](./Gemfile) specifies all the dependencies for your function +- [func.yaml](./func.yaml) that contains metadata about your function and declares properties +- [func.rb](./func.rb) which contains the ruby code + +The name of your function 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 +``` + +## Create a bucket called "test" + +![user input icon](./images/userinput.png) + +From the OCI Console > Core Infrastructure > Object Storage > Create Bucket with bucket name = "test" + +## Test + +Use the *fn* CLI to invoke your function with your own bucket name and app name: + +![user input icon](./images/userinput.png) +``` +echo -n '{"name": "", "bucketName":"", "content": ""}' | fn invoke +``` +e.g. +``` +echo -n '{"name": "file1.txt", "bucketName":"mybucket", "content": "This file was created in OCI object storage bucket using Oracle Functions"}' | fn invoke myapp oci-objectstorage-custom-cert-put-object-ruby +``` +You should see a success message appear in your 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-objectstorage-custom-cert-put-object-ruby/func.rb b/samples/oci-objectstorage-custom-cert-put-object-ruby/func.rb new file mode 100644 index 0000000..7fa9da2 --- /dev/null +++ b/samples/oci-objectstorage-custom-cert-put-object-ruby/func.rb @@ -0,0 +1,38 @@ +# +# oci-objectstorage-onsr-put-object-ruby version 1.0. +# +# Copyright (c) 2021 Oracle, Inc. All rights reserved. +# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. +# + +require 'fdk' + +# Certs location +$cert_file_path = '/etc/oci-pki/customer/customer-cert.pem' +# file to upload +$file_to_upload = "cert_test" +$file_to_upload_content = "This is test file for ONSR test" + +def put_object(bucket) + FDK.log(entry: "put_object: enter") + require 'oci' + principal_signer = OCI::Auth::Signers.resource_principals_signer + object_storage_client = OCI::ObjectStorage::ObjectStorageClient.new(signer: principal_signer) + namespace = object_storage_client.get_namespace.data + + if(File.exist?($cert_file_path)) + object_storage_client.api_client.request_option_overrides = { + ca_file: $cert_file_path + } + end + get_object_response = object_storage_client.put_object(namespace, bucket, $file_to_upload, $file_to_upload_content) + FDK.log(entry: "put_object: exit") +end + +def myfunction(context:, input:) + bucket = input.respond_to?(:fetch) ? input.fetch('bucketName') : input + put_object(bucket) + { message: "Completed Successfully!!!" } +end + +FDK.handle(target: :myfunction) diff --git a/samples/oci-objectstorage-custom-cert-put-object-ruby/func.yaml b/samples/oci-objectstorage-custom-cert-put-object-ruby/func.yaml new file mode 100644 index 0000000..7aa2c83 --- /dev/null +++ b/samples/oci-objectstorage-custom-cert-put-object-ruby/func.yaml @@ -0,0 +1,8 @@ +schema_version: 20180708 +name: oci-objectstorage-custom-cert-put-object-ruby +version: 0.0.1 +runtime: ruby +build_image: fnproject/ruby:2.7-dev +run_image: fnproject/ruby:2.7 +entrypoint: ruby func.rb +memory: 512 diff --git a/samples/oci-objectstorage-custom-cert-put-object-ruby/images/userinput.png b/samples/oci-objectstorage-custom-cert-put-object-ruby/images/userinput.png new file mode 100644 index 0000000000000000000000000000000000000000..ce6a2028d7a713959f0b61bb99fd1793e4dfdb14 GIT binary patch literal 3030 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