Deploy FunctionGraph Event Function from OBS

This sample demonstrates how to deploy a simple event function to FunctionGraph with code from OBS using Terraform.

This approach is used, if your unpacked FunctionGraph deployment package is less than 40MB.

Source code of this sample is available on GitHub.

Prerequisites

  • running on Linux / Windows Subsystem for Linux (WSL)

  • make installed

  • Terraform installed and configured, see Terraform Setup.

Example

An example for deploying a HTTP Function using Terraform can be found in: samples-doc/http_minimalWebAPI/terraform.

This example deploys a minimal C# HTTP Function and demonstrates how to:

  • upload the Function code as zip file to an OBS bucket (and update on changes), see: code_from_obs_bucket.tf

    ###################################################################################
    # Code bucket to store function code zip file
    ###################################################################################
    resource "opentelekomcloud_obs_bucket" "codebucket" {
      bucket = format("%s-%s", var.prefix, "codebucket")
      acl    = "private"
    
      tags = {
        "app_group" = var.tag_app_group
      }
    }
    
    ###################################################################################
    # Code bucket object to upload function code zip file
    ###################################################################################
    resource "opentelekomcloud_obs_bucket_object" "code_object" {
      bucket       = opentelekomcloud_obs_bucket.codebucket.bucket
      key          = format("%s/%s", "code", basename(var.zip_file_local))
      source       = var.zip_file_local
      etag         = filemd5(var.zip_file_local)
      content_type = "application/zip"
    }
    
  • create the Function using the code from the OBS bucket, see: function.tf

    ##########################################################
    # Create Function
    ##########################################################
    resource "opentelekomcloud_fgs_function_v2" "MyFunction" {
      depends_on = [opentelekomcloud_obs_bucket_object.code_object]
      name       = format("%s_%s", var.prefix, var.function_name)
      app        = "default"
    
      handler = var.function_handler_name
    
      description      = "Minimal WebAPI deployed with terraform."
      memory_size      = 256
      timeout          = 30
      max_instance_num = 10
    
      runtime = var.function_runtime
    
      user_data = jsonencode({
        "USE_SWAGGER_UI" = var.use_swagger_ui
      })
    
    
      ###### relevant part for deploy function code from obs file ######
      code_type = "obs"
      code_url = format("https://%s/%s/%s",
        opentelekomcloud_obs_bucket.codebucket.bucket_domain_name,
        "code",
        basename(var.zip_file_local)
      )
      # on change of the code object etag (hash) new code  version will be deployed.
      source_code_hash = opentelekomcloud_obs_bucket_object.code_object.etag
      ###### ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ######
    
      log_group_id   = opentelekomcloud_lts_group_v2.MyLogGroup.id
      log_group_name = opentelekomcloud_lts_group_v2.MyLogGroup.group_name
    
      log_topic_id   = opentelekomcloud_lts_stream_v2.MyLogStream.id
      log_topic_name = opentelekomcloud_lts_stream_v2.MyLogStream.stream_name
    
    
      tags = {
        "app_group" = var.tag_app_group
      }
    }
    
    output "MY_FUNCTION_URN" {
      value = opentelekomcloud_fgs_function_v2.MyFunction.urn
    }
    
    output "MY_FUNCTION_VERSION" {
      value = opentelekomcloud_fgs_function_v2.MyFunction.version
    }
    
  • configure the API Trigger for the Function using

    • API-Group,

    • API and

    • publishment to an environment,

    locals {
      API_GATEWAY_INSTANCE_ID = var.API_GATEWAY_INSTANCE_ID
      ENV_NAME                = "RELEASE"
      ENV_ID                  = "DEFAULT_ENVIRONMENT_RELEASE_ID"
    }
    
    ##########################################################
    # opentelekomcloud_apigw_group_v2.group
    ##########################################################
    resource "opentelekomcloud_apigw_group_v2" "group1" {
      # depends_on = [ opentelekomcloud_fgs_function_v2.MyFunction ]
      name        = replace(format("%s_%s_api_group", var.prefix, var.function_name), "-", "_")
      instance_id = local.API_GATEWAY_INSTANCE_ID
      description = format("API Group for %s, %s", var.prefix, var.function_name)
    }
    
    ##########################################################
    # opentelekomcloud_apigw_api_v2.api1
    # This is used to create the API Gateway trigger for the
    # FunctionGraph function.
    ##########################################################
    resource "opentelekomcloud_apigw_api_v2" "api1" {
    
      # TRIGGER-INSTANCE_id
      gateway_id = local.API_GATEWAY_INSTANCE_ID
    
      # TRIGGER-GROUP_id
      group_id = opentelekomcloud_apigw_group_v2.group1.id
    
      # TRIGGER-Name
      name = replace(format("%s_%s_apig_trigger", var.prefix, var.function_name), "-", "_")
    
      # TRIGGER-TYPE:1
      type = "Public"
    
      # TRIGGER-PROTOCOL: HTTPS
      request_protocol = "HTTPS"
    
      # TRIGGER-REG_METHOD: HTTPS
      request_method = "ANY"
    
      # TRIGGER-PATH
      request_uri = "/"
    
      # TRIGGER-AUTH: NONE
      security_authentication_type = "NONE"
    
      # TRIGGER-MATCH_MODE: SWA
      match_mode       = "PREFIX"
    
      success_response = "Success response"
      failure_response = "Failed response"
      description      = format("Created by script for %s-%s", var.prefix, var.function_name)
    
      func_graph {
        function_urn    = opentelekomcloud_fgs_function_v2.MyFunction.urn
        version         = "latest"
        timeout         = 5000
        invocation_type = "sync"
        network_type    = "NON-VPC"
      }
    
    }
    
    ##########################################################
    # Publish API to specific environment
    ##########################################################
    resource "opentelekomcloud_apigw_api_publishment_v2" "default" {
      gateway_id     = local.API_GATEWAY_INSTANCE_ID
      environment_id = local.ENV_ID
      api_id         = opentelekomcloud_apigw_api_v2.api1.id
      version_id     = opentelekomcloud_apigw_api_v2.api1.version
    
      # force publishing on change of api
      lifecycle {
        replace_triggered_by = [
          opentelekomcloud_apigw_api_v2.api1
        ]
      }
    }
    
    output "API_GATEWAY_TRIGGER_URL" {
      description = "The URL of the API Gateway triggering the FunctionGraph function"
      value       = format("https://%s.apic.%s.otc.t-systems.com", 
                    opentelekomcloud_apigw_group_v2.group1.id , 
                    opentelekomcloud_apigw_group_v2.group1.region)
      
    }
    
    output "SWAGGER_UI_URL" {
      description = "The URL for Swagger UI to test the API endpoints"
      value       = var.use_swagger_ui == "true" ? format("https://%s.apic.%s.otc.t-systems.com/swagger/index.html", 
                    opentelekomcloud_apigw_group_v2.group1.id , 
                    opentelekomcloud_apigw_group_v2.group1.region) : "Swagger UI is disabled"
      
    }
    
  • configure logging for the Function using LTS Log Group and Log Stream, see loggroup.tf

    ##########################################################
    # Create Log Group
    ##########################################################
    resource "opentelekomcloud_lts_group_v2" "MyLogGroup" {
      group_name  = format("%s_%s_%s", var.prefix, var.function_name, "log_group")
      ttl_in_days = 1
    
      tags = {
        "app_group" = var.tag_app_group
      }
    }
    
    ##########################################################
    # Create Log Stream
    ##########################################################
    resource "opentelekomcloud_lts_stream_v2" "MyLogStream" {
      group_id    = opentelekomcloud_lts_group_v2.MyLogGroup.id
      stream_name = format("%s_%s_%s", var.prefix, var.function_name, "log_stream")
    
      tags = {
        "app_group" = var.tag_app_group
      }
    }
    
  • configure test events for the Function to be used in the Function Graph console, see func_testevents.tf

    ##########################################################
    # Create Test Event
    ##########################################################
    resource "opentelekomcloud_fgs_event_v2" "apievent_hello" {
      function_urn = opentelekomcloud_fgs_function_v2.MyFunction.urn
      name         = "hello-event"
      content      = filebase64("${path.module}/../resources/apievent_hello.json")
    }
    
    ##########################################################
    # Create Test Event
    ##########################################################
    resource "opentelekomcloud_fgs_event_v2" "apievent_root" {
      function_urn = opentelekomcloud_fgs_function_v2.MyFunction.urn
      name         = "root-event"
      content      = filebase64("${path.module}/../resources/apievent_root.json")
    }
    

