From 804e230e6ac7ca7b6db51171290e4b75ca46901f Mon Sep 17 00:00:00 2001 From: Borne Mace Date: Wed, 22 Jul 2015 17:29:42 -0700 Subject: [PATCH] improved key generation behavior. partially implemented ssh_check_connection. --- .gitignore | 1 + kollaclient/host.py | 26 ++++++---- kollaclient/sshutils.py | 102 +++++++++++++++++++++++++++++++--------- kollaclient/utils.py | 4 ++ 4 files changed, 101 insertions(+), 32 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..52d05a0 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +etc/ diff --git a/kollaclient/host.py b/kollaclient/host.py index 72e265c..d55497d 100644 --- a/kollaclient/host.py +++ b/kollaclient/host.py @@ -1,6 +1,8 @@ import logging from kollaclient.i18n import _ +from kollaclient.sshutils import ssh_check_connect +from kollaclient.sshutils import ssh_check_keys from kollaclient.sshutils import ssh_keygen from kollaclient.utils import load_etc_yaml from kollaclient.utils import save_etc_yaml @@ -16,21 +18,21 @@ class HostAdd(Command): def get_parser(self, prog_name): parser = super(HostAdd, self).get_parser(prog_name) parser.add_argument('hostname') - parser.add_argument('ipaddress') + parser.add_argument('networkaddress') # TODO(bmace) error if args missing return parser def take_action(self, parsed_args): hostname = parsed_args.hostname - ipaddr = parsed_args.ipaddress + networkAddress = parsed_args.networkaddress contents = load_etc_yaml('hosts.yml') for host, hostdata in contents.items(): if host == hostname: # TODO(bmace) fix message self.log.info(_("host already exists")) return - hostEntry = {hostname: {'Services': '', 'IPAddress': - ipaddr, 'Zone': ''}} + hostEntry = {hostname: {'Services': '', 'NetworkAddress': + networkAddress, 'Zone': ''}} contents.update(hostEntry) save_etc_yaml('hosts.yml', contents) @@ -118,6 +120,9 @@ class HostCheck(Command): def take_action(self, parsed_args): self.log.info(_("host check")) + sshKeysExist = ssh_check_keys() + if not sshKeysExist: + ssh_keygen() hostname = parsed_args.hostname contents = load_etc_yaml('hosts.yml') hostFound = False @@ -125,8 +130,9 @@ class HostCheck(Command): if host == hostname: # TODO(bmace) fix message hostFound = True - self.log.info(hostdata['IPAddress']) - return + networkAddress = hostdata['NetworkAddress'] + self.log.info(networkAddress) + ssh_check_connect(networkAddress) if hostFound is False: self.log.info("no host by name (" + hostname + ") found") @@ -145,7 +151,9 @@ class HostInstall(Command): def take_action(self, parsed_args): self.log.info(_("host install")) - ssh_keygen() + sshKeysExist = ssh_check_keys() + if not sshKeysExist: + ssh_keygen() hostname = parsed_args.hostname contents = load_etc_yaml('hosts.yml') hostFound = False @@ -153,8 +161,8 @@ class HostInstall(Command): if host == hostname: # TODO(bmace) fix message hostFound = True - self.log.info(hostdata['IPAddress']) - return + networkAddress = hostdata['NetworkAddress'] + self.log.info(networkAddress) if hostFound is False: self.log.info("no host by name (" + hostname + ") found") diff --git a/kollaclient/sshutils.py b/kollaclient/sshutils.py index 22a440f..5a6d6d1 100644 --- a/kollaclient/sshutils.py +++ b/kollaclient/sshutils.py @@ -1,41 +1,97 @@ import logging +import os.path import paramiko +from kollaclient.utils import get_admin_user from kollaclient.utils import get_pk_bits from kollaclient.utils import get_pk_file from kollaclient.utils import get_pk_password -def ssh_connect(hostname): +def ssh_check_keys(): + privateKeyPath = get_pk_file() + publicKeyPath = privateKeyPath + ".pub" + if os.path.isfile(privateKeyPath) and os.path.isfile(publicKeyPath): + return True + else: + return False + +def ssh_connect(netAddr, username, password, useKeys): log = logging.getLogger(__name__) + log.info("ssh connect " + netAddr) + try: + sshClient = paramiko.SSHClient() + privateKey = ssh_get_private_key() + sshClient.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + if useKeys: + sshClient.connect(hostname=netAddr, username=username, + password=password, pkey=privateKey) + else: + sshClient.connect(hostname=netAddr, username=username, + password=password, pkey=None) + except Exception as e: + # TODO(bmace) better failure behavior here + log.error(e) + log.error(type(e)) + log.error(e.args) + sshClient.close() + return sshClient - log.info("ssh connect " + hostname) - # ssh = paramiko.SSHClient() - # privateKey = paramiko.RSAKey.from_private_key_file(get_pk_file()) - # ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - return + +def ssh_check_connect(netAddr): + log = logging.getLogger(__name__) + log.info("ssh check connect " + netAddr) + try: + sshClient = ssh_connect(netAddr, get_admin_user(), '', True) + try: + sshClient.exec_command("ls") + return True + except paramiko.SSHException as sshException: + log.error("exec failed" + sshException) + log.error("exec failed" + type(sshException)) + log.error("exec failed" + sshException.args) + sshClient.close() + return False + except Exception as e: + # TODO(bmace) better failure behavior here + log.error(e) + log.error(type(e)) + log.error(e.args) + sshClient.close() def ssh_keygen(): - log = logging.getLogger(__name__) try: - log.info("keygen") - privateKey = paramiko.RSAKey.generate(get_pk_bits()) - log.info("writekey") - privateKey.write_private_key_file(filename=get_pk_file(), - password=get_pk_password()) - log.info("genpubkey") - publicKey = paramiko.RSAKey(filename=get_pk_file(), - password=get_pk_password()) - log.info("writepubkey") - with open("%s.pub" % get_pk_file(), 'w') as pubFile: - pubFile.write("%s %s" % (publicKey.get_name(), - publicKey.get_base64())) - log.info("donekeygen") + privateKeyPath = get_pk_file() + publicKeyPath = privateKeyPath + ".pub" + privateKey = None + privateKeyGenerated = False + if os.path.isfile(privateKeyPath) is False: + privateKey = paramiko.RSAKey.generate(get_pk_bits()) + privateKey.write_private_key_file(filename=privateKeyPath, + password=get_pk_password()) + privateKeyGenerated = True + log.info("generated private key at: " + privateKeyPath) + + # If the public key exists already, only regenerate it if the private + # key has changed + if os.path.isfile(publicKeyPath) is False or privateKeyGenerated: + publicKey = paramiko.RSAKey(filename=privateKeyPath, + password=get_pk_password()) + with open(publicKeyPath, 'w') as pubFile: + pubFile.write("%s %s" % (publicKey.get_name(), + publicKey.get_base64())) + log.info("generated public key at: " + publicKeyPath) except Exception as e: - print e - print type(e) - print e.args + # TODO(bmace) better failure behavior here + log.error(e) + log.error(type(e)) + log.error(e.args) + + +def ssh_get_private_key(): + return paramiko.RSAKey.from_private_key_file(get_pk_file(), + get_pk_password()) diff --git a/kollaclient/utils.py b/kollaclient/utils.py index 5de70bd..d0070a7 100644 --- a/kollaclient/utils.py +++ b/kollaclient/utils.py @@ -25,6 +25,10 @@ def get_client_etc(): return get_env("KOLLA_CLIENT_ETC", "/etc/kollaclient/etc/") +def get_admin_user(): + return get_env("KOLLA_ADMIN_USER", "kolla") + + def get_pk_file(): return get_env("KOLLA_CLIENT_PKPATH", "/opt/kollaclient/etc/id_rsa")