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.
ImportantWe 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
jqJSON 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
-
Configure your Alibaba Cloud credentials:
ros-cdk config -
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 withhttps://.In the DescribeRegions API response, the
RegionEndpointfield 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
-
Replace the content of the
package.jsonfile 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" } } -
Run the following command to install the dependencies:
npm install
JavaScript
-
Replace the content of the
package.jsonfile 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" } } -
Run the following command to install the dependencies:
npm install
Java
-
Replace the content of the
pom.xmlfile 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> -
Run the following command to install the dependencies:
mvn compile
Python
-
Replace the content of the
requirements.txtfile with the following code:ros-cdk-core==1.4.0 ros-cdk-oss==1.4.0 ros-cdk-ossdeployment==1.4.0 -
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:
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
-
Run the following command to create a stack with your parameters:
ros-cdk deploy --parameters X=1 --parameters Y=2 --sync=true -
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