All Products
Search
Document Center

Elastic Compute Service:Run commands by using SDKs

Last Updated:Mar 06, 2025

You can use Cloud Assistant to simultaneously run a command on multiple Elastic Compute Service (ECS) instances. The command can be a shell, batch, or PowerShell command. This topic describes how to run a Cloud Assistant command by using an ECS SDK and query the execution results of the command.

Prerequisites

  • The ECS instances on which you want to run a Cloud Assistant command are in the Running state and Cloud Assistant Agent is installed on the instances. For information about how to install Cloud Assistant Agent, see Install Cloud Assistant Agent.

  • The ALIBABA_CLOUD_ACCESS_KEY_ID and ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variables are configured in the code runtime environment. For information about how to configure environment variables, see Configure environment variables in Linux, macOS, and Windows.

    Note

    To secure the AccessKey pair of your Alibaba Cloud account, we recommend that you create a Resource Access Management (RAM) user, grant the RAM user the permissions to access ECS resources, and then use the AccessKey pair of the RAM user to call an ECS SDK. For more information, see RAM users.

  • The RAM user is granted the permissions to use Cloud Assistant. For more information, see Grant a RAM user permissions to use Cloud Assistant.

  • The Cloud Assistant command that you want to run is prepared. The command can be a shell, batch, or PowerShell command.

  • ECS SDK dependencies are installed for the project. For more information, visit the Elastic Compute Service page in SDK Center.

Sample scenario

In modern cloud computing environments, an O&M management system is crucial for ensuring business stability. To ensure the performance and stability of ECS instances, make sure that you regularly check the resource usage, such as the CPU utilization, memory usage, and disk usage. For example, you want to develop an automated O&M management system. Based on the logon-free feature of Cloud Assistant, the automated O&M management system allows you to remotely run Cloud Assistant commands on ECS instances to meet diverse O&M requirements. The automated O&M management system can pass in different commands to ECS instances to implement multiple functions, such as resource monitoring, log collection, and troubleshooting. This significantly improves O&M efficiency and provides reliable support for efficient business operations.

import com.aliyun.ecs20140526.Client;
import com.aliyun.ecs20140526.models.*;
import com.aliyun.teaopenapi.models.Config;
import com.google.gson.Gson;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;


public class CloudAssistantService {

    /**
     * Obtain the AccessKey ID and the AccessKey secret from the environment variables.
     */
    private static final String ACCESS_KEY_ID = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
    private static final String ACCESS_KEY_SECRET = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
    private static final ScheduledExecutorService SCHEDULER = Executors.newScheduledThreadPool(1);
    private static volatile Client ecsClient;

    private CloudAssistantService() {
    }

    /**
     * Initialize the ECS client.
     *
     * @param regionId The region ID, which is used to specify the region in which the ECS client resides.
     * @return Return the initialized ECS client.
     * <p>
     * In the sample code, the double-checked locking pattern is used to ensure that the thread creates a single ECS client in a secure manner. 
     * Check whether an ECS client already exists. If no ECS client exists, check again in the synchronization block and create an ECS client. 
     */
    public static Client getEcsClient(String regionId) throws Exception {
        if (ecsClient == null) {
            synchronized (CloudAssistantService.class) {
                if (ecsClient == null) {
                    Config config = new Config().setAccessKeyId(ACCESS_KEY_ID).setAccessKeySecret(ACCESS_KEY_SECRET).setRegionId(regionId);
                    ecsClient = new Client(config);
                }
            }
        }
        return ecsClient;
    }

    public static void main(String[] args_) {
        try {
            // The region ID.
            String regionId = "cn-chengdu";
            getEcsClient(regionId);
            // The IDs of the ECS instances on which you want to run the command.
            List<String> instanceIds = Arrays.asList("i-2vcXXXXXXXXXXXXXXXb8", "i-2vcXXXXXXXXXXXXXXXot");
            // The content of the command.
            String commandContent = "#!/bin/bash\n cat /proc/meminfo";
            // The execution timeout period of the command.
            long commandTimeOut = 60;


            // Run the command.
            String invokeId = runCommand(commandContent, regionId, instanceIds, commandTimeOut);
            // Query the execution results of the command.
            DescribeInvocationsResponse invocationResult = describeInvocations(regionId, invokeId, commandTimeOut);
            System.out.println("The command execution result:" + new Gson().toJson(invocationResult));
            // The sample code does not contain logging settings.

        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            SCHEDULER.shutdown();
        }
    }

