135 lines
6.0 KiB
Python
135 lines
6.0 KiB
Python
# Copyright (C) 2013 Yahoo! Inc. All Rights Reserved.
|
|
#
|
|
# 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 datetime
|
|
import logging
|
|
import re
|
|
import time
|
|
|
|
from kombu import BrokerConnection
|
|
from kombu.common import maybe_declare
|
|
from kombu.pools import producers
|
|
from novaclient.client import Client
|
|
import paramiko
|
|
|
|
import base
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
class Audit(base.AuditBase):
|
|
# TODO(praneshp): this can be done with plumbum instead.
|
|
@staticmethod
|
|
def remote_call(cmd, **kwargs):
|
|
jumphost = kwargs['jump_host']
|
|
jump_user = kwargs['jump_user']
|
|
LOG.info('running %s remotely on %s', cmd, jumphost)
|
|
logging.getLogger("paramiko").setLevel(logging.WARNING)
|
|
ssh = paramiko.SSHClient()
|
|
# NOTE(praneshp): I'm working with a host I trust, this might
|
|
# not be true always, so be careful
|
|
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
|
ssh.connect(hostname=jumphost, username=jump_user)
|
|
stdin, stdout, stderr = ssh.exec_command(cmd)
|
|
return {'exit_status': stdout.channel.recv_exit_status(),
|
|
'stdout': stdout.readlines(),
|
|
'stderr': stderr.readlines()}
|
|
|
|
@staticmethod
|
|
def flavor_list_with_novaclient(**kwargs):
|
|
auth_url = 'http://{0}:5000/v2.0'.format(kwargs['api_host'])
|
|
LOG.info('auth url is %s', auth_url)
|
|
nc = Client(kwargs['nova_version'], kwargs['nova_username'],
|
|
kwargs['nova_password'], kwargs['nova_tenant'],
|
|
auth_url)
|
|
flavors = nc.flavors.list()
|
|
LOG.info('List of flavors: %s', flavors)
|
|
|
|
@staticmethod
|
|
def delete_with_cli(**kwargs):
|
|
auth_url = 'http://{0}:{1}/{2}'.format(kwargs['api_host'],
|
|
kwargs['auth_port'],
|
|
kwargs['auth_version'])
|
|
nova_prefix = 'nova --os-username {0} --os-password {1} ' \
|
|
'--os-tenant-name {2} ' \
|
|
'--os-auth-url {3} '.format(kwargs['nova_username'],
|
|
kwargs['nova_password'],
|
|
kwargs['nova_tenant'],
|
|
auth_url)
|
|
list_command = nova_prefix + ' list'
|
|
vm_list = Audit.remote_call(list_command, **kwargs)
|
|
if vm_list['exit_status'] == 0:
|
|
pattern = re.escape(kwargs['vm_id']) + r'-[0-9]*'
|
|
vms = re.findall(pattern, ' '.join(vm_list['stdout']))
|
|
uniq_vms = list(set(vms))
|
|
LOG.info('Deleting %s', uniq_vms)
|
|
delete_command = nova_prefix + ' delete ' + ' '.join(uniq_vms)
|
|
return Audit.remote_call(delete_command, **kwargs)
|
|
|
|
else:
|
|
return vm_list
|
|
|
|
@staticmethod
|
|
def flavor_list_with_cli(**kwargs):
|
|
auth_url = 'http://{0}:{1}/{2}'.format(kwargs['api_host'],
|
|
kwargs['auth_port'],
|
|
kwargs['auth_version'])
|
|
flavor_command = 'nova --os-username {0} --os-password {1} ' \
|
|
'--os-tenant-name {2} ' \
|
|
'--os-auth-url {3} ' \
|
|
'flavor-list'.format(kwargs['nova_username'],
|
|
kwargs['nova_password'],
|
|
kwargs['nova_tenant'],
|
|
auth_url)
|
|
return Audit.remote_call(flavor_command,
|
|
jump_host=kwargs['jump_host'],
|
|
jump_user=kwargs['jum[_user'])
|
|
|
|
@staticmethod
|
|
def boot_vm_with_cli(**kwargs):
|
|
delete_vms = Audit.delete_with_cli(**kwargs)
|
|
# NOTE(praneshp): we dont care if delete passed or not. Just
|
|
# boot vms, include both retuns in output
|
|
auth_url = 'http://{0}:{1}/{2}'.format(kwargs['api_host'],
|
|
kwargs['auth_port'],
|
|
kwargs['auth_version'])
|
|
boot_command = 'nova --os-username {0} --os-password {1} ' \
|
|
'--os-tenant-name {2} ' \
|
|
'--os-auth-url {3} ' \
|
|
'boot --flavor {4} --image {5} ' \
|
|
'{6}-{7}'.format(kwargs['nova_username'],
|
|
kwargs['nova_password'],
|
|
kwargs['nova_tenant'],
|
|
auth_url,
|
|
kwargs['flavor'],
|
|
kwargs['image'],
|
|
kwargs['vm_id'],
|
|
int(time.time()))
|
|
return {'delete_vms': delete_vms,
|
|
'boot': Audit.remote_call(boot_command, **kwargs)}
|
|
|
|
def send_message(self, **kwargs):
|
|
connection = BrokerConnection('amqp://%(mq_user)s:%(mq_password)s@'
|
|
'%(mq_host)s:%(mq_port)s//'
|
|
% kwargs['mq_args'])
|
|
message = {'From': __name__,
|
|
'Date': str(datetime.datetime.now().isoformat())}
|
|
with producers[connection].acquire(block=True) as producer:
|
|
maybe_declare(kwargs['exchange'], producer.channel)
|
|
message['payload'] = self.boot_vm_with_cli(**kwargs)
|
|
producer.publish(message,
|
|
exchange=self.exchange,
|
|
routing_key=self.routing_key,
|
|
serializer='json')
|