This topic describes how to use the third-party Python module Paramiko in a DataWorks node to remotely connect to an ECS instance and run a shell script. This topic provides code examples that show how to log on to an ECS instance from different types of nodes.
Notes
If you run a script on an ECS instance from a DataWorks node, the script continues to run on the ECS instance even if the DataWorks node stops.
This method of running scripts on an ECS instance from a DataWorks node is recommended only for data migration scenarios and not for daily production.
Overview
This topic provides examples of how to log on to an ECS instance using PyODPS and EMR Shell nodes:
DataWorks provides Secure Shell (SSH) nodes. You can use these nodes to access an ECS instance and run a script at a specified path.
Prerequisites
Create a Serverless resource group and configure its network connection.
For more information, see Network connection solutions.
NoteFor more information about how to retrieve the IP addresses of the Serverless resource group, see General configurations: Add IP addresses to a whitelist.
Install third-party Python packages in the Serverless resource group.
Install the required third-party package Paramiko using the custom image feature of the Serverless resource group. For more information, see Custom images.
Method 1: Use a PyODPS node to log on to an ECS instance with a username and password
You can log on to an ECS instance from a PyODPS node using a username and password. This example uses a PyODPS 3 node. The following code provides an example:
# For more information, see Call third-party packages in a PyODPS node: https://help.aliyun.com/document_detail/94159.html#section-f47-6lb-txv
# /home/tops/bin/pip3 install paramiko==2.11.0 -i https://pypi.tuna.tsinghua.edu.cn/simple
# /home/tops/bin/pip3 install --upgrade pip -i https://pypi.tuna.tsinghua.edu.cn/simple
from paramiko import SSHClient
import paramiko
import sys
client = SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect('172.16.0.0', username='root', password='****')
stdin, stdout, stderr = client.exec_command('sh /root/upload_mc_tpcds_1000_warehouse.sh')
stdout.channel.set_combine_stderr(True)
# print(type(stdin)) # <class 'paramiko.channel.ChannelStdinFile'>
# print(type(stdout)) # <class 'paramiko.channel.ChannelFile'>
# print(type(stderr)) # <class 'paramiko.channel.ChannelStderrFile'>
# Print output of command. Will wait for command to finish.
print(f'STDOUT: {stdout.read().decode("utf8")}')
# print(f'STDERR: {stderr.read().decode("utf8")}')
# Get return code from command (0 is default for success)
print(f'Return code: {stdout.channel.recv_exit_status()}')
return_code = stdout.channel.recv_exit_status()
stdin.close()
stdout.close()
stderr.close()
client.close()
if return_code == 0:
print(f'Over...')
sys.exit(0)
print(f'Remote shell is failed...')
Method 2: Use a PyODPS node to log on to an ECS instance with a username and private key and use a utility class
For more information about how to use a private key with Paramiko, see python - How do use paramiko.RSAKey.from_private_key()? - Stack Overflow.
Define a utility class.
You can define a utility class as a DataWorks Python resource. For more information about how to create a Python resource, see Create and use MaxCompute resources. In this example, the utility class is named
RemoteShell.py. The following code provides an example:# -*- coding: utf-8 -*- import sys from paramiko import SSHClient import paramiko class RemoteShell: def __init__(self, hostname, username, key_filename): self.hostname = hostname self.username = username self.key_filename = key_filename def run_remote_shell(self, cmd): client = SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) client.connect(hostname=self.hostname, username=self.username, key_filename=self.key_filename) stdin, stdout, stderr = client.exec_command(cmd) stdout.channel.set_combine_stderr(True) # Print output of command. Will wait for command to finish. print(f'STDOUT: {stdout.read().decode("utf8")}') # print(f'STDERR: {stderr.read().decode("utf8")}') # Get return code from command (0 is default for success) print(f'Return code: {stdout.channel.recv_exit_status()}') return_code = stdout.channel.recv_exit_status() stdin.close() stdout.close() stderr.close() client.close() if return_code == 0: print(f'Over...') sys.exit(0) print(f'Remote shell is failed...')Create the key file
run_remote_shell_user.pem.Upload the private key file as a File resource. For more information about how to upload a resource, see Create and use MaxCompute resources.
Create a PyODPS node and use the utility class and key file.
In this example, create a PyODPS 3 node named run_remote_shell_private_key_template. In the node, reference the
RemoteShell.pyutility class and therun_remote_shell_user.pemkey file. After you reference the resources, a comment is added to the code of the run_remote_shell_private_key_template node.In the run_remote_shell_private_key_template node, define variables and assign scheduling parameters to them. For more information about how to use scheduling parameters in a PyODPS node, see Use scheduling parameters in PyODPS.
##@resource_reference{"run_remote_shell_user.pem"} ##@resource_reference{"RemoteShell.py"} # For more information, see Call third-party packages in a PyODPS node: https://help.aliyun.com/document_detail/94159.html#section-f47-6lb-txv # /home/tops/bin/pip3 install paramiko==2.11.0 -i https://pypi.tuna.tsinghua.edu.cn/simple # /home/tops/bin/pip3 install --upgrade pip -i https://pypi.tuna.tsinghua.edu.cn/simple # Input parameters for PyODPS: https://help.aliyun.com/document_detail/417492.htm#section-uv0-uvh-oau # Dependencies on normal Python scripts: https://help.aliyun.com/document_detail/94159.html import sys import os sys.path.append(os.path.dirname(os.path.abspath('RemoteShell.py'))) # Import the resource to the current environment. from RemoteShell import RemoteShell # Reference the resource. You must remove the .py extension from the resource name. remoteShell = RemoteShell(hostname='172.16.0.0', username='****', key_filename='run_remote_shell_user.pem') dp = args['dp'] cmd = f'sh /root/dw-emr-shell.sh {dp}' print(f'Remote shell is : {cmd}') remoteShell.run_remote_shell(cmd) print("Remote Shell is finished.")
Method 3: Use an EMR Shell node to log on to an ECS instance with a username and password and use a utility class
Define a utility class.
Upload a Python file as an EMR resource file. For more information about Python resources, see Create an EMR resource. In this example, the Python resource is named
ecs.py.from paramiko import SSHClient import paramiko import sys, getopt username = '' password = '' ip = '' cmd = '' try: opts, args = getopt.getopt(sys.argv[1:], "u:p:i:c:", ["user=", "password=", "ip=", "cmd="]) except getopt.GetoptError: print('error get inputs') sys.exit(2) for opt, arg in opts: if opt in ("-u", "--user"): username = arg print('username: ' + username) elif opt in ("-p", "--password"): password = arg print('password: ' + password) elif opt in ("-i", "--ip"): ip = arg print('ip: ' + ip) elif opt in ("-c", "--cmd"): cmd = arg print('cmd: ' + cmd) print(username, password, ip, cmd) client = SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) client.connect(ip, username=username, password=password) stdin, stdout, stderr = client.exec_command(cmd) stdout.channel.set_combine_stderr(True) # Print output of command. Will wait for command to finish. print(f'STDOUT: {stdout.read().decode("utf8")}') # print(f'STDERR: {stderr.read().decode("utf8")}') # Get return code from command (0 is default for success) return_code = stdout.channel.recv_exit_status() print(f'Return code: {return_code}') stdin.close() stdout.close() stderr.close() client.close() if return_code == 0: print(f'Over...') sys.exit(0) print(f'Remote shell is failed...')Create an EMR Shell node and use the utility class.
In this example, create an EMR Shell node named run_remote_shell_EMR. In the run_remote_shell_EMR node, reference the
ecs.pyutility class. After you reference the resource, a comment is added.##@resource_reference{"ecs.py"} /home/tops/bin/python3 ecs.py -u root -p 'password' -i '172.0.X.X' -c 'sh /abc.sh'NoteThe parameters are described as follows:
-uspecifies the username to log on to the ECS instance.-pspecifies the password.-ispecifies the private IP address of the ECS instance.-cspecifies the command to run.
Method 4: Use an EMR Shell node to log on to an ECS instance with a username and private key and use a utility class
For more information about how to use a private key with Paramiko, see python - How do use paramiko.RSAKey.from_private_key()? - Stack Overflow.
Upload the private key.
Upload the private key for logging on to the ECS instance as an EMR File resource. For more information, see Create an EMR resource. In this example, the private key is
ssh_pair_yunlin_beijing.pem.Define a utility class.
You can define a utility class by uploading a Python file as an EMR resource file. For more information about how to upload a Python resource, see Create an EMR resource. In this example, the Python resource is named
run_remote_shell.py. The following code provides an example.NoteBefore you upload the Python file, modify the parameters as needed.
username: The username.ip: The IP address used to connect to the ECS instance.private_key: The name of the EMR resource file for the private key that you uploaded in Step 1.
from paramiko import SSHClient import paramiko import sys, getopt username = 'emr-user' # Replace the private_key name with the name of the uploaded private key resource. private_key = 'ssh_pair_yunlin_beijing.pem' password = '' ip = '172.16.8.188' cmd = sys.argv[1] print(f'params - ip: {ip}, username: {username}, ip: {ip}, cmd: {cmd}') client = SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) client.connect(ip, username=username, key_filename=private_key) stdin, stdout, stderr = client.exec_command(cmd) stdout.channel.set_combine_stderr(True) # Print output of command. Will wait for command to finish. print(f'STDOUT: {stdout.read().decode("utf8")}') # Get return code from command (0 is default for success) return_code = stdout.channel.recv_exit_status() print(f'Return code: {return_code}') stdin.close() stdout.close() stderr.close() client.close() if return_code == 0: print(f'Over...') sys.exit(0) print(f'Remote shell is failed...')Create an EMR Shell node and use the utility class.
In this example, create an EMR Shell node named
run_remote_shell. In the node, reference therun_remote_shell.pyutility class and thessh_pair_yunlin_beijing.pemprivate key. After you reference the resources, two comments are added. For more information about how to create an EMR Shell node and reference resources, see Create an EMR Shell node.##@resource_reference{"run_remote_shell.py"} ##@resource_reference{"ssh_pair_yunlin_beijing.pem"} /home/tops/bin/python3 run_remote_shell.py "ls /tmp/"NoteWhen you use the code, replace the resource_reference placeholder with the name of the resource that you uploaded.
The command that follows
run_remote_shell.pyis the command to run on the ECS instance.