Use ROS CDK to create a Function Compute function

更新时间:
复制 MD 格式

Create a Function Compute function by using ROS CDK to handle custom resource logic. TypeScript, JavaScript, Java, Python, and C# are supported.

Billing

ROS CDK is free. The Function Compute function and custom resource in this solution are also free of charge.

Prerequisites

Complete the following before you start:

  • Install and configure the Alibaba Cloud CLI and ROS CDK. Install ROS CDK.

  • Obtain an AccessKey pair. Create an AccessKey pair.

    Important

    We recommend creating a dedicated RAM user for API access and an AccessKey pair for that user. Create a RAM user. Manage RAM user permissions.

  • Ensure your language environment meets these requirements:

    • TypeScript: Node.js 8.0 or later.

    • JavaScript: The jq JSON parsing toolkit.

    • Java: JDK 1.8 or later and Maven 2.5 or later.

    • Python: Python 3.4 or later.

    • C#: .NET Core 2.0 or later and Visual Studio 2010 or later.

Step 1: Initialize a project

Run the following commands to create and initialize a project:

TypeScript

mkdir demo
cd demo
ros-cdk init --language=typescript --generate-only=true

JavaScript

mkdir demo
cd demo
ros-cdk init --language=javascript --generate-only=true

Java

mkdir demo
cd demo
ros-cdk init --language=java --generate-only=true

Python

mkdir demo
cd demo
ros-cdk init --language=python --generate-only=true

Create a virtual environment for the project:

Python projects require a virtualenv.

python3 -m venv .venv

Activate the virtualenv:

source .venv/bin/activate

C#

mkdir demo
cd demo
ros-cdk init --language=csharp --generate-only=true

