fuel-dev-tools/fuel_dev_tools/ssh.py

110 lines
3.3 KiB
Python

# Copyright 2015 Mirantis, Inc.
#
# 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.
import six
import subprocess
import fabric
from fabric import api as fabric_api
import exc
SSH_PASSWORD_CHECKED = False
print_verbose = six.print_
# TODO(pkaminski): ssh_command should be in some utils, not necessarily
# in this class?
class SSHMixin(object):
def __init__(self, *args, **kwargs):
super(SSHMixin, self).__init__(*args, **kwargs)
if self.app_args:
fabric_api.env.host_string = self.app_args.IP
fabric_api.env.user = 'root'
if not self.app_args.debug:
for key in fabric.state.output:
fabric.state.output[key] = False
def send_identity(self):
print_verbose('Sending identity %s for passwordless authentication' %
self.app_args.identity_file)
with open('%s.pub' % self.app_args.identity_file) as f:
contents = f.read()
result = fabric_api.run(
"echo '%s' >> ~/.ssh/authorized_keys" % contents
)
print_verbose(result)
# And while we're here, let's fix /etc/hosts for which 10.20.0.2
# points to some non-existing domain (with misconfigured reverse-DNS
# lookups each SSH connection can be quite slow)
result = fabric_api.run(
"sed -i 's/^%(IP)s.*/%(IP)s localhost/' /etc/hosts" % {
'IP': self.app_args.IP
}
)
print_verbose(result)
# Need to restart after /etc/hosts change
result = fabric_api.run('service sshd restart')
print_verbose(result)
return result
def ssh_command(self, *args):
global SSH_PASSWORD_CHECKED
if not SSH_PASSWORD_CHECKED:
# NOTE: test if key is added to .authorized_keys with
SSH_PASSWORD_CHECKED = True
try:
subprocess.check_output([
'ssh',
'-o',
'PasswordAuthentication=no',
'root@%s' % self.app_args.IP,
'echo 1'
], stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as e:
if 'remote host identification has changed' in \
six.u(e.output).decode('utf-8').lower():
# .ssh/known_hosts error
raise exc.SSHError(e.output)
# Exit code error -- send .pub key to host
self.send_identity()
return fabric_api.run(' '.join(args))
def ssh_command_interactive(self, *args):
print_verbose("COMMAND: %r" % list(args))
command = None
if args:
command = ' '.join(args)
print_verbose('interactive', command)
fabric_api.open_shell(command=command)