From c6ea8db8476d8624c6dc65640ee5efc2748eb658 Mon Sep 17 00:00:00 2001 From: mattstief Date: Tue, 24 Mar 2026 15:57:30 -0500 Subject: [PATCH] Added api gateway using nosql sample --- api-gateway-function-nosql-table/README.md | 260 ++++++++++++++++++ .../functions/customer/Dockerfile | 11 + .../functions/customer/func.go | 254 +++++++++++++++++ .../functions/customer/func.yaml | 8 + .../functions/customer/go.mod | 2 + .../terraform/data.tf | 12 + .../terraform/main.tf | 80 ++++++ .../terraform/modules/apigateway/main.tf | 10 + .../terraform/modules/apigateway/variables.tf | 9 + .../modules/container_repository/main.tf | 9 + .../modules/container_repository/variables.tf | 9 + .../terraform/modules/functions/main.tf | 29 ++ .../terraform/modules/functions/variables.tf | 46 ++++ .../terraform/modules/nosql/main.tf | 24 ++ .../terraform/modules/nosql/variables.tf | 9 + .../terraform/outputs.tf | 9 + .../terraform/provider.tf | 11 + .../terraform/terraform.tfvars | 11 + .../terraform/variables.tf | 50 ++++ 19 files changed, 853 insertions(+) create mode 100644 api-gateway-function-nosql-table/README.md create mode 100644 api-gateway-function-nosql-table/functions/customer/Dockerfile create mode 100644 api-gateway-function-nosql-table/functions/customer/func.go create mode 100644 api-gateway-function-nosql-table/functions/customer/func.yaml create mode 100644 api-gateway-function-nosql-table/functions/customer/go.mod create mode 100644 api-gateway-function-nosql-table/terraform/data.tf create mode 100644 api-gateway-function-nosql-table/terraform/main.tf create mode 100644 api-gateway-function-nosql-table/terraform/modules/apigateway/main.tf create mode 100644 api-gateway-function-nosql-table/terraform/modules/apigateway/variables.tf create mode 100644 api-gateway-function-nosql-table/terraform/modules/container_repository/main.tf create mode 100644 api-gateway-function-nosql-table/terraform/modules/container_repository/variables.tf create mode 100644 api-gateway-function-nosql-table/terraform/modules/functions/main.tf create mode 100644 api-gateway-function-nosql-table/terraform/modules/functions/variables.tf create mode 100644 api-gateway-function-nosql-table/terraform/modules/nosql/main.tf create mode 100644 api-gateway-function-nosql-table/terraform/modules/nosql/variables.tf create mode 100644 api-gateway-function-nosql-table/terraform/outputs.tf create mode 100644 api-gateway-function-nosql-table/terraform/provider.tf create mode 100644 api-gateway-function-nosql-table/terraform/terraform.tfvars create mode 100644 api-gateway-function-nosql-table/terraform/variables.tf diff --git a/api-gateway-function-nosql-table/README.md b/api-gateway-function-nosql-table/README.md new file mode 100644 index 0000000..9f09a18 --- /dev/null +++ b/api-gateway-function-nosql-table/README.md @@ -0,0 +1,260 @@ +# API Gateway Function NoSQL Table + +This project demonstrates a synchronous CRUD pattern using Oracle Cloud Infrastructure (OCI) services: + +- **API Gateway**: Receives HTTP requests and routes them to functions +- **OCI Functions**: Serverless functions for processing requests +- **OCI NoSQL**: Low-latency NoSQL database for storing customer data + +## Architecture + +The application follows a synchronous request/response pattern: + +1. HTTP request arrives at API Gateway → `/customer` endpoint +2. API Gateway routes to **customer-info OCI Function** +3. Function reads or writes customer data to/from **OCI NoSQL Table** +4. Function returns JSON response immediately + +``` +HTTP Request → API Gateway → customer-info Function → NoSQL Table + ↑↓ + (Sync Read/Write) +``` + +## Components + +### API Gateway +- Receives HTTP requests at `/customer` endpoint +- Routes GET and POST requests to the `customer-info` function + +### Functions +- **customer-info**: OCI Function (Go) that handles customer CRUD operations via API Gateway, reading and writing records to the NoSQL table + +### NoSQL Table +- **customer_info**: Stores customer records with fields: `customerId`, `name`, `address`, `email`, `phone` +- Provides low-latency key-value access for serverless workloads + +## Directory Structure + +``` +api-gateway-function-nosql-table/ +├── README.md # Project documentation +├── functions/ # Application components +│ └── customer/ # OCI Function for customer CRUD +└── terraform/ # Infrastructure as Code + └── modules/ # Reusable Terraform modules + ├── apigateway/ # API Gateway module + ├── container_repository/ # OCI Container Registry module + ├── functions/ # OCI Functions module + └── nosql/ # OCI NoSQL Table module +``` + +## Prerequisites + +Before you begin, ensure you have the following: + +- **OCI Account**: Active Oracle Cloud Infrastructure account with appropriate compartment access +- **Terraform**: Version 1.10.0 or higher installed on your local machine +- **Docker**: Docker Desktop or equivalent for building and pushing container images +- **OCI CLI**: Configured with your OCI credentials for authentication +- **Network**: A public subnet in your VCN for the API Gateway with port 443 opened via security list +- **IAM Permissions**: Your OCI user must have permissions to: + - Create API Gateways + - Create and manage OCI Functions + - Create and manage OCI NoSQL tables + - Create Container Registries + - Manage IAM policies and dynamic groups +- **Authentication**: OCI auth token for Docker Container Registry access + +## Getting Started + +1. **Configure OCI Variables**: + + Update `terraform/terraform.tfvars` with your OCI configuration. Provide your information for `region`, `tenancy_ocid`, `compartment_ocid`, and `subnet_ocid`: + ```hcl + region = "us-ashburn-1" # Your OCI region + tenancy_ocid = "ocid1.tenancy.oc1..." # Your tenancy OCID + compartment_ocid = "ocid1.compartment.oc1..." # Your compartment OCID + subnet_ocid = "ocid1.subnet.oc1..." # Your public subnet OCID + ... + ``` + +2. **Deploy Infrastructure**: + ```bash + cd terraform + terraform init + terraform apply -var-file=terraform.tfvars + ``` + + **Note**: After successful deployment, note the OCIR repository address from the Terraform output: + - `repository_path`: Container registry path for the customer-info function + + This will be used in the next step for building and pushing the Docker image. + +3. **Build and Deploy Customer-Info Image**: + ```bash + cd functions/customer + docker build -t customer-info:1 . + docker tag customer-info:1 :1 + docker push :1 + ``` + +4. **Update Terraform Variables with Image Tag**: + + Update `terraform/terraform.tfvars` to add the function image URI you just pushed: + ```hcl + functions = { + "customer_info" = { + source_image = ":1" + path = "/customer" + } + } + ``` + +5. **Re-apply Terraform Configuration**: + + Apply the updated configuration with the new image tag: + ```bash + cd terraform + terraform apply -var-file=terraform.tfvars + ``` + + This will deploy the OCI Function with the container image you just built and pushed. + + + +## Components + +### API Gateway +- Receives HTTP requests at `/customer` endpoint +- Routes GET and POST requests to the `customer-info` function + +### Functions +- **customer-info**: OCI Function (Go) that handles customer CRUD operations via API Gateway, reading and writing records to the NoSQL table + +### NoSQL Table +- **customer_info**: Stores customer records with fields: `customerId`, `name`, `address`, `email`, `phone` +- Provides low-latency key-value access for serverless workloads + +## Directory Structure + +``` +api-gateway-function-nosql-table/ +├── README.md # Project documentation +├── functions/ # Application components +│ └── customer/ # OCI Function for customer CRUD +└── terraform/ # Infrastructure as Code + └── modules/ # Reusable Terraform modules + ├── apigateway/ # API Gateway module + ├── container_repository/ # OCI Container Registry module + ├── functions/ # OCI Functions module + └── nosql/ # OCI NoSQL Table module +``` + +## Prerequisites + +Before you begin, ensure you have the following: + +- **OCI Account**: Active Oracle Cloud Infrastructure account with appropriate compartment access +- **Terraform**: Version 1.10.0 or higher installed on your local machine +- **Docker**: Docker Desktop or equivalent for building and pushing container images +- **OCI CLI**: Configured with your OCI credentials for authentication +- **Network**: A public subnet in your VPC for the API Gateway +- **IAM Permissions**: Your OCI user must have permissions to: + - Create API Gateways + - Create and manage OCI Functions + - Create and manage OCI NoSQL tables + - Create Container Registries + - Manage IAM policies and dynamic groups +- **Authentication**: OCI auth token for Docker Container Registry access + +## Getting Started + +1. **Configure OCI Variables**: + + Update `terraform/terraform.tfvars` with your OCI configuration: + ```hcl + region = "us-ashburn-1" # Your OCI region + compartment_ocid = "ocid1.compartment.oc1..." # Your compartment OCID + subnet_ocid = "ocid1.subnet.oc1..." # Your public subnet OCID + nosql_table_name = "customer_info" + container_repository_name = "customer_info_repo" + application_display_name = "customer_info_app" + functions = { + "customer_info" = { + source_image = null + path = "/customer" + } + } + ``` + +2. **Deploy Infrastructure**: + ```bash + cd terraform + terraform init + terraform apply -var-file=terraform.tfvars + ``` + + **Note**: After successful deployment, note the OCIR repository address from the Terraform output: + - `repository_path`: Container registry path for the customer-info function + + This will be used in the next step for building and pushing the Docker image. + +3. **Build and Deploy Customer-Info Image**: + ```bash + cd functions/customer + docker build -t customer-info:1 . + docker tag customer-info:1 :1 + docker push :1 + ``` + +4. **Update Terraform Variables with Image Tag**: + + Update `terraform/terraform.tfvars` to add the function image URI you just pushed: + ```hcl + functions = { + "customer_info" = { + source_image = ":1" + path = "/customer" + } + } + ``` + +5. **Re-apply Terraform Configuration**: + + Apply the updated configuration with the new image tag: + ```bash + cd terraform + terraform apply -var-file=terraform.tfvars + ``` + + This will deploy the OCI Function with the container image you just built and pushed. The `api_gateway_endpoint` will be printed in the Terraform output — save this URL for the next step. + +6. **Test the API**: + + Create a customer record: + ```bash + curl -X POST /customer \ + -H "Content-Type: application/json" \ + -d '{ + "data": { + "id": "CUST-001", + "name": "Jane Doe", + "address": "123 Main St", + "email": "jane@example.com", + "phone": "555-1234" + } + }' + ``` + + Retrieve a customer record: + ```bash + curl -X GET "/customer?id=CUST-001" + ``` + +## Benefits + +- **Simplicity**: Synchronous request/response pattern is easy to reason about and debug +- **Low Latency**: Direct NoSQL access returns results in the same request cycle +- **Scalability**: Serverless functions scale automatically with incoming traffic +- **Cost Efficiency**: Pay-per-use pricing for both Functions and NoSQL diff --git a/api-gateway-function-nosql-table/functions/customer/Dockerfile b/api-gateway-function-nosql-table/functions/customer/Dockerfile new file mode 100644 index 0000000..746d821 --- /dev/null +++ b/api-gateway-function-nosql-table/functions/customer/Dockerfile @@ -0,0 +1,11 @@ +FROM fnproject/go:1.24-dev as build-stage +WORKDIR /function +WORKDIR /go/src/func/ +ENV GO111MODULE=on +COPY . . +RUN go mod tidy +RUN go build -o func -v +FROM fnproject/go:1.24 +WORKDIR /function +COPY --from=build-stage /go/src/func/func /function/ +ENTRYPOINT ["./func"] \ No newline at end of file diff --git a/api-gateway-function-nosql-table/functions/customer/func.go b/api-gateway-function-nosql-table/functions/customer/func.go new file mode 100644 index 0000000..fe2178a --- /dev/null +++ b/api-gateway-function-nosql-table/functions/customer/func.go @@ -0,0 +1,254 @@ +package main + +import ( + "context" + "encoding/json" + "fmt" + "io" + "log" + "net/url" + "os" + + fdk "github.com/fnproject/fdk-go" + "github.com/oracle/nosql-go-sdk/nosqldb" + "github.com/oracle/nosql-go-sdk/nosqldb/auth/iam" + "github.com/oracle/nosql-go-sdk/nosqldb/common" + "github.com/oracle/nosql-go-sdk/nosqldb/types" +) + +type CustomerInfo struct { + ID string `json:"id"` + Name string `json:"name"` + Address string `json:"address"` + Email string `json:"email"` + Phone string `json:"phone"` +} + +type Request struct { + Method string `json:"method"` + Data json.RawMessage `json:"data"` +} + +func main() { + fdk.Handle(fdk.HandlerFunc(myHandler)) +} + +// myHandler dispatches requests based on the method specified in the request body. +func myHandler(ctx context.Context, in io.Reader, out io.Writer) { + httpCtx, ok := fdk.GetContext(ctx).(fdk.HTTPContext) + if !ok { + fdk.WriteStatus(out, 400) + fdk.SetHeader(out, "Content-Type", "application/json") + io.WriteString(out, `{"error":"function not invoked via http trigger","status":400}`) + return + } + + client, err := setupNoSQLClient() + if err != nil { + log.Printf("Failed to setup NoSQL client: %v", err) + httpError(out, "Internal error", 500, err) + return + } + defer client.Close() + + tableName := getTableName() + + switch httpCtx.RequestMethod() { + case "GET": + requestURL := httpCtx.RequestURL() + if requestURL == "" { + httpError(out, "Request URL is empty", 400, nil) + return + } + + parsedURL, err := url.Parse(requestURL) + if err != nil { + log.Printf("Failed to parse request URL: %v", err) + httpError(out, "Invalid request URL", 400, err) + return + } + + customerID := parsedURL.Query().Get("id") + if customerID == "" { + log.Printf("Missing required query parameter: id") + httpError(out, "Missing required query parameter: id", 400, nil) + return + } + handleGetRequest(ctx, customerID, out, client, tableName) + case "POST": + var req Request + if err := json.NewDecoder(in).Decode(&req); err != nil { + log.Printf("Failed to parse request: %v", err) + httpError(out, "Invalid input", 400, err) + return + } + handlePostRequest(ctx, req.Data, out, client, tableName) + default: + err := fmt.Errorf("unsupported HTTP method: %s", httpCtx.RequestMethod()) + log.Printf("%v", err) + httpError(out, "Method not allowed", 405, err) + } +} + +// setupNoSQLClient initializes the Oracle NoSQL client with resource principal authentication. +func setupNoSQLClient() (*nosqldb.Client, error) { + provider, err := iam.NewSignatureProviderWithResourcePrincipal(os.Getenv("COMPARTMENT_ID")) + if err != nil { + return nil, fmt.Errorf("failed to create resource principal provider: %w", err) + } + cfg := nosqldb.Config{ + Region: common.Region(os.Getenv("OCI_REGION")), + AuthorizationProvider: provider, + } + client, err := nosqldb.NewClient(cfg) + if err != nil { + return nil, fmt.Errorf("failed to create NoSQL client: %w", err) + } + return client, nil +} + +// getTableName retrieves the table name from environment or returns default. +func getTableName() string { + tableName := os.Getenv("NOSQL_TABLE_NAME") + if tableName == "" { + return "customer_info" + } + return tableName +} + +// parseGetRequest parses the input for a GET request from the request body. +func parseGetRequest(in []byte) (string, error) { + var req struct { + ID string `json:"id"` + } + if len(in) > 0 { + if err := json.Unmarshal(in, &req); err != nil { + return "", fmt.Errorf("failed to parse input: %w", err) + } + } + if req.ID == "" { + req.ID = "123" // fallback or default + } + return req.ID, nil +} + +// parsePostRequest parses the input for a POST request, returning the CustomerInfo. +func parsePostRequest(in []byte) (CustomerInfo, error) { + var info CustomerInfo + if err := json.Unmarshal(in, &info); err != nil { + return CustomerInfo{}, fmt.Errorf("failed to parse input: %w", err) + } + if info.ID == "" { + return CustomerInfo{}, fmt.Errorf("customer ID is required") + } + return info, nil +} + +// getCustomer retrieves a customer record from the NoSQL database by ID. +func getCustomer(client *nosqldb.Client, tableName, customerID string) (CustomerInfo, error) { + key := &types.MapValue{} + key.Put("customerId", customerID) + + getReq := &nosqldb.GetRequest{ + TableName: tableName, + Key: key, + } + getRes, err := client.Get(getReq) + if err != nil { + return CustomerInfo{}, fmt.Errorf("failed to get row: %w", err) + } + if !getRes.RowExists() { + return CustomerInfo{}, fmt.Errorf("customer not found for id: %s", customerID) + } + + var info CustomerInfo + b, err := json.Marshal(getRes.Value.Map()) + if err != nil { + return CustomerInfo{}, fmt.Errorf("failed to marshal result: %w", err) + } + if err := json.Unmarshal(b, &info); err != nil { + return CustomerInfo{}, fmt.Errorf("failed to unmarshal result: %w", err) + } + return info, nil +} + +// putCustomer inserts or updates a customer record in the NoSQL database. +func putCustomer(client *nosqldb.Client, tableName string, info CustomerInfo) error { + row := &types.MapValue{} + row.Put("customerId", info.ID) + row.Put("id", info.ID) + row.Put("name", info.Name) + row.Put("address", info.Address) + row.Put("email", info.Email) + row.Put("phone", info.Phone) + + putReq := &nosqldb.PutRequest{ + TableName: tableName, + Value: row, + } + _, err := client.Put(putReq) + if err != nil { + return fmt.Errorf("failed to put row: %w", err) + } + return nil +} + +// handleGetRequest processes GET requests to retrieve customer data. +func handleGetRequest(ctx context.Context, customerID string, out io.Writer, client *nosqldb.Client, tableName string) { + + info, err := getCustomer(client, tableName, customerID) + if err != nil { + log.Printf("%v", err) + if err.Error() == fmt.Sprintf("customer not found for id: %s", customerID) { + httpError(out, "Customer not found", 404, err) + } else { + httpError(out, "Internal error", 500, err) + } + return + } + + writeSuccessResponse(out, info) +} + +// handlePostRequest processes POST requests to create or update customer data. +func handlePostRequest(ctx context.Context, in []byte, out io.Writer, client *nosqldb.Client, tableName string) { + info, err := parsePostRequest(in) + if err != nil { + log.Printf("%v", err) + httpError(out, "Invalid input", 400, err) + return + } + + if err := putCustomer(client, tableName, info); err != nil { + log.Printf("%v", err) + httpError(out, "Internal error", 500, err) + return + } + + writeSuccessResponse(out, map[string]interface{}{ + "message": "Customer created or updated successfully", + "data": info, + }) +} + +// writeSuccessResponse writes a JSON success response to the output. +func writeSuccessResponse(out io.Writer, data interface{}) { + if err := json.NewEncoder(out).Encode(data); err != nil { + log.Printf("failed to write response: %v", err) + } +} + +// httpError writes a JSON error response to the output. +func httpError(out io.Writer, msg string, code int, err error) { + errMsg := "" + if err != nil { + errMsg = err.Error() + } + if err := json.NewEncoder(out).Encode(map[string]interface{}{ + "error": msg, + "status": code, + "details": errMsg, + }); err != nil { + log.Printf("failed to write error response: %v", err) + } +} diff --git a/api-gateway-function-nosql-table/functions/customer/func.yaml b/api-gateway-function-nosql-table/functions/customer/func.yaml new file mode 100644 index 0000000..281f22e --- /dev/null +++ b/api-gateway-function-nosql-table/functions/customer/func.yaml @@ -0,0 +1,8 @@ +schema_version: 20180708 +name: get-customer-info +version: 0.0.1 +description: Get customer information (GET) +runtime: go +build_image: fnproject/go:1.24-dev +run_image: fnproject/go:1.24 +entrypoint: ./func.go \ No newline at end of file diff --git a/api-gateway-function-nosql-table/functions/customer/go.mod b/api-gateway-function-nosql-table/functions/customer/go.mod new file mode 100644 index 0000000..81cd53d --- /dev/null +++ b/api-gateway-function-nosql-table/functions/customer/go.mod @@ -0,0 +1,2 @@ +module func +require github.com/fnproject/fdk-go v0.0.60 \ No newline at end of file diff --git a/api-gateway-function-nosql-table/terraform/data.tf b/api-gateway-function-nosql-table/terraform/data.tf new file mode 100644 index 0000000..1c19704 --- /dev/null +++ b/api-gateway-function-nosql-table/terraform/data.tf @@ -0,0 +1,12 @@ +data "oci_identity_tenancy" "home" { + tenancy_id = var.tenancy_ocid +} + +data "oci_identity_regions" "current" { + filter { + name = "name" + values = [var.region] + } +} + +data "oci_objectstorage_namespace" "this" {} diff --git a/api-gateway-function-nosql-table/terraform/main.tf b/api-gateway-function-nosql-table/terraform/main.tf new file mode 100644 index 0000000..79b8bf5 --- /dev/null +++ b/api-gateway-function-nosql-table/terraform/main.tf @@ -0,0 +1,80 @@ +locals { + function_configs = { + COMPARTMENT_ID = var.compartment_ocid + OCI_REGION = var.region + NOSQL_TABLE_NAME = var.nosql_table_name + } +} + +module "apigateway" { + source = "./modules/apigateway" + compartment_id = var.compartment_ocid + subnet_id = var.subnet_ocid +} + +module "nosql" { + source = "./modules/nosql" + compartment_id = var.compartment_ocid + nosql_table_name = var.nosql_table_name +} + +resource "oci_functions_application" "customer_info_app" { + compartment_id = var.compartment_ocid + display_name = var.application_display_name + subnet_ids = [var.subnet_ocid] + shape = "GENERIC_ARM" +} + +module "functions" { + source = "./modules/functions" + for_each = { for name, f in var.functions : name => f if f.source_image != null } + function_name = each.key + application_id = oci_functions_application.customer_info_app.id + path = each.value.path + source_image = each.value.source_image + compartment_id = var.compartment_ocid + region = var.region + apigw_id = module.apigateway.gateway_id + function_config = local.function_configs + +} + +resource "oci_identity_policy" "function_nosql_policy" { + compartment_id = var.compartment_ocid + description = "Allows function applications to use NoSQL tables in compartment ${var.compartment_ocid}" + name = "function_nosql_access" + statements = [ + "Allow dynamic-group function_dynamic_group to manage nosql-family in compartment id ${var.compartment_ocid}" + ] + depends_on = [oci_identity_dynamic_group.function_dynamic_group] +} + +resource "oci_identity_policy" "apigw_function_policy" { + compartment_id = var.compartment_ocid + description = "Allows API Gateways to use functions in compartment ${var.compartment_ocid}" + name = "apigw_function_access" + statements = [ + "Allow dynamic-group apigw_dynamic_group to manage functions-family in compartment id ${var.compartment_ocid}" + ] + depends_on = [oci_identity_dynamic_group.apigw_dynamic_group] +} + +resource "oci_identity_dynamic_group" "function_dynamic_group" { + compartment_id = var.tenancy_ocid + description = "Dynamic group containing all functions in compartment ${var.compartment_ocid}" + matching_rule = "ALL {resource.type = 'fnfunc', resource.compartment.id = '${var.compartment_ocid}'}" + name = "function_dynamic_group" +} + +resource "oci_identity_dynamic_group" "apigw_dynamic_group" { + compartment_id = var.tenancy_ocid + description = "Dynamic group containing all API Gateways in compartment ${var.compartment_ocid}" + matching_rule = "ALL {resource.type = 'ApiGateway', resource.compartment.id = '${var.compartment_ocid}'}" + name = "apigw_dynamic_group" +} + +module "container_repository" { + source = "./modules/container_repository" + compartment_id = var.compartment_ocid + container_repository_name = var.container_repository_name +} diff --git a/api-gateway-function-nosql-table/terraform/modules/apigateway/main.tf b/api-gateway-function-nosql-table/terraform/modules/apigateway/main.tf new file mode 100644 index 0000000..48c1d92 --- /dev/null +++ b/api-gateway-function-nosql-table/terraform/modules/apigateway/main.tf @@ -0,0 +1,10 @@ +resource "oci_apigateway_gateway" "main" { + compartment_id = var.compartment_id + display_name = "main-gateway" + endpoint_type = "PUBLIC" + subnet_id = var.subnet_id +} + +output "gateway_id" { + value = oci_apigateway_gateway.main.id +} diff --git a/api-gateway-function-nosql-table/terraform/modules/apigateway/variables.tf b/api-gateway-function-nosql-table/terraform/modules/apigateway/variables.tf new file mode 100644 index 0000000..ab0dd28 --- /dev/null +++ b/api-gateway-function-nosql-table/terraform/modules/apigateway/variables.tf @@ -0,0 +1,9 @@ +variable "compartment_id" { + description = "The OCID of the compartment." + type = string +} + +variable "subnet_id" { + description = "The OCID of the subnet." + type = string +} diff --git a/api-gateway-function-nosql-table/terraform/modules/container_repository/main.tf b/api-gateway-function-nosql-table/terraform/modules/container_repository/main.tf new file mode 100644 index 0000000..f685500 --- /dev/null +++ b/api-gateway-function-nosql-table/terraform/modules/container_repository/main.tf @@ -0,0 +1,9 @@ +resource "oci_artifacts_container_repository" "container_repo" { + compartment_id = var.compartment_id + display_name = var.container_repository_name + is_public = false +} + +output "container_repository_id" { + value = oci_artifacts_container_repository.container_repo.id +} diff --git a/api-gateway-function-nosql-table/terraform/modules/container_repository/variables.tf b/api-gateway-function-nosql-table/terraform/modules/container_repository/variables.tf new file mode 100644 index 0000000..03b5b9b --- /dev/null +++ b/api-gateway-function-nosql-table/terraform/modules/container_repository/variables.tf @@ -0,0 +1,9 @@ +variable "compartment_id" { + description = "The OCID of the compartment." + type = string +} + +variable "container_repository_name" { + description = "The name of the OCI Container Repository." + type = string +} diff --git a/api-gateway-function-nosql-table/terraform/modules/functions/main.tf b/api-gateway-function-nosql-table/terraform/modules/functions/main.tf new file mode 100644 index 0000000..500a225 --- /dev/null +++ b/api-gateway-function-nosql-table/terraform/modules/functions/main.tf @@ -0,0 +1,29 @@ +resource "oci_functions_function" "fn" { + display_name = var.function_name + application_id = var.application_id + image = var.source_image + memory_in_mbs = 128 + config = var.function_config +} + +resource "oci_apigateway_deployment" "customer_info" { + compartment_id = var.compartment_id + gateway_id = var.apigw_id + display_name = var.function_name + path_prefix = "/api" + + specification { + routes { + path = var.path + methods = ["GET", "POST"] + backend { + type = "ORACLE_FUNCTIONS_BACKEND" + function_id = oci_functions_function.fn.id + } + } + } +} + +output "deployment_endpoint" { + value = oci_apigateway_deployment.customer_info.endpoint +} diff --git a/api-gateway-function-nosql-table/terraform/modules/functions/variables.tf b/api-gateway-function-nosql-table/terraform/modules/functions/variables.tf new file mode 100644 index 0000000..6054308 --- /dev/null +++ b/api-gateway-function-nosql-table/terraform/modules/functions/variables.tf @@ -0,0 +1,46 @@ +variable "function_name" { + description = "The name of the function." + type = string +} + +variable "application_id" { + description = "The OCID of the Functions application." + type = string +} + +variable "source_image" { + description = "The source image for the function." + type = string +} + +variable "compartment_id" { + description = "The OCID of the compartment." + type = string +} + +variable "region" { + description = "The OCI region." + type = string +} + + +variable "path" { + description = "The API Gateway path for the function route." + type = string + default = null +} + +variable "apigw_id" { + description = "The OCID of the API Gateway." + type = string + default = null +} + +variable "function_config" { + type = map(string) + # default = { + # COMPARTMENT_ID = "" + # OCI_REGION = "" + # NOSQL_TABLE_NAME = "" + # } +} diff --git a/api-gateway-function-nosql-table/terraform/modules/nosql/main.tf b/api-gateway-function-nosql-table/terraform/modules/nosql/main.tf new file mode 100644 index 0000000..705e047 --- /dev/null +++ b/api-gateway-function-nosql-table/terraform/modules/nosql/main.tf @@ -0,0 +1,24 @@ + +resource "oci_nosql_table" "customer_info" { + compartment_id = var.compartment_id + name = var.nosql_table_name + table_limits { + max_read_units = 50 + max_write_units = 50 + max_storage_in_gbs = 1 + } + ddl_statement = < m.deployment_endpoint } +} diff --git a/api-gateway-function-nosql-table/terraform/provider.tf b/api-gateway-function-nosql-table/terraform/provider.tf new file mode 100644 index 0000000..06ebaa2 --- /dev/null +++ b/api-gateway-function-nosql-table/terraform/provider.tf @@ -0,0 +1,11 @@ +terraform { + required_version = ">= 1.10.0" + required_providers { + oci = { + source = "oracle/oci" + version = ">= 7.14.0" + } + } +} + +provider "oci" {} diff --git a/api-gateway-function-nosql-table/terraform/terraform.tfvars b/api-gateway-function-nosql-table/terraform/terraform.tfvars new file mode 100644 index 0000000..80c769e --- /dev/null +++ b/api-gateway-function-nosql-table/terraform/terraform.tfvars @@ -0,0 +1,11 @@ +region = "us-ashburn-1" +tenancy_ocid = "ocid1.tenancy.oc1..exampleuniqueID" +compartment_ocid = "ocid1.compartment.oc1..exampleuniqueID" +subnet_ocid = "ocid1.subnet.oc1..exampleuniqueID" +functions = { + "customer_info" = { + # This function will be SKIPPED because its source_image is null. + source_image = null #Change this to image name after uploading image to OCIR + path = "/customer" + } +} diff --git a/api-gateway-function-nosql-table/terraform/variables.tf b/api-gateway-function-nosql-table/terraform/variables.tf new file mode 100644 index 0000000..d24c172 --- /dev/null +++ b/api-gateway-function-nosql-table/terraform/variables.tf @@ -0,0 +1,50 @@ + +variable "tenancy_ocid" { + default = "ocid1.tenancy.oc1..exampleuniqueID" +} + +variable "region" { + default = "us-ashburn-1" +} + +variable "compartment_ocid" { + default = "ocid1.compartment.oc1..exampleuniqueID" +} + +variable "subnet_ocid" { + default = "ocid1.subnet.oc1..exampleuniqueID" +} + +variable "nosql_table_name" { + default = "customer_info" +} + +variable "container_repository_name" { + description = "Name of the OCI Container Repository" + default = "customer_info_repo" +} + +variable "application_display_name" { + description = "Name of function application" + default = "customer_info_app" +} + + +variable "functions" { + description = "A map of function configurations. The key is the function name." + type = map(object({ + source_image = optional(string, null) + path = optional(string, null) + + })) + default = { + "get_customer_info" = { + # This function will be SKIPPED because its source_image is null. + source_image = null #Change this to image name after uploading image to OCIR + path = "/customer" + } + } +} + + +