ECS Sample to start/stop/reboot an instance¶
This sample demonstrates how to start/stop/reboot an ECS instance using FunctionGraph and:
Prerequisites¶
For this example an ECS instance must exist.
The function must have permissions to start/stop/reboot the ECS instance.
This can be achieved by creating an agency with a policy granting the permission ecs:*:start, ecs:*:stop, and ecs:*:reboot and specifying this agency when creating the function. (E.g. create an agency with ECS User System-defined policy).
Source¶
Source for this sample can be found in: /samples-doc/sdk-ecs.
package main
/**
SDK ECS example
This example shows how to use the OpenTelekomCloud API SDK to start, stop or reboot an ECS instance using the FunctionGraph service.
For API reference, see:
- https://docs.otc.t-systems.com/elastic-cloud-server/api-ref/apis_recommended/batch_operations/restarting_ecss_in_a_batch.html#restarting-ecss-in-a-batch
The function reads the following user data parameters:
- ECS_ENDPOINT_URL: The endpoint URL of the ECS service (optional, default value is used if not provided)
- ECS_INSTANCE_ID: The ID of the ECS instance to be managed
- ECS_ACTION: The action to be performed on the instance (start, stop, reboot)
- ECS_ACTION_TYPE: The type of action for stop and reboot (SOFT, HARD) (not required for start action)
The function uses the security credentials (temporary AK/SK/Token) from the runtime context to sign the API requests.
*/
import (
"bytes"
"encoding/json"
"io"
"strings"
"errors"
"net/http"
"github.com/opentelekomcloud-community/otc-functiongraph-go-runtime/go-runtime/go-api/context"
"github.com/opentelekomcloud-community/otc-functiongraph-go-runtime/go-runtime/pkg/runtime"
"github.com/opentelekomcloud-community/otc-api-sign-sdk-go/core"
)
func handlerECS(payload []byte, ctx context.RuntimeContext) (interface{}, error) {
// get ProjectID from context
project_id := ctx.GetProjectID()
// get ECS endpoint from user data or use default value
var endpoint = ctx.GetUserData("ECS_ENDPOINT_URL")
if endpoint == "" {
endpoint = "https://ecs.eu-de.otc.t-systems.com"
}
// get InstanceID from user data
instance_id := ctx.GetUserData("ECS_INSTANCE_ID")
if (instance_id) == "" {
ctx.GetLogger().Logf("ECS_INSTANCE_ID not defined")
return "ECS_INSTANCE_ID not defined", errors.New("ECS_INSTANCE_ID not defined")
}
action := strings.ToLower(ctx.GetUserData("ECS_ACTION"))
if action == "" {
ctx.GetLogger().Logf("ECS_ACTION not defined, supported: start, stop, reboot")
return "ECS_ACTION not defined", errors.New("ECS_ACTION not defined")
}
if action != "start" && action != "stop" && action != "reboot" {
ctx.GetLogger().Logf("ECS_ACTION not supported, supported: start, stop, reboot")
return "ECS_ACTION not supported", errors.New("ECS_ACTION not supported")
}
actionType := strings.ToUpper(ctx.GetUserData("ECS_ACTION_TYPE"))
if actionType == "" && action != "start" {
ctx.GetLogger().Logf("ECS_ACTION_TYPE not defined, supported: SOFT, HARD")
return "ECS_ACTION_TYPE not defined", errors.New("ECS_ACTION_TYPE not defined")
}
if actionType != "SOFT" && actionType != "HARD" && action != "start" {
ctx.GetLogger().Logf("ECS_ACTION_TYPE not supported, supported: SOFT, HARD")
return "ECS_ACTION_TYPE not supported", errors.New("ECS_ACTION_TYPE not supported")
}
var jsonStr map[string]interface{}
//
switch action {
case "start":
jsonStr = map[string]interface{}{
"os-start": map[string]interface{}{
"servers": []map[string]string{
{"id": instance_id},
},
},
}
case "stop":
jsonStr = map[string]interface{}{
"os-stop": map[string]interface{}{
"type": actionType,
"servers": []map[string]string{
{"id": instance_id},
},
},
}
case "reboot":
jsonStr = map[string]interface{}{
"reboot": map[string]interface{}{
"type": actionType,
"servers": []map[string]string{
{"id": instance_id},
},
},
}
}
// Marshal the JSON body
jsonData, err := json.Marshal(jsonStr)
if err != nil {
ctx.GetLogger().Logf("JSON marshal failed:", err)
return "invalid json", err
}
// Create the HTTP request
request, err := http.NewRequest("POST", endpoint+"/v1/"+project_id+"/cloudservers/action",
bytes.NewReader(jsonData))
if err != nil {
ctx.GetLogger().Logf("ECS request failed:", err)
return "invalid request", err
}
// set headers
request.Header.Set("content-type", "application/json; charset=utf-8")
if project_id != "" {
// To access resources in a sub-project (e.g. eu_de/myproject)
// by calling APIs, X-Project-Id of "eu_de/myproject" is needed
request.Header.Set("X-Project-Id", project_id)
}
// create signer
signer := core.Signer{
Key: ctx.GetSecurityAccessKey(),
Secret: ctx.GetSecuritySecretKey(),
SecurityToken: ctx.GetSecurityToken(),
}
// sign the request
signer.Sign(request)
// create http client
client := http.DefaultClient
// Send the request
resp, err := client.Do(request)
if err != nil {
ctx.GetLogger().Logf("ECS request failed:", err)
return "invalid request", err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
panic(err)
}
// prepare return value
ret := map[string]interface{}{
"statusCode": resp.StatusCode,
"body": string(body),
}
return ret, nil
}
func main() {
runtime.Register(handlerECS)
}
This files contains the main program.
/go.mod¶module sample-sdk-ecs go 1.17 require github.com/opentelekomcloud-community/otc-functiongraph-go-runtime v0.0.0-00010101000000-000000000000 require github.com/opentelekomcloud-community/otc-api-sign-sdk-go/core v0.0.0-20251112091753-b8b34d231d68 // indirect replace github.com/opentelekomcloud-community/otc-functiongraph-go-runtime => ../../../otc-functiongraph-go-runtime
Build the project¶
To build the project, navigate to the project directory and run the following command:
For Windows Subsystem for Linux (WSL) or Linux/MacOS systems use following makefile:
/Makefile¶HANDLER_NAME=go-ecs-demo build: GOARCH=amd64 GOOS=linux CGO_ENABLED=0 go build -o target/$(HANDLER_NAME) src/main.go zip: printf "# Handler name\n${HANDLER_NAME}" > target/handler_name.txt cd target && zip -r ../deploy.zip . clean: rm -f deploy.zip rm -rf target all: build zip .PHONY: build zip clean allThen run the command:
make allThis command builds the project in target folder and creates a zip file in the project folder.
The generated zip file is: deploy.zip
For Windows use following script:
rem #############################################################
rem # Build script for Golang Event Function
rem # for Linux target on Windows
rem #############################################################
rem set visibility of environment changes to local only
SETLOCAL
rem Set the following parameters to the corresponding value of Linux
set GOARCH=amd64
set GOOS=linux
set CGO_ENABLED=0
set GO111MODULE=on
rem set handler name
set HANDLER_NAME=go-ecs-demo
rem create target_win folder if not exists
if not exist "target_win" md "target_win"
rem build the Go HTTP function in target_win folder
go build -o target_win/%HANDLER_NAME% src/main.go
rem package the target_win folder to a zip file
tar.exe -c -a -f deploy.zip -C target_win *
Then run the command:
build.cmd
This command builds the project in target_win folder and creates a zip file in the project folder.
The generated zip file is: deploy.zip
Deploy the function¶
Use OpentelekomCloud FunctionGraph console to create a function with following settings:
Create function¶
Create With: Create from scratch
Basic Information
Function Type Event Function
Region <YOUR REGION>
Function Name <YOUR FUNCTION NAME>
Agency Specify an agency with policy to start ECS instance
Runtime Go 1.x
Upload code¶
Use Upload > Local ZIP and upload deploy.zip from previous step.
Configure function¶
In Configuration > Basic Settings > Handler: set value to name as defined in handler.txt
In Configuration > Environment Variables add following variables:
Environment variables¶ Environment variable name
Value
Remarks
ECS_INSTANCE_ID
<ID of ecs instance>
ID of ECS instance to start
ECS_ENDPOINT_URL
<ecs endpoint>
Default: https://ecs.eu-de.otc.t-systems.com see Regions and Endpoints
ECS_ACTION
<action>
Action to perform on the ECS instance (“start”, “stop”, “reboot”), default: “start”
ECS_ACTION_TYPE
<action type>
Action type to perform on the ECS instance for reboot/stop (“SOFT”, “HARD”), default: “SOFT”
Test the function¶
Create Test Event¶
In Code create a Test Event using “Blank Template” (Event is not used in function).
Test function¶
Click Test to test function.
The function execution result is displayed in the Execution Result section.