    /**
     * Run the command on the specified ECS instances.
     *
     * @param commandContent The content of the command.
     * @param regionId       The ID of the region in which the ECS instances reside.
     * @param instanceIds    The IDs of the ECS instances on which you want to run the command.
     * @param commandTimeOut The execution timeout period of the command.
     * @return Return the task ID of the command.
     */
    public static String runCommand(String commandContent, String regionId, List<String> instanceIds, long commandTimeOut) {
        try {
            System.out.println("runCommand start...");
            RunCommandRequest request = new RunCommandRequest();
            request.setRegionId(regionId);
            request.setType(Constants.COMMAND_TYPE.RUN_SHELL_SCRIPT);
            request.setCommandContent(commandContent);
            request.setInstanceId(instanceIds);
            request.setTimeout(commandTimeOut);
            RunCommandResponse runCommandResponse = ecsClient.runCommand(request);
            return runCommandResponse.body.invokeId;
        } catch (Exception e) {
            throw new RuntimeException("runCommand failed", e);
        }
    }

    /**
     * Query the execution results of the Cloud Assistant command.
     *
     * @param regionId       The region ID, which is used to specify the region to which the execution results belong.
     * @param invokeId       The task ID, which uniquely identifies a task.
     * @param commandTimeOut The execution timeout period of the command.
     */
    public static DescribeInvocationsResponse describeInvocations(String regionId, String invokeId, long commandTimeOut) {
        DescribeInvocationsRequest describeInvocationsRequest = new DescribeInvocationsRequest()
                .setRegionId(regionId)
                .setInvokeId(invokeId);

        long delay = 2;
        // Specify the maximum number of retries.
        int maxRetries = (int) (commandTimeOut / delay); 
        int retryCount = 0;

        try {
            while (retryCount < maxRetries) {
                ScheduledFuture<DescribeInvocationsResponse> future = SCHEDULER.schedule(() ->
                        ecsClient.describeInvocations(describeInvocationsRequest), delay, TimeUnit.SECONDS);
                DescribeInvocationsResponse results = future.get();
                List<DescribeInvocationsResponseBody.DescribeInvocationsResponseBodyInvocationsInvocation> invocationList = results.body.invocations.invocation;
                if (invocationList.isEmpty()) {
                    throw new RuntimeException("The command execution result was not found.");
                }
                DescribeInvocationsResponseBody.DescribeInvocationsResponseBodyInvocationsInvocation invocationResult = results.body.invocations.invocation.get(0);
                String invocationStatus = invocationResult.invocationStatus;
                switch (invocationStatus) {
                    case Constants.INVOCATION_STATUS.PENDING:
                    case Constants.INVOCATION_STATUS.RUNNING:
                    case Constants.INVOCATION_STATUS.STOPPING:
                        retryCount++;
                        continue;
                    default:
                        return results;
                }
            }
            throw new RuntimeException("Max retries exceeded for command execution result.");
        } catch (Exception e) {
            throw new RuntimeException("describeInvocationResults failed", e);
        }
    }


    public static class Constants {
        // The type of the command.
        public static final class COMMAND_TYPE {
            // Shell command, applicable to Windows instances. 
            public static final String RUN_SHELL_SCRIPT = "RunShellScript";
            // Batch command, applicable to Windows instances. 
            public static final String RUN_BAT_SCRIPT = "RunBatScript";
            // PowerShell command, applicable to Windows instances. 
            public static final String RUN_POWERSHELL_SCRIPT = "RunPowerShellScript";
        }

