Terraform is an open-source tool that allows you to safely and efficiently preview, provision, and manage your cloud infrastructure and resources. Although CloudFlow scheduling is implemented using EventBridge and is available in the console, you cannot schedule workflows directly with APIs or Terraform. This topic shows you how to automate workflow scheduling by using Terraform to create the required EventBridge resources.
You can run the sample code in this topic with a few clicks.
Prerequisites
An Alibaba Cloud account has full permissions for all its resources. This poses a security risk if the account's credentials are compromised. We recommend using a RAM user with only the necessary permissions. Create an AccessKey pair for the RAM user to make API calls. For more information, see Create a RAM user and Create an AccessKey.
Attach the AliyunFnFFullAccess policy to the RAM user to grant permissions to manage CloudFlow (FNF) resources. For more information, see Manage RAM user permissions.
Prepare a Terraform runtime environment. You can choose one of the following methods:
Use Terraform in Terraform Explorer: Alibaba Cloud provides Terraform Explorer, an online environment where you can run Terraform commands without installation. This method is suitable for quickly testing and debugging Terraform at no cost.
Create resources with Terraform: Cloud Shell comes pre-installed with Terraform and is already configured with your identity credentials. You can run Terraform commands directly in Cloud Shell. This method provides quick, low-cost access to Terraform.
Install and configure Terraform on your on-premises machine: This method is suitable for environments with poor network connectivity or when you need a custom development setup.
Use Terraform v0.12.28 or later. To check the version, run the terraform --version command.
Resources used
alicloud_fnf_flow: Creates a CloudFlow resource.
alicloud_ram_policy: Creates a permission policy.
alicloud_ram_role: Creates a role.
alicloud_ram_role_policy_attachment: Attaches a permission policy to a RAM role.
alicloud_mns_queue: Creates a Simple Message Queue (MNS) resource.
alicloud_event_bridge_event_bus: Creates an event bus.
alicloud_event_bridge_event_source: Creates an event source resource.
alicloud_event_bridge_rule: Creates an event rule.
Schedule a CloudFlow workflow with Terraform
Create a working directory and a
main.tfconfiguration file within it.main.tfis the primary file that defines the resources to deploy.variable "region" { default = "cn-hangzhou" } provider "alicloud" { region = var.region } # Define a variable for the resource name prefix. variable "name" { default = "test-mns" } # Define a variable for the policy name. variable "policy_name" { type = string description = "The name of the policy." default = "test-policy" } # Define a variable for the role name. variable "role_name" { type = string description = "The role that EventBridge assumes to start a flow execution." default = "eb-to-fnf-role" } # Define a variable for the CloudFlow name. variable "flow_name" { type = string description = "The name of the flow." default = "test-flow" } # Define a variable for the flow description. variable "flow_description" { default = "For flow_description" } # Define a variable for the event bus name. variable "event_bus_name" { type = string description = "The name of the event bus." default = "test-eventbus1" } # Define a variable for the event bus description. variable "event_bus_description" { default = "For event_bus_description" } # Define a variable for the event source name. variable "event_source_name" { type = string description = "The name of the event source." default = "test-eventsource1" } # Define a variable for the event rule name. variable "event_rule_name" { type = string description = "The name of the event rule." default = "test-eventrule1" } # Define a variable for the custom event target ID. variable "target_id" { type = string description = "The ID of the target." default = "test-target1" } # Get the current Alibaba Cloud account ID. data "alicloud_account" "current" { } # Create a random integer to ensure unique resource names. resource "random_integer" "default" { min = 10000 max = 99999 } # Create a RAM policy to define permissions. resource "alicloud_ram_policy" "policy_exmaple" { # The name of the RAM policy. policy_name = "${var.policy_name}-${random_integer.default.result}" # (Optional) Specifies whether to forcibly destroy the resource. Default value: false. force = true # The policy document. policy_document = <<EOF { "Statement": [ { "Action": [ "fnf:*", "mns:*", "eventbridge:*", "ram:*" ], "Effect": "Allow", "Resource": [ "*" ] } ], "Version": "1" } EOF } # Create a RAM role. resource "alicloud_ram_role" "role_example" { # The name of the role. name = var.role_name # (Optional) Specifies whether to forcibly destroy the resource. Default value: false. force = true # The trust policy of the RAM role. document = <<EOF { "Statement": [ { "Action": "sts:AssumeRole", "Effect": "Allow", "Principal": { "Service": [ "fnf.aliyuncs.com" ] } } ], "Version": "1" } EOF } # Attach the created RAM policy to the RAM role to grant the corresponding permissions. resource "alicloud_ram_role_policy_attachment" "attach_example" { # The name of the permission policy. policy_name = alicloud_ram_policy.policy_exmaple.policy_name # The type of the permission policy. policy_type = alicloud_ram_policy.policy_exmaple.type # The name of the RAM role. role_name = alicloud_ram_role.role_example.name } # Create a CloudFlow resource. resource "alicloud_fnf_flow" "flow_example" { depends_on = [alicloud_ram_role_policy_attachment.attach_example] # (Required) The definition of the flow, which must conform to the Flow Definition Language (FDL) syntax. definition = <<EOF Type: StateMachine Name: ${var.flow_name} SpecVersion: v1 StartAt: Hello World States: - Type: Pass Name: Hello World End: true EOF # The ARN of the RAM role that Serverless Workflow assumes to execute the flow. role_arn = alicloud_ram_role.role_example.arn # The description of the flow. description = var.flow_description # The name of the flow. name = var.flow_name # The type of the flow. Valid values: FDL and DEFAULT. type = "FDL" } # Create an event bus to receive and route events. resource "alicloud_event_bridge_event_bus" "eventbus_example" { # The name of the event bus. event_bus_name = var.event_bus_name # (Optional) The description of the event bus. description = var.event_bus_description } # Create an MNS queue resource. resource "alicloud_mns_queue" "example" { # The name of the queue. name = "${var.name}-${random_integer.default.result}" # The delay, in seconds, before a message sent to the queue can be dequeued. delay_seconds = 0 # The maximum size, in bytes, of a message body. maximum_message_size = 65536 # The duration, in seconds, for a message to remain in the queue. message_retention_period = 345600 # The visibility timeout of the queue, in seconds. visibility_timeout = 30 # The long-polling wait time, in seconds. polling_wait_seconds = 0 } # Create an event source to generate scheduled events. resource "alicloud_event_bridge_event_source" "eventsource_example" { # The name of the event bus. event_bus_name = alicloud_event_bridge_event_bus.eventbus_example.event_bus_name # The name of the event source. event_source_name = var.event_source_name # (Optional, Computed) Specifies whether to connect to an external data source. Default value: false. linked_external_source = true # (Optional) The type of the external data source. Valid values: RabbitMQ, RocketMQ, and MNS. Note: This parameter is valid only when linked_external_source is true. external_source_type = "MNS" # (Optional, Map) The configuration of the external source. external_source_config = { QueueName = alicloud_mns_queue.example.name } } # Define a local variable to store the ARN of the CloudFlow flow. locals { flow_arn = format("acs:fnf:::flow/%s", var.flow_name) } # Create an event rule to match events generated by the event source and route the events to the specified CloudFlow flow. resource "alicloud_event_bridge_rule" "eventrule_example" { # The name of the event bus. event_bus_name = alicloud_event_bridge_event_bus.eventbus_example.event_bus_name # The name of the event rule. rule_name = var.event_rule_name # The event-matching pattern in JSON format. For more information about the values, see StringEqual pattern and StringExpression pattern. filter_pattern = format("{\"source\":[\"%s\"]}", var.event_source_name) # The targets of the rule. targets { # The custom ID of the event target. target_id = var.target_id # The endpoint of the event target. endpoint = local.flow_arn # The type of the event target. type = "acs.fnf" param_list { resource_key = "Input" form = "ORIGINAL" } param_list { form = "CONSTANT" resource_key = "FlowName" value = var.flow_name } param_list { form = "CONSTANT" resource_key = "RoleName" value = var.role_name } } }Run the following command to initialize
Terraform.terraform initThe following output indicates that the initialization is successful.
Initializing the backend... Initializing provider plugins... - Finding latest version of hashicorp/alicloud... - Installing hashicorp/alicloud v1.234.0... - Installed hashicorp/alicloud v1.234.0 (signed by HashiCorp) Terraform has created a lock file .terraform.lock.hcl to record the provider selections it made above. Include this file in your version control repository so that Terraform can guarantee to make the same selections by default when you run "terraform init" in the future. Terraform has been successfully initialized! You may now begin working with Terraform. Try running "terraform plan" to see any changes that are required for your infrastructure. All Terraform commands should now work. If you ever set or change modules or backend configuration for Terraform, rerun this command to reinitialize your working directory. If you forget, other commands will detect it and remind you to do so if necessary.Create an execution plan and preview the changes.
terraform planRun the following command to create the CloudFlow schedule.
terraform applyWhen prompted, enter
yesand press Enter. Wait for the command to complete. The following output indicates that the CloudFlow schedule was created successfully.Plan: 9 to add, 0 to change, 0 to destroy. Do you want to perform these actions? Terraform will perform the actions described above. Only 'yes' will be accepted to approve. Enter a value: yes random_integer.default: Creating... random_integer.default: Creation complete after 0s [id=10***] alicloud_ram_policy.policy_exmaple: Creating... alicloud_ram_role.role_example: Creating... alicloud_mns_queue.example: Creating... alicloud_event_bridge_event_bus.eventbus_example: Creating... alicloud_mns_queue.example: Creation complete after 0s [id=test-mns-10***] alicloud_ram_policy.policy_exmaple: Creation complete after 1s [id=test-policy-10***] alicloud_ram_role.role_example: Creation complete after 1s [id=eb-to-fnf-r***] alicloud_ram_role_policy_attachment.attach_example: Creating... alicloud_ram_role_policy_attachment.attach_example: Creation complete after 0s [id=role:test-policy-10486:Custom:eb-to-f***] alicloud_fnf_flow.flow_example: Creating... alicloud_fnf_flow.flow_example: Creation complete after 0s [id=test-f***] alicloud_event_bridge_event_bus.eventbus_example: Creation complete after 2s [id=test-event***] alicloud_event_bridge_rule.eventrule_example: Creating... alicloud_event_bridge_event_source.eventsource_example: Creating... alicloud_event_bridge_event_source.eventsource_example: Creation complete after 0s [id=test-eventsour***] alicloud_event_bridge_rule.eventrule_example: Creation complete after 0s [id=test-eventbus1:test-event***] Apply complete! Resources: 9 added, 0 changed, 0 destroyed.Verify the results.
Terraform show command
Run the following command to view the details of the resources that Terraform created:
terraform showshell@Alicloud:~/ens/fnf02$ terraform show # alicloud_event_bridge_event_bus.eventbus_example: resource "alicloud_event_bridge_event_bus" "eventbus_example" { description = "For event_bus_description" event_bus_name = "test-eventbus1" id = "xxx" } # alicloud_event_bridge_event_source.eventsource_example: resource "alicloud_event_bridge_event_source" "eventsource_example" { event_bus_name = "test-eventbus1" event_source_name = "test-eventsource1" external_source_config = { "QueueName" = "test-mns-10486" } external_source_type = "MNS" id = "test-eventsource1" linked_external_source = true } # alicloud_event_bridge_rule.eventrule_example: resource "alicloud_event_bridge_rule" "eventrule_example" { event_bus_name = "test-eventbus1" filter_pattern = jsonencode( { source = [ "test-eventsource1", ] } ) id = "xxx" rule_name = "test-eventrule1" status = "ENABLE" targets { endpoint = "xxx" push_retry_strategy = "BACKOFF_RETRY" target_id = "test-target1" type = "acs.fnf" param_list { form = "CONSTANT" resource_key = "FlowName" } } }CloudFlow console
After the resources are created, log on to the CloudFlow console. On the Flows page, verify that a workflow named
test-flowhas been created.
Clean up resources
When you no longer need the resources managed by Terraform, run the following command to destroy them. For more information about the terraform destroy command, see Common commands.
terraform destroyComplete example
You can run the sample code with a few clicks.
Sample code
Find more complete examples in the corresponding product folder within More complete examples.