To deploy the HTTP Function using Terraform follow these steps:

  1. Create an API Gateway or use an existing one. (Creating an API Gateway is not part of this Terraform setup.) See Creating a Gateway for instructions on how to create an API Gateway. Note down the instance ID to be used in Terraform configuration.

  2. Adjust the http.tfvars file according to your needs.

    Set the API_GATEWAY_INSTANCE_ID variable to your API Gateway instance ID (or define it as environment variable TF_VAR_API_GATEWAY_INSTANCE_ID).

    # Terraform variables for http_minimalWebAPI sample
    
    # prefix of all resources
    prefix="csharp" 
    
    # name of the function (will be prefixed)
    function_name="doc-sample-minimal-webapi"
    
    # function handler name, for http functions always "bootstrap"
    function_handler_name="bootstrap"
    
    # function runtime, for http functions always "http"
    function_runtime="http"
    
    # path to local zip file to be deployed
    zip_file_local="../src/http_minimalWebAPI_net8.0.zip"
    
    # resources will be tagged with this app_group tag
    tag_app_group="csharp-doc-sample-minimal-webapi"
    
    # change to your API Gateway instance ID
    # set as env var TF_VAR_API_GATEWAY_INSTANCE_ID or uncomment and set here
    #API_GATEWAY_INSTANCE_ID="YOUR_API_GATEWAY_INSTANCE_ID"
    
  3. Create a Makefile in the project folder and adjust the variables in the Makefile according to your needs:

    mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))/..
    current_dir := $(notdir $(patsubst %/,%,$(dir $(mkfile_path))))
    
    BACKEND_CONFIG_BUCKET := "doc-samples-tf-backend"
    BACKEND_CONFIG_KEY := "terraform_state/csharp/http_minimalWebAPI.tf"
    BACKEND_CONFIG_REGION := "eu-de"
    BACKEND_CONFIG_ENDPOINTS := "endpoints={s3=\"https://obs.eu-de.otc.t-systems.com\"}"
    
    clean:
    	rm -f $(mkfile_path)/src/*.zip
    	rm -rf $(mkfile_path)/src/bin 
    	rm -rf $(mkfile_path)/src/obj
    
    build:
    	dotnet build
    
    all: build
    
    release: 
    	dotnet publish -c Release
    
    initTerraform:
    	terraform -chdir=terraform \
    	  init \
    	  -backend-config=$(BACKEND_CONFIG_ENDPOINTS) \
    	  -backend-config="bucket=$(BACKEND_CONFIG_BUCKET)" \
    	  -backend-config="key=$(BACKEND_CONFIG_KEY)" \
    	  -backend-config="region=$(BACKEND_CONFIG_REGION)"
    
    plan: release
    	if [ ! -f "terraform/.terraform.lock.hcl" ]; then \
    		$(MAKE) initTerraform; \
    	fi
    	terraform -chdir=terraform \
    	  plan \
    		-var-file="http.tfvars"
    
    
    deploy: release
    	if [ ! -f "terraform/.terraform.lock.hcl" ]; then \
    		$(MAKE) initTerraform; \
    	fi
    	terraform -chdir=terraform \
    		apply -auto-approve \
    		-var-file="http.tfvars"
    
    deploy_nobuild: 
    	@if [ ! -f "terraform/.terraform.lock.hcl" ]; then \
    		 echo "backend not initialized..."; \
    	else \
    		terraform -chdir=terraform \
    			apply -auto-approve \
    			-var-file="http.tfvars"; \
    	fi
    
    
    destroy:
    	terraform -chdir=terraform \
    	  destroy -auto-approve \
    		-var-file="http.tfvars"
    
    .PHONY: build zip clean all release deploy destroy initTerraform plan
    
  4. To deploy using the terraform/http.tfvars configuration, execute the following commands in the project root folder:

    make deploy
    

Note

To destroy the deployed resources again you can use:

make destroy