[james-page] Add support for resizing of instances.

This commit is contained in:
James Page 2014-02-11 13:41:12 +00:00
commit c15a4ae91d
3 changed files with 70 additions and 33 deletions

@ -291,6 +291,11 @@ def compute_changed():
ssh_compute_add(key)
relation_set(known_hosts=ssh_known_hosts_b64(),
authorized_keys=ssh_authorized_keys_b64())
if relation_get('nova_ssh_public_key'):
key = relation_get('nova_ssh_public_key')
ssh_compute_add(key, user='nova')
relation_set(nova_known_hosts=ssh_known_hosts_b64(user='nova'),
nova_authorized_keys=ssh_authorized_keys_b64(user='nova'))
@hooks.hook('cloud-compute-relation-departed')

@ -335,8 +335,10 @@ def keystone_ca_cert_b64():
return b64encode(_in.read())
def ssh_directory_for_unit():
def ssh_directory_for_unit(user=None):
remote_service = remote_unit().split('/')[0]
if user:
remote_service = "{}_{}".format(remote_service, user)
_dir = os.path.join(NOVA_SSH_DIR, remote_service)
for d in [NOVA_SSH_DIR, _dir]:
if not os.path.isdir(d):
@ -348,26 +350,26 @@ def ssh_directory_for_unit():
return _dir
def known_hosts():
return os.path.join(ssh_directory_for_unit(), 'known_hosts')
def known_hosts(user=None):
return os.path.join(ssh_directory_for_unit(user), 'known_hosts')
def authorized_keys():
return os.path.join(ssh_directory_for_unit(), 'authorized_keys')
def authorized_keys(user=None):
return os.path.join(ssh_directory_for_unit(user), 'authorized_keys')
def ssh_known_host_key(host):
cmd = ['ssh-keygen', '-f', known_hosts(), '-H', '-F', host]
def ssh_known_host_key(host, user=None):
cmd = ['ssh-keygen', '-f', known_hosts(user), '-H', '-F', host]
return subprocess.check_output(cmd).strip()
def remove_known_host(host):
def remove_known_host(host, user=None):
log('Removing SSH known host entry for compute host at %s' % host)
cmd = ['ssh-kegen', '-f', known_hosts(), '-R', host]
cmd = ['ssh-keygen', '-f', known_hosts(user), '-R', host]
subprocess.check_call(cmd)
def add_known_host(host):
def add_known_host(host, user=None):
'''Add variations of host to a known hosts file.'''
cmd = ['ssh-keyscan', '-H', '-t', 'rsa', host]
try:
@ -376,30 +378,30 @@ def add_known_host(host):
log('Could not obtain SSH host key from %s' % host, level=ERROR)
raise e
current_key = ssh_known_host_key(host)
current_key = ssh_known_host_key(host, user)
if current_key:
if remote_key == current_key:
log('Known host key for compute host %s up to date.' % host)
return
else:
remove_known_host(host)
remove_known_host(host, user)
log('Adding SSH host key to known hosts for compute node at %s.' % host)
with open(known_hosts(), 'a') as out:
with open(known_hosts(user), 'a') as out:
out.write(remote_key + '\n')
def ssh_authorized_key_exists(public_key):
with open(authorized_keys()) as keys:
def ssh_authorized_key_exists(public_key, user=None):
with open(authorized_keys(user)) as keys:
return (' %s ' % public_key) in keys.read()
def add_authorized_key(public_key):
with open(authorized_keys(), 'a') as keys:
def add_authorized_key(public_key, user=None):
with open(authorized_keys(user), 'a') as keys:
keys.write(public_key + '\n')
def ssh_compute_add(public_key):
def ssh_compute_add(public_key, user=None):
# If remote compute node hands us a hostname, ensure we have a
# known hosts entry for its IP, hostname and FQDN.
private_address = relation_get('private-address')
@ -414,31 +416,31 @@ def ssh_compute_add(public_key):
hosts.append(hn.split('.')[0])
for host in list(set(hosts)):
if not ssh_known_host_key(host):
add_known_host(host)
if not ssh_known_host_key(host, user):
add_known_host(host, user)
if not ssh_authorized_key_exists(public_key):
if not ssh_authorized_key_exists(public_key, user):
log('Saving SSH authorized key for compute host at %s.' %
private_address)
add_authorized_key(public_key)
add_authorized_key(public_key, user)
def ssh_known_hosts_b64():
with open(known_hosts()) as hosts:
def ssh_known_hosts_b64(user=None):
with open(known_hosts(user)) as hosts:
return b64encode(hosts.read())
def ssh_authorized_keys_b64():
with open(authorized_keys()) as keys:
def ssh_authorized_keys_b64(user=None):
with open(authorized_keys(user)) as keys:
return b64encode(keys.read())
def ssh_compute_remove(public_key):
if not (os.path.isfile(authorized_keys()) or
os.path.isfile(known_hosts())):
def ssh_compute_remove(public_key, user=None):
if not (os.path.isfile(authorized_keys(user)) or
os.path.isfile(known_hosts(user))):
return
with open(authorized_keys()) as _keys:
with open(authorized_keys(user)) as _keys:
keys = [k.strip() for k in _keys.readlines()]
if public_key not in keys:
@ -446,7 +448,7 @@ def ssh_compute_remove(public_key):
[keys.remove(key) for key in keys if key == public_key]
with open(authorized_keys(), 'w') as _keys:
with open(authorized_keys(user), 'w') as _keys:
_keys.write('\n'.join(keys))

