Files
openGauss-OM/script/gs_ssh
2022-03-23 21:35:20 +08:00

250 lines
8.8 KiB
Python

#!/usr/bin/env python3
# -*- coding:utf-8 -*-
#############################################################################
# Copyright (c) 2020 Huawei Technologies Co.,Ltd.
#
# openGauss is licensed under Mulan PSL v2.
# You can use this software according to the terms
# and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
#
# http://license.coscl.org.cn/MulanPSL2
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.
# ----------------------------------------------------------------------------
# Description : gs_ssh is a utility to execute one command on all nodes.
#############################################################################
import os
import sys
import socket
from unittest import expectedFailure
package_path = os.path.dirname(os.path.realpath(__file__))
ld_path = package_path + "/gspylib/clib"
if 'LD_LIBRARY_PATH' not in os.environ:
os.environ['LD_LIBRARY_PATH'] = ld_path
os.execve(os.path.realpath(__file__), sys.argv, os.environ)
if not os.environ.get('LD_LIBRARY_PATH').startswith(ld_path):
os.environ['LD_LIBRARY_PATH'] = \
ld_path + ":" + os.environ['LD_LIBRARY_PATH']
os.execve(os.path.realpath(__file__), sys.argv, os.environ)
from gspylib.common.GaussLog import GaussLog
from gspylib.common.Common import DefaultValue
from gspylib.common.ErrorCode import ErrorCode
from gspylib.common.DbClusterInfo import dbClusterInfo
from gspylib.threads.SshTool import SshTool
from gspylib.common.ParameterParsecheck import Parameter
from gspylib.common.ParallelBaseOM import ParallelBaseOM
from gspylib.os.gsfile import g_file
from base_utils.os.env_util import EnvUtil
from base_utils.os.file_util import FileUtil
from domain_utils.cluster_file.version_info import VersionInfo
from base_utils.os.user_util import UserUtil
class ParallelSsh(ParallelBaseOM):
"""
The class is used to execute one command on all nodes.
"""
def __init__(self):
"""
function: initialize the parameters
input : NA
output: NA
"""
ParallelBaseOM.__init__(self)
self.userInfo = ""
self.cmd = ""
def usage(self):
"""
gs_ssh is a utility to execute one command on all %s cluster nodes.
Usage:
gs_ssh -? | --help
gs_ssh -V | --version
gs_ssh -c COMMAND
General options:
-c Command to be executed in cluster.
-?, --help Show help information for this utility,
and exit the command line mode.
-V, --version Show version information.
"""
print(self.usage.__doc__ % VersionInfo.PRODUCT_NAME)
def parseCommandLine(self):
"""
function: parse command line
input : NA
output: NA
"""
##Parse command
ParaObj = Parameter()
ParaDict = ParaObj.ParameterCommandLine("ssh")
# If help is included in the parameter,
# the help message is printed and exited
if (ParaDict.__contains__("helpFlag")):
self.usage()
sys.exit(0)
# Gets the cmd parameter
if (ParaDict.__contains__("cmd")):
self.cmd = ParaDict.get("cmd")
# The cmd parameter is required
if (self.cmd == ""):
GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50001"]
% 'c' + ".")
def check_nodename_recognized(self, node_names):
"""
function: Check if nodename can be recognized.
input : NA
output: NA
"""
try:
for name in node_names:
socket.gethostbyname(name)
except Exception as e:
GaussLog.printMessage(
"[Warning] Name or service not known on node [%s]." % name)
return False
return True
def initGlobal(self):
"""
function: Init global parameter
input : NA
output: NA
"""
try:
# Get user information
self.user = UserUtil.getUserInfo()["name"]
self.clusterInfo = dbClusterInfo()
self.clusterInfo.initFromStaticConfig(self.user)
nodeNames = self.clusterInfo.getClusterNodeNames()
if self.check_nodename_recognized(nodeNames):
self.sshTool = SshTool(nodeNames)
else:
nodeSshIps = self.clusterInfo.getClusterSshIps()[0]
self.sshTool = SshTool(nodeSshIps)
except Exception as e:
GaussLog.exitWithError(str(e))
def executeCommand(self):
"""
function: execute command
input : NA
output: NA
"""
failedNodes = ""
succeedNodes = ""
# Create a temporary shell file
cmdFile = "%s/ClusterCall_%d.sh"\
% (EnvUtil.getTmpDirFromEnv(), os.getpid())
try:
# Queries the existence of objects that
# the command executes in all nodes
command = (self.cmd.strip()).split(" ")
checkCmd = g_file.SHELL_CMD_DICT["getFullPathForShellCmd"] % \
command[0]
(status, output) = self.sshTool.getSshStatusOutput(checkCmd)
# Resolve all node execution results
for node in status.keys():
if (status[node] != DefaultValue.SUCCESS):
failedNodes += "%s " % node
else:
succeedNodes += "%s " % node
if (failedNodes != ""):
GaussLog.exitWithError(ErrorCode.GAUSS_524["GAUSS_52403"]
% (command[0], failedNodes))
failedNodes = ""
succeedNodes = ""
executeCmd = self.cmd
#############################################################
FileUtil.createFile(cmdFile, True, DefaultValue.FILE_MODE)
# Writes the cmd command to the shell
with open(cmdFile, "a") as fp:
fp.write("#!/bin/sh")
fp.write(os.linesep)
fp.write("%s" % executeCmd)
fp.write(os.linesep)
fp.flush()
##############################################################
cmdDir = EnvUtil.getTmpDirFromEnv() + '/'
# Distribute the shell file to the temporary directory
# for each node
self.sshTool.scpFiles(cmdFile, cmdDir)
# Execute the shell file on all nodes
cmdExecute = g_file.SHELL_CMD_DICT["execShellFile"] % cmdFile
(status, output) = self.sshTool.getSshStatusOutput(cmdExecute)
# Resolve the execution results of all nodes
for node in status.keys():
if (status[node] != DefaultValue.SUCCESS):
failedNodes += "%s " % node
else:
succeedNodes += "%s " % node
# Some nodes fail to execute
if (failedNodes != "" and succeedNodes != ""):
GaussLog.printMessage(
"Failed to execute command on %s." % failedNodes)
GaussLog.printMessage(
"Successfully execute command on %s.\n" % succeedNodes)
# All nodes execute successfully
elif (failedNodes == ""):
GaussLog.printMessage(
"Successfully execute command on all nodes.\n")
# All nodes fail to execute
elif (succeedNodes == ""):
GaussLog.printMessage(
"Failed to execute command on all nodes.\n")
# Output Execution result
GaussLog.printMessage("Output:\n%s" % output)
# Delete the temporary shell file at all nodes
cmdFileRm = g_file.SHELL_CMD_DICT["deleteFile"]\
% (cmdFile, cmdFile)
self.sshTool.executeCommand(cmdFileRm)
except Exception as e:
cmdFileRm = g_file.SHELL_CMD_DICT["deleteFile"]\
% (cmdFile, cmdFile)
self.sshTool.executeCommand(cmdFileRm)
GaussLog.exitWithError(str(e))
def run(self):
"""
function: Perform the whole process
input : NA
output: NA
"""
# parse cmd lines
self.parseCommandLine()
# init globals
self.initGlobal()
# execute command
self.executeCommand()
if __name__ == '__main__':
# main function
# Can not run as root
if (os.getuid() == 0):
GaussLog.exitWithError(ErrorCode.GAUSS_501["GAUSS_50105"])
try:
parallelSsh = ParallelSsh()
parallelSsh.run()
except Exception as e:
GaussLog.exitWithError(str(e))
sys.exit(0)