Step 2: Configure Alibaba Cloud credentials

  1. Configure your Alibaba Cloud credentials:

    ros-cdk config
  2. Enter the configuration as prompted.

    endpoint(optional, default:https://ros.aliyuncs.com):
    defaultRegionId(optional, default:cn-hangzhou):cn-beijing
    [1] AK
    [2] StsToken
    [3] RamRoleArn
    [4] EcsRamRole
    [0] CANCEL
    Authenticate mode [1...4 / 0]: 1
    accessKeyId:************************
    accessKeySecret:******************************
      Your cdk configuration has been saved successfully!

    The following table describes the parameters.

    Parameter

    Description

    defaultRegionId

    The deployment region for the ROS stack. The default is cn-hangzhou. Call the DescribeRegions API operation to get the IDs of other regions.

    {
      "RegionId": "cn-hangzhou",
      "RegionEndpoint": "ros.aliyuncs.com",
      "LocalName": "China (Hangzhou)"
    }

    endpoint

    The ROS service endpoint. The default is https://ros.aliyuncs.com. Call the DescribeRegions API operation to obtain the public or VPC endpoint for a region. Prefix the endpoint with https://.

    In the DescribeRegions API response, the RegionEndpoint field contains the ROS endpoint:

    {
      "RegionId": "cn-hangzhou",
      "RegionEndpoint": "ros.aliyuncs.com",
      "LocalName": "China (Hangzhou)"
    }

    Authenticate mode

    The authentication method. In this example, select [1] AK. Enter the AccessKey ID and AccessKey Secret from the Prerequisites section. Configure and manage credentials.

Step 3: Install dependencies

Update your project configuration files and install dependencies.

TypeScript

  1. Replace the content of the package.json file with the following code:

    {
      "name": "demo",
      "version": "0.1.0",
      "bin": {
        "demo": "bin/demo.js"
      },
      "scripts": {
        "build": "tsc",
        "test": "jest"
      },
      "devDependencies": {
        "@types/jest": "^25.2.1",
        "@types/node": "10.17.5",
        "typescript": "^3.9.7",
        "jest": "^25.5.0",
        "ts-jest": "^25.3.1",
        "ts-node": "^8.1.0",
        "babel-jest": "^26.6.3",
        "@babel/core": "^7.12.9",
        "@babel/preset-env": "7.12.7",
        "@babel/preset-typescript": "^7.12.7",
        "@alicloud/ros-cdk-assert": "^1.4.0"
      },
      "dependencies": {
        "@alicloud/ros-cdk-core": "^1.4.0",
        "@alicloud/ros-cdk-oss": "^1.4.0",
        "@alicloud/ros-cdk-ossdeployment": "^1.4.0"
      }
    }
  2. Run the following command to install the dependencies:

    npm install

JavaScript

  1. Replace the content of the package.json file with the following code:

    {
      "name": "demo",
      "version": "0.1.0",
      "bin": {
        "demo": "bin/demo.js"
      },
      "scripts": {
        "build": "echo \"The build step is not required when using JavaScript!\" && exit 0",
        "cdk": "cdk",
        "test": "jest"
      },
      "devDependencies": {
        "@types/jest": "^25.2.1",
        "@types/node": "10.17.5",
        "typescript": "^3.9.7",
        "jest": "^25.5.0",
        "ts-jest": "^25.3.1",
        "ts-node": "^8.1.0",
        "babel-jest": "^26.6.3",
        "@babel/core": "^7.12.9",
        "@babel/preset-env": "7.12.7",
        "@babel/preset-typescript": "^7.12.7",
        "@alicloud/ros-cdk-assert": "^1.0.25"
      },
      "dependencies": {
        "@alicloud/ros-cdk-core": "^1.4.0",
        "@alicloud/ros-cdk-oss": "^1.4.0",
        "@alicloud/ros-cdk-ossdeployment": "^1.4.0"
      }
    }
  2. Run the following command to install the dependencies:

    npm install

Java

  1. Replace the content of the pom.xml file with the following code:

    <?xml version="1.0" encoding="UTF-8"?>
    <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
             xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.myorg</groupId>
        <artifactId>demo</artifactId>
        <version>0.1</version>
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <cdk.version>1.0.25</cdk.version>
        </properties>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.8.1</version>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>exec-maven-plugin</artifactId>
                    <version>1.6.0</version>
                    <configuration>
                        <mainClass>com.myorg.DemoApp</mainClass>
                    </configuration>
                </plugin>
            </plugins>
        </build>
        <dependencies>
            <!-- Alibaba Cloud ROS CDK -->
            <dependency>
                <groupId>com.aliyun</groupId>
                <artifactId>ros-cdk-core</artifactId>
                <version>1.4.0</version>
            </dependency>
            <dependency>
                <groupId>com.aliyun</groupId>
                <artifactId>ros-cdk-oss</artifactId>
                <version>1.4.0</version>
            </dependency>
            <dependency>
                <groupId>com.aliyun</groupId>
                <artifactId>ros-cdk-ossdeployment</artifactId>
                <version>1.4.0</version>
            </dependency>
            <!-- https://mvnrepository.com/artifact/junit/junit -->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
                <scope>test</scope>
            </dependency>
        </dependencies>
    </project>
  2. Run the following command to install the dependencies:

    mvn compile

Python

  1. Replace the content of the requirements.txt file with the following code:

    ros-cdk-core==1.4.0
    ros-cdk-oss==1.4.0
    ros-cdk-ossdeployment==1.4.0
  2. Run the following command to install the dependencies:

    pip install -r requirements.txt

C#

Replace the content of the src/Demo/Demo.csproj file with the following code:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <!-- Roll forward to future major versions of the netcoreapp as needed -->
    <RollForward>Major</RollForward>
  </PropertyGroup>
  <ItemGroup>
    <!-- CDK Construct Library dependencies -->
    <PackageReference Include="AlibabaCloud.SDK.ROS.CDK.Core" Version="1.4.0" />
    <PackageReference Include="AlibabaCloud.SDK.ROS.CDK.Oss" Version="1.4.0" />
    <PackageReference Include="AlibabaCloud.SDK.ROS.CDK.Ossdeployment" Version="1.4.0" />
    <!-- To enable compile-time checks for missing required properties, uncomment the following PackageReference:
    <PackageReference Include="Amazon.Jsii.Analyzers" Version="*" PrivateAssets="all" />
    -->
  </ItemGroup>
</Project>

Step 4: Add resources

Add the following resources to the project:

ALIYUN::FC3::Function

ALIYUN::ROS::CustomResource

import * as ros from '@alicloud/ros-cdk-core';
import * as fc from '@alicloud/ros-cdk-fc3';
import * as ROS from '@alicloud/ros-cdk-ros';

export class DemoStack extends ros.Stack {
  constructor(scope: ros.Construct, id: string, props?: ros.StackProps) {
    super(scope, id, props);
    new ros.RosInfo(this, ros.RosInfo.description, "This is the simple ros cdk app example.");
    // The code that defines your stack goes here

    const x = new ros.RosParameter(this, 'X', {
      type: ros.RosParameterType.NUMBER,
    });
    const y = new ros.RosParameter(this, 'Y', {
      type: ros.RosParameterType.NUMBER,
    });

    const function1 = new fc.Function(this, 'Function', {
      functionName: 'mytest',
      handler: 'index.handler',
      runtime: 'python3',
      code: {
        sourceCode: `import time\nimport json\nimport urllib.request\nimport logging\n\ndef handler(event, context):\n    logger = logging.getLogger()\n    logger.setLevel(logging.INFO)\n    event = json.loads(event)\n    logger.info('receive request: %s', event)\n\n    res_props = event['ResourceProperties']\n\n    result = {\n        'RequestId': event['RequestId'],\n        'LogicalResourceId': event['LogicalResourceId'],\n        'StackId': event['StackId'],\n        'Status': 'SUCCESS',\n        'PhysicalResourceId': 'MyCustomResourceId',\n        'Data': {}\n    }\n\n    if event['RequestType'] != 'Delete':\n        result['Data']['z'] = res_props['X'] + res_props['Y']\n\n    headers = {\n        'Content-type': 'application/json',\n        'Accept': 'application/json',\n        'Date': time.strftime('%a, %d %b %Y %X GMT', time.gmtime()),\n        'User-Agent': 'MyCustomUserAgent'\n    }\n\n    req = urllib.request.Request(event['ResponseURL'], data=json.dumps(result).encode('utf-8'), headers=headers)\n    resp = urllib.request.urlopen(req)\n    resp_content = resp.read().decode('utf-8')\n    logger.info('response: %s', resp_content)\n\n    if resp.getcode() != 200:\n        logger.error('Failed to send response, status code: %s', resp.getcode())\n    else:\n        logger.info('Response sent successfully')\n`
      }
    });

    const customResource = new ROS.CustomResource(this, 'SimpleTest', {
      timeout: 60,
      serviceToken: function1.attrArn,
      parameters: {
        X: x.valueAsNumber,
        Y: y.valueAsNumber
      }
    });
    new ros.RosOutput(this, 'SimpleTestOutputs', {
      value: customResource.attrOutputs
    });
  }
}
const ros = require('@alicloud/ros-cdk-core');
const ROS = require('@alicloud/ros-cdk-ros');
const fc = require('@alicloud/ros-cdk-fc3');

class DemoStack extends ros.Stack {
  /**
   *
   * @param {ros.Construct} scope
   * @param {string} id
   * @param {ros.StackProps} props
   */
  constructor(scope, id, props) {
    super(scope, id, props);
    new ros.RosInfo(this, ros.RosInfo.description, "This is the simple ros cdk app example.");
    // The code that defines your stack goes here
    const x = new ros.RosParameter(this, 'X', {
      type: ros.RosParameterType.NUMBER
    });
    const y = new ros.RosParameter(this, 'Y', {
      type: ros.RosParameterType.NUMBER,
    });

    const function1 = new fc.Function(this, 'Function', {
      functionName: 'mytest',
      handler: 'index.handler',
      runtime: 'python3',
      code: {
        sourceCode: `import time\nimport json\nimport urllib.request\nimport logging\n\ndef handler(event, context):\n    logger = logging.getLogger()\n    logger.setLevel(logging.INFO)\n    event = json.loads(event)\n    logger.info('receive request: %s', event)\n\n    res_props = event['ResourceProperties']\n\n    result = {\n        'RequestId': event['RequestId'],\n        'LogicalResourceId': event['LogicalResourceId'],\n        'StackId': event['StackId'],\n        'Status': 'SUCCESS',\n        'PhysicalResourceId': 'MyCustomResourceId',\n        'Data': {}\n    }\n\n    if event['RequestType'] != 'Delete':\n        result['Data']['z'] = res_props['X'] + res_props['Y']\n\n    headers = {\n        'Content-type': 'application/json',\n        'Accept': 'application/json',\n        'Date': time.strftime('%a, %d %b %Y %X GMT', time.gmtime()),\n        'User-Agent': 'MyCustomUserAgent'\n    }\n\n    req = urllib.request.Request(event['ResponseURL'], data=json.dumps(result).encode('utf-8'), headers=headers)\n    resp = urllib.request.urlopen(req)\n    resp_content = resp.read().decode('utf-8')\n    logger.info('response: %s', resp_content)\n\n    if resp.getcode() != 200:\n        logger.error('Failed to send response, status code: %s', resp.getcode())\n    else:\n        logger.info('Response sent successfully')\n`
      }
    });

    const customResource = new ROS.CustomResource(this, 'SimpleTest', {
      timeout: 60,
      serviceToken: function1.attrArn,
      parameters: {
        X: x.valueAsNumber,
        Y: y.valueAsNumber
      }
    });
    new ros.RosOutput(this, 'SimpleTestOutputs', {
      value: customResource.attrOutputs
    });
  }
}

module.exports = { DemoStack }
package com.myorg;


import com.aliyun.ros.cdk.core.RosParameter;
import com.aliyun.ros.cdk.core.RosOutput;
import com.aliyun.ros.cdk.core.RosOutputProps;
import com.aliyun.ros.cdk.core.RosParameterType;
import com.aliyun.ros.cdk.core.Construct;
import com.aliyun.ros.cdk.core.StackProps;
import com.aliyun.ros.cdk.core.Stack;
import com.aliyun.ros.cdk.ros.CustomResource;
import com.aliyun.ros.cdk.ros.CustomResourceProps;
import com.aliyun.ros.cdk.fc3.*;
import java.util.Map;

public class DemoStack extends Stack {
    public DemoStack(final Construct scope, final String id) {
        this(scope, id, null);
    }

    public DemoStack(final Construct scope, final String id, final StackProps props) {
        super(scope, id, props);

        // The code that defines your stack goes here

        RosParameter x = RosParameter.Builder.create(this, "X")
                .type(RosParameterType.NUMBER)
                .build();

        RosParameter y = RosParameter.Builder.create(this, "Y")
                .type(RosParameterType.NUMBER)
                .build();

        // Create a function.
        Function function = new Function(this, "Function", FunctionProps.builder()
                .functionName("mytest")
                .handler("index.handler")
                .runtime("python3")
                .code(RosFunction.CodeProperty.builder()
                        .sourceCode("" +
                                "import time\n" +
                                "import json\n" +
                                "import urllib.request\n" +
                                "import logging\n\n" +
                                "def handler(event, context):\n" +
                                "    logger = logging.getLogger()\n" +
                                "    logger.setLevel(logging.INFO)\n" +
                                "    event = json.loads(event)\n" +
                                "    logger.info('receive request: %s', event)\n\n" +
                                "    res_props = event['ResourceProperties']\n\n" +
                                "    result = {\n" +
                                "        'RequestId': event['RequestId'],\n" +
                                "        'LogicalResourceId': event['LogicalResourceId'],\n" +
                                "        'StackId': event['StackId'],\n" +
                                "        'Status': 'SUCCESS',\n" +
                                "        'PhysicalResourceId': 'MyCustomResourceId',\n" +
                                "        'Data': {}\n" +
                                "    }\n\n" +
                                "    if event['RequestType'] != 'Delete':\n" +
                                "        result['Data']['z'] = res_props['X'] + res_props['Y']\n\n" +
                                "    headers = {\n" +
                                "        'Content-type': 'application/json',\n" +
                                "        'Accept': 'application/json',\n" +
                                "        'Date': time.strftime('%a, %d %b %Y %X GMT', time.gmtime()),\n" +
                                "        'User-Agent': 'MyCustomUserAgent'\n" +
                                "    }\n\n" +
                                "    req = urllib.request.Request(event['ResponseURL'], data=json.dumps(result).encode('utf-8'), headers=headers)\n" +
                                "    resp = urllib.request.urlopen(req)\n" +
                                "    resp_content = resp.read().decode('utf-8')\n" +
                                "    logger.info('response: %s', resp_content)\n\n" +
                                "    if resp.getcode() != 200:\n" +
                                "        logger.error('Failed to send response, status code: %s', resp.getcode())\n" +
                                "    else:\n" +
                                "        logger.info('Response sent successfully')\n"
                        )
                        .build())
                .build());

        // Create a custom resource.
        CustomResource customResource = new CustomResource(this, "SimpleTest", CustomResourceProps.builder()
                .timeout(60)
                .serviceToken(function.getAttrArn())
                .parameters(Map.of(
                        "X", x.getValueAsNumber(),
                        "Y", y.getValueAsNumber()
                ))
                .build());

        // Obtain outputs.
        new RosOutput(this, "SimpleTestOutputs", RosOutputProps.builder()
                .value(customResource.getAttrOutputs())
                .build());
    }
}
import ros_cdk_core as core
import ros_cdk_fc3 as fc
import ros_cdk_ros as ros


class DemoStack(core.Stack):

    def __init__(self, scope: core.Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        # The code that defines your stack goes here

        x = core.RosParameter(self, "X", type=core.RosParameterType.NUMBER)

        y = core.RosParameter(self, "Y", type=core.RosParameterType.NUMBER)

        function = fc.Function(self, "Function", fc.FunctionProps(
            function_name='mytest',
            handler='index.handler',
            runtime='python3',
            code={
                'sourceCode': "import time\nimport json\nimport urllib.request\nimport logging\n\ndef handler(event, context):\n    logger = logging.getLogger()\n    logger.setLevel(logging.INFO)\n    event = json.loads(event)\n    logger.info('receive request: %s', event)\n\n    res_props = event['ResourceProperties']\n\n    result = {\n        'RequestId': event['RequestId'],\n        'LogicalResourceId': event['LogicalResourceId'],\n        'StackId': event['StackId'],\n        'Status': 'SUCCESS',\n        'PhysicalResourceId': 'MyCustomResourceId',\n        'Data': {}\n    }\n\n    if event['RequestType'] != 'Delete':\n        result['Data']['z'] = res_props['X'] + res_props['Y']\n\n    headers = {\n        'Content-type': 'application/json',\n        'Accept': 'application/json',\n        'Date': time.strftime('%a, %d %b %Y %X GMT', time.gmtime()),\n        'User-Agent': 'MyCustomUserAgent'\n    }\n\n    req = urllib.request.Request(event['ResponseURL'], data=json.dumps(result).encode('utf-8'), headers=headers)\n    resp = urllib.request.urlopen(req)\n    resp_content = resp.read().decode('utf-8')\n    logger.info('response: %s', resp_content)\n\n    if resp.getcode() != 200:\n        logger.error('Failed to send response, status code: %s', resp.getcode())\n    else:\n        logger.info('Response sent successfully')\n"
            }
        ))

        custom_resource = ros.CustomResource(self, "SimpleTest", ros.CustomResourceProps(
            timeout=60,
            service_token=function.attr_arn,
            parameters={
                "X": x.value_as_number,
                "Y": y.value_as_number
            }
        ))

        core.RosOutput(self, "SimpleTestOutputs", value=custom_resource.attr_outputs)
using System.Collections.Generic;
using AlibabaCloud.SDK.ROS.CDK.Core;
using AlibabaCloud.SDK.ROS.CDK.Fc3;
using AlibabaCloud.SDK.ROS.CDK.Ros;
using Stack = AlibabaCloud.SDK.ROS.CDK.Core.Stack;
using IStackProps = AlibabaCloud.SDK.ROS.CDK.Core.IStackProps;
using RosOutput = AlibabaCloud.SDK.ROS.CDK.Core.RosOutput;
using RosOutputProps = AlibabaCloud.SDK.ROS.CDK.Core.RosOutputProps;


namespace Demo
{
    public class DemoStack : Stack
    {
        public DemoStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props)
                {
            new RosInfo(this, RosInfo.Description, "This is the simple ros cdk app example.");

            var x = new RosParameter(this, "X", new RosParameterProps
            {
                Type = RosParameterType.NUMBER
            });

            var y = new RosParameter(this, "Y", new RosParameterProps
            {
                Type = RosParameterType.NUMBER
            });

            var function1 = new Function(this, "Function", new FunctionProps
            {
                FunctionName = "mytest",
                Handler = "index.handler",
                Runtime = "python3",
                Code = new RosFunction.CodeProperty
                {
                    SourceCode = @"import time
import json
import urllib.request
import logging

def handler(event, context):
    logger = logging.getLogger()
    logger.setLevel(logging.INFO)
    event = json.loads(event)
    logger.info('receive request: %s', event)

    res_props = event['ResourceProperties']

    result = {
        'RequestId': event['RequestId'],
        'LogicalResourceId': event['LogicalResourceId'],
        'StackId': event['StackId'],
        'Status': 'SUCCESS',
        'PhysicalResourceId': 'MyCustomResourceId',
        'Data': {}
    }

    if event['RequestType'] != 'Delete':
        result['Data']['z'] = res_props['X'] + res_props['Y']

    headers = {
        'Content-type': 'application/json',
        'Accept': 'application/json',
        'Date': time.strftime('%a, %d %b %Y %X GMT', time.gmtime()),
        'User-Agent': 'MyCustomUserAgent'
    }

    req = urllib.request.Request(event['ResponseURL'], data=json.dumps(result).encode('utf-8'), headers=headers)
    resp = urllib.request.urlopen(req)
    resp_content = resp.read().decode('utf-8')
    logger.info('response: %s', resp_content)

    if resp.getcode() != 200:
        logger.error('Failed to send response, status code: %s', resp.getcode())
    else:
        logger.info('Response sent successfully')
"
                }
            });

            var customResource = new CustomResource(this, "SimpleTest", new CustomResourceProps
            {
                Timeout = 60,
                ServiceToken = function1.AttrArn,
                Parameters = new Dictionary<string, object>
                {
                    { "X", x.ValueAsNumber },
                    { "Y", y.ValueAsNumber }
                }
            });

            new RosOutput(this, "SimpleTestOutputs", new RosOutputProps
            {
                Value = customResource.AttrOutputs
            });
        }
    }
}

Step 5: Create a stack

  1. Run the following command to create a stack with your parameters:

    ros-cdk deploy --parameters X=1 --parameters Y=2 --sync=true
  2. Select a region and run the command. If The deployment(sync create stack) has completed! appears in the output, the stack is created. Example output:

    Create bucket(cdk-ut58ogqt8-assets-cn-beijing) successfully!
    Upload file(./cdk.out/DemoStack.template.json) to bucket(cdk-ut58ogqt8-assets-cn-beijing) successfully!
    DemoStack: deploying...
    |DemoStack               |2025-03-26T10:25:18 | CREATE_COMPLETE      | ALIYUN::FC3::Function   | 9bc03d9d-ca7d-431c-a6b5-e9ded2506266 | Function
    
    |DemoStack               |2025-03-26T10:25:18 | CREATE_COMPLETE      | ALIYUN::ROS::CustomResource | MyCustomResourceId | SimpleTest
    
    
    Outputs:
    
     Key: SimpleTestOutputs  Value: [Object: null prototype] { z: 3 } Description: No description given
    
     ✅ The deployment(sync create stack) has completed!
    Status: CREATE_COMPLETE
    StatusReason: Stack CREATE completed successfully
    StackId: 8cda****-5ca4-4206-99dc-d7b3c****ba2