@ -303,7 +303,7 @@ class NovaCCUtilsTests(CharmTestCase):
host_key.return_value = 'fookey_old'
with patch_open() as (_open, _file):
utils.add_known_host('foohost')
rm.assert_called_with('foohost')
rm.assert_called_with('foohost', None)
@patch.object(utils, 'known_hosts')
@patch.object(utils, 'remove_known_host')
@ -336,11 +336,17 @@ class NovaCCUtilsTests(CharmTestCase):
def test_known_hosts(self, ssh_dir):
ssh_dir.return_value = '/tmp/foo'
self.assertEquals(utils.known_hosts(), '/tmp/foo/known_hosts')
ssh_dir.assert_called_with(None)
self.assertEquals(utils.known_hosts('bar'), '/tmp/foo/known_hosts')
ssh_dir.assert_called_with('bar')
@patch.object(utils, 'ssh_directory_for_unit')
def test_authorized_keys(self, ssh_dir):
ssh_dir.return_value = '/tmp/foo'
self.assertEquals(utils.authorized_keys(), '/tmp/foo/authorized_keys')
ssh_dir.assert_called_with(None)
self.assertEquals(utils.authorized_keys('bar'), '/tmp/foo/authorized_keys')
ssh_dir.assert_called_with('bar')
@patch.object(utils, 'known_hosts')
@patch('subprocess.check_call')
@ -348,7 +354,7 @@ class NovaCCUtilsTests(CharmTestCase):
known_hosts.return_value = '/tmp/known_hosts'
utils.remove_known_host('foo')
check_call.assert_called_with([
'ssh-kegen', '-f', known_hosts(), '-R', 'foo'])
'ssh-keygen', '-f', known_hosts(), '-R', 'foo'])
@patch.object(utils, 'authorized_keys')
def test_ssh_authorized_key_exists(self, keys):
@ -424,3 +430,27 @@ class NovaCCUtilsTests(CharmTestCase):
'quantum_service': 'quantum'})
self.assertEquals(
endpoints, utils.determine_endpoints('http://foohost.com'))
@patch.object(utils, 'known_hosts')
@patch('subprocess.check_output')
def test_ssh_known_host_key(self, _check_output, _known_hosts):
_known_hosts.return_value = '/foo/known_hosts'
utils.ssh_known_host_key('test')
_check_output.assert_called_with(
['ssh-keygen', '-f', '/foo/known_hosts',
'-H', '-F', 'test'])
_known_hosts.assert_called_with(None)
utils.ssh_known_host_key('test', 'bar')
_known_hosts.assert_called_with('bar')
@patch.object(utils, 'known_hosts')
@patch('subprocess.check_call')
def test_remove_known_host(self, _check_call, _known_hosts):
_known_hosts.return_value = '/foo/known_hosts'
utils.remove_known_host('test')
_check_call.assert_called_with(
['ssh-keygen', '-f', '/foo/known_hosts',
'-R', 'test'])
_known_hosts.assert_called_with(None)
utils.remove_known_host('test', 'bar')
_known_hosts.assert_called_with('bar')