        // The execution results of the Cloud Assistant command.
        public static final class INVOCATION_STATUS {
            // The system is verifying or sending the command. 
            public static final String PENDING = "Pending";
            // The command is being run on the ECS instances. 
            public static final String RUNNING = "Running";
            // The command is being stopped. 
            public static final String STOPPING = "Stopping";
        }
    }
}
import os
import time
import logging
from alibabacloud_ecs20140526 import models as ecs_20140526_models
from alibabacloud_ecs20140526.client import Client as Ecs20140526Client
from alibabacloud_tea_openapi import models as open_api_models

# Configure logs.
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

ACCESS_KEY_ID = os.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID")
ACCESS_KEY_SECRET = os.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET")

if not ACCESS_KEY_ID or not ACCESS_KEY_SECRET:
    raise EnvironmentError(
        "Missing required environment variables: ALIBABA_CLOUD_ACCESS_KEY_ID and ALIBABA_CLOUD_ACCESS_KEY_SECRET")


def get_ecs_client(region_id):
    config = open_api_models.Config(
        access_key_id=ACCESS_KEY_ID,
        access_key_secret=ACCESS_KEY_SECRET,
        region_id=region_id
    )
    return Ecs20140526Client(config)


def execute_command(client, command_content, region_id, instance_ids, command_timeout, command_type):
    if not instance_ids:
        raise ValueError("Instance IDs list cannot be empty.")

    valid_command_types = ["RunShellScript", "RunBatScript", "RunPowerShellScript"]
    if command_type not in valid_command_types:
        raise ValueError(f"Invalid command type: {command_type}. Valid types are {valid_command_types}.")

    request = ecs_20140526_models.RunCommandRequest()
    request.region_id = region_id
    request.type = command_type
    request.command_content = command_content
    request.instance_ids = instance_ids
    request.timeout = command_timeout

    try:
        run_command_response = client.run_command(request)
        return run_command_response.to_map()['body']['InvokeId']
    except Exception as e:
        logging.error(f"Failed to execute command: {e}")
        raise


def query_invocations(client, region_id, invoke_id):
    request = ecs_20140526_models.DescribeInvocationsRequest()
    request.region_id = region_id
    request.invoke_ids = [invoke_id]

    try:
        describe_invocations_response = client.describe_invocations(request)
        return describe_invocations_response.to_map()['body']
    except Exception as e:
        logging.error(f"Failed to query invocations: {e}")
        raise


def wait_for_command_completion(client, region_id, invoke_id, max_retries, backoff_factor=2):
    retry_count = 0
    while retry_count < max_retries:
        time.sleep(backoff_factor ** retry_count)
        results = query_invocations(client, region_id, invoke_id)
        invocation_list = results.get('Invocations', {}).get('Invocation', [])
        if not invocation_list:
            raise RuntimeError("The command execution result was not found.")

        invocation_result = invocation_list[0]
        invocation_status = invocation_result.get('InvocationStatus')
        logging.info(f"Current invocation status: {invocation_status}")

        if invocation_status == "Finished":
            print("query_invocations result:", results)
            break
        elif invocation_status in ["Failed", "Stopped"]:
            raise RuntimeError(f"Command execution failed with status: {invocation_status}")
        else:
            retry_count += 1
    else:
        raise TimeoutError("Command execution timed out.")


def main():
    # The region ID.
    region_id = "cn-chengdu"
    # The IDs of the ECS instances on which you want to run the command.
    instance_ids = ["i-2vcXXXXXXXXXXXXXXXb8", "i-2vcXXXXXXXXXXXXXXXot"]
    # The content of the command.
    command_content = "#!/bin/bash\n cat /proc/meminfo"
    # The execution timeout period of the command.
    command_timeout = 60
    # The type of the command. Valid values: RunShellScript, RunBatScript, and RunPowerShellScript.
    command_type = "RunShellScript"

    client = get_ecs_client(region_id)
    invoke_id = execute_command(client, command_content, region_id, instance_ids, command_timeout, command_type)

    max_retries = max(int(command_timeout // 2), 1)
    wait_for_command_completion(client, region_id, invoke_id, max_retries)


if __name__ == "__main__":
    main()