/teuthology/task/ssh_keys.py
https://github.com/hjwsm1989/teuthology · Python · 180 lines · 109 code · 28 blank · 43 comment · 21 complexity · cd242a46574a163e542103c0011bc2d3 MD5 · raw file
- #!/usr/bin/python
- """
- Ssh-key key handlers and associated routines
- """
- import contextlib
- import logging
- import paramiko
- import re
- from cStringIO import StringIO
- from teuthology import contextutil
- import teuthology.misc as misc
- from ..orchestra import run
- log = logging.getLogger(__name__)
- ssh_keys_user = 'ssh-keys-user'
- def generate_keys():
- """
- Generatees a public and private key
- """
- key = paramiko.RSAKey.generate(2048)
- privateString = StringIO()
- key.write_private_key(privateString)
- return key.get_base64(), privateString.getvalue()
- def particular_ssh_key_test(line_to_test, ssh_key):
- """
- Check the validity of the ssh_key
- """
- match = re.match('[\w-]+ {key} \S+@\S+'.format(key=re.escape(ssh_key)), line_to_test)
- if match:
- return False
- else:
- return True
- def ssh_keys_user_line_test(line_to_test, username ):
- """
- Check the validity of the username
- """
- match = re.match('[\w-]+ \S+ {username}@\S+'.format(username=username), line_to_test)
- if match:
- return False
- else:
- return True
- def cleanup_added_key(ctx):
- """
- Delete the keys and removes ~/.ssh/authorized_keys2 entries we added
- """
- log.info('cleaning up keys added for testing')
- for remote in ctx.cluster.remotes:
- username, hostname = str(remote).split('@')
- if "" == username or "" == hostname:
- continue
- else:
- log.info(' cleaning up keys for user {user} on {host}'.format(host=hostname, user=username))
- misc.delete_file(remote, '/home/{user}/.ssh/id_rsa'.format(user=username))
- misc.delete_file(remote, '/home/{user}/.ssh/id_rsa.pub'.format(user=username))
- misc.delete_file(remote, '/home/{user}/.ssh/authorized_keys2'.format(user=username))
- @contextlib.contextmanager
- def tweak_ssh_config(ctx, config):
- """
- Turn off StrictHostKeyChecking
- """
- run.wait(
- ctx.cluster.run(
- args=[
- 'echo',
- 'StrictHostKeyChecking no\n',
- run.Raw('>'),
- run.Raw('/home/ubuntu/.ssh/config'),
- run.Raw('&&'),
- 'echo',
- 'UserKnownHostsFile ',
- run.Raw('/dev/null'),
- run.Raw('>>'),
- run.Raw('/home/ubuntu/.ssh/config'),
- run.Raw('&&'),
- run.Raw('chmod 600 /home/ubuntu/.ssh/config'),
- ],
- wait=False,
- )
- )
- try:
- yield
- finally:
- run.wait(
- ctx.cluster.run(
- args=['rm',run.Raw('/home/ubuntu/.ssh/config')],
- wait=False
- ),
- )
- @contextlib.contextmanager
- def push_keys_to_host(ctx, config, public_key, private_key):
- """
- Push keys to all hosts
- """
- log.info('generated public key {pub_key}'.format(pub_key=public_key))
- # add an entry for all hosts in ctx to auth_keys_data
- auth_keys_data = ''
- for inner_host in ctx.cluster.remotes.iterkeys():
- inner_username, inner_hostname = str(inner_host).split('@')
- # create a 'user@hostname' string using our fake hostname
- fake_hostname = '{user}@{host}'.format(user=ssh_keys_user, host=str(inner_hostname))
- auth_keys_data += '\nssh-rsa {pub_key} {user_host}\n'.format(pub_key=public_key, user_host=fake_hostname)
- # for each host in ctx, add keys for all other hosts
- for remote in ctx.cluster.remotes:
- username, hostname = str(remote).split('@')
- if "" == username or "" == hostname:
- continue
- else:
- log.info('pushing keys to {host} for {user}'.format(host=hostname, user=username))
- # adding a private key
- priv_key_file = '/home/{user}/.ssh/id_rsa'.format(user=username)
- priv_key_data = '{priv_key}'.format(priv_key=private_key)
- misc.delete_file(remote, priv_key_file, force=True)
- # Hadoop requires that .ssh/id_rsa have permissions of '500'
- misc.create_file(remote, priv_key_file, priv_key_data, str(500))
- # then a private key
- pub_key_file = '/home/{user}/.ssh/id_rsa.pub'.format(user=username)
- pub_key_data = 'ssh-rsa {pub_key} {user_host}'.format(pub_key=public_key, user_host=str(remote))
- misc.delete_file(remote, pub_key_file, force=True)
- misc.create_file(remote, pub_key_file, pub_key_data)
- # adding appropriate entries to the authorized_keys2 file for this host
- auth_keys_file = '/home/{user}/.ssh/authorized_keys2'.format(user=username)
- # now add the list of keys for hosts in ctx to ~/.ssh/authorized_keys2
- misc.create_file(remote, auth_keys_file, auth_keys_data, str(600))
- try:
- yield
- finally:
- # cleanup the keys
- log.info("Cleaning up SSH keys")
- cleanup_added_key(ctx)
- @contextlib.contextmanager
- def task(ctx, config):
- """
- Creates a set of RSA keys, distributes the same key pair
- to all hosts listed in ctx.cluster, and adds all hosts
- to all others authorized_keys list.
- During cleanup it will delete .ssh/id_rsa, .ssh/id_rsa.pub
- and remove the entries in .ssh/authorized_keys while leaving
- pre-existing entries in place.
- """
- if config is None:
- config = {}
- assert isinstance(config, dict), \
- "task hadoop only supports a dictionary for configuration"
- # this does not need to do cleanup and does not depend on
- # ctx, so I'm keeping it outside of the nested calls
- public_key_string, private_key_string = generate_keys()
- with contextutil.nested(
- lambda: tweak_ssh_config(ctx, config),
- lambda: push_keys_to_host(ctx, config, public_key_string, private_key_string),
- #lambda: tweak_ssh_config(ctx, config),
- ):
- yield