/**
 * Copyright (c) 2020, 2021 Oracle and/or its affiliates.  All rights reserved.
 * This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license.
 */ import fn = require ( "oci-functions" ) ; import core = require ( "oci-core" ) ; import identity = require ( "oci-identity" ) ; import common = require ( "oci-common" ) ; const provider = new common . ConfigFileAuthenticationDetailsProvider ( ) ; param args const SETUP = "setup" ; const INVOKE = "invoke" ; const TEARDOWN = "teardown" ; const args = process . argv . slice ( 2 ) ; let commands = new Set ( ) ; commands . add ( args [ 0 ] ) ; commands . add ( args [ 1 ] ) ; commands . add ( args [ 2 ] ) ; const name = "oci-ts-sdk-function-example" ; const compartmentId = process . env . COMPARTMENT_ID ; const image = process . env . OCIR_FN_IMAGE ; if ( ! compartmentId ) { console . log ( "Please set the mandatory environment variables - COMPARTMENT_ID, OCIR_FN_IMAGE" ) ; process . exit ( - 1 ) ; } const payload = process . env . FN_PAYLOAD ? process . env . FN_PAYLOAD : "" ; const identityClient = new identity . IdentityClient ( { authenticationDetailsProvider : provider } ) ; const fnManagementClient = new fn . FunctionsManagementClient ( { authenticationDetailsProvider : provider } ) ; const vcnClient = new core . VirtualNetworkClient ( { authenticationDetailsProvider : provider } ) ; const fnInvokeClient = new fn . FunctionsInvokeClient ( { authenticationDetailsProvider : provider } ) ; ( async ( ) => { try { if ( commands . has ( SETUP ) ) { await setupResources ( compartmentId ! , name , image ! ) ; } if ( commands . has ( INVOKE ) ) { await invokeFunction ( compartmentId ! , name , payload ) ; } if ( commands . has ( TEARDOWN ) ) { await tearDownResources ( compartmentId ! , name ) ; } } catch ( error ) { console . log ( "Not able to run Invoke function example . Error" + error ) ; } } ) ( ) ; param compartmentId param name param image async function setupResources ( compartmentId , name , image ) { try { const availabiityDomains = await getAvailabilityDomains ( identityClient , compartmentId ) ; const ad = availabiityDomains [ 0 ] ; console . log ( "using availability domain :: " + ad . name ) ; const vcnDisplayName = vcnName ( name ) ; const vcnCidrBlock = "10.0.0.0/16" ; const vcn = await createVcn ( vcnClient , compartmentId , vcnDisplayName , vcnCidrBlock ) ; console . log ( "created VCN : " + vcn . displayName ) ; const igDisplayName = igName ( name ) ; const ig = await createInternetGateway ( vcnClient , compartmentId , igDisplayName , vcn . id ) ; const drtDisplayName = drtName ( name ) ; await configureInternetGateway ( vcnClient , compartmentId , vcn . id , ig . id , drtDisplayName ) ; const subnetDisplayName = subnetName ( name ) ; const subnetCidrBlock = "10.0.0.0/24" ; const subnet = await createSubnet ( vcnClient , compartmentId , vcn . id , subnetDisplayName , ad . name ! , subnetCidrBlock ) ; console . log ( "Created VCN subnet: " + subnet . displayName ) ; const appDisplayName = applicationName ( name ) ; let subnetIds = new Array ( ) ; subnetIds . push ( subnet . id ) ; const app = await createApplicaiton ( fnManagementClient , compartmentId , appDisplayName , subnetIds ) ; console . log ( "Created Application: " + app . displayName ! ) ; const fnDisplayName = functionName ( name ) ; const memoryInMBs = 128 ; const timeoutInSeconds = 30 ; const fn = await CreateFunctionDetails ( fnManagementClient , app . id ! , fnDisplayName , image , memoryInMBs , timeoutInSeconds ) ; console . log ( "Created Function" + fn . displayName ! ) ; } catch ( error ) { console . log ( "Error in function: " , JSON . stringify ( error ) ) ; } } param compartmentId param name param image async function invokeFunction ( compartmentId , name , payload ) { try { const appName = applicationName ( name ) ; const fnName = functionName ( name ) ; const fnSummary = await getUniqueFunctionByName ( fnManagementClient , compartmentId , appName , fnName ) ; const response = await invokeFunctionHelper ( fnInvokeClient , fnSummary , payload ) ; console . log ( await common . getStringFromResponseBody ( response . value ) ) ; } catch ( error ) { console . log ( "Error invoking function " + error ) ; } } param compartmentId param name param image async function tearDownResources ( compartmentId , name ) { console . log ( "Cleaning up" ) ; const vcn = vcnName ( name ) ; const gatewayName = igName ( name ) ; const routeTableName = drtName ( name ) ; const stName = subnetName ( name ) ; const appName = applicationName ( name ) ; const fnName = functionName ( name ) ; const virtualNetwork = await getUniqueVcnByName ( vcnClient , compartmentId , vcn ) ; const ig = await getUniqueInternetGatewayByName ( vcnClient , compartmentId , virtualNetwork . id , gatewayName ) ; const rt = await getUniqueRouteTableByName ( vcnClient , compartmentId , virtualNetwork . id , routeTableName ) ; const subnet = await getUniqueSubnetByName ( vcnClient , compartmentId , virtualNetwork . id , stName ) ; const application = await getUniqueApplicationByName ( fnManagementClient , compartmentId , appName ) ; const fn = await getUniqueFunction ( fnManagementClient , application . id ! , fnName ) ; if ( fn !== undefined ) { await deleteFunction ( fnManagementClient , fn . id ! ) ; console . log ( "Deleted function " + fn . displayName ! ) ; } if ( application !== undefined ) { await deleteApplication ( fnManagementClient , application . id ! ) ; console . log ( "Deleted applicatoion " + application . displayName ! ) ; } if ( subnet !== undefined ) { await deleteSubnet ( vcnClient , subnet . id ) ; console . log ( "Deleted  subnet " + subnet . id ) ; } if ( rt !== undefined ) { await prepareDefaultRouteTableForDelete ( vcnClient , rt . id ) ; console . log ( "cleaned route table " + rt . displayName ) ; } if ( ig !== undefined ) { await deleteInternetGateway ( vcnClient , ig . id ) ; console . log ( "deleted internet gateway " + ig . displayName ) ; } if ( virtualNetwork !== undefined ) { await deleteVcn ( vcnClient , virtualNetwork ) ; console . log ( "Deleted VCN " + virtualNetwork . displayName ) ; } } param fnManagementClient param compartmentId param displayName param subnetIds return async function createApplicaiton ( client , compartmentId , displayName , subnetIds ) { const createAppDetails = { compartmentId : compartmentId , displayName : displayName , subnetIds : subnetIds } ; const createAppRequest = { createApplicationDetails : createAppDetails } ; const createAppResponse = await client . createApplication ( createAppRequest ) ; await delay ( 15 ) ; return createAppResponse . application ; } param fnManagementClient param applicationId throws async function deleteApplication ( client , applicationId ) { const delAppRequest = { applicationId : applicationId } ; await client . deleteApplication ( delAppRequest ) ; await delay ( 15 ) ; } param identityClient param compartmentId return async function getAvailabilityDomains ( client , compartmentId ) { const listADRequest = { compartmentId : compartmentId } ; const listADResponse = await client . listAvailabilityDomains ( listADRequest ) ; return listADResponse . items ; } param vcnClient param compartmentId param cidrBlock return async function createVcn ( client , compartmentId , vcnDisplayName , cidrBlock ) { const createVcnDetails = { compartmentId : compartmentId , displayName : vcnDisplayName , cidrBlock : cidrBlock } ; const createVcnRequest = { createVcnDetails : createVcnDetails } ; const createVcnResponse = await client . createVcn ( createVcnRequest ) ; await delay ( 15 ) ; return createVcnResponse . vcn ; } param vcnClient param compartmentId param vcnDisplayName return async function getUniqueVcnByName ( client , compartmentId , vcnDisplayName ) { const listVcnsRequest = { compartmentId : compartmentId , displayName : vcnDisplayName } ; const listVcnResponse = await client . listVcns ( listVcnsRequest ) ; if ( listVcnResponse . items . length !== 1 ) { throw "could not find unique VCN with the name" + vcnDisplayName + " in compartment" + compartmentId ; } return listVcnResponse . items [ 0 ] ; } param vcnClient param vcn async function deleteVcn ( client , vcn ) { const deleteVcnRequest = { vcnId : vcn . id } ; await client . deleteVcn ( deleteVcnRequest ) ; await delay ( 15 ) ; } async function createInternetGateway ( client , compartmentId , displayName , vcnId ) { const createIGDetails = { compartmentId : compartmentId , displayName : displayName , vcnId : vcnId , isEnabled : true } ; const createIGRequest = { createInternetGatewayDetails : createIGDetails } ; const createIGResponse = await client . createInternetGateway ( createIGRequest ) ; await delay ( 15 ) ; return createIGResponse . internetGateway ; } param vcnClient param compartmentId param vcnId param igDisplayName return throws async function getUniqueInternetGatewayByName ( client , compartmentId , vcnId , displayName ) { const listIgRequest = { compartmentId : compartmentId , vcnId : vcnId , displayName : displayName } ; const listIgResponse = await client . listInternetGateways ( listIgRequest ) ; if ( listIgResponse . items . length !== 1 ) { throw "Could not find internet gatewat with name " + displayName + " in the compartment " + compartmentId ; } return listIgResponse . items [ 0 ] ; } param vcnClient param igId throws async function deleteInternetGateway ( client , igID ) { const deleteIgRequest = { igId : igID } ; await client . deleteInternetGateway ( deleteIgRequest ) ; await delay ( 15 ) ; } param vcnClient param compartmentId param vcnId param igId param rtDisplayName return async function configureInternetGateway ( client , compartmentId , vcnId , igId , drtDisplayName ) { const defaultRouteTable = await getUniqueRouteTableByName ( vcnClient , compartmentId , vcnId , drtDisplayName ) ; const destinationCidr = "0.0.0.0/0" ; const routeRules = defaultRouteTable . routeRules ; const rr = { cidrBlock : destinationCidr , destination : destinationCidr , destinationType : core . models . RouteRule . DestinationType . CidrBlock , networkEntityId : igId } ; routeRules . push ( rr ) ; const updateRTDetails = { routeRules : routeRules } ; const updateRTRequest = { updateRouteTableDetails : updateRTDetails , rtId : defaultRouteTable . id } ; const updateRTResponse = await client . updateRouteTable ( updateRTRequest ) ; return updateRTResponse . routeTable ; } param vcnClient param compartmentId param vcnId param rtDisplayName return async function getUniqueRouteTableByName ( client , compartmentId , vcnId , rtdisplayName ) { const listRTRequest = { compartmentId : compartmentId , vcnId : vcnId , displayName : rtdisplayName } ; const listRTresponse = await client . listRouteTables ( listRTRequest ) ; if ( listRTresponse . items . length != 1 ) { throw "couldnot find unique routing table with name:" + rtdisplayName + " in the compartment " + compartmentId ; } return listRTresponse . items [ 0 ] ; } param vcnClient param rtId throws async function prepareDefaultRouteTableForDelete ( client , rtId ) { const updateRtDetails = { routeRules : [ ] } ; const updateRtRequest = { updateRouteTableDetails : updateRtDetails , rtId : rtId } ; await client . updateRouteTable ( updateRtRequest ) ; } param vcnClient param compartmentId param vcnId param displayName param availabilityDomain param subnetCidrBlock return async function createSubnet ( client , compartmentId , vcnId , displayName , availabilityDomainName , subnetCidrBlock ) { const createSubnetDetails = { availabilityDomain : availabilityDomainName , compartmentId : compartmentId , displayName : displayName , cidrBlock : subnetCidrBlock , vcnId : vcnId } ; const createSubnetRequest = { createSubnetDetails : createSubnetDetails } ; const createSubnetResponse = await client . createSubnet ( createSubnetRequest ) ; await delay ( 15 ) ; return createSubnetResponse . subnet ; } param vcnClient param compartmentId param vcnId param subnetDisplayName return async function getUniqueSubnetByName ( client , compartmentId , vcnId , subnetDisplayName ) { const listSubnetRequest = { compartmentId : compartmentId , vcnId : vcnId , displayName : subnetDisplayName } ; const listSubnetResponse = await client . listSubnets ( listSubnetRequest ) ; if ( listSubnetResponse . items . length !== 1 ) { throw " Could not find unique subnet with name " + subnetDisplayName + " in the compartment " + compartmentId ; } return listSubnetResponse . items [ 0 ] ; } param vcnClient param subnetId throws async function deleteSubnet ( client , subnetId ) { const DELETE_SUBNET_ATTEMPTS = 5 ; let numAttempts = 0 ; while ( true ) { try { const deleteSubnetRequest = { subnetId : subnetId } ; await client . deleteSubnet ( deleteSubnetRequest ) ; break ; } catch ( error ) { numAttempts ++ ; if ( error . statusCode === 409 && numAttempts < DELETE_SUBNET_ATTEMPTS ) await delay ( 10 ) ; else throw error ; } } await delay ( 15 ) ; } param fnManagementClient param applicationId param displayName param image param memoryInMBs param timeoutInSeconds return async function CreateFunctionDetails ( client , applocationId , displayName , image , memoryInMBs , timeoutInSeconds ) { const createFnDEtails = { applicationId : applocationId , displayName : displayName , image : image , memoryInMBs : memoryInMBs , timeoutInSeconds : timeoutInSeconds } ; const createFnRequest = { createFunctionDetails : createFnDEtails } ; const createFnResponse = await client . createFunction ( createFnRequest ) ; await delay ( 15 ) ; return createFnResponse . function ; } param fnManagementClient param compartmentId param applicationDisplayName param functionDisplayName return async function getUniqueFunctionByName ( client , compartmentId , applicationDisplayName , functionDisplayName ) { const application = await getUniqueApplicationByName ( fnManagementClient , compartmentId , applicationDisplayName ) ; const fn = await getUniqueFunction ( fnManagementClient , application . id ! , functionDisplayName ) ; return fn ; } param fnManagementClient param compartmentId param applicationDisplayName return async function getUniqueApplicationByName ( client , compartmentId , applicationDisplayName ) { const listAppRequest = { displayName : applicationDisplayName , compartmentId : compartmentId } ; const listAppResponse = await client . listApplications ( listAppRequest ) ; if ( listAppResponse . items . length !== 1 ) { throw "Could not find unique application with name " + applicationDisplayName + " in compartment " + compartmentId ; } return listAppResponse . items [ 0 ] ; } param fnManagementClient param applicationId param functionDisplayName return throws async function getUniqueFunction ( client , applicationId , functionDisplayName ) { const listFnRequest = { applicationId : applicationId , displayName : functionDisplayName } ; const listFnResponse = await client . listFunctions ( listFnRequest ) ; if ( listFnResponse . items . length !== 1 ) { throw "Could not find function with name " + functionDisplayName + " in application " + applicationId ; } return listFnResponse . items [ 0 ] ; } param fnManagementClient param functionId async function deleteFunction ( client , fnId ) { const delFunctionRequest = { functionId : fnId } ; await client . deleteFunction ( delFunctionRequest ) ; await delay ( 15 ) ; } param fnInvokedClient param function param payload throws async function invokeFunctionHelper ( client , fnSummary , payload ) { console . log ( "Invoking function endpoint - " + fnSummary . invokeEndpoint ) ; client . endpoint = fnSummary . invokeEndpoint ! ; const functionId = fnSummary . id || "" ; const request = { functionId : functionId } ; const response = await client . invokeFunction ( request ) ; return response ; } function vcnName ( name ) { return name + "-vcn" ; } function igName ( name ) { return name + "-ig" ; } function drtName ( name ) { return "Default Route Table for " + name + "-vcn" ; } function subnetName ( name ) { return name + "-subnet" ; } function applicationName ( name ) { return name + "-app" ; } function functionName ( name ) { return name + "-fn" ; } async function delay ( s ) { return new Promise ( resolve => setTimeout ( resolve , s * 1000 ) ) ; }