Use python package instead of sshpass to execute remote commands.
Use python package instead of sshpass to execute remote commands. Fixing this issue, by using paramiko. Co-Authored-By: Sridhar Ramaswamy <srics.r@gmail.com> Closes-bug: #1511658 Change-Id: I102d178b2fb1f621f2a61b26a939e69613156c19
This commit is contained in:
parent
de6cc86ae0
commit
2259e752c8
|
@ -39,3 +39,4 @@ python-novaclient!=2.33.0,>=2.29.0 # Apache-2.0
|
|||
tosca-parser>=0.5.0 # Apache-2.0
|
||||
heat-translator>=0.4.0 # Apache-2.0
|
||||
cryptography!=1.3.0,>=1.0 # BSD/Apache-2.0
|
||||
paramiko>=2.0 # LGPLv2.1+
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from oslo_log import log as logging
|
||||
import paramiko
|
||||
|
||||
from tacker.common.exceptions import NotAuthorized
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CommandResult(object):
|
||||
"""Result class contains command, stdout, stderror and return code."""
|
||||
def __init__(self, cmd, stdout, stderr, return_code):
|
||||
self.__cmd = cmd
|
||||
self.__stdout = stdout
|
||||
self.__stderr = stderr
|
||||
self.__return_code = return_code
|
||||
|
||||
def get_command(self):
|
||||
return self.__cmd
|
||||
|
||||
def get_stdout(self):
|
||||
return self.__stdout
|
||||
|
||||
def get_stderr(self):
|
||||
return self.__stderr
|
||||
|
||||
def get_return_code(self):
|
||||
return self.__return_code
|
||||
|
||||
def __str__(self):
|
||||
return "cmd: %s, stdout: %s, stderr: %s, return code: %s" \
|
||||
% (self.__cmd, self.__stdout, self.__stderr, self.__return_code)
|
||||
|
||||
def __repr__(self):
|
||||
return "cmd: %s, stdout: %s, stderr: %s, return code: %s" \
|
||||
% (self.__cmd, self.__stdout, self.__stderr, self.__return_code)
|
||||
|
||||
|
||||
class RemoteCommandExecutor(object):
|
||||
"""Class to execute a command on remote location"""
|
||||
def __init__(self, user, password, host, timeout=10):
|
||||
self.__user = user
|
||||
self.__password = password
|
||||
self.__host = host
|
||||
self.__paramiko_conn = None
|
||||
self.__ssh = None
|
||||
self.__timeout = timeout
|
||||
self.__connect()
|
||||
|
||||
def __connect(self):
|
||||
try:
|
||||
self.__ssh = paramiko.SSHClient()
|
||||
self.__ssh.set_missing_host_key_policy(paramiko.WarningPolicy())
|
||||
self.__ssh.connect(self.__host, username=self.__user,
|
||||
password=self.__password, timeout=self.__timeout)
|
||||
LOG.info(_("Connected to %s") % self.__host)
|
||||
except paramiko.AuthenticationException:
|
||||
LOG.error(_("Authentication failed when connecting to %s")
|
||||
% self.__host)
|
||||
raise NotAuthorized
|
||||
except paramiko.SSHException:
|
||||
LOG.error(_("Could not connect to %s. Giving up") % self.__host)
|
||||
raise
|
||||
|
||||
def close_session(self):
|
||||
self.__ssh.close()
|
||||
LOG.debug(_("Connection close"))
|
||||
|
||||
def execute_command(self, cmd, input_data=None):
|
||||
try:
|
||||
stdin, stdout, stderr = self.__ssh.exec_command(cmd)
|
||||
if input_data:
|
||||
stdin.write(input_data)
|
||||
LOG.debug(_("Input data written successfuly"))
|
||||
stdin.flush()
|
||||
LOG.debug(_("Indput data flushed"))
|
||||
stdin.channel.shutdown_write()
|
||||
|
||||
# NOTE (dkushwaha): There might be a case, when server can take
|
||||
# too long time to write data in stdout buffer or sometimes hang
|
||||
# itself, in that case readlines() will stuck for long/infinite
|
||||
# time. To handle such cases, timeout logic should be introduce
|
||||
# here.
|
||||
cmd_out = stdout.readlines()
|
||||
cmd_err = stderr.readlines()
|
||||
return_code = stdout.channel.recv_exit_status()
|
||||
except paramiko.SSHException:
|
||||
LOG.error(_("Command execution failed at %s. Giving up")
|
||||
% self.__host)
|
||||
raise
|
||||
result = CommandResult(cmd, cmd_out, cmd_err, return_code)
|
||||
LOG.debug(_("Remote command execution result: %s"), result)
|
||||
return result
|
||||
|
||||
def __del__(self):
|
||||
self.close_session()
|
|
@ -239,3 +239,7 @@ class DeviceIDNotOwnedByTenant(Conflict):
|
|||
|
||||
class InvalidCIDR(BadRequest):
|
||||
message = _("Invalid CIDR %(input)s given as IP prefix")
|
||||
|
||||
|
||||
class MgmtDriverException(TackerException):
|
||||
message = _("VNF configuration failed")
|
||||
|
|
|
@ -19,7 +19,8 @@ from oslo_log import log as logging
|
|||
from oslo_serialization import jsonutils
|
||||
import yaml
|
||||
|
||||
from tacker.agent.linux import utils
|
||||
from tacker.common import cmd_executer
|
||||
from tacker.common.exceptions import MgmtDriverException
|
||||
from tacker.common import log
|
||||
from tacker.vm.mgmt_drivers import abstract_driver
|
||||
from tacker.vm.mgmt_drivers import constants as mgmt_constants
|
||||
|
@ -51,11 +52,16 @@ class DeviceMgmtOpenWRT(abstract_driver.DeviceMGMTAbstractDriver):
|
|||
def _config_service(self, mgmt_ip_address, service, config):
|
||||
user = cfg.CONF.openwrt.user
|
||||
password = cfg.CONF.openwrt.password
|
||||
cmd = ["sshpass", "-p", "%s" % password,
|
||||
"ssh", "-o", "StrictHostKeyChecking=no",
|
||||
"%s@%s" % (user, mgmt_ip_address),
|
||||
"uci import %s; /etc/init.d/%s restart" % (service, service)]
|
||||
utils.execute(cmd, process_input=config)
|
||||
try:
|
||||
cmd = "uci import %s; /etc/init.d/%s restart" % (service, service)
|
||||
LOG.debug(_('execute command: %s'), (cmd))
|
||||
commander = cmd_executer.RemoteCommandExecutor(user,
|
||||
password,
|
||||
mgmt_ip_address)
|
||||
commander.execute_command(cmd, input_data=config)
|
||||
except Exception as ex:
|
||||
LOG.error(_("While executing command on remote: %s"), ex)
|
||||
raise MgmtDriverException()
|
||||
|
||||
@log.log
|
||||
def mgmt_call(self, plugin, context, device, kwargs):
|
||||
|
|
|
@ -25,6 +25,7 @@ from oslo_utils import excutils
|
|||
|
||||
from tacker.api.v1 import attributes
|
||||
from tacker.common import driver_manager
|
||||
from tacker.common.exceptions import MgmtDriverException
|
||||
from tacker.db.vm import vm_db
|
||||
from tacker.extensions import vnfm
|
||||
from tacker.i18n import _LE
|
||||
|
@ -231,11 +232,11 @@ class VNFMPlugin(vm_db.VNFMPluginDb, VNFMMgmtMixin):
|
|||
new_status = constants.ACTIVE
|
||||
try:
|
||||
self.mgmt_call(context, device_dict, kwargs)
|
||||
except Exception:
|
||||
LOG.exception(_('create_device_wait'))
|
||||
except MgmtDriverException:
|
||||
LOG.error(_('VNF configuration failed'))
|
||||
new_status = constants.ERROR
|
||||
self.set_device_error_status_reason(context, device_id,
|
||||
'Unable to configure VDU')
|
||||
'Unable to configure VDU')
|
||||
device_dict['status'] = new_status
|
||||
self._create_device_status(context, device_id, new_status)
|
||||
|
||||
|
@ -307,8 +308,8 @@ class VNFMPlugin(vm_db.VNFMPluginDb, VNFMMgmtMixin):
|
|||
context=context, device_id=instance_id, auth_attr=vim_auth,
|
||||
region_name=region_name)
|
||||
self.mgmt_call(context, device_dict, kwargs)
|
||||
except Exception as e:
|
||||
LOG.exception(_('_update_device_wait'))
|
||||
except MgmtDriverException as e:
|
||||
LOG.error(_('VNF configuration failed'))
|
||||
new_status = constants.ERROR
|
||||
self.set_device_error_status_reason(context, device_dict['id'],
|
||||
six.text_type(e))
|
||||
|
|
Loading…
Reference in New Issue