Exemple #1
0
 def __init__(self,
              hostname,
              username='******',
              password=None,
              keypath=None,
              region_domain=None,
              proxy_hostname=None,
              proxy_username=None,
              proxy_password=None,
              proxy_keypath=None,
              config_yml=None,
              config_qa=None,
              credpath=None,
              aws_access_key=None,
              aws_secret_key=None,
              log_level='INFO',
              boto_debug_level=0,
              euca_user='******',
              euca_account='eucalyptus',
              https=True):
     self.machine_connect_kwargs = {
         'hostname': hostname,
         'username': username,
         'password': password,
         'keypath': keypath,
         'proxy_hostname': proxy_hostname,
         'proxy_username': proxy_username or username,
         'proxy_password': proxy_password or password,
         'proxy_keypath': proxy_keypath or keypath,
         'log_level': log_level
     }
     self._clc_machine = None
     self.hostname = hostname
     self.config_qa = config_qa
     self.config_yml = config_yml
     # self._aws_access_key = aws_access_key
     # self._aws_secret_key = aws_secret_key
     self._eucahosts = {}
     self._credpath = credpath
     self.log = Eulogger(identifier=self.__class__.__name__,
                         stdout_level=log_level)
     self.creds = AutoCreds(credpath=self._credpath,
                            region_domain=region_domain,
                            aws_access_key=aws_access_key,
                            aws_secret_key=aws_secret_key,
                            aws_account_name=euca_account,
                            aws_user_name=euca_user,
                            https=https,
                            logger=self.log,
                            **self.machine_connect_kwargs)
     super(SystemConnection,
           self).__init__(hostname=hostname,
                          aws_secret_key=self.creds.aws_secret_key,
                          aws_access_key=self.creds.aws_access_key,
                          logger=self.log,
                          boto_debug_level=boto_debug_level)
Exemple #2
0
    def __init__(self,
                 access_key=None,
                 secret_key=None,
                 account_id=None,
                 region_domain=None,
                 s3_url=None,
                 ec2_url=None,
                 bootstrap_url=None,
                 ec2_cert_path=None,
                 worker_hostname=None,
                 worker_keypath=None,
                 worker_username='******',
                 worker_password=None,
                 worker_machine=None,
                 user_context=None,
                 log_level='debug',
                 destpath=None,
                 time_per_gig=300,
                 eof=True):

        self.access_key = access_key
        self.secret_key = secret_key
        self.account_id = account_id
        self.region_domain = region_domain
        self.bootstrap_url = bootstrap_url
        self.s3_url = s3_url
        self.ec2_url = ec2_url
        self.ec2_cert_path = ec2_cert_path

        self.log = Eulogger('Euca2oolsImageUtils', stdout_level=log_level)
        # Setup the work machine, this is the machine which will be used for
        # performing the 'work' (download, bundle, etc)
        self.worker_hostname = worker_hostname
        self.worker_keypath = worker_keypath
        self.worker_username = worker_username
        self.worker_password = worker_password
        self._worker_machine = None
        self._user_context = user_context
        if worker_machine:
            self._worker_machine = worker_machine

        self.time_per_gig = time_per_gig
        self.eof = eof

        if destpath is not None:
            self.destpath = str(destpath)
        else:
            self.destpath = "/disk1/storage"

        self.time_per_gig = time_per_gig
Exemple #3
0
    def __init__(self, xml_element, eucanetd=None, log_level='INFO'):

        if xml_element is not None and not isinstance(xml_element, Element):
            raise ValueError('xml_element must be of type: {0}.{1}'.format(
                Element.__module__, Element.__name__))
        self._xml = xml_element
        self._eucanetd = eucanetd
        self._tag = None
        self._name = None
        self._log = Eulogger("{0}:{1}:{2}".format(self.__class__.__name__,
                                                  self.tag or "", self.name
                                                  or ""),
                             stdout_level=log_level)
        self._update_from_xml(xml=self._xml)
Exemple #4
0
 def __init__(self, connection=None):
     super(ConversionTask, self).__init__(connection)
     self.connection = connection
     self.conversiontaskid = None
     self.expirationtime = None
     self.state = None
     self.statusmessage = None
     self._importinstancetask = None
     self._importvolumetask = None
     self._instance = None
     self._snapshots = None
     self.tags = None
     self.notfound = False
     self.log = Eulogger('ConversionTask:{0}'.format(self.id))
Exemple #5
0
 def enable_connection_debug(self, level=DEBUG, format_string=None):
     try:
         level = Eulogger.format_log_level(level, 'DEBUG')
         set_stream_logger('botocore', level=level, format_string=None)
     except:
         self.log.error('Could not enable debug for: "{0}"'.format(self))
         raise
Exemple #6
0
 def enable_connection_debug(self, level=DEBUG, format_string=None):
     try:
         level = Eulogger.format_log_level(level, 'DEBUG')
         set_stream_logger('botocore', level=level, format_string=None)
     except:
         self.log.error('Could not enable debug for: "{0}"'.format(self))
         raise
    def __init__(self, hostfile=None, ips=None, password=None, keypath=None, username='******',
                 command='echo "ALIVE', timeout=5, no_pty=False, thread_count=20,
                 log_level='debug'):

        self.parser = argparse.ArgumentParser(
            description='Run a command on list of remote hosts',
            formatter_class=argparse.ArgumentDefaultsHelpFormatter)
        self.parser.add_argument('-f', '--hostfile', default=hostfile,
                            help='file with list of ips and/or hostnames')
        self.parser.add_argument('-i', '--ips', default=ips,
                            help='comma or space separated list of ips and/or hostnames')
        self.parser.add_argument('-p', '--password', default=password,
                            help='Ssh password used to connect to hosts')
        self.parser.add_argument('-k', '--keypath', default=keypath,
                            help='Local path to specific ssh key used to connect to hosts')
        self.parser.add_argument('-u', '--username', default=username,
                            help='Ssh username used to connect to hosts')
        self.parser.add_argument('-c', '--command', default=command,
                            help='file with list of ips and/or hostnames')
        self.parser.add_argument('-t', '--timeout', default=timeout, type=int,
                            help='Ssh connection timeout in seconds')
        self.parser.add_argument('-b', '--batch-timeout', default=0, type=int,
                            help='Timeout for sum of all tasks to complete in seconds. '
                                 'This includes time to create all remote '
                                 'connections + execute commands')
        self.parser.add_argument('--thread-count', default=thread_count, type=int,
                            help='Number of threads used to run commands on hosts')
        self.parser.add_argument('--no-pty', default=no_pty, action='store_false',
                                 help='Do not request a pseudo-terminal from the server.')
        self.parser.add_argument('-l', '--log-level', default=log_level,
                            help='Loglevel')
        if ips or hostfile:
            args = ""
        else:
            args = None
        self.args = self.parser.parse_args(args=args)
        self.hostfile = self.args.hostfile
        self.password = self.args.password
        self.keypath = self.args.keypath
        self.username = self.args.username
        self.command = self.args.command
        self.timeout = self.args.timeout
        self.log_level = self.args.log_level
        self.results = {}
        self.maxwait = .5
        self.ips = ips or self.args.ips or []
        self.logger = Eulogger('RemoteCmds', stdout_level=self.log_level)
        if self.ips:
            if isinstance(self.ips, basestring):
                self.ips = str(self.ips).replace(',', ' ')
                self.ips = self.ips.split()
            else:
                self.ips = list(self.ips)
        if self.args.hostfile:
            with open(os.path.expanduser(self.args.hostfile)) as f:
                self.ips.extend(f.readlines())
        if not self.ips:
            raise ValueError('No hosts provided. Use --hostfile or --ips to provide hosts to run '
                             'command against')
Exemple #8
0
 def disable_boto3_connection_debug(self, level=NOTSET):
     try:
         self.connection.debug = 0
         level = Eulogger.format_log_level(level, 'NOTSET')
         b3_set_stream_logger('botocore', level=level, format_string=None)
     except:
         self.log.error('Could not disable debug for: "{0}"'.format(self))
         raise
Exemple #9
0
    def __init__(self,
                 host=None,
                 password=None,
                 keypath=None,
                 sshconnection=None,
                 machine=None,
                 eucalyptus_run_path='/var/run/eucalyptus',
                 log_level='INFO'):
        if (machine and (sshconnection or host)) or sshconnection and host:
            warning = 'Duplicate and or possibly conflicting machine connection info provided:' \
                      'host:{0}, sshconnection:{1}, machine:{2}'.format(host, sshconnection,
                                                                        machine)
        else:
            warning = ""
        if machine:
            sshconnection = machine.ssh

        if sshconnection:
            host = host or sshconnection.host
            password = password or sshconnection.password
            keypath = sshconnection or sshconnection.keypair
        if host:
            if not machine:
                machine = Machine(hostname=host,
                                  password=password,
                                  keypath=keypath,
                                  sshconnection=sshconnection)
        host = host or "unknown"
        self.log = Eulogger("{0}.{1}".format(self.__class__.__name__, host))
        self.log.set_stdout_loglevel(log_level)
        if not host:
            self.log.warning(
                'Connection info not provided for: {0}.init()'.format(
                    self.__class__.__name__))

        self.host = host
        self.password = password
        self.keypath = keypath
        self._machine = machine
        self._global_xml_path = None
        self._global_xml = None
        self.eucalyptus_run_path = eucalyptus_run_path or ""
        self.eucanetd_pid_file = path.join(self.eucalyptus_run_path,
                                           'eucanetd.pid')
        self.global_xml_version = path.join(self.eucalyptus_run_path,
                                            'global_network_info.version')
Exemple #10
0
 def disable_connection_debug(self, level=NOTSET):
     try:
         self.connection.debug = 0
         level = Eulogger.format_log_level(level, 'NOTSET')
         set_stream_logger('botocore', level=level, format_string=None)
     except:
         self.log.error('Could not disable debug for: "{0}"'.format(self))
         raise
Exemple #11
0
    def __init__(self,
                 creds=None,
                 host=None,
                 aws_access_key=None,
                 aws_secret_key=None,
                 is_secure=None,
                 port=None,
                 path=None,
                 logger=None,
                 boto_debug=0,
                 **kwargs):

        self.debug = boto_debug
        if self.debug:
            set_stream_logger('boto')
        if creds and not isinstance(creds, Eucarc):
            credsattr = getattr(creds, 'creds', None)
            if not isinstance(credsattr, Eucarc):
                raise ValueError(
                    'Unknown type passed for creds arg: "{0}/{1}"'.format(
                        creds, type(creds)))
            creds = credsattr
        self._eucarc = creds
        self.account_id = None
        self.user_id = None
        if not logger:
            logger = Eulogger(identifier=self.__class__.__name__)
        self.log = logger
        if creds:
            self.user_id = creds.ec2_user_id
            self.account_id = creds.ec2_account_number
            assert isinstance(creds, Eucarc), 'UserAdmin. eucarc not type Eucarc(), got:"{0}/{1}"'\
                .format(creds, type(creds))
            urlp = urlparse(creds.euare_url)
            host = host or getattr(urlp, 'hostname', None)
            port = port or getattr(urlp, 'port', 8773)
            path = path or getattr(urlp, 'path', '/services/Euare')
            if is_secure is None and urlp.scheme == 'https':
                is_secure = True
            aws_secret_key = aws_secret_key or creds.aws_secret_key
            aws_access_key = aws_access_key or creds.aws_access_key
        is_secure = is_secure or False
        ac_kwargs = {
            'host': host,
            'aws_access_key_id': aws_access_key,
            'aws_secret_access_key': aws_secret_key,
            'is_secure': is_secure,
            'port': port,
            'path': path
        }
        ac_kwargs.update(kwargs)
        try:
            super(AccessConnection, self).__init__(**ac_kwargs)
        except:
            self.log.error(
                'Failed to create AccessConnection with kwargs:"{0}"'.format(
                    ac_kwargs))
            raise
Exemple #12
0
 def __init__(
     self,
     hostname,
     username="******",
     password=None,
     keypath=None,
     proxy_hostname=None,
     proxy_username="******",
     proxy_password=None,
     proxy_keypath=None,
     config_yml=None,
     config_qa=None,
     credpath=None,
     aws_access_key=None,
     aws_secret_key=None,
     log_level="INFO",
     boto_debug_level=0,
     euca_user="******",
     euca_account="eucalyptus",
 ):
     self.clc_connect_kwargs = {
         "hostname": hostname,
         "username": username,
         "password": password,
         "keypath": keypath,
         "proxy_hostname": proxy_hostname,
         "proxy_username": proxy_username,
         "proxy_password": proxy_password,
         "proxy_keypath": proxy_keypath,
     }
     self._clc_machine = None
     self.hostname = hostname
     self.config_qa = config_qa
     self.config_yml = config_yml
     # self._aws_access_key = aws_access_key
     # self._aws_secret_key = aws_secret_key
     self._eucahosts = {}
     self._credpath = credpath
     self.log = Eulogger(identifier=self.__class__.__name__, stdout_level=log_level)
     self.creds = AutoCreds(
         credpath=self._credpath,
         aws_access_key=aws_access_key,
         aws_secret_key=aws_secret_key,
         aws_account_name=euca_account,
         aws_user_name=euca_user,
         logger=self.log,
         **self.clc_connect_kwargs
     )
     super(SystemConnection, self).__init__(
         hostname=hostname,
         aws_secret_key=self.creds.aws_secret_key,
         aws_access_key=self.creds.aws_access_key,
         logger=self.log,
         boto_debug_level=boto_debug_level,
     )
Exemple #13
0
def set_boto_logger_level(level='NOTSET', format_string=None):
    """
    Set the global boto loggers levels to 'level'. ie "DEBUG", "INFO", "CRITICAL"
    default is "NOTSET"
    :param level: string matching logging class levels, or integer representing the equiv value
    :param format_string: logging class formatter string
    """
    level = Eulogger.format_log_level(level, 'NOTSET')
    set_stream_logger('boto', level=level, format_string=None)
    set_stream_logger('boto3', level=level, format_string=None)
    set_stream_logger('botocore', level=level, format_string=None)
Exemple #14
0
def set_boto_logger_level(level='NOTSET', format_string=None):
    """
    Set the global boto loggers levels to 'level'. ie "DEBUG", "INFO", "CRITICAL"
    default is "NOTSET"
    :param level: string matching logging class levels, or integer representing the equiv value
    :param format_string: logging class formatter string
    """
    level = Eulogger.format_log_level(level, 'NOTSET')
    set_stream_logger('boto', level=level, format_string=None)
    set_stream_logger('boto3', level=level, format_string=None)
    set_stream_logger('botocore', level=level, format_string=None)
Exemple #15
0
 def __init__(self,
              hostname,
              username='******',
              password=None,
              keypath=None,
              region_domain=None,
              proxy_hostname=None,
              proxy_username=None,
              proxy_password=None,
              proxy_keypath=None,
              config_yml=None,
              config_qa=None,
              credpath=None,
              aws_access_key=None,
              aws_secret_key=None,
              log_level='INFO',
              boto_debug_level=0,
              euca_user='******',
              euca_account='eucalyptus',
              ):
     self.machine_connect_kwargs = {
         'hostname': hostname,
         'username': username,
         'password': password,
         'keypath': keypath,
         'proxy_hostname': proxy_hostname,
         'proxy_username': proxy_username or username,
         'proxy_password': proxy_password or password,
         'proxy_keypath': proxy_keypath or keypath,
         'log_level': log_level
     }
     self._clc_machine = None
     self.hostname = hostname
     self.config_qa = config_qa
     self.config_yml = config_yml
     # self._aws_access_key = aws_access_key
     # self._aws_secret_key = aws_secret_key
     self._eucahosts = {}
     self._credpath = credpath
     self.log = Eulogger(identifier=self.__class__.__name__, stdout_level=log_level)
     self.creds = AutoCreds(credpath=self._credpath,
                            region_domain=region_domain,
                            aws_access_key=aws_access_key,
                            aws_secret_key=aws_secret_key,
                            aws_account_name=euca_account,
                            aws_user_name=euca_user,
                            logger=self.log,
                            **self.machine_connect_kwargs)
     super(SystemConnection, self).__init__(hostname=hostname,
                                            aws_secret_key=self.creds.aws_secret_key,
                                            aws_access_key=self.creds.aws_access_key,
                                            logger=self.log,
                                            boto_debug_level=boto_debug_level)
Exemple #16
0
 def __init__(self, connection=None):
     super(ConversionTask, self).__init__(connection)
     self.connection = connection
     self.conversiontaskid = None
     self.expirationtime = None
     self.state = None
     self.statusmessage = None
     self._importinstancetask = None
     self._importvolumetask = None
     self._instance = None
     self._snapshots = None
     self.tags = None
     self.notfound = False
     self.log = Eulogger('ConversionTask:{0}'.format(self.id))
Exemple #17
0
    def __init__(self, hostfile=None, ips=None, password=None, username='******',
                 command='echo "ALIVE', timeout=5, thread_count=20, log_level='debug'):

        self.parser = argparse.ArgumentParser(
            description='Run a command on list of remote hosts',
            formatter_class=argparse.ArgumentDefaultsHelpFormatter)
        self.parser.add_argument('-f', '--hostfile', default=hostfile,
                            help='file with list of ips and/or hostnames')
        self.parser.add_argument('-i', '--ips', default=ips,
                            help='comma or space separated list of ips and/or hostnames')
        self.parser.add_argument('-p', '--password', default=password,
                            help='Ssh password used to connect to hosts')
        self.parser.add_argument('-u', '--username', default=username,
                            help='Ssh username used to connect to hosts')
        self.parser.add_argument('-c', '--command', default=command,
                            help='file with list of ips and/or hostnames')
        self.parser.add_argument('-t', '--timeout', default=timeout, type=int,
                            help='Ssh connection timeout in seconds')
        self.parser.add_argument('--thread-count', default=thread_count, type=int,
                            help='Number of threads used to run commands on hosts')
        self.parser.add_argument('-l', '--log-level', default=log_level,
                            help='Loglevel')
        if ips or hostfile:
            args = ""
        else:
            args = None
        self.args = self.parser.parse_args(args=args)
        self.hostfile = self.args.hostfile
        self.password = self.args.password
        self.username = self.args.username
        self.command = self.args.command
        self.timeout = self.args.timeout
        self.log_level = self.args.log_level
        self.results = {}
        self.maxwait = .5
        self.ips = ips or self.args.ips or []
        self.logger = Eulogger('RemoteCmds', stdout_level=self.log_level)
        if self.ips:
            if isinstance(self.ips, basestring):
                self.ips = str(self.ips).replace(',', ' ')
                self.ips = self.ips.split()
            else:
                self.ips = list(self.ips)
        if self.args.hostfile:
            with open(os.path.expanduser(self.args.hostfile)) as f:
                self.ips.extend(f.readlines())
        if not self.ips:
            raise ValueError('No hosts provided. Use --hostfile or --ips to provide hosts to run '
                             'command against')
    def __init__(self, access_key=None, secret_key=None, account_id=None, region_domain=None,
                 s3_url=None, ec2_url=None, bootstrap_url=None, ec2_cert_path=None,
                 worker_hostname=None, worker_keypath=None, worker_username='******',
                 worker_password=None, worker_machine=None, user_context=None, log_level='debug',
                 destpath=None, time_per_gig=300, eof=True):
        
        self.access_key = access_key
        self.secret_key = secret_key
        self.account_id = account_id
        self.region_domain = region_domain
        self.bootstrap_url = bootstrap_url
        self.s3_url = s3_url
        self.ec2_url = ec2_url
        self.ec2_cert_path = ec2_cert_path

        self.log = Eulogger('Euca2oolsImageUtils', stdout_level=log_level)
        # Setup the work machine, this is the machine which will be used for
        # performing the 'work' (download, bundle, etc)
        self.worker_hostname = worker_hostname
        self.worker_keypath = worker_keypath
        self.worker_username = worker_username
        self.worker_password = worker_password
        self._worker_machine = None
        self._user_context = user_context
        if worker_machine:
            self._worker_machine = worker_machine
        
        self.time_per_gig = time_per_gig
        self.eof = eof
        
        if destpath is not None:
            self.destpath = str(destpath)
        else:
            self.destpath = "/disk1/storage"

        self.time_per_gig = time_per_gig
Exemple #19
0
class SystemConnection(ServiceConnection):
    def __init__(self,
                 hostname,
                 username='******',
                 password=None,
                 keypath=None,
                 region_domain=None,
                 proxy_hostname=None,
                 proxy_username=None,
                 proxy_password=None,
                 proxy_keypath=None,
                 config_yml=None,
                 config_qa=None,
                 credpath=None,
                 aws_access_key=None,
                 aws_secret_key=None,
                 log_level='INFO',
                 boto_debug_level=0,
                 euca_user='******',
                 euca_account='eucalyptus',
                 https=True):
        self.machine_connect_kwargs = {
            'hostname': hostname,
            'username': username,
            'password': password,
            'keypath': keypath,
            'proxy_hostname': proxy_hostname,
            'proxy_username': proxy_username or username,
            'proxy_password': proxy_password or password,
            'proxy_keypath': proxy_keypath or keypath,
            'log_level': log_level
        }
        self._clc_machine = None
        self.hostname = hostname
        self.config_qa = config_qa
        self.config_yml = config_yml
        # self._aws_access_key = aws_access_key
        # self._aws_secret_key = aws_secret_key
        self._eucahosts = {}
        self._credpath = credpath
        self.log = Eulogger(identifier=self.__class__.__name__,
                            stdout_level=log_level)
        self.creds = AutoCreds(credpath=self._credpath,
                               region_domain=region_domain,
                               aws_access_key=aws_access_key,
                               aws_secret_key=aws_secret_key,
                               aws_account_name=euca_account,
                               aws_user_name=euca_user,
                               https=https,
                               logger=self.log,
                               **self.machine_connect_kwargs)
        super(SystemConnection,
              self).__init__(hostname=hostname,
                             aws_secret_key=self.creds.aws_secret_key,
                             aws_access_key=self.creds.aws_access_key,
                             logger=self.log,
                             boto_debug_level=boto_debug_level)

    def set_loglevel(self, level, parent=False):
        """
        wrapper for log.setLevel, accept int or string.
        Levels can be found in logging class. At the time this was written they are:
        CRITICAL:50
        DEBUG:10
        ERROR:40
        FATAL:50
        INFO:20
        NOTSET:0
        WARN:30
        WARNING:30
        """
        level = level or logging.NOTSET
        if not isinstance(level, int) and not isinstance(level, basestring):
            raise ValueError(
                'set_loglevel. Level must be of type int or string, got: "{0}/{1}"'
                .format(level, type(level)))
        if isinstance(level, basestring):
            level = getattr(logging, str(level).upper())
        return self.log.set_parentloglevel(level)

    @property
    def clc_machine(self):
        if not self._clc_machine:
            hostname = self.machine_connect_kwargs['hostname']
            if hostname:
                #  See if a host exists matching the provided hostname
                if hostname in self.eucahosts:
                    self._clc_machine = self.eucahosts[hostname]
                #  See if this is a localhost connection
                elif self._get_clc_eucahost_for_localhost():
                    self._clc_machine = self._get_clc_eucahost_for_localhost()
                else:
                    self._clc_machine = Machine(**self.machine_connect_kwargs)
                    self.eucahosts[self.machine_connect_kwargs[
                        'hostname']] = self._clc_machine
        return self._clc_machine

    @property
    def eucahosts(self):
        if not self._eucahosts:
            self._eucahosts = self._update_host_list()
        return self._eucahosts

    def _get_clc_eucahost_for_localhost(self):
        ifaces = self._get_all_local_ip_interfaces()
        for iface, ip in ifaces:
            if ip in self.eucahosts:
                self.log.debug('CLC is bound to iface:{0} ip:{1}'.format(
                    iface, ip))
                return self.eucahosts[ip]
        return None

    def _get_all_local_ip_interfaces(self):
        max_possible = 1028
        bytes = max_possible * 32
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        names = array.array('B', '\0' * bytes)
        outbytes = struct.unpack(
            'iL',
            fcntl.ioctl(
                s.fileno(),
                0x8912,  # SIOCGIFCONF
                struct.pack('iL', bytes,
                            names.buffer_info()[0])))[0]
        namestr = names.tostring()
        interfaces = []
        for i in range(0, outbytes, 40):
            name = namestr[i:i + 16].split('\0', 1)[0]
            addr = namestr[i + 20:i + 24]
            ip = "{0}.{1}.{2}.{3}".format(ord(addr[0]), ord(addr[1]),
                                          ord(addr[2]), ord(addr[3]))
            interfaces.append((name, ip))
        return interfaces

    def _update_host_list(self):
        machines = self.get_all_machine_mappings()
        connect_kwargs = copy.copy(self.machine_connect_kwargs)
        if 'hostname' in connect_kwargs:
            connect_kwargs.pop('hostname')
        hostlock = threading.Lock()

        def add_host(ip, services, self=self, connect_kwargs=connect_kwargs):
            host = EucaHost(connection=self,
                            hostname=ip,
                            services=services,
                            **connect_kwargs)
            with hostlock:
                self._eucahosts[ip] = host

        threads = []
        for ip, services in machines.iteritems():
            t = threading.Thread(target=add_host, args=(ip, services))
            t.start()
            threads.append(t)
        for t in threads:
            t.join()

        return self._eucahosts

    def get_host_by_hostname(self, hostname):
        return self.eucahosts.get(hostname, None)

    def get_hosts_by_service_type(self, servicetype):
        ret_list = []
        for ip, host in self.eucahosts.iteritems():
            for service in host.services:
                if service.type == servicetype:
                    ret_list.append(host)
        return ret_list

    def get_hosts_for_cloud_controllers(self):
        clc = None
        return self.get_hosts_by_service_type(servicetype='eucalyptus')

    def get_hosts_for_node_controllers(self, partition=None, instanceid=None):
        if instanceid is not None and not isinstance(instanceid, basestring):
            raise ValueError(
                'Instance id not of string type, got:"{0}"/"{1}"'.format(
                    instanceid, type(instanceid)))
        ncs = self.get_hosts_by_service_type(servicetype='node')
        if not partition and not instanceid:
            return ncs
        retlist = []
        if instanceid:
            try:
                reservation = self.ec2_connection.get_all_instances(
                    instance_ids=['verbose', instanceid])
            except:
                self.log.error(
                    '{0}\nFailed to find instance:"{1}" on system'.format(
                        get_traceback(), instanceid))
                return []
            if reservation:
                instance = reservation[0].instances[0]
                node_addr = instance.tags.get('euca:node')
                if node_addr:
                    for nc in ncs:
                        if nc.hostname == node_addr:
                            return [nc]
        if partition and partition in nc.partitions:
            retlist.append(nc)
        return retlist

    def get_hosts_for_cluster_controllers(self, partition=None):
        ccs = self.get_hosts_by_service_type(servicetype='cluster')
        if not partition:
            return ccs
        retlist = []
        for cc in ccs:
            if partition in cc.partitions:
                retlist.append(cc)
        return retlist

    def get_hosts_for_storage_controllers(self, partition=None):
        scs = self.get_hosts_by_service_type(servicetype='storage')
        if not partition:
            return scs
        retlist = []
        for sc in scs:
            if partition in sc.partitions:
                retlist.append(sc)
        return retlist

    def get_hosts_for_ufs(self):
        ufs = None
        return self.get_hosts_by_service_type(servicetype='user-api')

    def get_hosts_for_walrus(self):
        walrus = None
        return self.get_hosts_by_service_type(servicetype='walrusbackend')

    def show_cloud_legacy_summary(self,
                                  repo_info=True,
                                  print_method=None,
                                  file_path=None,
                                  print_table=True):
        """
        Creates a table representing the legacy Eutester/QA reprsentation of a Eucalyptus
        cloud. This can be used for legacy eutester tests, etc..
        :param repo_info: bool, if True will use the work REPO in place of Zone for the 5th column
        :param print_method: method used to print this table, defaults to self.log.info
        :param print_table: bool, if False will return the table obj
        :param file_path: string representing a local file path to save this information to
        :return: table obj if print_table is False
        """
        ret = ""
        print_method = print_method or self.log.info
        if repo_info:
            rz_col = 'REPO'
        else:
            rz_col = 'ZONE'
        pt = PrettyTable(
            ['# HOST', 'DISTRO', 'VER', 'ARCH', rz_col, 'SERVICE CODES'])
        pt.align = 'l'
        pt.border = 0
        for ip, host in self.eucahosts.iteritems():
            split = host.summary_string.split()
            service_codes = " ".join(split[5:])
            if repo_info:
                rz_col = 'REPO'
            else:
                rz_col = split[4]
            pt.add_row([
                split[0], split[1], split[2], split[3], rz_col, service_codes
            ])
            ret += "{0}\n".format(host.summary_string)
        if file_path:
            with open(file_path, 'w') as save_file:
                save_file.write(str(pt))
                save_file.flush()
        if print_table:
            print_method("\n{0}\n".format(str(pt)))
        else:
            return pt

    @staticmethod
    def vm_state_markup(state):
        if state in ['shutting-down', 'stopped', 'stopping']:
            return [1, 91]
        if state == 'terminated':
            return [1, 97]
        if state == 'running':
            return [1, 92]
        return [1, 93]

    def show_hosts(self,
                   hosts=None,
                   partition=None,
                   service_type=None,
                   serv_columns=None,
                   update=True,
                   print_method=None,
                   print_table=True,
                   save_file=None):
        print_method = print_method or self._show_method
        ins_id_len = 10
        ins_type_len = 13
        ins_dev_len = 16
        ins_st_len = 15
        ins_total = (ins_id_len + ins_dev_len + ins_type_len + ins_st_len) + 5
        machine_hdr = (markup('MACHINE INFO'), 30)
        service_hdr = (markup('EUCALYPTUS SERVICES'), 90)
        pt = PrettyTable([machine_hdr[0], service_hdr[0]])
        pt.header = False
        pt.align = 'l'
        pt.hrules = 1
        pt.max_width[machine_hdr[0]] = machine_hdr[1]
        total = []
        eucahosts = {}
        if hosts is None:
            eucahosts = self.eucahosts
        elif isinstance(hosts, list):
            for host in hosts:
                eucahosts[host.hostname] = host
        elif isinstance(hosts, EucaHost):
            eucahosts[hosts.hostname] = hosts

        if not isinstance(eucahosts, dict):
            raise ValueError('show_machine_mappings requires dict example: '
                             '{"host ip":[host objs]}, got:"{0}/{1}"'.format(
                                 eucahosts, type(eucahosts)))
        # To format the tables services, print them all at once and then sort the table
        # rows string into the machines columns
        try:
            sorted_ips = sorted(
                list(eucahosts),
                key=lambda ip: struct.unpack("!L", socket.inet_aton(ip))[0])
        except Exception as SE:
            self.log.warning(
                '"Failed to sort host list by IP, error:"{0}"'.format(SE))
            sorted_ips = sorted(list(eucahosts))
        for hostip in sorted_ips:
            host = eucahosts[hostip]
            for serv in host.services:
                if update:
                    serv.update()
                total.append(serv)
                if serv.child_services:
                    total.extend(serv.child_services)
        # Create a table showing the service states, grab the first 3 columns
        # for type, name, state, and zone
        servpt = self.show_services(total, print_table=False)
        # Get a subset of the show services fields...
        if serv_columns is None:
            fields = servpt._field_names[0:4]
        else:
            fields = servpt._fields_names[serv_columns]
        serv_lines = servpt.get_string(border=0,
                                       padding_width=2,
                                       fields=fields).splitlines()
        header = serv_lines[0]
        ansi_escape = re.compile(r'\x1b[^m]*m')
        # Now build the machine table...
        threads = []
        hostlock = threading.Lock()

        # Method to allow host info to be gathered concurrently
        def add_host(hostip, host, self=self):
            assert isinstance(host, EucaHost)
            servbuf = header + "\n"
            mservices = []
            # Get the child services (ie for UFS)
            for serv in host.services:
                mservices.append(serv)
                mservices.extend(serv.child_services)
            for serv in mservices:
                for line in serv_lines:
                    # Remove the ansi markup for parsing purposes, but leave it in the
                    # displayed line
                    clean_line = ansi_escape.sub('', line)
                    splitline = clean_line.split()
                    if len(splitline) < 2:
                        continue
                    line_type = splitline[0]
                    line_name = splitline[1]
                    # Pull matching lines out of the pre-formatted service table...
                    if (splitline
                            and re.match("^{0}$".format(serv.type), line_type)
                            and re.match("^{0}$".format(serv.name),
                                         line_name)):
                        # Add this line to the services to be displayed for this machine
                        if line_name not in servbuf:
                            servbuf += line + "\n"
                if serv.type == 'node':
                    if getattr(serv, 'instances', None):
                        if serv.instances:
                            vm_pt = PrettyTable([
                                markup('INSTANCES', [1, 4]),
                                markup('STATE:', [1, 4]),
                                markup('VMTYPE:', [1, 4]),
                                markup('ROOT_DEV:', [1, 4])
                            ])
                            vm_pt.align = 'l'
                            vm_pt.border = 1
                            vm_pt.vrules = 2
                            vm_pt.hrules = 0
                            for x in serv.instances:
                                vm_pt.add_row([
                                    x.id,
                                    markup(x.state,
                                           self.vm_state_markup(x.state)),
                                    x.instance_type, x.root_device_type
                                ])
                            servbuf += "{0}\n".format(vm_pt)
                    av_pt = host.helpers.node_controller.show_availability_for_node(
                        print_table=False)
                    servbuf += av_pt.get_string()
            ps_sum_pt = host.show_euca_process_summary(print_table=False)
            servbuf += "\n" + ps_sum_pt.get_string(
                border=1, vrules=2, hrules=0)
            host_info = markup('Euca Versions:').ljust(machine_hdr[1])
            host_info += "Cloud: {0}".format(
                host.get_eucalyptus_version()).ljust(machine_hdr[1])
            host_info += "2ools: {0}".format(
                host.get_euca2ools_version()).ljust(machine_hdr[1])
            host_info += markup("Hostname:").ljust(machine_hdr[1])
            host_info += str(host.hostname).ljust(machine_hdr[1])
            sys_pt = host.show_sys_info(print_table=False)
            host_info += "{0}".format(sys_pt)
            with hostlock:
                pt.add_row([
                    markup("HOST:") + markup(hostip, [1, 94]),
                    markup('EUCALYPTUS SERVICES:') + markup(
                        '[ {0} ]'.format(" ".join(
                            str(x) for x in host.euca_service_codes)), [1, 34])
                ])
                pt.add_row([host_info, servbuf])

        for hostip, host in eucahosts.iteritems():
            t = threading.Thread(target=add_host, args=(hostip, host))
            t.start()
            threads.append(t)
        for t in threads:
            t.join()
        if save_file:
            with open(save_file, 'w') as sf:
                sf.write("\n{0}\n".format(pt.get_string()))
        if print_table:
            # print_method("\n{0}\n".format(pt.get_string(sortby=pt.field_names[1])))
            print_method("\n{0}\n".format(pt.get_string()))
        else:
            return pt

    def upgrade_cloud(self,
                      network_mode=None,
                      ccs=None,
                      ncs=None,
                      clcs=None,
                      scs=None,
                      ufs=None,
                      ws=None,
                      gpgcheck=False,
                      yum_arg_list=None,
                      dry_run=False,
                      rerun=False):
        if rerun:
            if not hasattr(self, '_upgrade_dict'):
                raise ValueError(
                    'self._upgrade_dict not found, can not use "rerun"')
            return self.upgrade_cloud(**self._upgrade_dict)
        if yum_arg_list is None:
            yum_arg_list = []
        if not isinstance(yum_arg_list, list):
            yum_arg_list = [yum_arg_list]
        if not gpgcheck:
            yum_arg_list.append("--nogpg")
        yum_args = " -y {0}".format(" ".join(yum_arg_list))
        # Sort out the host machines by services...
        known_net_modes = ['EDGE', 'VPCMIDO', 'MANAGED']
        if network_mode is None:
            try:
                cluster_name = self.get_all_cluster_names()[0]
                prop = self.get_property(
                    "{0}.cluster.networkmode".format(cluster_name))
                network_mode = prop.value
            except:
                self.log.error('Could not retrieve network mode for cloud')
                raise
        if re.search('MANAGED', network_mode):
            network_mode = 'MANAGED'
        if network_mode not in known_net_modes:
            raise ValueError(
                'Unknown network mode:{0}, known types {1}'.format(
                    network_mode, ", ".join(known_net_modes)))
        # service arrays
        eucalyptus_cloud_hosts = []
        eucanetd_hosts = []

        ccs = ccs or self.get_hosts_for_cluster_controllers()
        ncs = ncs or self.get_hosts_for_node_controllers()
        clcs = clcs or self.get_hosts_for_cloud_controllers()
        scs = scs or self.get_hosts_for_storage_controllers()
        ufs = ufs or self.get_hosts_for_ufs()
        ws = ws or self.get_hosts_for_walrus()

        upgrade_dict = {
            'network_mode': network_mode,
            'ccs': ccs,
            'ncs': ncs,
            'clcs': clcs,
            'scs': scs,
            'ufs': ufs,
            'ws': ws,
            'gpgcheck': gpgcheck,
            'yum_arg_list': yum_arg_list
        }
        if dry_run:
            return upgrade_dict
        for host in clcs + ufs + scs + ws:
            if host not in eucalyptus_cloud_hosts:
                eucalyptus_cloud_hosts.append(host)
        if network_mode == "MANAGED":
            eucanetd_hosts = ccs
        elif network_mode == 'EDGE':
            eucanetd_hosts = ncs
        elif network_mode == 'VPCMIDO':
            eucanetd_hosts = clcs
        else:
            raise ValueError(
                'Unsupported network mode: "{0}"'.format(network_mode))

        def stop_service(host, service, timeout=300):
            try:
                host.sys('service {0} stop'.format(service),
                         code=0,
                         timeout=timeout)
            except CommandExitCodeException as CE:
                if CE.status == 2:
                    # service is already stopped
                    pass
                else:
                    raise

        try:
            # Shutdown all the Eucalyptus cloud services...
            self.log.info(
                'Beginning upgrade. Shutting down all cloud services now...')
            for host in clcs:
                stop_service(host, 'eucalyptus-cloud')
            for host in eucalyptus_cloud_hosts:
                # Skip the CLCs which have already been stopped
                if host not in clcs:
                    stop_service(host, 'eucalyptus-cloud')
            for host in ccs:
                stop_service(host, 'eucalyptus-cc')
            for host in ncs:
                stop_service(host, 'eucalyptus-nc')
            for host in eucanetd_hosts:
                stop_service(host, 'eucanetd')

            # Upgrade packages...
            self.log.info('Upgrading Eucalyptus packages on all hosts')
            for host in self.eucahosts.itervalues():
                host.sys('yum upgrade eucalyptus {0}'.format(yum_args),
                         code=0,
                         timeout=400)
            self.log.info(
                'Package upgrade complete, restarting cloud services now...')
            # Start all the Eucalyptus cloud services...
            # Do the CLCs first than the other Java/Cloud services
            self.log.info('Starting CLCs...')
            for host in clcs:
                host.sys('service eucalyptus-cloud start', code=0, timeout=300)
            self.log.info('Starting remaining Java Components...')
            for host in eucalyptus_cloud_hosts:
                # Skip the CLCs which have already been started
                if host not in clcs:
                    host.sys('service eucalyptus-cloud start',
                             code=0,
                             timeout=300)
            self.log.info('Starting Cluster Controllers...')
            for host in ccs:
                host.sys('service eucalyptus-cc start', code=0, timeout=300)
            self.log.info('Starting Node Controllers...')
            for host in ncs:
                host.sys('service eucalyptus-nc start', code=0, timeout=300)
            self.log.info('Starting Eucanetd...')
            for host in eucanetd_hosts:
                host.sys('service eucanetd start', code=0, timeout=300)
            self.log.info('Upgrade Done')
        except:
            self.log.error(
                'Upgrade failed. The upgrade params are found in self._upgrade_dict.'
                'These can be used via the "rerun" argument to rerun this upgrade'
                'using the same environment/machines')
            raise
        finally:
            # write to this dict for before/after comparison of the cloud after upgrade
            self._upgrade_dict = upgrade_dict

    def build_machine_dict_from_config(cls):
        raise NotImplementedError()

    def build_machine_dict_from_cloud_services(self):
        raise NotImplementedError('not yet implemented')
Exemple #20
0
 def tag(self, tag):
     if tag != self.tag:
         self._tag = tag
         self._log = Eulogger("{0}:{1}:{2}".format(self.__class__.__name__,
                                                   self.tag or "", self.name
                                                   or ""))
Exemple #21
0
    def __init__(self,
                 aws_access_key=None,
                 aws_secret_key=None,
                 aws_account_name=None,
                 aws_user_name=None,
                 port=8773,
                 credpath=None,
                 string=None,
                 region=None,
                 machine=None,
                 keysdir=None,
                 logger=None,
                 service_connection=None,
                 eucarc=None,
                 existing_certs=False,
                 boto_debug=0,
                 https=True,
                 api_version=None,
                 log_level=None):
        if log_level is None:
            if service_connection:
                log_level = service_connection.log.stdout_level
            else:
                log_level = DEBUG
        super(UserContext,
              self).__init__(aws_access_key=aws_access_key,
                             aws_secret_key=aws_secret_key,
                             aws_account_name=aws_account_name,
                             aws_user_name=aws_user_name,
                             service_port=port,
                             region_domain=region,
                             credpath=credpath,
                             string=string,
                             machine=machine,
                             keysdir=keysdir,
                             logger=logger,
                             log_level=log_level,
                             existing_certs=existing_certs,
                             service_connection=service_connection,
                             https=https,
                             auto_create=False)
        self._user_info = {}
        self._session = None
        self._connections = {}
        self.region = region
        self.api_version = api_version or __DEFAULT_API_VERSION__

        # Logging setup
        if not logger:
            logger = Eulogger(str(self), stdout_level=log_level)
        self.log = logger
        self.log.debug = self.log.debug
        self.critical = self.log.critical
        self.info = self.log.info
        if eucarc:
            for key, value in eucarc.__dict__.iteritems():
                setattr(self, key, value)
        elif not (aws_access_key and aws_secret_key
                  and self.serviceconnection):
            try:
                self.auto_find_credentials(assume_admin=False)
            except ValueError as VE:
                self.log.error(
                    'Failed to auto create user credentials and service paths:"{0}"'
                    .format(VE))
        if service_connection:
            self.update_attrs_from_cloud_services()
        self._test_resources = {}
        self._connection_kwargs = {
            'eucarc': self,
            'connection_debug': boto_debug,
            'user_context': self,
            'region': region,
            'api_version': self.api_version,
            'log_level': log_level
        }
        self.log.identifier = str(self)
        self.log.debug('Successfully created User Context')
Exemple #22
0
    def __init__(self,
                 eucarc=None,
                 credpath=None,
                 service_url=None,
                 aws_access_key_id=None,
                 aws_secret_access_key=None,
                 is_secure=False,
                 port=None,
                 host=None,
                 region=None,
                 connection_debug=0,
                 path=None,
                 validate_certs=True,
                 test_resources=None,
                 logger=None,
                 log_level=None,
                 user_context=None,
                 session=None,
                 boto2_api_version=None,
                 verbose_requests=None):
        if self.EUCARC_URL_NAME is None:
            raise NotImplementedError(
                'EUCARC_URL_NAME not set for this class:"{0}"'.format(
                    self.__class__.__name__))
        if self.SERVICE_PREFIX is None:
            raise NotImplementedError(
                'Service Prefix has not been defined for this class:"{0}"'.
                format(self.__class__.__name__))
        init_kwargs = locals()
        init_kwargs.__delitem__('self')
        self._session = session
        self.service_host = None
        self.service_port = None
        self.service_path = None
        # Store info about created resources and how to clean/delete them for this ops connection
        self.test_resources_clean_methods = {}
        self.test_resources = test_resources or {}
        # Store the user context for this connection if provided
        self._user_context = user_context
        if not region and self._user_context:
            region = self._user_context.region
        self.service_region = region
        # Create the logger for this ops connection
        if log_level is None:
            log_level = DEBUG

        def get_logger_context():
            host = self.service_host or ""
            context = ""
            try:
                if self._user_context:
                    if self._user_context._user_name and self._user_context._account_name:

                        context = "({0}:{1})".format(
                            self._user_context.user_name,
                            self._user_context.account_name)
                    elif self._user_context.access_key:
                        context = "(AK:{0}...)".format(
                            self._user_context.__access_key[5:])
            except Exception as LE:
                print 'error fetching user context: "{0}"'.format(LE)
            if not context:
                if aws_access_key_id:
                    context = "(AK:{0}...)".format(aws_access_key_id[5:])
                else:
                    context = "()"
            return context

        if not logger:
            logger = Eulogger("{0}{1}".format(self.__class__.__name__,
                                              get_logger_context()),
                              stdout_level=log_level)
        self.log = logger
        self.log.debug('Creating ops: {0}'.format(self.__class__.__name__))
        self.log.set_stdout_loglevel(log_level)
        # Store the runtime configuration for this ops connection
        if not eucarc:
            if credpath:
                eucarc = Eucarc(filepath=credpath)
            else:
                eucarc = Eucarc()
        self.eucarc = eucarc
        # Set the connection params...
        self._try_verbose = verbose_requests
        self._is_secure = is_secure
        if aws_secret_access_key:
            self.eucarc.aws_secret_key = aws_secret_access_key
        if aws_access_key_id:
            self.eucarc.aws_access_key = aws_access_key_id
        self._service_url = service_url
        if not (host or port or path):
            if self.service_url:
                urlp = urlparse(self.service_url)
                host = host or urlp.hostname
                port = port or urlp.port
                path = path or urlp.path
        self.service_host = host
        self.service_port = port or getattr(self.eucarc, 'service_port', None)
        self.service_path = path
        self.service_region = region
        # Build out kwargs used to create service connection/client
        # Pass all the args/kwargs provided at init to the create_connection_kwargs method for the
        # ops class to use to build it's kwargs as needed.
        self._connection_kwargs = self.create_connection_kwargs(**init_kwargs)
        # Remaining setup...
        self._b2_connection = None
        self._b3_connection = None
        self.setup()
Exemple #23
0
class SystemConnection(ServiceConnection):
    def __init__(
        self,
        hostname,
        username="******",
        password=None,
        keypath=None,
        proxy_hostname=None,
        proxy_username="******",
        proxy_password=None,
        proxy_keypath=None,
        config_yml=None,
        config_qa=None,
        credpath=None,
        aws_access_key=None,
        aws_secret_key=None,
        log_level="INFO",
        boto_debug_level=0,
        euca_user="******",
        euca_account="eucalyptus",
    ):
        self.clc_connect_kwargs = {
            "hostname": hostname,
            "username": username,
            "password": password,
            "keypath": keypath,
            "proxy_hostname": proxy_hostname,
            "proxy_username": proxy_username,
            "proxy_password": proxy_password,
            "proxy_keypath": proxy_keypath,
        }
        self._clc_machine = None
        self.hostname = hostname
        self.config_qa = config_qa
        self.config_yml = config_yml
        # self._aws_access_key = aws_access_key
        # self._aws_secret_key = aws_secret_key
        self._eucahosts = {}
        self._credpath = credpath
        self.log = Eulogger(identifier=self.__class__.__name__, stdout_level=log_level)
        self.creds = AutoCreds(
            credpath=self._credpath,
            aws_access_key=aws_access_key,
            aws_secret_key=aws_secret_key,
            aws_account_name=euca_account,
            aws_user_name=euca_user,
            logger=self.log,
            **self.clc_connect_kwargs
        )
        super(SystemConnection, self).__init__(
            hostname=hostname,
            aws_secret_key=self.creds.aws_secret_key,
            aws_access_key=self.creds.aws_access_key,
            logger=self.log,
            boto_debug_level=boto_debug_level,
        )

    def set_loglevel(self, level, parent=False):
        """
        wrapper for log.setLevel, accept int or string.
        Levels can be found in logging class. At the time this was written they are:
        CRITICAL:50
        DEBUG:10
        ERROR:40
        FATAL:50
        INFO:20
        NOTSET:0
        WARN:30
        WARNING:30
        """
        level = level or logging.NOTSET
        if not isinstance(level, int) and not isinstance(level, basestring):
            raise ValueError(
                'set_loglevel. Level must be of type int or string, got: "{0}/{1}"'.format(level, type(level))
            )
        if isinstance(level, basestring):
            level = getattr(logging, str(level).upper())
        return self.log.set_parentloglevel(level)

    @property
    def clc_machine(self):
        if not self._clc_machine:
            if self.clc_connect_kwargs["hostname"]:
                if self.eucahosts[self.clc_connect_kwargs["hostname"]]:
                    self._clc_machine = self.eucahosts[self.clc_connect_kwargs["hostname"]]
                else:
                    self._clc_machine = Machine(**self.clc_connect_kwargs)
                    self.eucahosts[self.clc_connect_kwargs["hostname"]] = self._clc_machine
        return self._clc_machine

    @property
    def eucahosts(self):
        if not self._eucahosts:
            self._eucahosts = self._update_host_list()
        return self._eucahosts

    def _update_host_list(self):
        machines = self.get_all_machine_mappings()
        connect_kwargs = copy.copy(self.clc_connect_kwargs)
        if "hostname" in connect_kwargs:
            connect_kwargs.pop("hostname")
        hostlock = threading.Lock()

        def add_host(ip, services, self=self, connect_kwargs=connect_kwargs):
            host = EucaHost(connection=self, hostname=ip, services=services, **connect_kwargs)
            with hostlock:
                self._eucahosts[ip] = host

        threads = []
        for ip, services in machines.iteritems():
            t = threading.Thread(target=add_host, args=(ip, services))
            t.start()
            threads.append(t)
            # self._eucahosts[ip] = EucaHost(connection=self, hostname=ip, services=services,
            #                               **connect_kwargs)
        for t in threads:
            t.join()

        return self._eucahosts

    def get_host_by_hostname(self, hostname):
        return self.eucahosts.get(hostname, None)

    def get_hosts_by_service_type(self, servicetype):
        ret_list = []
        for ip, host in self.eucahosts.iteritems():
            for service in host.services:
                if service.type == servicetype:
                    ret_list.append(host)
        return ret_list

    def get_hosts_for_cloud_controllers(self):
        clc = None
        return self.get_hosts_by_service_type(servicetype="eucalyptus")

    def get_hosts_for_node_controllers(self, partition=None, instanceid=None):
        ncs = self.get_hosts_by_service_type(servicetype="node")
        if not partition and not instanceid:
            return ncs
        retlist = []
        for nc in ncs:
            if instanceid:
                for instance in nc.instances:
                    if instance == instanceid:
                        return [nc]
            if nc.partition == partition:
                retlist.append(nc)
        return retlist

    def get_hosts_cluster_controllers(self, partition=None):
        ccs = self.get_hosts_by_service_type(servicetype="cluster")
        if not partition:
            return ccs
        retlist = []
        for cc in ccs:
            if cc.partition == partition:
                retlist.append(cc)
        return retlist

    def get_hosts_for_storage_controllers(self, partition=None):
        scs = self.get_hosts_by_service_type(servicetype="storage")
        if not partition:
            return scs
        retlist = []
        for sc in scs:
            if sc.partition == partition:
                retlist.append(sc)
        return retlist

    def get_hosts_for_ufs(self):
        ufs = None
        out = self.get_hosts_by_service_type(servicetype="user-api")
        if out:
            ufs = out[0]
        return ufs

    def get_hosts_for_walrus(self):
        walrus = None
        out = self.get_hosts_by_service_type(servicetype="walrusbackend")
        if out:
            walrus = out[0]
        return walrus

    def show_cloud_legacy_summary(self, repo_info=True, print_method=None, file_path=None, print_table=True):
        """
        Creates a table representing the legacy Eutester/QA reprsentation of a Eucalyptus
        cloud. This can be used for legacy eutester tests, etc..
        :param repo_info: bool, if True will use the work REPO in place of Zone for the 5th column
        :param print_method: method used to print this table, defaults to self.log.info
        :param print_table: bool, if False will return the table obj
        :param file_path: string representing a local file path to save this information to
        :return: table obj if print_table is False
        """
        ret = ""
        print_method = print_method or self.log.info
        if repo_info:
            rz_col = "REPO"
        else:
            rz_col = "ZONE"
        pt = PrettyTable(["# HOST", "DISTRO", "VER", "ARCH", rz_col, "SERVICE CODES"])
        pt.align = "l"
        pt.border = 0
        for ip, host in self.eucahosts.iteritems():
            split = host.summary_string.split()
            service_codes = " ".join(split[5:])
            if repo_info:
                rz_col = "REPO"
            else:
                rz_col = split[4]
            pt.add_row([split[0], split[1], split[2], split[3], rz_col, service_codes])
            ret += "{0}\n".format(host.summary_string)
        if file_path:
            with open(file_path, "w") as save_file:
                save_file.write(str(pt))
                save_file.flush()
        if print_table:
            print_method("\n{0}\n".format(str(pt)))
        else:
            return pt

    @staticmethod
    def vm_state_markup(state):
        if state in ["shutting-down", "stopped", "stopping"]:
            return [1, 91]
        if state == "terminated":
            return [1, 97]
        if state == "running":
            return [1, 92]
        return [1, 93]

    def show_hosts(
        self,
        hosts=None,
        partition=None,
        service_type=None,
        serv_columns=None,
        update=True,
        print_method=None,
        print_table=True,
        save_file=None,
    ):
        print_method = print_method or self._show_method
        ins_id_len = 10
        ins_type_len = 13
        ins_dev_len = 16
        ins_st_len = 15
        ins_total = (ins_id_len + ins_dev_len + ins_type_len + ins_st_len) + 5
        machine_hdr = (markup("MACHINE INFO"), 30)
        service_hdr = (markup("EUCALYPTUS SERVICES"), 90)
        pt = PrettyTable([machine_hdr[0], service_hdr[0]])
        pt.header = False
        pt.align = "l"
        pt.hrules = 1
        pt.max_width[machine_hdr[0]] = machine_hdr[1]
        total = []
        eucahosts = {}
        if hosts is None:
            eucahosts = self.eucahosts
        elif isinstance(hosts, list):
            for host in hosts:
                eucahosts[host.hostname] = host
        elif isinstance(hosts, EucaHost):
            eucahosts[hosts.hostname] = hosts

        if not isinstance(eucahosts, dict):
            raise ValueError(
                "show_machine_mappings requires dict example: "
                '{"host ip":[host objs]}, got:"{0}/{1}"'.format(eucahosts, type(eucahosts))
            )
        # To format the tables services, print them all at once and then sort the table
        # rows string into the machines columns
        for hostip, host in eucahosts.iteritems():
            for serv in host.services:
                if update:
                    serv.update()
                total.append(serv)
                if serv.child_services:
                    total.extend(serv.child_services)
        # Create a table showing the service states, grab the first 3 columns
        # for type, name, state, and zone
        servpt = self.show_services(total, print_table=False)
        # Get a subset of the show services fields...
        if serv_columns is None:
            fields = servpt._field_names[0:4]
        else:
            fields = servpt._fields_names[serv_columns]
        serv_lines = servpt.get_string(border=0, padding_width=2, fields=fields).splitlines()
        header = serv_lines[0]
        ansi_escape = re.compile(r"\x1b[^m]*m")
        # Now build the machine table...
        threads = []
        hostlock = threading.Lock()

        # Method to allow host info to be gathered concurrently
        def add_host(hostip, host, self=self):
            assert isinstance(host, EucaHost)
            servbuf = header + "\n"
            mservices = []
            # Get the child services (ie for UFS)
            for serv in host.services:
                mservices.append(serv)
                mservices.extend(serv.child_services)
            for serv in mservices:
                for line in serv_lines:
                    # Remove the ansi markup for parsing purposes, but leave it in the
                    # displayed line
                    clean_line = ansi_escape.sub("", line)
                    splitline = clean_line.split()
                    if len(splitline) < 2:
                        continue
                    line_type = splitline[0]
                    line_name = splitline[1]
                    # Pull matching lines out of the pre-formatted service table...
                    if (
                        splitline
                        and re.match("^{0}$".format(serv.type), line_type)
                        and re.match("^{0}$".format(serv.name), line_name)
                    ):
                        # Add this line to the services to be displayed for this machine
                        if line_name not in servbuf:
                            servbuf += line + "\n"
                if serv.type == "node":
                    if getattr(serv, "instances", None):
                        if serv.instances:
                            vm_pt = PrettyTable(
                                [
                                    markup("INSTANCES", [1, 4]),
                                    markup("STATE:", [1, 4]),
                                    markup("VMTYPE:", [1, 4]),
                                    markup("ROOT_DEV:", [1, 4]),
                                ]
                            )
                            vm_pt.align = "l"
                            vm_pt.border = 1
                            vm_pt.vrules = 2
                            vm_pt.hrules = 0
                            for x in serv.instances:
                                vm_pt.add_row(
                                    [
                                        x.id,
                                        markup(x.state, self.vm_state_markup(x.state)),
                                        x.instance_type,
                                        x.root_device_type,
                                    ]
                                )
                            servbuf += "{0}\n".format(vm_pt)
                    av_pt = host.helpers.node_controller.show_availability_for_node(print_table=False)
                    servbuf += av_pt.get_string()
            ps_sum_pt = host.show_euca_process_summary(print_table=False)
            servbuf += "\n" + ps_sum_pt.get_string(border=1, vrules=2, hrules=0)
            host_info = markup("Euca Versions:").ljust(machine_hdr[1])
            host_info += "Cloud: {0}".format(host.get_eucalyptus_version()).ljust(machine_hdr[1])
            host_info += "2ools: {0}".format(host.get_euca2ools_version()).ljust(machine_hdr[1])
            host_info += markup("Hostname:").ljust(machine_hdr[1])
            host_info += str(host.hostname).ljust(machine_hdr[1])
            sys_pt = host.show_sys_info(print_table=False)
            host_info += "{0}".format(sys_pt)
            with hostlock:
                pt.add_row(
                    [
                        markup("HOST:") + markup(hostip, [1, 94]),
                        markup("EUCALYPTUS SERVICES:")
                        + markup("[ {0} ]".format(" ".join(str(x) for x in host.euca_service_codes)), [1, 34]),
                    ]
                )
                pt.add_row([host_info, servbuf])

        for hostip, host in eucahosts.iteritems():
            t = threading.Thread(target=add_host, args=(hostip, host))
            t.start()
            threads.append(t)
        for t in threads:
            t.join()
        if save_file:
            with open(save_file, "w") as sf:
                sf.write("\n{0}\n".format(pt.get_string()))
        if print_table:
            # print_method("\n{0}\n".format(pt.get_string(sortby=pt.field_names[1])))
            print_method("\n{0}\n".format(pt.get_string()))
        else:
            return pt

    def build_machine_dict_from_config(cls):
        raise NotImplementedError()

    def build_machine_dict_from_cloud_services(self):
        raise NotImplementedError("not yet implemented")
Exemple #24
0
class RemoteCommands(object):
    """
    Utility to run commands on remote machines via ssh in batches.
    """
    def __init__(self,
                 hostfile=None,
                 ips=None,
                 password=None,
                 keypath=None,
                 username='******',
                 command='echo "ALIVE',
                 timeout=5,
                 thread_count=20,
                 log_level='debug'):

        self.parser = argparse.ArgumentParser(
            description='Run a command on list of remote hosts',
            formatter_class=argparse.ArgumentDefaultsHelpFormatter)
        self.parser.add_argument('-f',
                                 '--hostfile',
                                 default=hostfile,
                                 help='file with list of ips and/or hostnames')
        self.parser.add_argument(
            '-i',
            '--ips',
            default=ips,
            help='comma or space separated list of ips and/or hostnames')
        self.parser.add_argument('-p',
                                 '--password',
                                 default=password,
                                 help='Ssh password used to connect to hosts')
        self.parser.add_argument(
            '-k',
            '--keypath',
            default=keypath,
            help='Local path to specific ssh key used to connect to hosts')
        self.parser.add_argument('-u',
                                 '--username',
                                 default=username,
                                 help='Ssh username used to connect to hosts')
        self.parser.add_argument('-c',
                                 '--command',
                                 default=command,
                                 help='file with list of ips and/or hostnames')
        self.parser.add_argument('-t',
                                 '--timeout',
                                 default=timeout,
                                 type=int,
                                 help='Ssh connection timeout in seconds')
        self.parser.add_argument(
            '-b',
            '--batch-timeout',
            default=0,
            type=int,
            help='Timeout for sum of all tasks to complete in seconds. '
            'This includes time to create all remote '
            'connections + execute commands')
        self.parser.add_argument(
            '--thread-count',
            default=thread_count,
            type=int,
            help='Number of threads used to run commands on hosts')
        self.parser.add_argument('-l',
                                 '--log-level',
                                 default=log_level,
                                 help='Loglevel')
        if ips or hostfile:
            args = ""
        else:
            args = None
        self.args = self.parser.parse_args(args=args)
        self.hostfile = self.args.hostfile
        self.password = self.args.password
        self.keypath = self.args.keypath
        self.username = self.args.username
        self.command = self.args.command
        self.timeout = self.args.timeout
        self.log_level = self.args.log_level
        self.results = {}
        self.maxwait = .5
        self.ips = ips or self.args.ips or []
        self.logger = Eulogger('RemoteCmds', stdout_level=self.log_level)
        if self.ips:
            if isinstance(self.ips, basestring):
                self.ips = str(self.ips).replace(',', ' ')
                self.ips = self.ips.split()
            else:
                self.ips = list(self.ips)
        if self.args.hostfile:
            with open(os.path.expanduser(self.args.hostfile)) as f:
                self.ips.extend(f.readlines())
        if not self.ips:
            raise ValueError(
                'No hosts provided. Use --hostfile or --ips to provide hosts to run '
                'command against')

    def do_ssh(self, q, lock, name, command):
        empty = False
        q = q or None
        while not empty:
            try:
                ssh = None
                logger = None
                self.logger.debug('Thread: {0}, in Q loop...'.format(name))
                host = None
                try:
                    host = q.get(timeout=self.maxwait)
                except Empty:
                    empty = True
                    break
                start = time.time()
                try:
                    self.logger.debug('Connecting to new host:' + str(host))
                    logger = Eulogger(str(host))
                    ssh = SshConnection(host=host,
                                        username=self.username,
                                        password=self.password,
                                        keypath=self.keypath,
                                        debug_connect=True,
                                        timeout=self.args.timeout,
                                        verbose=True,
                                        logger=logger)
                    logger.debug('host: {0} running command:{1} '.format(
                        host, command))
                    out = ssh.cmd(str(command),
                                  listformat=True,
                                  timeout=self.args.timeout)
                    logger.debug('Done with host: {0}'.format(host))

                    with lock:
                        self.results[host] = {
                            'status': out.get('status'),
                            'output': out.get('output'),
                            'elapsed': int(time.time() - start)
                        }
                except Exception as E:
                    err = "{0}\n{1}".format(get_traceback(), E)
                    with lock:
                        self.results[host] = {
                            'status': -1,
                            'output': [err],
                            'elapsed': int(time.time() - start)
                        }
                finally:
                    logger.debug('Closing ssh to host: {0}'.format(host))
                    if ssh:
                        ssh.connection.close()
                        logger.debug('Closed ssh to host: {0}'.format(host))
                    try:
                        if logger:
                            logger.close()
                    except:
                        pass
            except Exception as SE:
                self.logger.error('{0}\nError in do_ssh:{0}'.format(
                    get_traceback(), SE))
            finally:
                if q is not None and not empty:
                    q.task_done()
                self.logger.debug('Finished task in thread:{0}'.format(name))
        self.logger.debug('{0}: Done with thread'.format(name))

    def run_remote_commands(
        self,
        ips=None,
        command=None,
    ):
        command = command or self.command
        ips = ips or self.ips
        self.results = {}
        if not ips:
            self.logger.warning('No IPs provided to run_remote_commands!')
            return self.results
        command = command or ""
        iq = Queue()
        #if not ips:
        #    raise ValueError('run_remote_commands: IP list was empty:"{0}"'.format(ips))
        for ip in ips:
            ip = str(ip).strip().rstrip()
            iq.put(ip)
        tlock = Lock()
        threadcount = self.args.thread_count
        if threadcount > iq.qsize():
            threadcount = iq.qsize()
        if not iq:
            return
        self.results = {}
        for i in range(threadcount):
            t = Thread(target=self.do_ssh, args=(iq, tlock, i, command))
            t.daemon = True
            t.start()
        self.logger.debug('Threads started now waiting for join')
        if not self.args.batch_timeout:
            iq.join()
        else:
            start = time.time()
            while iq.unfinished_tasks and (time.time() - start < int(
                    self.args.batch_timeout)):
                time.sleep(.5)
            if iq.unfinished_tasks:
                self.logger.warning(
                    red('Possible unfinished tasks detected '
                        'after elapsed:{0}. Queue:{1}'.format(
                            time.time() - start, iq.queue)))
                time.sleep(.1 * len(ips))
                for ip in ips:
                    with tlock:
                        if ip not in self.results.keys():
                            self.results[ip] = {
                                'status':
                                -1,
                                'output': [
                                    'Timed out after {0} '
                                    'seconds'.format(
                                        int(self.args.batch_timeout))
                                ],
                                'elapsed':
                                int(self.args.batch_timeout)
                            }
        self.logger.debug('Done with join')
        time.sleep(self.maxwait + .1)
        return self.results

    def show_results(self, results=None, max_width=None, printmethod=None):
        results = results or self.results
        if not max_width:
            max_height, max_width = get_terminal_size()
            self.logger.debug(
                green('Got terminal width: {0}'.format(max_width)))
            max_width = max_width or 100
        output_hdr = "OUTPUT"
        pt = PrettyTable(['HOST', 'RES', 'TIME', output_hdr])
        host_w = 0
        for host in results.keys():
            if len(host) > host_w:
                host_w = len(host)
        res_w = 4
        time_w = 6
        pad_w = len(pt.field_names) * 2
        pt.align = 'l'
        pt.hrules = 1
        pt.padding_width = 0
        max_width = max_width - (host_w + res_w + time_w + pad_w)
        pt.max_width[output_hdr] = max_width

        def sort_meth(ip):
            try:
                if re.match("^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$"):
                    return struct.unpack("!L", inet_aton(ip))[0]
            except:
                pass
            return ip

        for host in sorted(results, key=sort_meth):
            result = self.results.get(host)
            output = ""
            for line in result.get('output'):
                line.rstrip()
                for x in xrange(0, len(line), max_width - 1):
                    part = str('{output: <{length}}'.format(
                        output=line[x:(x + max_width - 1)], length=max_width))
                    output += part
            status = result.get('status')
            if status == 0:
                color = green
            else:
                color = red
            pt.add_row([
                blue(host),
                color(result.get('status', None)),
                color(result.get('elapsed', None)),
                color(output)
            ])
        buf = "\n{0}\n".format(pt)
        if printmethod:
            printmethod(buf)
        else:
            print buf
Exemple #25
0
class RemoteCommands(object):
    """
    Utility to run commands on remote machines via ssh in batches.
    """
    
    def __init__(self, hostfile=None, ips=None, password=None, username='******',
                 command='echo "ALIVE', timeout=5, thread_count=20, log_level='debug'):

        self.parser = argparse.ArgumentParser(
            description='Run a command on list of remote hosts',
            formatter_class=argparse.ArgumentDefaultsHelpFormatter)
        self.parser.add_argument('-f', '--hostfile', default=hostfile,
                            help='file with list of ips and/or hostnames')
        self.parser.add_argument('-i', '--ips', default=ips,
                            help='comma or space separated list of ips and/or hostnames')
        self.parser.add_argument('-p', '--password', default=password,
                            help='Ssh password used to connect to hosts')
        self.parser.add_argument('-u', '--username', default=username,
                            help='Ssh username used to connect to hosts')
        self.parser.add_argument('-c', '--command', default=command,
                            help='file with list of ips and/or hostnames')
        self.parser.add_argument('-t', '--timeout', default=timeout, type=int,
                            help='Ssh connection timeout in seconds')
        self.parser.add_argument('--thread-count', default=thread_count, type=int,
                            help='Number of threads used to run commands on hosts')
        self.parser.add_argument('-l', '--log-level', default=log_level,
                            help='Loglevel')
        if ips or hostfile:
            args = ""
        else:
            args = None
        self.args = self.parser.parse_args(args=args)
        self.hostfile = self.args.hostfile
        self.password = self.args.password
        self.username = self.args.username
        self.command = self.args.command
        self.timeout = self.args.timeout
        self.log_level = self.args.log_level
        self.results = {}
        self.maxwait = .5
        self.ips = ips or self.args.ips or []
        self.logger = Eulogger('RemoteCmds', stdout_level=self.log_level)
        if self.ips:
            if isinstance(self.ips, basestring):
                self.ips = str(self.ips).replace(',', ' ')
                self.ips = self.ips.split()
            else:
                self.ips = list(self.ips)
        if self.args.hostfile:
            with open(os.path.expanduser(self.args.hostfile)) as f:
                self.ips.extend(f.readlines())
        if not self.ips:
            raise ValueError('No hosts provided. Use --hostfile or --ips to provide hosts to run '
                             'command against')

    def do_ssh(self, q, lock, name, command):
        empty = False
        q = q or None
        while not empty:
            try:
                ssh = None
                logger = None
                self.logger.debug('Thread: {0}, in Q loop...'.format(name))
                host = None
                try:
                    host = q.get(timeout=self.maxwait)
                except Empty:
                    empty = True
                    break
                start = time.time()
                try:
                    self.logger.debug('Connecting to new host:' + str(host))
                    logger = Eulogger(str(host))
                    ssh = SshConnection(host=host, username=self.username, password=self.password,
                                        debug_connect=True, timeout=self.args.timeout, verbose=True,
                                        logger=logger)
                    logger.debug('host: {0} running command:{1} '.format(host, command))
                    out = ssh.cmd(str(command), listformat=True)
                    logger.debug('Done with host: {0}'.format(host))
                    elapsed = int(time.time() - start)
                    with lock:
                        self.results[host] = {'status': out.get('status'),
                                              'output': out.get('output'),
                                              'elapsed': elapsed}
                except Exception as E:
                    elapsed = int(time.time() - start)
                    with lock:
                        self.results[host] = {'status': -1, 'output': [str(E)],
                                         'elapsed': elapsed}
                finally:
                    logger.debug('Closing ssh to host: {0}'.format(host))
                    if ssh:
                        ssh.connection.close()
                        logger.debug('Closed ssh to host: {0}'.format(host))
                    try:
                        if logger:
                            logger.close()
                    except:
                        pass
            except Exception as SE:
                self.logger.error('{0}\nError in do_ssh:{0}'.format(get_traceback(), SE))
            finally:
                if q is not None and not empty:
                    q.task_done()
                self.logger.debug('Finished task in thread:{0}'.format(name))
        self.logger.debug('{0}: Done with thread'.format(name))

    def run_remote_commands(self, ips=None, command=None, ):
        command = command or self.command
        ips = ips or self.ips
        if not ips:
            self.logger.warning('No IPs provided to run_remote_commands!')
            return self.results
        command = command or ""
        iq = Queue()
        #if not ips:
        #    raise ValueError('run_remote_commands: IP list was empty:"{0}"'.format(ips))
        for ip in ips:
            ip = str(ip).strip().rstrip()
            iq.put(ip)
        tlock = Lock()
        threadcount = self.args.thread_count
        if threadcount  > iq.qsize():
            threadcount = iq.qsize()
        if not iq:
            return
        self.results = {}
        for i in range(threadcount):
             t = Thread(target=self.do_ssh, args=(iq, tlock, i, command))
             t.daemon = True
             t.start()
        self.logger.debug('Threads started now waiting for join')
        iq.join()
        self.logger.debug('Done with join')
        time.sleep(self.maxwait + .1)
        return self.results

    def show_results(self, results=None, max_width=None, printmethod=None):
        results = results or self.results
        if not max_width:
            max_height, max_width = get_terminal_size()
        host_w = 24
        res_w = 4
        time_w = 6
        max_width = max_width - (host_w + res_w + time_w) - 5
        output_hdr = "OUTPUT"
        pt = PrettyTable(['HOST', 'RES', 'TIME', output_hdr])
        pt.align = 'l'
        pt.hrules = 1
        pt.padding_width = 0
        max_width = max_width - (host_w + res_w + time_w)
        pt.max_width[output_hdr] = max_width
        def sort_meth(ip):
            try:
                if re.match("^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$"):
                    return struct.unpack("!L", inet_aton(ip))[0]
            except:
                pass
            return ip

        for host in sorted(results, key=sort_meth):
            result = self.results.get(host)
            output = ""
            for line in result.get('output'):
                line.rstrip()
                for x in xrange(0, len(line), max_width - 1):
                    part = str('{output: <{length}}'.format(output=line[x:(x + max_width - 1)],
                                                            length=max_width))
                    output += part
            status = result.get('status')
            if status == 0:
                color = green
            else:
                color = red
            pt.add_row([blue(host), color(result.get('status')), color(result.get('elapsed')),
                        color(output)])
        buf = "\n{0}\n".format(pt)
        if printmethod:
            printmethod(buf)
        else:
            print buf
Exemple #26
0
    def __init__(self,
                 hostname=None, username='******', password=None, keypath=None, region=None,
                 domain=None,
                 proxy_hostname=None, proxy_password=None,
                 clouduser_account='nephotest', clouduser_name='sys_admin', clouduser_credpath=None,
                 clouduser_accesskey=None, clouduser_secretkey=None,
                 cloudadmin_credpath=None, cloudadmin_accesskey=None, cloudadmin_secretkey=None,
                 timeout=10, log_level='DEBUG', log_file=None, log_file_level='DEBUG',
                 environment_file=None, https=False, validate_certs=False,
                 cred_depot_hostname=None, cred_depot_username='******', cred_depot_password=None,
                 boto2_api_version=None):

        """

        :param hostname: CLC ssh hostname
        :param username: CLC ssh username
        :param password: CLC ssh password
        :param proxy_hostname: CLC ssh proxy hostname
        :param proxy_password: CLC ssh proxy password
        :param clouduser_account:
        :param clouduser_name:
        :param clouduser_credpath:
        :param clouduser_accesskey:
        :param clouduser_secretkey:
        :param cloudadmin_credpath:
        :param cloudadmin_accesskey:
        :param cloudadmin_secretkey:
        :param timeout:
        """
        if isinstance(log_level, basestring):
            log_level = getattr(logging, log_level.upper(), logging.DEBUG)
        self.log = Eulogger("TESTER:{0}".format(hostname), stdout_level=log_level,
                            logfile=log_file, logfile_level=log_file_level)
        if not hostname and environment_file:
            try:
                component = self.get_component_from_topology(environment_file, 'clc-1')
                hostname = component['clc-1']
            except KeyError:
                component = self.get_component_from_topology(environment_file,
                                                             'clc')
                hostname = component['clc'][0]
        self.log.identifier = "TESTER:{0}".format(hostname)
        self.log = Eulogger("TESTER:{0}".format(hostname), stdout_level=log_level)
        self._region = region
        self._sysadmin = None
        self._cloudadmin = None
        self._test_user = None
        self._cred_depot = None
        self._default_timeout = timeout
        self._domain = domain
        self._https = https
        self._validate_certs = validate_certs
        self._cloud_admin_connection_info = {}
        self._test_user_connection_info = {}
        boto2_api_version = boto2_api_version or __DEFAULT_API_VERSION__
        self._system_connection_info = {'hostname': hostname,
                                        'username': username,
                                        'password': password,
                                        'keypath': keypath,
                                        'proxy_hostname': proxy_hostname,
                                        'proxy_password': proxy_password,
                                        'proxy_username': None,
                                        'config_qa': None,
                                        'credpath': cloudadmin_credpath,
                                        'aws_access_key': cloudadmin_accesskey,
                                        'aws_secret_key': cloudadmin_secretkey,
                                        'log_level': log_level,
                                        'boto_debug_level': 0,
                                        'euca_user': '******',
                                        'euca_account': 'eucalyptus',
                                        'https': https,
                                        'domain': domain}

        self._cloud_admin_connection_info = {'aws_account_name': 'eucalyptus',
                                             'aws_user_name': 'admin',
                                             'credpath': cloudadmin_credpath,
                                             'region': self.region,
                                             'domain': self.domain,
                                             'aws_access_key': cloudadmin_accesskey,
                                             'aws_secret_key': cloudadmin_secretkey,
                                             'service_connection': self.sysadmin,
                                             'log_level': log_level,
                                             'validate_certs': validate_certs,
                                             'boto2_api_version': boto2_api_version,
                                             'https': https}

        self._test_user_connection_info = {'aws_account_name': clouduser_account,
                                           'aws_user_name': clouduser_name,
                                           'credpath': clouduser_credpath,
                                           'aws_access_key': clouduser_accesskey,
                                           'aws_secret_key': clouduser_secretkey,
                                           'region': self.region,
                                           'domain': self.domain,
                                           'log_level': log_level,
                                           'validate_certs': validate_certs,
                                           'boto2_api_version': boto2_api_version,
                                           'https': https}

        self._cred_depot_connection_info = {'hostname': cred_depot_hostname,
                                            'username': cred_depot_username,
                                            'password': cred_depot_password or password,
                                            'log_level': log_level}

        # TODO ??
        self.test_resources = \
            {
                '_instances': [],
                '_volumes': []
            }
Exemple #27
0
class EucaNetXml(object):
    def __init__(self,
                 host=None,
                 password=None,
                 keypath=None,
                 sshconnection=None,
                 machine=None,
                 eucalyptus_run_path='/var/run/eucalyptus',
                 log_level='INFO'):
        if (machine and (sshconnection or host)) or sshconnection and host:
            warning = 'Duplicate and or possibly conflicting machine connection info provided:' \
                      'host:{0}, sshconnection:{1}, machine:{2}'.format(host, sshconnection,
                                                                        machine)
        else:
            warning = ""
        if machine:
            sshconnection = machine.ssh

        if sshconnection:
            host = host or sshconnection.host
            password = password or sshconnection.password
            keypath = sshconnection or sshconnection.keypair
        if host:
            if not machine:
                machine = Machine(hostname=host,
                                  password=password,
                                  keypath=keypath,
                                  sshconnection=sshconnection)
        host = host or "unknown"
        self.log = Eulogger("{0}.{1}".format(self.__class__.__name__, host))
        self.log.set_stdout_loglevel(log_level)
        if not host:
            self.log.warning(
                'Connection info not provided for: {0}.init()'.format(
                    self.__class__.__name__))

        self.host = host
        self.password = password
        self.keypath = keypath
        self._machine = machine
        self._global_xml_path = None
        self._global_xml = None
        self.eucalyptus_run_path = eucalyptus_run_path or ""
        self.eucanetd_pid_file = path.join(self.eucalyptus_run_path,
                                           'eucanetd.pid')
        self.global_xml_version = path.join(self.eucalyptus_run_path,
                                            'global_network_info.version')

    @property
    def machine(self):
        if not self._machine:
            try:
                if self.host:
                    self._machine = Machine(hostname=self.host,
                                            password=self.password,
                                            keypath=self.keypath)
            except Exception as E:
                self.log.warning(
                    '{0}\nFailed to create machine object to host:"{1}", error:"{2}"'
                    .format(get_traceback(), self.host, E))
        return self._machine

    @machine.setter
    def machine(self, machine):
        if machine is None or isinstance(machine, Machine):
            self._machine = machine
        else:
            self.log.error(
                'In correct machine type provided: "{0} {1}"'.format(
                    machine, type(machine)))

    ##############################################################################################
    #                                  Global XML methods
    ##############################################################################################

    @property
    def global_xml(self):
        try:
            if not self._global_xml:
                self._global_xml = GlobalXML(
                    xml_element=self._get_global_xml_root(),
                    eucanetd=self,
                    log_level=self.log.stdout_level)
            return self._global_xml
        except Exception as E:
            self.log.error(
                "{0}\nFailed to create global xml element. Error:{1}".format(
                    get_traceback(), E))

    @global_xml.setter
    def global_xml(self, global_xml):
        if global_xml is not None and not isinstance(global_xml, GlobalXML):
            raise ValueError('Global xml must be of type:{0} or None'.format(
                GlobalXML.__name__))

    @property
    def global_xml_path(self):
        # Since this file name may be different in different releases...
        if not self._global_xml_path:
            for fname in [
                    'eucanetd_global_network_info.xml',
                    'global_network_info.xml'
            ]:
                fpath = path.join(self.eucalyptus_run_path, fname)
                if self.machine.is_file(fpath):
                    self._global_xml_path = fpath
                    break
                self._global_xml_path = None
        return self._global_xml_path

    def _get_global_xml_string(self, path=None):
        path = path or self.global_xml_path
        with self.machine.sftp.open(path) as f:
            out = f.read()
        return out

    def show_global_xml(self,
                        path=None,
                        indent=4,
                        printmethod=None,
                        printme=True):
        i_space = ""
        indent = indent or 0
        for x in xrange(0, indent):
            i_space += " "
        indent = i_space
        xml_str = self._get_global_xml_string(path=path)
        xml = minidom.parseString(xml_str)
        if printme:
            printmethod = printmethod or self.log.info
            printmethod("\n{0}".format(xml.toprettyxml(indent=indent)))
        else:
            return xml.toprettyxml(indent=indent)

    def _get_global_xml_root(self, path=None):
        path = path or self.global_xml_path
        xml = ElementTree.fromstring(self._get_global_xml_string(path=path))
        return xml
Exemple #28
0
    def __init__(self, filepath=None, string=None, sshconnection=None, keysdir=None, logger=None,
                 loglevel='INFO'):
        """
        Will populate a Eucalyptus Runtime Configuration (eucarc) obj with values from a local
         file, remote file, or string buffer.
        The parser expect values in the following format:
        export key=value
        For example:
        export S3_URL=http://169.254.123.123:8773/services/objectstorage

        The value 'http://169.254.123.123:8773/services/objectstorage' will be assigned to an
        of the eucarc obj using the lower case version of the key, ie: eucarc.s3
        :param filepath: the local or remote filepath to the eucarc
        :param string: a string buffer containing the eucarc contents to be parsed
        :param sshconnection: an SshConnection() obj to a remote machine to read the eucarc
                              at 'filepath' from.
        :param keysdir: A value to replace _KEY_DIR_STR (${EUCA_KEY_DIR}) with, by defualt this is
                       the filepath, but when parsing from a string buffer filepath is unknown.
                       Remote files will be prefixed with an sftp://<user>@<hostname>/ before
                       the keys dir for later download.
        :param logger: logging.logger or equiv for logging output. By default a logger will
                        be created with the class name as the identifier
        """
        # init most common eucarc values to None...
        self._account_name = None
        self._account_id = None
        self._user_id = None
        self._user_name = None
        self._access_key = None
        self._secret_key = None

        self._ec2_url = None
        self._iam_url = None
        self._sts_url = None
        self._token_url = None
        self._cloudwatch_url = None
        self._elb_url = None
        self._cloudformation_url = None
        self._autoscaling_url = None
        self._simpleworkflow_url = None

        self.aws_credential_file = None

        self.aws_simpleworkflow_url = None
        self.ec2_access_key = None
        self.ec2_cert = None
        self.ec2_jvm_args = None
        self.ec2_private_key = None
        self.ec2_secret_key = None
        self.eucalyptus_cert = None
        self.eustore_url = 'http://emis.eucalyptus.com/'
        self._bootstrap_url = None
        self._properties_url = None

        self.s3_url = None

        # End of init default eucarc attrs
        if not logger:
            logger = Eulogger(identifier=self.__class__.__name__, stdout_level=loglevel)
        logger.set_stdout_loglevel(loglevel)
        self._log = logger
        self._debug = self.log.debug
        self._credpath = filepath
        if keysdir is None:
            keysdir = filepath
        self._keysdir = keysdir
        self._string = string
        self._sshconnection = sshconnection
        self._unparsed_lines = None
        if string:
            self._from_string()
        elif filepath:
            self._from_filepath(filepath=filepath, sshconnection=sshconnection, keysdir=filepath)
Exemple #29
0
 def do_ssh(self, q, lock, name, command):
     empty = False
     q = q or None
     while not empty:
         try:
             ssh = None
             logger = None
             self.logger.debug('Thread: {0}, in Q loop...'.format(name))
             host = None
             try:
                 host = q.get(timeout=self.maxwait)
             except Empty:
                 empty = True
                 break
             start = time.time()
             try:
                 self.logger.debug('Connecting to new host:' + str(host))
                 logger = Eulogger(str(host))
                 ssh = SshConnection(host=host, username=self.username, password=self.password,
                                     debug_connect=True, timeout=self.args.timeout, verbose=True,
                                     logger=logger)
                 logger.debug('host: {0} running command:{1} '.format(host, command))
                 out = ssh.cmd(str(command), listformat=True)
                 logger.debug('Done with host: {0}'.format(host))
                 elapsed = int(time.time() - start)
                 with lock:
                     self.results[host] = {'status': out.get('status'),
                                           'output': out.get('output'),
                                           'elapsed': elapsed}
             except Exception as E:
                 elapsed = int(time.time() - start)
                 with lock:
                     self.results[host] = {'status': -1, 'output': [str(E)],
                                      'elapsed': elapsed}
             finally:
                 logger.debug('Closing ssh to host: {0}'.format(host))
                 if ssh:
                     ssh.connection.close()
                     logger.debug('Closed ssh to host: {0}'.format(host))
                 try:
                     if logger:
                         logger.close()
                 except:
                     pass
         except Exception as SE:
             self.logger.error('{0}\nError in do_ssh:{0}'.format(get_traceback(), SE))
         finally:
             if q is not None and not empty:
                 q.task_done()
             self.logger.debug('Finished task in thread:{0}'.format(name))
     self.logger.debug('{0}: Done with thread'.format(name))
Exemple #30
0
    def __init__(self,
                 hostname=None, username='******', password=None,
                 proxy_hostname=None, proxy_password=None,
                 clouduser_account='nephotest', clouduser_name='admin', clouduser_credpath=None,
                 clouduser_accesskey=None, clouduser_secretkey=None,
                 cloudadmin_credpath=None, cloudadmin_accesskey=None, cloudadmin_secretkey=None,
                 timeout=10, log_level='DEBUG',
                 cred_depot_hostname=None, cred_depot_username='******', cred_depot_password=None):

        """

        :param hostname: CLC ssh hostname
        :param username: CLC ssh username
        :param password: CLC ssh password
        :param proxy_hostname: CLC ssh proxy hostname
        :param proxy_password: CLC ssh proxy password
        :param clouduser_account:
        :param clouduser_name:
        :param clouduser_credpath:
        :param clouduser_accesskey:
        :param clouduser_secretkey:
        :param cloudadmin_credpath:
        :param cloudadmin_accesskey:
        :param cloudadmin_secretkey:
        :param timeout:
        """
        self.log = Eulogger("TESTER:{0}".format(hostname), stdout_level=log_level)
        self._sysadmin = None
        self._cloudadmin = None
        self._test_user = None
        self._cred_depot = None
        self._default_timeout = timeout
        self._system_connection_info = {'hostname': hostname,
                                        'username': username,
                                        'password': password,
                                        'proxy_hostname': proxy_hostname,
                                        'proxy_password': proxy_password,
                                        'proxy_username': None,
                                        'config_qa': None,
                                        'credpath': cloudadmin_credpath,
                                        'aws_access_key': cloudadmin_accesskey,
                                        'aws_secret_key': cloudadmin_secretkey,
                                        'log_level': log_level,
                                        'boto_debug_level': 0,
                                        'euca_user': '******',
                                        'euca_account': 'eucalyptus'}

        self._cloud_admin_connection_info = {'account_name': 'eucalyptus',
                                             'user_name': 'admin',
                                             'credpath': cloudadmin_credpath,
                                             'access_key': cloudadmin_accesskey,
                                             'secret_key': cloudadmin_secretkey,
                                             'log_level': log_level}

        self._test_user_connection_info = {'aws_account_name': clouduser_account,
                                           'aws_user_name': clouduser_name,
                                           'credpath': clouduser_credpath,
                                           'aws_access_key': clouduser_accesskey,
                                           'aws_secret_key': clouduser_secretkey,
                                           'log_level': log_level}
        self._cred_depot_connection_info = {'hostname': cred_depot_hostname,
                                            'username': cred_depot_username,
                                            'password': cred_depot_password or password,
                                            'log_level': log_level}
Exemple #31
0
class ConversionTask(TaggedEC2Object):
    _IMPORTINSTANCE = 'importinstance'
    _IMPORTVOLUME = 'importvolume'

    def __init__(self, connection=None):
        super(ConversionTask, self).__init__(connection)
        self.connection = connection
        self.conversiontaskid = None
        self.expirationtime = None
        self.state = None
        self.statusmessage = None
        self._importinstancetask = None
        self._importvolumetask = None
        self._instance = None
        self._snapshots = None
        self.tags = None
        self.notfound = False
        self.log = Eulogger('ConversionTask:{0}'.format(self.id))

    def __repr__(self):
        volumes = ",".join([vol.id for vol in self.volumes])
        return ('ConversionTask:"{0}", state:"{1}", instance:"{2}", '
                'volumes:"{3}", status:"{4}"'.format(
                    str(self.conversiontaskid), self.state, self.instanceid,
                    volumes, self.statusmessage))

    @property
    def availabilityzone(self):
        if self.importvolumes:
            return self.importvolumes[0].availabilityzone
        return None

    @property
    def importvolumes(self):
        if self._importinstancetask:
            return self._importinstancetask.importvolumes
        if self._importvolumetask:
            return [self._importvolumetask]
        return []

    @property
    def platform(self):
        if self._importinstancetask:
            return self._importinstancetask.platform
        return None

    @property
    def instanceid(self):
        if self._importinstancetask:
            return self._importinstancetask.instanceid
        return None

    @property
    def instance(self):
        if not self._instance and self.instanceid:
            try:
                ins = self._instance = self.connection.get_only_instances(
                    instance_ids=[self.instanceid])
                if ins:
                    self._instance = ins[0]
            except Exception as E:
                self.log.warning(
                    'Failed to fetch instance:{0} for conversiontask:{1} err:'.
                    format(self.instanceid, self.id, E))
        return self._instance

    @property
    def volumes(self):
        '''
        Volumes are updated during the task and there may not be a volume(s)
        associated with a task response right away, EUCA-9337
        '''
        ret = []
        for im in self.importvolumes:
            if im and im.volume:
                ret.append(im.volume)
        return ret

    @property
    def snapshots(self):
        if not self._snapshots:
            self._snapshots = []
            for volume in self.volumes:
                self._snapshots.extend(
                    self.connection.get_all_snapshots(
                        filters={'volume-id': volume.id}))
        return self._snapshots

    @property
    def image_id(self):
        if self.instance:
            return self.instance.image_id

    @property
    def tasktype(self):
        if self._importinstancetask:
            return self._IMPORTINSTANCE
        elif self._importvolumetask:
            return self._IMPORTVOLUME
        else:
            return None

    @property
    def id(self):
        return self.conversiontaskid

    @id.setter
    def id(self, taskid):
        self.conversiontaskid = taskid

    def cancel(self):
        params = {'ConversionTaskId': str(self.conversiontaskid)}
        task = self.connection.get_object('CancelConversionTask',
                                          params,
                                          ConversionTask,
                                          verb='POST')
        if task:
            self.update(updatedtask=task)
        return task

    def update(self, updatedtask=None):
        params = {}
        params['ConversionTaskId'] = str(self.conversiontaskid)
        if not updatedtask:
            updatedtask = self.connection.get_object('DescribeConversionTasks',
                                                     params,
                                                     ConversionTask,
                                                     verb='POST')
        if updatedtask:
            self.__dict__.update(updatedtask.__dict__)
        else:
            print sys.stderr, 'Update. Failed to find task:"{0}"'\
                .format(str(self.conversiontaskid))
            self.notfound = True

    def startElement(self, name, attrs, connection):
        ename = name.replace('euca:', '')
        elem = super(ConversionTask,
                     self).startElement(name, attrs, connection)
        if elem is not None:
            return elem
        if ename == 'importVolume':
            self._importvolumetask = ImportVolume(connection=connection)
            self.importvolumes.append(self._importvolumetask)
            return self._importvolumetask
        elif ename == 'importInstance':
            self._importinstancetask = ImportInstance(connection=connection)
            return self._importinstancetask
        elif ename == 'tagSet' or ename == 'resourceTagSet':
            self.tags = ResultSet([('item', Tag)])
            return self.tags
        else:
            return None

    def endElement(self, name, value, connection):
        ename = name.lower().replace('euca:', '')
        if ename == 'conversiontaskid':
            self.conversiontaskid = value
        elif ename == 'expirationtime':
            self.expirationtime = value
        elif ename == 'state':
            self.state = value
        elif ename == 'statusmessage':
            self.statusmessage = value
        else:
            setattr(self, ename, value)
Exemple #32
0
    def __init__(self, filepath=None, string=None, sshconnection=None, keysdir=None, logger=None,
                 loglevel='INFO'):
        """
        Will populate a Eucalyptus Runtime Configuration (eucarc) obj with values from a local
         file, remote file, or string buffer.
        The parser expect values in the following format:
        export key=value
        For example:
        export S3_URL=http://169.254.123.123:8773/services/objectstorage

        The value 'http://169.254.123.123:8773/services/objectstorage' will be assigned to an
        of the eucarc obj using the lower case version of the key, ie: eucarc.s3
        :param filepath: the local or remote filepath to the eucarc
        :param string: a string buffer containing the eucarc contents to be parsed
        :param sshconnection: an SshConnection() obj to a remote machine to read the eucarc
                              at 'filepath' from.
        :param keysdir: A value to replace _KEY_DIR_STR (${EUCA_KEY_DIR}) with, by defualt this is
                       the filepath, but when parsing from a string buffer filepath is unknown.
                       Remote files will be prefixed with an sftp://<user>@<hostname>/ before
                       the keys dir for later download.
        :param logger: logging.logger or equiv for logging output. By default a logger will
                        be created with the class name as the identifier
        """
        # init most common eucarc values to None...
        self._account_name = None
        self._account_id = None
        self._user_id = None
        self._user_name = None
        self._access_key = None
        self._secret_key = None

        self._ec2_url = None
        self._iam_url = None
        self._sts_url = None
        self._sqs_url = None
        self._token_url = None
        self._cloudwatch_url = None
        self._elb_url = None
        self._cloudformation_url = None
        self._autoscaling_url = None
        self._simpleworkflow_url = None

        self.aws_credential_file = None

        self.aws_simpleworkflow_url = None
        self.ec2_access_key = None
        self.ec2_cert = None
        self.ec2_jvm_args = None
        self.ec2_private_key = None
        self.ec2_secret_key = None
        self.eucalyptus_cert = None
        self.eustore_url = 'http://emis.eucalyptus.com/'
        self._bootstrap_url = None
        self._properties_url = None

        self.s3_url = None

        # End of init default eucarc attrs
        if not logger:
            logger = Eulogger(identifier=self.__class__.__name__, stdout_level=loglevel)
        logger.set_stdout_loglevel(loglevel)
        self._log = logger
        self._debug = self.log.debug
        self._credpath = filepath
        if keysdir is None:
            keysdir = filepath
        self._keysdir = keysdir
        self._string = string
        self._sshconnection = sshconnection
        self._unparsed_lines = None
        if string:
            self._from_string()
        elif filepath:
            self._from_filepath(filepath=filepath, sshconnection=sshconnection, keysdir=filepath)
Exemple #33
0
class BaseElement(object):
    def __init__(self, xml_element, eucanetd=None, log_level='INFO'):

        if xml_element is not None and not isinstance(xml_element, Element):
            raise ValueError('xml_element must be of type: {0}.{1}'.format(
                Element.__module__, Element.__name__))
        self._xml = xml_element
        self._eucanetd = eucanetd
        self._tag = None
        self._name = None
        self._log = Eulogger("{0}:{1}:{2}".format(self.__class__.__name__,
                                                  self.tag or "", self.name
                                                  or ""),
                             stdout_level=log_level)
        self._update_from_xml(xml=self._xml)

    def _update(self):
        raise NotImplementedError(
            'update not implemented for this class:{0}'.format(
                self.__class__.__name))

    def __repr__(self):
        try:
            attrs = [self.__class__.__name__]
            if self.tag:
                attrs.append(str(self.tag))
            if self.name:
                attrs.append(str(self.name))
            return ":".join(attrs)
        except Exception as E:
            print '{0}\nFailed to create repr, err:{1}'.format(
                get_traceback(), E)
            self.log.error('{0}\nFailed to create repr, err:{1}'.format(
                get_traceback(), E))

    def show(self, printme=True, printmethod=None):
        val_len = 70
        key_len = 30
        pt = PrettyTable(['key', 'value'])
        pt.align = 'l'
        pt.max_width['key'] = key_len
        pt.max_width['value'] = val_len
        pt.header = False
        pt.border = False
        pt.add_row(['tag', self.tag])
        pt.add_row(['name', self.name])
        for key, value in self.__dict__.iteritems():
            if not str(key).startswith('_'):
                if not isinstance(value, list):
                    pt.add_row([key, str(value)])
                else:
                    buf = ""
                    max = (val_len) / (len(str(value[0])) + 2)
                    count = 0
                    for v in value:
                        count += 1
                        buf += "{0},".format(v)
                        if not count % max:
                            buf += "\n"
                        else:
                            buf += " "
                    buf.strip(',')
                    pt.add_row([key, buf])

        if printme:
            printmethod = printmethod or self.log.info
            printmethod("\n{0}".format(pt))
        else:
            return pt

    @property
    def xml(self):
        return getattr(self, '__xml', None)

    @xml.setter
    def xml(self, xml):
        if xml != self.xml:
            self._xml = xml
            self._update_from_xml(xml=self._xml)

    @property
    def tag(self):
        try:
            if getattr(self, '__tag', None) is None:
                if getattr(self, '__xml', None) is not None:
                    self._tag = self.xml.tag
            return self._tag
        except Exception as E:
            print '{0}\nFailed to fetch tag, err:{1}'.format(
                get_traceback(), E)
            self.log.error('{0}\nFailed to fetch tag, err:{1}'.format(
                get_traceback(), E))

    @tag.setter
    def tag(self, tag):
        if tag != self.tag:
            self._tag = tag
            self._log = Eulogger("{0}:{1}:{2}".format(self.__class__.__name__,
                                                      self.tag or "", self.name
                                                      or ""))

    @property
    def log(self):
        return self._log

    @property
    def name(self):
        try:
            if getattr(self, '__name', None) is None:
                if self.xml is not None:
                    if 'name' in self.xml.attrib:
                        self._name = self.xml.attrib.get('name')
            return self._name
        except Exception as E:
            print '{0}\nFailed to fetch name, err:{1}'.format(
                get_traceback(), E)
            self.log.error('{0}\nFailed to fetch name, err:{1}'.format(
                get_traceback(), E))

    @name.setter
    def name(self, name):
        if name != self.name:
            self._name = name
            self._log = Eulogger("{0}:{1}:{2}".format(self.__class__.__name__,
                                                      self.tag or "", self.name
                                                      or ""))

    def _update_from_xml(self, xml):
        attrs = vars(self).keys()
        for var in attrs:
            if not var.startswith('_'):
                self.__delattr__(var)
        self._set_defaults()
        if xml is not None:
            self.tag = xml.tag
            self._parse(xml=xml)
        self._xml = xml

    def _set_defaults(self):
        # Method to set default values of any attributes prior to parsing xml
        pass

    def _get_class_by_tag(self, tag):
        if tag in tag_element_map:
            return tag_element_map.get(tag)
        else:
            return BaseElement

    def _is_element_list(self, xml):
        # todo replace this guess work with populated tag_element_map
        if len(xml) > 1:
            for child in xml:
                if len(xml.findall(child.tag)) > 1:
                    return True
                else:
                    return False
        elif xml.text:
            return False
        elif hasattr(self, xml.tag):
            # If this attribute exists, possibly set by defaults check it's type
            return isinstance(getattr(self, xml.tag), list)
        elif str(xml.tag).endswith('s'):
            # There's not enough info available so guess based on the name :-(
            return True

    def _parse(self, xml):
        self.log.debug('Beginning parsing of element with tag:{0}'.format(
            xml.tag))
        if not isinstance(xml, Element):
            raise ValueError(
                'parse expected Element type for xml, got:{0}, type:{1}'.
                format(xml, type(xml)))
        # Set attrs from xml attrib dict...
        for attr, value in xml.attrib.iteritems():
            try:
                setattr(self, attr, value)
            except Exception as E:
                self.log.error(
                    'Failed to set attr:{0}, value:{1} for obj:{2}'.format(
                        attr, value, self))
                raise E
        if self._is_element_list(xml):
            new_list = ElementList()
            sub_child = None
            for sub_child in xml:
                tag = sub_child.tag
                tag_class = self._get_class_by_tag(tag)
                newobj = tag_class(xml_element=sub_child,
                                   log_level=self.log.stdout_level)
                new_list.append(newobj)
            return new_list
        else:
            for child in xml:
                if not child.tag:
                    self._log.warning('No tag for element:"{0}"'.format(
                        child.__dict__))
                else:
                    if not len(child):
                        # No additional children so this is the final attribute
                        setattr(self, child.tag, child.text)
                    else:
                        tag_class = self._get_class_by_tag(child.tag)
                        newobj = tag_class(
                            None,
                            log_level=self.log.stdout_level)._parse(child)
                        setattr(self, child.tag, newobj)
            return self
Exemple #34
0
 def name(self, name):
     if name != self.name:
         self._name = name
         self._log = Eulogger("{0}:{1}:{2}".format(self.__class__.__name__,
                                                   self.tag or "", self.name
                                                   or ""))
Exemple #35
0
    def do_ssh(self, q, lock, name, command):
        empty = False
        q = q or None
        while not empty:
            try:
                ssh = None
                logger = None
                self.logger.debug('Thread: {0}, in Q loop...'.format(name))
                host = None
                try:
                    host = q.get(timeout=self.maxwait)
                except Empty:
                    empty = True
                    break
                start = time.time()
                try:
                    self.logger.debug('Connecting to new host:' + str(host))
                    logger = Eulogger(str(host))
                    ssh = SshConnection(host=host,
                                        username=self.username,
                                        password=self.password,
                                        keypath=self.keypath,
                                        debug_connect=True,
                                        timeout=self.args.timeout,
                                        verbose=True,
                                        logger=logger)
                    logger.debug('host: {0} running command:{1} '.format(
                        host, command))
                    out = ssh.cmd(str(command),
                                  listformat=True,
                                  timeout=self.args.timeout)
                    logger.debug('Done with host: {0}'.format(host))

                    with lock:
                        self.results[host] = {
                            'status': out.get('status'),
                            'output': out.get('output'),
                            'elapsed': int(time.time() - start)
                        }
                except Exception as E:
                    err = "{0}\n{1}".format(get_traceback(), E)
                    with lock:
                        self.results[host] = {
                            'status': -1,
                            'output': [err],
                            'elapsed': int(time.time() - start)
                        }
                finally:
                    logger.debug('Closing ssh to host: {0}'.format(host))
                    if ssh:
                        ssh.connection.close()
                        logger.debug('Closed ssh to host: {0}'.format(host))
                    try:
                        if logger:
                            logger.close()
                    except:
                        pass
            except Exception as SE:
                self.logger.error('{0}\nError in do_ssh:{0}'.format(
                    get_traceback(), SE))
            finally:
                if q is not None and not empty:
                    q.task_done()
                self.logger.debug('Finished task in thread:{0}'.format(name))
        self.logger.debug('{0}: Done with thread'.format(name))
Exemple #36
0
class Euca2oolsImageUtils(object):
    #Define the bytes per gig
    gig = 1073741824
    mb = 1048576
    kb = 1024

    def __init__(self,
                 access_key=None,
                 secret_key=None,
                 account_id=None,
                 region_domain=None,
                 s3_url=None,
                 ec2_url=None,
                 bootstrap_url=None,
                 ec2_cert_path=None,
                 worker_hostname=None,
                 worker_keypath=None,
                 worker_username='******',
                 worker_password=None,
                 worker_machine=None,
                 user_context=None,
                 log_level='debug',
                 destpath=None,
                 time_per_gig=300,
                 eof=True):

        self.access_key = access_key
        self.secret_key = secret_key
        self.account_id = account_id
        self.region_domain = region_domain
        self.bootstrap_url = bootstrap_url
        self.s3_url = s3_url
        self.ec2_url = ec2_url
        self.ec2_cert_path = ec2_cert_path

        self.log = Eulogger('Euca2oolsImageUtils', stdout_level=log_level)
        # Setup the work machine, this is the machine which will be used for
        # performing the 'work' (download, bundle, etc)
        self.worker_hostname = worker_hostname
        self.worker_keypath = worker_keypath
        self.worker_username = worker_username
        self.worker_password = worker_password
        self._worker_machine = None
        self._user_context = user_context
        if worker_machine:
            self._worker_machine = worker_machine

        self.time_per_gig = time_per_gig
        self.eof = eof

        if destpath is not None:
            self.destpath = str(destpath)
        else:
            self.destpath = "/disk1/storage"

        self.time_per_gig = time_per_gig

    def status_log(self, msg):
        return self.log.info(
            markup(msg,
                   markups=[
                       ForegroundColor.WHITE, BackGroundColor.BG_GREEN,
                       TextStyle.BOLD
                   ]))

    @property
    def worker_machine(self):
        '''
        Attempts to verify the worker passed is a Machine() class else assume
        it's a host name of the machine work should be performed on and
        attempt to return a Machine() created from the hostname

        param: worker Machine() or 'hostname' to be used to perform image utils
        work on.
        returns Machine obj
        '''
        if not self._worker_machine:
            if self.worker_hostname:
                self.log.debug(
                    'Attempting to connect to machine: "{0}" for image utility work...'
                    .format(self.worker_hostname))
                self._worker_machine = Machine(hostname=self.worker_hostname,
                                               username=self.worker_username,
                                               password=self.worker_password,
                                               keypath=self.worker_keypath)
        return self._worker_machine

    @worker_machine.setter
    def worker_machine(self, machine):
        if isinstance(machine, Machine):
            self._worker_machine = machine
        else:
            raise ValueError(
                'worker_machine must be of type Machine, got:"{0}/{1}"'.format(
                    machine, type(machine)))

    def create_user_context(self,
                            access_key,
                            secret_key,
                            account_id=None,
                            region_domain=None,
                            ec2_url=None,
                            s3_url=None,
                            bootstrap_url=None):
        if not (region_domain or s3_url or ec2_url):
            raise ValueError(
                'Can not derive service endpoints for user. '
                'Must supply either region_domain:"{0}", or ec2_url:"{1}" '
                's3_url:"{2}"'.format(region_domain, ec2_url, s3_url))
        access_key = access_key or self.access_key
        secret_key = secret_key or self.secret_key
        region_domain = region_domain or self.region_domain
        if (not access_key and secret_key and region_domain):
            raise ValueError(
                'Must supply access_key, secret_key and region domain to '
                'create user context')
        user = UserContext(aws_access_key=access_key,
                           aws_secret_key=secret_key,
                           region=region_domain)
        if ec2_url:
            user.ec2_url = ec2_url
        if s3_url:
            user.s3_url = s3_url
        if bootstrap_url:
            user.bootstrap_url = bootstrap_url
        if account_id:
            user.account_id = account_id
        return user

    @property
    def user_context(self):
        if not self._user_context:
            try:
                self._user_context = self.create_user_context(
                    access_key=self.access_key,
                    secret_key=self.secret_key,
                    region_domain=self.region_domain,
                    ec2_url=self.ec2_url,
                    s3_url=self.s3_url,
                    bootstrap_url=self.bootstrap_url,
                    account_id=self.account_id)
            except ValueError as VE:
                self.log.warning(
                    'Could not create user context, err:"{0}"'.format(VE))
        return self._user_context

    @user_context.setter
    def user_context(self, user_context):
        if user_context is None or isinstance(user_context, UserContext):
            if user_context:
                self._user_context = user_context
                self.access_key = user_context.access_key
                self.secret_key = user_context.secret_key
                self.ec2_url = user_context.ec2_url
                self.s3_url = user_context.s3_url
                self.bootstrap_url = user_context.bootstrap_url
                self.account_id = user_context.account_id
        else:
            raise ValueError(
                'Usercontext must be of type UserContext. Got:"{0}/{1}"'.
                format(user_context, type(user_context)))

    def getHttpRemoteImageSize(self, url, unit=None, maxredirect=5):
        return Euca2oolsImageUtils._getHttpRemoteImageSize(
            url, unit=unit, maxredirect=maxredirect)

    @staticmethod
    def _getHttpRemoteImageSize(url, unit=None, maxredirect=5, debug=None):
        '''
        Get the remote file size from the http header of the url given
        Returns size in GB unless unit is given.
        '''
        unit = unit or 1073741824
        if debug is None:

            def printdebug(msg):
                print msg

            debug = printdebug

        def get_location(url, depth, maxdepth):
            if depth > maxdepth:
                raise ValueError(
                    'Max redirects limit has been reached:{0}/{1}'.format(
                        depth, maxdepth))
            conn = None
            try:
                url = url.replace('http://', '')
                host = url.split('/')[0]
                path = url.replace(host, '')
                res = None
                err = None
                retries = 5
                for retry in xrange(0, retries):
                    try:
                        debug('HTTP HEAD request for: {0}, attempt:{1}/{2}'.
                              format(url, retry, retries))
                        conn = httplib.HTTPConnection(host)
                        conn.request("HEAD", path)
                        res = conn.getresponse()
                        break
                    except Exception as HE:
                        err = '{0}\nError attempting to fetch url:{1}, attempt:{2}/{3}, ' \
                              'error:{4}'.format(get_traceback(), url, retry, retries, HE)
                        debug(err)
                        time.sleep(retry)
                if not res:
                    err = err or "Error retrieving url:{0}".format(url)
                    raise RuntimeError(err)
                location = res.getheader('location')
                if location and location != url:
                    depth += 1
                    debug('Redirecting: depth:{0}, url:{1}'.format(
                        depth, location))
                    return get_location(location,
                                        depth=depth,
                                        maxdepth=maxdepth)
                else:
                    content_length = res.getheader('content-length')
                    if content_length is None:
                        raise ValueError(
                            'No content-length header found for url:{0}'.
                            format(url))
                    fbytes = int(content_length)
                    return fbytes
            except Exception as HE:
                debug('Failed to fetch content-length header from url:{0}'.
                      format(url))
                raise HE
            finally:
                if conn:
                    conn.close()

        try:
            fbytes = get_location(url, depth=0, maxdepth=maxredirect)
            debug("content-length:" + str(fbytes))
            if fbytes == 0:
                rfsize = 0
            else:
                rfsize = (((fbytes / unit) + 1) or 1)
            debug("Remote file size: " + str(rfsize) + "g")
        except Exception, e:
            debug("Failed to get remote file size...")
            raise e
        return rfsize
Exemple #37
0
    def __init__(self,
                 hostfile=None,
                 ips=None,
                 password=None,
                 keypath=None,
                 username='******',
                 command='echo "ALIVE',
                 timeout=5,
                 thread_count=20,
                 log_level='debug'):

        self.parser = argparse.ArgumentParser(
            description='Run a command on list of remote hosts',
            formatter_class=argparse.ArgumentDefaultsHelpFormatter)
        self.parser.add_argument('-f',
                                 '--hostfile',
                                 default=hostfile,
                                 help='file with list of ips and/or hostnames')
        self.parser.add_argument(
            '-i',
            '--ips',
            default=ips,
            help='comma or space separated list of ips and/or hostnames')
        self.parser.add_argument('-p',
                                 '--password',
                                 default=password,
                                 help='Ssh password used to connect to hosts')
        self.parser.add_argument(
            '-k',
            '--keypath',
            default=keypath,
            help='Local path to specific ssh key used to connect to hosts')
        self.parser.add_argument('-u',
                                 '--username',
                                 default=username,
                                 help='Ssh username used to connect to hosts')
        self.parser.add_argument('-c',
                                 '--command',
                                 default=command,
                                 help='file with list of ips and/or hostnames')
        self.parser.add_argument('-t',
                                 '--timeout',
                                 default=timeout,
                                 type=int,
                                 help='Ssh connection timeout in seconds')
        self.parser.add_argument(
            '-b',
            '--batch-timeout',
            default=0,
            type=int,
            help='Timeout for sum of all tasks to complete in seconds. '
            'This includes time to create all remote '
            'connections + execute commands')
        self.parser.add_argument(
            '--thread-count',
            default=thread_count,
            type=int,
            help='Number of threads used to run commands on hosts')
        self.parser.add_argument('-l',
                                 '--log-level',
                                 default=log_level,
                                 help='Loglevel')
        if ips or hostfile:
            args = ""
        else:
            args = None
        self.args = self.parser.parse_args(args=args)
        self.hostfile = self.args.hostfile
        self.password = self.args.password
        self.keypath = self.args.keypath
        self.username = self.args.username
        self.command = self.args.command
        self.timeout = self.args.timeout
        self.log_level = self.args.log_level
        self.results = {}
        self.maxwait = .5
        self.ips = ips or self.args.ips or []
        self.logger = Eulogger('RemoteCmds', stdout_level=self.log_level)
        if self.ips:
            if isinstance(self.ips, basestring):
                self.ips = str(self.ips).replace(',', ' ')
                self.ips = self.ips.split()
            else:
                self.ips = list(self.ips)
        if self.args.hostfile:
            with open(os.path.expanduser(self.args.hostfile)) as f:
                self.ips.extend(f.readlines())
        if not self.ips:
            raise ValueError(
                'No hosts provided. Use --hostfile or --ips to provide hosts to run '
                'command against')
Exemple #38
0
class SystemConnection(ServiceConnection):

    def __init__(self,
                 hostname,
                 username='******',
                 password=None,
                 keypath=None,
                 proxy_hostname=None,
                 proxy_username=None,
                 proxy_password=None,
                 proxy_keypath=None,
                 config_yml=None,
                 config_qa=None,
                 credpath=None,
                 aws_access_key=None,
                 aws_secret_key=None,
                 log_level='INFO',
                 boto_debug_level=0,
                 euca_user='******',
                 euca_account='eucalyptus',
                 ):
        self.machine_connect_kwargs = {
            'hostname': hostname,
            'username': username,
            'password': password,
            'keypath': keypath,
            'proxy_hostname': proxy_hostname,
            'proxy_username': proxy_username or username,
            'proxy_password': proxy_password or password,
            'proxy_keypath': proxy_keypath or keypath,
            'log_level': log_level
        }
        self._clc_machine = None
        self.hostname = hostname
        self.config_qa = config_qa
        self.config_yml = config_yml
        # self._aws_access_key = aws_access_key
        # self._aws_secret_key = aws_secret_key
        self._eucahosts = {}
        self._credpath = credpath
        self.log = Eulogger(identifier=self.__class__.__name__, stdout_level=log_level)
        self.creds = AutoCreds(credpath=self._credpath,
                               aws_access_key=aws_access_key,
                               aws_secret_key=aws_secret_key,
                               aws_account_name=euca_account,
                               aws_user_name=euca_user,
                               logger=self.log,
                               **self.machine_connect_kwargs)
        super(SystemConnection, self).__init__(hostname=hostname,
                                               aws_secret_key=self.creds.aws_secret_key,
                                               aws_access_key=self.creds.aws_access_key,
                                               logger=self.log,
                                               boto_debug_level=boto_debug_level)

    def set_loglevel(self, level, parent=False):
        """
        wrapper for log.setLevel, accept int or string.
        Levels can be found in logging class. At the time this was written they are:
        CRITICAL:50
        DEBUG:10
        ERROR:40
        FATAL:50
        INFO:20
        NOTSET:0
        WARN:30
        WARNING:30
        """
        level = level or logging.NOTSET
        if not isinstance(level, int) and not isinstance(level, basestring):
            raise ValueError('set_loglevel. Level must be of type int or string, got: "{0}/{1}"'
                             .format(level, type(level)))
        if isinstance(level, basestring):
            level = getattr(logging, str(level).upper())
        return self.log.set_parentloglevel(level)

    @property
    def clc_machine(self):
        if not self._clc_machine:
            hostname = self.machine_connect_kwargs['hostname']
            if hostname:
                #  See if a host exists matching the provided hostname
                if hostname in self.eucahosts:
                    self._clc_machine = self.eucahosts[hostname]
                #  See if this is a localhost connection
                elif self._get_clc_eucahost_for_localhost():
                    self._clc_machine = self._get_clc_eucahost_for_localhost()
                else:
                    self._clc_machine = Machine(**self.machine_connect_kwargs)
                    self.eucahosts[self.machine_connect_kwargs['hostname']] = self._clc_machine
        return self._clc_machine

    @property
    def eucahosts(self):
        if not self._eucahosts:
            self._eucahosts = self._update_host_list()
        return self._eucahosts

    def _get_clc_eucahost_for_localhost(self):
        ifaces = self._get_all_local_ip_interfaces()
        for iface, ip in ifaces:
            if ip in self.eucahosts:
                self.log.debug('CLC is bound to iface:{0} ip:{1}'.format(iface, ip))
                return self.eucahosts[ip]
        return None

    def _get_all_local_ip_interfaces(self):
        max_possible = 1028
        bytes = max_possible * 32
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        names = array.array('B', '\0' * bytes)
        outbytes = struct.unpack('iL', fcntl.ioctl(
            s.fileno(),
            0x8912,  # SIOCGIFCONF
            struct.pack('iL', bytes, names.buffer_info()[0])
        ))[0]
        namestr = names.tostring()
        interfaces = []
        for i in range(0, outbytes, 40):
            name = namestr[i:i+16].split('\0', 1)[0]
            addr   = namestr[i+20:i+24]
            ip = "{0}.{1}.{2}.{3}".format(ord(addr[0]), ord(addr[1]), ord(addr[2]), ord(addr[3]))
            interfaces.append((name, ip))
        return interfaces

    def _update_host_list(self):
        machines = self.get_all_machine_mappings()
        connect_kwargs = copy.copy(self.machine_connect_kwargs)
        if 'hostname' in connect_kwargs:
            connect_kwargs.pop('hostname')
        hostlock = threading.Lock()

        def add_host(ip, services, self=self, connect_kwargs=connect_kwargs):
            host = EucaHost(connection=self, hostname=ip, services=services, **connect_kwargs)
            with hostlock:
                self._eucahosts[ip] = host
        threads = []
        for ip, services in machines.iteritems():
            t = threading.Thread(target=add_host, args=(ip, services))
            t.start()
            threads.append(t)
        for t in threads:
            t.join()

        return self._eucahosts

    def get_host_by_hostname(self, hostname):
        return self.eucahosts.get(hostname, None)

    def get_hosts_by_service_type(self, servicetype):
        ret_list = []
        for ip, host in self.eucahosts.iteritems():
            for service in host.services:
                if service.type == servicetype:
                    ret_list.append(host)
        return ret_list

    def get_hosts_for_cloud_controllers(self):
        clc = None
        return self.get_hosts_by_service_type(servicetype='eucalyptus')

    def get_hosts_for_node_controllers(self, partition=None, instanceid=None):
        if instanceid is not None and not isinstance(instanceid, basestring):
            raise ValueError('Instance id not of string type, got:"{0}"/"{1}"'
                             .format(instanceid, type(instanceid)))
        ncs = self.get_hosts_by_service_type(servicetype='node')
        if not partition and not instanceid:
            return ncs
        retlist = []
        if instanceid:
            try:
                reservation = self.ec2_connection.get_all_instances(instance_ids=[instanceid])
            except:
                self.log.error('{0}\nFailed to find instance:"{1}" on system'
                               .format(get_traceback(), instanceid))
                return []
            if reservation:
                instance = reservation[0].instances[0]
                node_addr = instance.tags.get('euca:node')
                if node_addr:
                    for nc in ncs:
                        if nc.hostname == node_addr:
                            return [nc]
        if partition and partition in nc.partitions:
            retlist.append(nc)
        return retlist

    def get_hosts_for_cluster_controllers(self, partition=None):
        ccs = self.get_hosts_by_service_type(servicetype='cluster')
        if not partition:
            return ccs
        retlist = []
        for cc in ccs:
            if partition in cc.partitions:
                retlist.append(cc)
        return retlist

    def get_hosts_for_storage_controllers(self, partition=None):
        scs = self.get_hosts_by_service_type(servicetype='storage')
        if not partition:
            return scs
        retlist = []
        for sc in scs:
            if partition in sc.partitions:
                retlist.append(sc)
        return retlist

    def get_hosts_for_ufs(self):
        ufs = None
        return self.get_hosts_by_service_type(servicetype='user-api')


    def get_hosts_for_walrus(self):
        walrus = None
        return self.get_hosts_by_service_type(servicetype='walrusbackend')

    def show_cloud_legacy_summary(self, repo_info=True, print_method=None, file_path=None,
                                  print_table=True):
        """
        Creates a table representing the legacy Eutester/QA reprsentation of a Eucalyptus
        cloud. This can be used for legacy eutester tests, etc..
        :param repo_info: bool, if True will use the work REPO in place of Zone for the 5th column
        :param print_method: method used to print this table, defaults to self.log.info
        :param print_table: bool, if False will return the table obj
        :param file_path: string representing a local file path to save this information to
        :return: table obj if print_table is False
        """
        ret = ""
        print_method = print_method or self.log.info
        if repo_info:
            rz_col = 'REPO'
        else:
            rz_col = 'ZONE'
        pt = PrettyTable(['# HOST', 'DISTRO', 'VER', 'ARCH', rz_col, 'SERVICE CODES'])
        pt.align = 'l'
        pt.border = 0
        for ip, host in self.eucahosts.iteritems():
            split = host.summary_string.split()
            service_codes = " ".join(split[5:])
            if repo_info:
                rz_col = 'REPO'
            else:
                rz_col = split[4]
            pt.add_row([split[0], split[1], split[2], split[3], rz_col, service_codes])
            ret += "{0}\n".format(host.summary_string)
        if file_path:
            with open(file_path, 'w') as save_file:
                save_file.write(str(pt))
                save_file.flush()
        if print_table:
            print_method("\n{0}\n".format(str(pt)))
        else:
            return pt

    @staticmethod
    def vm_state_markup(state):
        if state in ['shutting-down', 'stopped', 'stopping']:
            return [1, 91]
        if state == 'terminated':
            return [1, 97]
        if state == 'running':
            return [1, 92]
        return [1, 93]

    def show_hosts(self, hosts=None, partition=None, service_type=None, serv_columns=None,
                   update=True, print_method=None, print_table=True, save_file=None):
        print_method = print_method or self._show_method
        ins_id_len = 10
        ins_type_len = 13
        ins_dev_len = 16
        ins_st_len = 15
        ins_total = (ins_id_len + ins_dev_len + ins_type_len + ins_st_len) + 5
        machine_hdr = (markup('MACHINE INFO'), 30)
        service_hdr = (markup('EUCALYPTUS SERVICES'), 90)
        pt = PrettyTable([machine_hdr[0], service_hdr[0]])
        pt.header = False
        pt.align = 'l'
        pt.hrules = 1
        pt.max_width[machine_hdr[0]] = machine_hdr[1]
        total = []
        eucahosts = {}
        if hosts is None:
            eucahosts = self.eucahosts
        elif isinstance(hosts, list):
            for host in hosts:
                eucahosts[host.hostname] = host
        elif isinstance(hosts, EucaHost):
            eucahosts[hosts.hostname] = hosts

        if not isinstance(eucahosts, dict):
            raise ValueError('show_machine_mappings requires dict example: '
                             '{"host ip":[host objs]}, got:"{0}/{1}"'
                             .format(eucahosts, type(eucahosts)))
        # To format the tables services, print them all at once and then sort the table
        # rows string into the machines columns
        try:
            sorted_ips = sorted(list(eucahosts),
                key=lambda ip: struct.unpack("!L", socket.inet_aton(ip))[0])
        except Exception as SE:
            self.log.warning('"Failed to sort host list by IP, error:"{0}"'.format(SE))
            sorted_ips = sorted(list(eucahosts))
        for hostip in sorted_ips:
            host = eucahosts[hostip]
            for serv in host.services:
                if update:
                    serv.update()
                total.append(serv)
                if serv.child_services:
                    total.extend(serv.child_services)
        # Create a table showing the service states, grab the first 3 columns
        # for type, name, state, and zone
        servpt = self.show_services(total, print_table=False)
        # Get a subset of the show services fields...
        if serv_columns is None:
            fields = servpt._field_names[0:4]
        else:
            fields = servpt._fields_names[serv_columns]
        serv_lines = servpt.get_string(border=0, padding_width=2, fields=fields).splitlines()
        header = serv_lines[0]
        ansi_escape = re.compile(r'\x1b[^m]*m')
        # Now build the machine table...
        threads = []
        hostlock = threading.Lock()

        # Method to allow host info to be gathered concurrently
        def add_host(hostip, host, self=self):
            assert isinstance(host, EucaHost)
            servbuf = header + "\n"
            mservices = []
            # Get the child services (ie for UFS)
            for serv in host.services:
                mservices.append(serv)
                mservices.extend(serv.child_services)
            for serv in mservices:
                for line in serv_lines:
                    # Remove the ansi markup for parsing purposes, but leave it in the
                    # displayed line
                    clean_line = ansi_escape.sub('', line)
                    splitline = clean_line.split()
                    if len(splitline) < 2:
                        continue
                    line_type = splitline[0]
                    line_name = splitline[1]
                    # Pull matching lines out of the pre-formatted service table...
                    if (splitline and re.match("^{0}$".format(serv.type), line_type) and
                            re.match("^{0}$".format(serv.name), line_name)):
                        # Add this line to the services to be displayed for this machine
                        if line_name not in servbuf:
                            servbuf += line + "\n"
                if serv.type == 'node':
                    if getattr(serv, 'instances', None):
                        if serv.instances:
                            vm_pt = PrettyTable([markup('INSTANCES', [1, 4]),
                                                 markup('STATE:', [1, 4]),
                                                 markup('VMTYPE:', [1, 4]),
                                                 markup('ROOT_DEV:', [1, 4])])
                            vm_pt.align = 'l'
                            vm_pt.border = 1
                            vm_pt.vrules = 2
                            vm_pt.hrules = 0
                            for x in serv.instances:
                                vm_pt.add_row([x.id,
                                               markup(x.state, self.vm_state_markup(x.state)),
                                               x.instance_type,
                                               x.root_device_type])
                            servbuf += "{0}\n".format(vm_pt)
                    av_pt = host.helpers.node_controller.show_availability_for_node(
                        print_table=False)
                    servbuf += av_pt.get_string()
            ps_sum_pt = host.show_euca_process_summary(print_table=False)
            servbuf += "\n" + ps_sum_pt.get_string(border=1, vrules=2, hrules=0)
            host_info = markup('Euca Versions:').ljust(machine_hdr[1])
            host_info += "Cloud: {0}".format(host.get_eucalyptus_version()).ljust(machine_hdr[1])
            host_info += "2ools: {0}".format(host.get_euca2ools_version()).ljust(machine_hdr[1])
            host_info += markup("Hostname:").ljust(machine_hdr[1])
            host_info += str(host.hostname).ljust(machine_hdr[1])
            sys_pt = host.show_sys_info(print_table=False)
            host_info += "{0}".format(sys_pt)
            with hostlock:
                pt.add_row([markup("HOST:") + markup(hostip, [1, 94]),
                            markup('EUCALYPTUS SERVICES:') +
                            markup('[ {0} ]'
                                   .format(" ".join(str(x) for x in host.euca_service_codes)),
                                   [1, 34])])
                pt.add_row([host_info, servbuf])

        for hostip, host in eucahosts.iteritems():
            t = threading.Thread(target=add_host, args=(hostip, host))
            t.start()
            threads.append(t)
        for t in threads:
            t.join()
        if save_file:
            with open(save_file, 'w') as sf:
                sf.write("\n{0}\n".format(pt.get_string()))
        if print_table:
            # print_method("\n{0}\n".format(pt.get_string(sortby=pt.field_names[1])))
            print_method("\n{0}\n".format(pt.get_string()))
        else:
            return pt

    def upgrade_cloud(self, network_mode=None, ccs=None, ncs=None, clcs=None, scs=None, ufs=None,
                      ws=None, gpgcheck=False,  yum_arg_list=None, dry_run=False, rerun=False):
        if rerun:
            if not hasattr(self, '_upgrade_dict'):
                raise ValueError('self._upgrade_dict not found, can not use "rerun"')
            return self.upgrade_cloud(**self._upgrade_dict)
        if yum_arg_list is None:
            yum_arg_list = []
        if not isinstance(yum_arg_list, list):
            yum_arg_list = [yum_arg_list]
        if not gpgcheck:
            yum_arg_list.append("--nogpg")
        yum_args = " -y {0}".format(" ".join(yum_arg_list))
        # Sort out the host machines by services...
        known_net_modes = ['EDGE', 'VPCMIDO', 'MANAGED']
        if network_mode is None:
            try:
                cluster_name = self.get_all_cluster_names()[0]
                prop = self.get_property("{0}.cluster.networkmode".format(cluster_name))
                network_mode = prop.value
            except:
                self.log.error('Could not retrieve network mode for cloud')
                raise
        if re.search('MANAGED', network_mode):
                    network_mode = 'MANAGED'
        if network_mode not in known_net_modes:
            raise ValueError('Unknown network mode:{0}, known types {1}'
                             .format(network_mode, ", ".join(known_net_modes)))
        # service arrays
        eucalyptus_cloud_hosts = []
        eucanetd_hosts = []

        ccs = ccs or self.get_hosts_for_cluster_controllers()
        ncs = ncs or self.get_hosts_for_node_controllers()
        clcs = clcs or self.get_hosts_for_cloud_controllers()
        scs = scs or self.get_hosts_for_storage_controllers()
        ufs = ufs or self.get_hosts_for_ufs()
        ws = ws or self.get_hosts_for_walrus()

        upgrade_dict = {'network_mode': network_mode, 'ccs': ccs, 'ncs': ncs,
                        'clcs': clcs, 'scs': scs, 'ufs': ufs, 'ws': ws, 'gpgcheck': gpgcheck,
                        'yum_arg_list': yum_arg_list}
        if dry_run:
            return upgrade_dict
        for host in clcs + ufs + scs + ws:
            if host not in eucalyptus_cloud_hosts:
                eucalyptus_cloud_hosts.append(host)
        if network_mode == "MANAGED":
            eucanetd_hosts = ccs
        elif network_mode == 'EDGE':
            eucanetd_hosts = ncs
        elif network_mode == 'VPCMIDO':
            eucanetd_hosts = clcs
        else:
            raise ValueError('Unsupported network mode: "{0}"'.format(network_mode) )

        def stop_service(host, service, timeout=300):
            try:
                host.sys('service {0} stop'.format(service), code=0, timeout=timeout)
            except CommandExitCodeException as CE:
                if CE.status == 2:
                    # service is already stopped
                    pass
                else:
                    raise
        try:
            # Shutdown all the Eucalyptus cloud services...
            self.log.info('Beginning upgrade. Shutting down all cloud services now...')
            for host in clcs:
                stop_service(host, 'eucalyptus-cloud')
            for host in eucalyptus_cloud_hosts:
                # Skip the CLCs which have already been stopped
                if host not in clcs:
                    stop_service(host, 'eucalyptus-cloud')
            for host in ccs:
                stop_service(host, 'eucalyptus-cc')
            for host in ncs:
                stop_service(host, 'eucalyptus-nc')
            for host in eucanetd_hosts:
                stop_service(host, 'eucanetd')

            # Upgrade packages...
            self.log.info('Upgrading Eucalyptus packages on all hosts')
            for host in self.eucahosts.itervalues():
                host.sys('yum upgrade eucalyptus {0}'.format(yum_args), code=0, timeout=400)
            self.log.info('Package upgrade complete, restarting cloud services now...')
            # Start all the Eucalyptus cloud services...
            # Do the CLCs first than the other Java/Cloud services
            self.log.info('Starting CLCs...')
            for host in clcs:
                host.sys('service eucalyptus-cloud start', code=0, timeout=300)
            self.log.info('Starting remaining Java Components...')
            for host in eucalyptus_cloud_hosts:
                # Skip the CLCs which have already been started
                if host not in clcs:
                    host.sys('service eucalyptus-cloud start', code=0, timeout=300)
            self.log.info('Starting Cluster Controllers...')
            for host in ccs:
                host.sys('service eucalyptus-cc start', code=0, timeout=300)
            self.log.info('Starting Node Controllers...')
            for host in ncs:
                host.sys('service eucalyptus-nc start', code=0, timeout=300)
            self.log.info('Starting Eucanetd...')
            for host in eucanetd_hosts:
                host.sys('service eucanetd start', code=0, timeout=300)
            self.log.info('Upgrade Done')
        except:
            self.log.error('Upgrade failed. The upgrade params are found in self._upgrade_dict.'
                           'These can be used via the "rerun" argument to rerun this upgrade'
                           'using the same environment/machines')
            raise
        finally:
            # write to this dict for before/after comparison of the cloud after upgrade
            self._upgrade_dict = upgrade_dict





    def build_machine_dict_from_config(cls):
        raise NotImplementedError()

    def build_machine_dict_from_cloud_services(self):
        raise NotImplementedError('not yet implemented')
class Euca2oolsImageUtils(object):
    #Define the bytes per gig
    gig = 1073741824
    mb = 1048576
    kb = 1024
    def __init__(self, access_key=None, secret_key=None, account_id=None, region_domain=None,
                 s3_url=None, ec2_url=None, bootstrap_url=None, ec2_cert_path=None,
                 worker_hostname=None, worker_keypath=None, worker_username='******',
                 worker_password=None, worker_machine=None, user_context=None, log_level='debug',
                 destpath=None, time_per_gig=300, eof=True):
        
        self.access_key = access_key
        self.secret_key = secret_key
        self.account_id = account_id
        self.region_domain = region_domain
        self.bootstrap_url = bootstrap_url
        self.s3_url = s3_url
        self.ec2_url = ec2_url
        self.ec2_cert_path = ec2_cert_path

        self.log = Eulogger('Euca2oolsImageUtils', stdout_level=log_level)
        # Setup the work machine, this is the machine which will be used for
        # performing the 'work' (download, bundle, etc)
        self.worker_hostname = worker_hostname
        self.worker_keypath = worker_keypath
        self.worker_username = worker_username
        self.worker_password = worker_password
        self._worker_machine = None
        self._user_context = user_context
        if worker_machine:
            self._worker_machine = worker_machine
        
        self.time_per_gig = time_per_gig
        self.eof = eof
        
        if destpath is not None:
            self.destpath = str(destpath)
        else:
            self.destpath = "/disk1/storage"

        self.time_per_gig = time_per_gig
        
    def status_log(self, msg):
        return self.log.info(markup(msg, 
                                    markups=[ForegroundColor.WHITE, 
                                             BackGroundColor.BG_GREEN, 
                                             TextStyle.BOLD]))
        
        
    @property
    def worker_machine(self):
        '''
        Attempts to verify the worker passed is a Machine() class else assume
        it's a host name of the machine work should be performed on and
        attempt to return a Machine() created from the hostname

        param: worker Machine() or 'hostname' to be used to perform image utils
        work on.
        returns Machine obj
        '''
        if not self._worker_machine:     
            if self.worker_hostname:
                self.log.debug('Attempting to connect to machine: "{0}" for image utility work...'
                               .format(self.worker_hostname))
                self._worker_machine = Machine(hostname=self.worker_hostname,
                                               username=self.worker_username,
                                               password=self.worker_password,
                                               keypath=self.worker_keypath)
        return self._worker_machine
    
    @worker_machine.setter
    def worker_machine(self, machine):
        if isinstance(machine, Machine):
                self._worker_machine = machine
        else:
            raise ValueError('worker_machine must be of type Machine, got:"{0}/{1}"'
                             .format(machine, type(machine)))

    def create_user_context(self, access_key, secret_key, account_id=None,
                            region_domain=None, ec2_url=None, s3_url=None, bootstrap_url=None):
        if not (region_domain or s3_url or ec2_url):
            raise ValueError('Can not derive service endpoints for user. '
                             'Must supply either region_domain:"{0}", or ec2_url:"{1}" '
                             's3_url:"{2}"'.format(region_domain, ec2_url, s3_url))
        access_key = access_key or self.access_key
        secret_key = secret_key or self.secret_key
        region_domain = region_domain or self.region_domain
        if (not access_key and secret_key and region_domain):
            raise ValueError('Must supply access_key, secret_key and region domain to '
                             'create user context')
        user = UserContext(aws_access_key=access_key, aws_secret_key=secret_key,
                           region=region_domain)
        if ec2_url:
            user.ec2_url = ec2_url
        if s3_url:
            user.s3_url = s3_url
        if bootstrap_url:
            user.bootstrap_url = bootstrap_url
        if account_id:
            user.account_id = account_id
        return user

    @property
    def user_context(self):
        if not self._user_context:
            try:
                self._user_context = self.create_user_context(access_key=self.access_key,
                                                             secret_key=self.secret_key,
                                                             region_domain=self.region_domain,
                                                             ec2_url=self.ec2_url,
                                                             s3_url=self.s3_url,
                                                             bootstrap_url=self.bootstrap_url,
                                                             account_id=self.account_id)
            except ValueError as VE:
                self.log.warning('Could not create user context, err:"{0}"'.format(VE))
        return self._user_context

    @user_context.setter
    def user_context(self, user_context):
        if user_context is None or isinstance(user_context, UserContext):
            if user_context:
                self._user_context = user_context
                self.access_key = user_context.access_key
                self.secret_key = user_context.secret_key
                self.ec2_url = user_context.ec2_url
                self.s3_url = user_context.s3_url
                self.bootstrap_url = user_context.bootstrap_url
                self.account_id = user_context.account_id
        else:
            raise ValueError('Usercontext must be of type UserContext. Got:"{0}/{1}"'
                             .format(user_context, type(user_context)))



    def getHttpRemoteImageSize(self, url, unit=None, maxredirect=5):
        return Euca2oolsImageUtils._getHttpRemoteImageSize(url, unit=unit, maxredirect=maxredirect)

    @staticmethod
    def _getHttpRemoteImageSize(url, unit=None, maxredirect=5, debug=None):
        '''
        Get the remote file size from the http header of the url given
        Returns size in GB unless unit is given.
        '''
        unit = unit or 1073741824
        if debug is None:
            def printdebug(msg):
                print msg
            debug = printdebug

        def get_location(url, depth, maxdepth):
            if depth > maxdepth:
                raise ValueError('Max redirects limit has been reached:{0}/{1}'
                                 .format(depth, maxdepth))
            conn = None
            try:
                url = url.replace('http://', '')
                host = url.split('/')[0]
                path = url.replace(host, '')
                res = None
                err = None
                retries = 5
                for retry in xrange(0, retries):
                    try:
                        debug('HTTP HEAD request for: {0}, attempt:{1}/{2}'
                              .format(url, retry, retries))
                        conn = httplib.HTTPConnection(host)
                        conn.request("HEAD", path)
                        res = conn.getresponse()
                        break
                    except Exception as HE:
                        err = '{0}\nError attempting to fetch url:{1}, attempt:{2}/{3}, ' \
                              'error:{4}'.format(get_traceback(), url, retry, retries, HE)
                        debug(err)
                        time.sleep(retry)
                if not res:
                    err = err or "Error retrieving url:{0}".format(url)
                    raise RuntimeError(err)
                location = res.getheader('location')
                if location and location != url:
                    depth += 1
                    debug('Redirecting: depth:{0}, url:{1}'.format(depth, location))
                    return get_location(location, depth=depth,maxdepth=maxdepth)
                else:
                    content_length = res.getheader('content-length')
                    if content_length is None:
                        raise ValueError('No content-length header found for url:{0}'
                                         .format(url))
                    fbytes = int(content_length)
                    return fbytes
            except Exception as HE:
                debug('Failed to fetch content-length header from url:{0}'.format(url))
                raise HE
            finally:
                if conn:
                    conn.close()
        try:
            fbytes = get_location(url, depth=0, maxdepth=maxredirect)
            debug("content-length:" + str(fbytes))
            if fbytes == 0:
                rfsize = 0
            else:
                rfsize = (((fbytes/unit) + 1) or 1)
            debug("Remote file size: " + str(rfsize) + "g")
        except Exception, e:
            debug("Failed to get remote file size...")
            raise e
        return rfsize
Exemple #40
0
class ConversionTask(TaggedEC2Object):
    _IMPORTINSTANCE = 'importinstance'
    _IMPORTVOLUME  = 'importvolume'

    def __init__(self, connection=None):
        super(ConversionTask, self).__init__(connection)
        self.connection = connection
        self.conversiontaskid = None
        self.expirationtime = None
        self.state = None
        self.statusmessage = None
        self._importinstancetask = None
        self._importvolumetask = None
        self._instance = None
        self._snapshots = None
        self.tags = None
        self.notfound = False
        self.log = Eulogger('ConversionTask:{0}'.format(self.id))

    def __repr__(self):
        volumes = ",".join([vol.id for vol in self.volumes])
        return ('ConversionTask:"{0}", state:"{1}", instance:"{2}", '
                'volumes:"{3}", status:"{4}"'
                .format(str(self.conversiontaskid),
                        self.state,
                        self.instanceid,
                           volumes,
                        self.statusmessage))

    @property
    def availabilityzone(self):
        if self.importvolumes:
            return self.importvolumes[0].availabilityzone
        return None

    @property
    def importvolumes(self):
        if self._importinstancetask:
            return self._importinstancetask.importvolumes
        if self._importvolumetask:
            return [self._importvolumetask]
        return []

    @property
    def platform(self):
        if self._importinstancetask:
            return self._importinstancetask.platform
        return None

    @property
    def instanceid(self):
        if self._importinstancetask:
            return self._importinstancetask.instanceid
        return None

    @property
    def instance(self):
        if not self._instance and self.instanceid:
            try:
                ins = self._instance = self.connection.get_only_instances(
                    instance_ids=[self.instanceid])
                if ins:
                    self._instance = ins[0]
            except Exception as E:
                self.log.warning('Failed to fetch instance:{0} for conversiontask:{1} err:'
                                 .format(self.instanceid, self.id, E))
        return self._instance

    @property
    def volumes(self):
        '''
        Volumes are updated during the task and there may not be a volume(s)
        associated with a task response right away, EUCA-9337
        '''
        ret = []
        for im in self.importvolumes:
            if im and im.volume:
                ret.append(im.volume)
        return ret

    @property
    def snapshots(self):
        if not self._snapshots:
            self._snapshots = []
            for volume in self.volumes:
                self._snapshots.extend(self.connection.get_all_snapshots(
                    filters={'volume-id':volume.id}))
        return self._snapshots

    @property
    def image_id(self):
        if self.instance:
            return self.instance.image_id

    @property
    def tasktype(self):
        if self._importinstancetask:
            return self._IMPORTINSTANCE
        elif self._importvolumetask:
            return self._IMPORTVOLUME
        else:
            return None

    @property
    def id(self):
        return self.conversiontaskid

    @id.setter
    def id(self, taskid):
        self.conversiontaskid = taskid

    def cancel(self):
        params = {'ConversionTaskId':str(self.conversiontaskid)}
        task = self.connection.get_object('CancelConversionTask',
                                          params,
                                          ConversionTask,
                                          verb='POST')
        if task:
            self.update(updatedtask=task)
        return task

    def update(self, updatedtask=None):
        params = {}
        params['ConversionTaskId'] = str(self.conversiontaskid)
        if not updatedtask:
            updatedtask = self.connection.get_object('DescribeConversionTasks',
                                                     params,
                                                     ConversionTask,
                                                     verb='POST')
        if updatedtask:
            self.__dict__.update(updatedtask.__dict__)
        else:
            print sys.stderr, 'Update. Failed to find task:"{0}"'\
                .format(str(self.conversiontaskid))
            self.notfound = True

    def startElement(self, name, attrs, connection):
        ename = name.replace('euca:','')
        elem = super(ConversionTask, self).startElement(name,
                                                        attrs,
                                                        connection)
        if elem is not None:
            return elem
        if ename == 'importVolume':
            self._importvolumetask = ImportVolume(connection=connection)
            self.importvolumes.append(self._importvolumetask)
            return self._importvolumetask
        elif ename == 'importInstance':
            self._importinstancetask = ImportInstance(connection=connection)
            return self._importinstancetask
        elif ename == 'tagSet' or ename == 'resourceTagSet':
            self.tags = ResultSet([('item', Tag)])
            return self.tags
        else:
            return None

    def endElement(self, name, value, connection):
        ename = name.lower().replace('euca:','')
        if ename == 'conversiontaskid':
            self.conversiontaskid = value
        elif ename == 'expirationtime':
            self.expirationtime = value
        elif ename == 'state':
            self.state = value
        elif ename == 'statusmessage':
            self.statusmessage = value
        else:
            setattr(self, ename, value)
Exemple #41
0
class TestController(object):
    def __init__(self,
                 hostname=None,
                 username='******',
                 password=None,
                 keypath=None,
                 region=None,
                 domain=None,
                 proxy_hostname=None,
                 proxy_password=None,
                 clouduser_account='nephotest',
                 clouduser_name='sys_admin',
                 clouduser_credpath=None,
                 clouduser_accesskey=None,
                 clouduser_secretkey=None,
                 cloudadmin_credpath=None,
                 cloudadmin_accesskey=None,
                 cloudadmin_secretkey=None,
                 timeout=10,
                 log_level='DEBUG',
                 log_file=None,
                 log_file_level='DEBUG',
                 environment_file=None,
                 https=False,
                 validate_certs=False,
                 cred_depot_hostname=None,
                 cred_depot_username='******',
                 cred_depot_password=None,
                 boto2_api_version=None):
        """

        :param hostname: CLC ssh hostname
        :param username: CLC ssh username
        :param password: CLC ssh password
        :param proxy_hostname: CLC ssh proxy hostname
        :param proxy_password: CLC ssh proxy password
        :param clouduser_account:
        :param clouduser_name:
        :param clouduser_credpath:
        :param clouduser_accesskey:
        :param clouduser_secretkey:
        :param cloudadmin_credpath:
        :param cloudadmin_accesskey:
        :param cloudadmin_secretkey:
        :param timeout:
        """
        if isinstance(log_level, basestring):
            log_level = getattr(logging, log_level.upper(), logging.DEBUG)
        self.log = Eulogger("TESTER:{0}".format(hostname),
                            stdout_level=log_level,
                            logfile=log_file,
                            logfile_level=log_file_level)
        if not hostname and environment_file:
            try:
                component = self.get_component_from_topology(
                    environment_file, 'clc-1')
                hostname = component['clc-1']
            except KeyError:
                component = self.get_component_from_topology(
                    environment_file, 'clc')
                hostname = component['clc'][0]
        self.log.identifier = "TESTER:{0}".format(hostname)
        self.log = Eulogger("TESTER:{0}".format(hostname),
                            stdout_level=log_level)
        self._region = region
        self._sysadmin = None
        self._cloudadmin = None
        self._test_user = None
        self._cred_depot = None
        self._default_timeout = timeout
        self._domain = domain
        self._https = https
        self._validate_certs = validate_certs
        self._cloud_admin_connection_info = {}
        self._test_user_connection_info = {}
        boto2_api_version = boto2_api_version or __DEFAULT_API_VERSION__
        self._system_connection_info = {
            'hostname': hostname,
            'username': username,
            'password': password,
            'keypath': keypath,
            'proxy_hostname': proxy_hostname,
            'proxy_password': proxy_password,
            'proxy_username': None,
            'config_qa': None,
            'credpath': cloudadmin_credpath,
            'aws_access_key': cloudadmin_accesskey,
            'aws_secret_key': cloudadmin_secretkey,
            'log_level': log_level,
            'boto_debug_level': 0,
            'euca_user': '******',
            'euca_account': 'eucalyptus',
            'https': https,
            'domain': domain
        }

        self._cloud_admin_connection_info = {
            'aws_account_name': 'eucalyptus',
            'aws_user_name': 'admin',
            'credpath': cloudadmin_credpath,
            'region': self.region,
            'domain': self.domain,
            'aws_access_key': cloudadmin_accesskey,
            'aws_secret_key': cloudadmin_secretkey,
            'service_connection': self.sysadmin,
            'log_level': log_level,
            'validate_certs': validate_certs,
            'boto2_api_version': boto2_api_version,
            'https': https
        }

        self._test_user_connection_info = {
            'aws_account_name': clouduser_account,
            'aws_user_name': clouduser_name,
            'credpath': clouduser_credpath,
            'aws_access_key': clouduser_accesskey,
            'aws_secret_key': clouduser_secretkey,
            'region': self.region,
            'domain': self.domain,
            'log_level': log_level,
            'validate_certs': validate_certs,
            'boto2_api_version': boto2_api_version,
            'https': https
        }

        self._cred_depot_connection_info = {
            'hostname': cred_depot_hostname,
            'username': cred_depot_username,
            'password': cred_depot_password or password,
            'log_level': log_level
        }

        # TODO ??
        self.test_resources = \
            {
                '_instances': [],
                '_volumes': []
            }

    def __repr__(self):
        try:
            myrepr = "{0}:{1}(sysadmin+eucalyptus/admin)".format(
                self.__class__.__name__,
                self._system_connection_info.get('hostname', ""))
            return myrepr
        except Exception as E:
            self.log.debug(E)
            return str(self.__class__.__name__)

    @property
    def domain(self):
        if self._domain is None:
            prop_name = 'system.dns.dnsdomain'
            try:
                # First try from the cloud property...
                region_prop = self.sysadmin.get_property(prop_name)
                if region_prop.value:
                    self._domain = region_prop.value
            except Exception as E:
                self.log.error(
                    '{0}\nError fetching cloud property:"{1}". Error:"{2}"'.
                    format(get_traceback(), prop_name, E))
        return self._domain or self.region

    @property
    def region(self):
        return self._region

    @region.setter
    def region(self, value):
        if self._region is not None and self._region != value:
            self.log.error('Can not change region once it has been set')
            raise ValueError('Can not change region once it has been set')
        self._cloud_admin_connection_info['region'] = value
        self._test_user_connection_info['region'] = value
        self._region = value

    @property
    def cred_depot(self):
        if not self._cred_depot and self._cred_depot_connection_info.get(
                'hostname'):
            try:
                self._cred_depot = Machine(**self._cred_depot_connection_info)
            except Exception as E:
                self.log.error(
                    '{0}\nError connecting to cred depot machine:"{1}"'.format(
                        get_traceback(), E))
                raise E
        return self._cred_depot

    @property
    def sysadmin(self):
        if not self._sysadmin:
            if not self._system_connection_info.get('hostname', None):
                return None
            try:
                self._sysadmin = SystemConnection(
                    **self._system_connection_info)
            except Exception as TE:
                self.log.error(
                    '{0}\nCould not create sysadmin interface, timed out: "{1}"'
                    .format(get_traceback(), TE))
                raise TE
        return self._sysadmin

    @property
    def admin(self):
        if not self._cloudadmin:
            try:
                conn_info = self._cloud_admin_connection_info
                if (conn_info.get('credpath')
                        or (conn_info.get('aws_access_key')
                            and conn_info.get('aws_secret_key'))):
                    if conn_info.get('credpath'):
                        conn_info['machine'] = self.cred_depot
                else:
                    rc_config = self.sysadmin.creds or {}
                    rc_config.domain = self.domain
                    rc_config.region = self.region
                    conn_info['eucarc'] = rc_config
                self._cloudadmin = UserContext(**conn_info)
            except Exception as E:
                self.log.error(
                    '{0}\nError creating admin user, err:"{1}"'.format(
                        get_traceback(), E))
                raise E
        return self._cloudadmin

    @property
    def user(self):
        if not self._test_user:
            try:
                self._test_user = self.create_user_using_cloudadmin(
                    **self._test_user_connection_info)
            except Exception as E:
                self.log.error(
                    '{0}\nError Creating test user, error:"{1}"'.format(
                        get_traceback(), E))
                raise E
        return self._test_user

    @user.setter
    def user(self, user):
        if user is None:
            self._test_user = None
        if isinstance(user, UserContext):
            self._test_user = user
            return
        raise ValueError('Unsupported type for test_user:"******", "{1}"'.format(
            user, type(user)))

    def reset_connections(self):
        self._sysadmin = None
        self._cloudadmin = None
        self._test_user = None

    def get_user_by_name(self,
                         aws_account_name,
                         aws_user_name,
                         aws_account_id=None,
                         machine=None,
                         service_connection=None,
                         region=None,
                         domain=None,
                         validate_certs=False,
                         path='/',
                         https=None,
                         log_level=None,
                         boto2_api_version=None):
        """
        Fetch an existing cloud user and convert into a usercontext object.
        For checking basic existence of a cloud user, use the iam interface instead.
        """
        boto2_api_version = boto2_api_version or \
                            self._test_user_connection_info.get('boto2_api_version', None)
        try:
            account_info = self.admin.iam.get_account(
                account_name=aws_account_name, account_id=aws_account_id)

            if account_info:
                aws_account_id = account_info.get('account_id')
                if aws_account_name and aws_account_name != account_info.get(
                        'account_name'):
                    raise ValueError(
                        'Account id incorrect:{0} for provided account name:{1}'
                        .format(aws_account_id, aws_account_name))
                user = self.admin.iam.get_user_info(
                    user_name=aws_user_name, delegate_account=aws_account_id)
            else:
                raise ValueError(
                    'Account not found using id:"{0}", name:"{1}"'.format(
                        aws_account_id, aws_account_name))
        except Exception:
            self.log.error(
                'Error fetching "account:{0}, user:{1}" has this user been created '
                'already?'.format(aws_account_name, aws_user_name))
            raise
        if user:
            return self.create_user_using_cloudadmin(
                aws_account_name=aws_account_name,
                aws_user_name=aws_user_name,
                aws_account_id=aws_account_id,
                region=region,
                domain=domain,
                validate_certs=validate_certs,
                machine=machine,
                service_connection=service_connection,
                path=path,
                https=https,
                log_level=log_level,
                boto2_api_version=boto2_api_version)
        else:
            raise ValueError(
                'User info not returned for "account:{0}, user:{1}"'.format(
                    aws_account_name, aws_user_name))

    def create_user_using_cloudadmin(self,
                                     aws_account_name=None,
                                     aws_user_name='admin',
                                     aws_account_id=None,
                                     aws_access_key=None,
                                     aws_secret_key=None,
                                     credpath=None,
                                     eucarc=None,
                                     machine=None,
                                     service_connection=None,
                                     path='/',
                                     region=None,
                                     domain=None,
                                     https=None,
                                     validate_certs=False,
                                     boto2_api_version=None,
                                     log_level=None):
        if log_level is None:
            log_level = self.log.stdout_level or 'DEBUG'
        if region is None:
            region = self.region
        if domain is None:
            domain = self.domain
        if https is None:
            https = self._https
        boto2_api_version = boto2_api_version or \
                            self._test_user_connection_info.get('boto2_api_version', None)
        self.log.debug(
            'Attempting to create user with params: account:{0}, name:{1}'
            'access_key:{2}, secret_key:{3}, credpath:{4}, eucarc:{5}'
            ', machine:{6}, service_connection:{7}, path:{8}, region:{9},'
            'loglevel:{10}, https:{11}, boto2_api_version:{12}'.format(
                aws_account_name, aws_user_name, aws_access_key,
                aws_secret_key, credpath, eucarc, machine, service_connection,
                path, region, log_level, https, boto2_api_version))
        service_connection = service_connection or self.sysadmin
        if eucarc:
            if aws_access_key:
                eucarc.access_key = aws_access_key
            if aws_secret_key:
                eucarc.secret_key = aws_secret_key
            if aws_user_name:
                eucarc.user_name = aws_user_name
            if aws_account_name:
                eucarc.account_name = aws_account_name
            if aws_account_id:
                eucarc.account_id = aws_account_id

            return UserContext(eucarc=eucarc,
                               region=region,
                               domain=domain,
                               service_connection=service_connection,
                               log_level=log_level,
                               https=https,
                               boto2_api_version=boto2_api_version)
        if aws_access_key and aws_secret_key:
            return UserContext(aws_access_key=aws_access_key,
                               aws_secret_key=aws_secret_key,
                               aws_account_name=aws_account_name,
                               aws_user_name=aws_user_name,
                               region=region,
                               domain=domain,
                               service_connection=service_connection,
                               log_level=log_level,
                               boto2_api_version=boto2_api_version,
                               https=https)
        if credpath:
            return UserContext(credpath=credpath,
                               region=region,
                               domain=domain,
                               machine=machine,
                               log_level=log_level,
                               boto2_api_version=boto2_api_version)

        user = {}
        info = self.admin.iam.get_account(account_name=aws_account_name,
                                          account_id=aws_account_id) or {}
        if not info:
            info = self.admin.iam.create_account(account_name=aws_account_name,
                                                 ignore_existing=True)
        aws_account_id = aws_account_id or info.get('account_id', None)
        try:
            user = self.admin.iam.get_user(user_name=aws_user_name,
                                           delegate_account=aws_account_id)
        except BotoServerError as BE:
            if int(E.status) == 404:
                self.log.debug('User not found, attempting to create...')
        if not user:
            user = self.admin.iam.create_user(
                user_name=aws_user_name,
                delegate_account=info.get('account_name'),
                path=path)
        if not user:
            raise RuntimeError(
                'Failed to create and/or fetch Account:"{0}", for User:"******"'.
                format(aws_account_name, aws_user_name))
        else:
            info.update(user)

        ak = self.admin.iam.get_aws_access_key(
            user_name=info.get('user_name'),
            delegate_account=info.get('account_name'))
        if not ak:
            ak = self.admin.iam.create_access_key(
                user_name=info.get('user_name'),
                delegate_account=info.get('account_name'))
        try:
            info['access_key_id'] = ak['access_key_id']
        except KeyError:
            err_msg = (
                'Failed to fetch access key for USER:"******", ACCOUNT:"{1}"'.
                format(aws_user_name, aws_account_name))
            self.log.error('{0}\n{1}'.format(get_traceback(), err_msg))
            raise RuntimeError(err_msg)
        if self.admin.iam.get_all_signing_certs(
                user_name=info.get('user_name'),
                delegate_account=info.get('account_name')):
            certs = True
        else:
            certs = False
        user = UserContext(aws_access_key=info.get('access_key_id'),
                           aws_secret_key=info.get('secret_access_key'),
                           aws_account_name=info.get('account_name'),
                           aws_user_name=info.get('user_name'),
                           region=region,
                           domain=domain,
                           existing_certs=certs,
                           machine=self.sysadmin.clc_machine,
                           service_connection=self.sysadmin,
                           log_level=log_level,
                           boto2_api_version=boto2_api_version,
                           https=https)
        user._user_info = self.admin.iam.get_user_info(
            user_name=user.user_name, delegate_account=user.account_id)
        return user

    def dump_conn_debug(self, info):
        """
        Helper method to format and display the connection info contained in a specific dict.
        Example: self.dump_conn_debug(self._system_connection_info)
        :param info:  connection dict.
        """
        try:
            self.log.debug('Connection info:\n{0}'.format("\n".join(
                "{0}:{1}".format(x, y) for x, y in info.iteritems())))
        except Exception as doh:
            self.log.error(
                '{0}\nError attempting to dump connection info:{1}'.format(
                    get_traceback(), doh))

    def set_boto_logger_level(self, level='NOTSET', format_string=None):
        """
        Set the global boto loggers levels to 'level'. ie "DEBUG", "INFO", "CRITICAL"
        default is "NOTSET"
        :param level: string matching logging class levels, or integer representing the equiv value
        :param format_string: logging class formatter string
        """
        return set_boto_logger_level(level=level, format_string=format_string)

    def get_component_from_topology(self,
                                    environment_file,
                                    component_type=None):
        """
        Reads eucalyptus topology from environment file and returns value of expected component.

        Args:
            environment_file - environment file to extract Eucalyptus topology
            component_type - type of the component that needs to be extracted
        Returns:
            a dict with component_type as key and value from the environment file
        """
        try:
            with open(environment_file) as myenv:
                env_dict = yaml.load(myenv)
        except Exception as EE:
            self.log.error('Failed to read env file:"{0}", err:{1}'.format(
                environment_file, EE))
            raise EE

        result = env_dict['default_attributes']['eucalyptus']['topology'][
            component_type]

        return {component_type: result}
Exemple #42
0
class TestController(object):
    def __init__(self,
                 hostname=None, username='******', password=None, keypath=None, region=None,
                 domain=None,
                 proxy_hostname=None, proxy_password=None,
                 clouduser_account='nephotest', clouduser_name='sys_admin', clouduser_credpath=None,
                 clouduser_accesskey=None, clouduser_secretkey=None,
                 cloudadmin_credpath=None, cloudadmin_accesskey=None, cloudadmin_secretkey=None,
                 timeout=10, log_level='DEBUG', log_file=None, log_file_level='DEBUG',
                 environment_file=None, https=False, validate_certs=False,
                 cred_depot_hostname=None, cred_depot_username='******', cred_depot_password=None,
                 boto2_api_version=None):

        """

        :param hostname: CLC ssh hostname
        :param username: CLC ssh username
        :param password: CLC ssh password
        :param proxy_hostname: CLC ssh proxy hostname
        :param proxy_password: CLC ssh proxy password
        :param clouduser_account:
        :param clouduser_name:
        :param clouduser_credpath:
        :param clouduser_accesskey:
        :param clouduser_secretkey:
        :param cloudadmin_credpath:
        :param cloudadmin_accesskey:
        :param cloudadmin_secretkey:
        :param timeout:
        """
        if isinstance(log_level, basestring):
            log_level = getattr(logging, log_level.upper(), logging.DEBUG)
        self.log = Eulogger("TESTER:{0}".format(hostname), stdout_level=log_level,
                            logfile=log_file, logfile_level=log_file_level)
        if not hostname and environment_file:
            try:
                component = self.get_component_from_topology(environment_file, 'clc-1')
                hostname = component['clc-1']
            except KeyError:
                component = self.get_component_from_topology(environment_file,
                                                             'clc')
                hostname = component['clc'][0]
        self.log.identifier = "TESTER:{0}".format(hostname)
        self.log = Eulogger("TESTER:{0}".format(hostname), stdout_level=log_level)
        self._region = region
        self._sysadmin = None
        self._cloudadmin = None
        self._test_user = None
        self._cred_depot = None
        self._default_timeout = timeout
        self._domain = domain
        self._https = https
        self._validate_certs = validate_certs
        self._cloud_admin_connection_info = {}
        self._test_user_connection_info = {}
        boto2_api_version = boto2_api_version or __DEFAULT_API_VERSION__
        self._system_connection_info = {'hostname': hostname,
                                        'username': username,
                                        'password': password,
                                        'keypath': keypath,
                                        'proxy_hostname': proxy_hostname,
                                        'proxy_password': proxy_password,
                                        'proxy_username': None,
                                        'config_qa': None,
                                        'credpath': cloudadmin_credpath,
                                        'aws_access_key': cloudadmin_accesskey,
                                        'aws_secret_key': cloudadmin_secretkey,
                                        'log_level': log_level,
                                        'boto_debug_level': 0,
                                        'euca_user': '******',
                                        'euca_account': 'eucalyptus',
                                        'https': https,
                                        'domain': domain}

        self._cloud_admin_connection_info = {'aws_account_name': 'eucalyptus',
                                             'aws_user_name': 'admin',
                                             'credpath': cloudadmin_credpath,
                                             'region': self.region,
                                             'domain': self.domain,
                                             'aws_access_key': cloudadmin_accesskey,
                                             'aws_secret_key': cloudadmin_secretkey,
                                             'service_connection': self.sysadmin,
                                             'log_level': log_level,
                                             'validate_certs': validate_certs,
                                             'boto2_api_version': boto2_api_version,
                                             'https': https}

        self._test_user_connection_info = {'aws_account_name': clouduser_account,
                                           'aws_user_name': clouduser_name,
                                           'credpath': clouduser_credpath,
                                           'aws_access_key': clouduser_accesskey,
                                           'aws_secret_key': clouduser_secretkey,
                                           'region': self.region,
                                           'domain': self.domain,
                                           'log_level': log_level,
                                           'validate_certs': validate_certs,
                                           'boto2_api_version': boto2_api_version,
                                           'https': https}

        self._cred_depot_connection_info = {'hostname': cred_depot_hostname,
                                            'username': cred_depot_username,
                                            'password': cred_depot_password or password,
                                            'log_level': log_level}

        # TODO ??
        self.test_resources = \
            {
                '_instances': [],
                '_volumes': []
            }

    def __repr__(self):
        try:
            myrepr = "{0}:{1}(sysadmin+eucalyptus/admin)".format(
                self.__class__.__name__,
                self._system_connection_info.get('hostname', ""))
            return myrepr
        except Exception as E:
            self.log.debug(E)
            return str(self.__class__.__name__)

    @property
    def domain(self):
        if self._domain is None:
            prop_name = 'system.dns.dnsdomain'
            try:
                # First try from the cloud property...
                region_prop = self.sysadmin.get_property(prop_name)
                if region_prop.value:
                    self._domain = region_prop.value
            except Exception as E:
                self.log.error('{0}\nError fetching cloud property:"{1}". Error:"{2}"'
                               .format(get_traceback(), prop_name, E))
        return self._domain or self.region

    @property
    def region(self):
        return self._region

    @region.setter
    def region(self, value):
        if self._region is not None and self._region != value:
            self.log.error('Can not change region once it has been set')
            raise ValueError('Can not change region once it has been set')
        self._cloud_admin_connection_info['region'] = value
        self._test_user_connection_info['region'] = value
        self._region = value

    @property
    def cred_depot(self):
        if not self._cred_depot and self._cred_depot_connection_info.get('hostname'):
            try:
                self._cred_depot = Machine(**self._cred_depot_connection_info)
            except Exception as E:
                self.log.error('{0}\nError connecting to cred depot machine:"{1}"'
                               .format(get_traceback(), E))
                raise E
        return self._cred_depot

    @property
    def sysadmin(self):
        if not self._sysadmin:
            if not self._system_connection_info.get('hostname', None):
                return None
            try:
                self._sysadmin = SystemConnection(**self._system_connection_info)
            except Exception as TE:
                self.log.error('{0}\nCould not create sysadmin interface, timed out: "{1}"'
                                  .format(get_traceback(), TE))
                raise TE
        return self._sysadmin

    @property
    def admin(self):
        if not self._cloudadmin:
            try:
                conn_info = self._cloud_admin_connection_info
                if (conn_info.get('credpath') or
                    (conn_info.get('aws_access_key') and conn_info.get('aws_secret_key'))):
                    if conn_info.get('credpath'):
                        conn_info['machine'] = self.cred_depot
                else:
                    rc_config = self.sysadmin.creds or {}
                    rc_config.domain = self.domain
                    rc_config.region = self.region
                    conn_info['eucarc'] = rc_config
                self._cloudadmin = UserContext(**conn_info)
            except Exception as E:
                self.log.error('{0}\nError creating admin user, err:"{1}"'
                               .format(get_traceback(), E))
                raise E
        return self._cloudadmin

    @property
    def user(self):
        if not self._test_user:
            try:
                self._test_user = self.create_user_using_cloudadmin(
                    **self._test_user_connection_info)
            except Exception as E:
                self.log.error('{0}\nError Creating test user, error:"{1}"'
                               .format(get_traceback(), E))
                raise E
        return self._test_user

    @user.setter
    def user(self, user):
        if user is None:
            self._test_user = None
        if isinstance(user, UserContext):
            self._test_user = user
            return
        raise ValueError('Unsupported type for test_user:"******", "{1}"'.format(user, type(user)))

    def reset_connections(self):
        self._sysadmin = None
        self._cloudadmin = None
        self._test_user = None

    def get_user_by_name(self, aws_account_name, aws_user_name,
                         machine=None, service_connection=None, region=None, domain=None,
                         validate_certs=False, path='/',
                         https=None, log_level=None, boto2_api_version=None):
        """
        Fetch an existing cloud user and convert into a usercontext object.
        For checking basic existence of a cloud user, use the iam interface instead.
        """
        boto2_api_version = boto2_api_version or \
                            self._test_user_connection_info.get('boto2_api_version', None)
        try:
            user = self.admin.iam.get_user_info(user_name=aws_user_name,
                                                delegate_account=aws_account_name)
        except Exception:
            self.log.error('Error fetching "account:{0}, user:{1}" has this user been created '
                           'already?'.format(aws_account_name, aws_user_name))
            raise
        if user:
            return self.create_user_using_cloudadmin(aws_account_name=aws_account_name,
                                                     aws_user_name=aws_user_name,
                                                     region=region, domain=domain,
                                                     validate_certs=validate_certs,
                                                     machine=machine,
                                                     service_connection=service_connection,
                                                     path=path, https=https, log_level=log_level,
                                                     boto2_api_version=boto2_api_version)
        else:
            raise ValueError('User info not returned for "account:{0}, user:{1}"'
                             .format(aws_account_name, aws_user_name))


    def create_user_using_cloudadmin(self, aws_account_name=None, aws_user_name='admin',
                                     aws_access_key=None, aws_secret_key=None,
                                     credpath=None, eucarc=None,
                                     machine=None, service_connection=None, path='/',
                                     region=None, domain=None, https=None,
                                     validate_certs=False,
                                     boto2_api_version=None, log_level=None):
        if log_level is None:
            log_level = self.log.stdout_level or 'DEBUG'
        if region is None:
            region = self.region
        if domain is None:
            domain = self.domain
        if https is None:
            https = self._https
        boto2_api_version = boto2_api_version or \
                            self._test_user_connection_info.get('boto2_api_version', None)
        self.log.debug('Attempting to create user with params: account:{0}, name:{1}'
                          'access_key:{2}, secret_key:{3}, credpath:{4}, eucarc:{5}'
                          ', machine:{6}, service_connection:{7}, path:{8}, region:{9},'
                          'loglevel:{10}, https:{11}, boto2_api_version:{12}'
                       .format(aws_account_name, aws_user_name, aws_access_key, aws_secret_key,
                               credpath, eucarc, machine, service_connection, path, region,
                               log_level, https, boto2_api_version))
        service_connection = service_connection or self.sysadmin
        if eucarc:
            if aws_access_key:
                eucarc.access_key = aws_access_key
            if aws_secret_key:
                eucarc.secret_key = aws_secret_key
            if aws_user_name:
                eucarc.user_name = aws_user_name
            if aws_account_name:
                eucarc.account_name = aws_account_name

            return UserContext(eucarc=eucarc,
                               region=region,
                               domain=domain,
                               service_connection=service_connection,
                               log_level=log_level,
                               https=https,
                               boto2_api_version=boto2_api_version)
        if aws_access_key and aws_secret_key:
            return UserContext(aws_access_key=aws_access_key,
                               aws_secret_key=aws_secret_key,
                               aws_account_name=aws_account_name,
                               aws_user_name=aws_user_name,
                               region=region,
                               domain=domain,
                               service_connection=service_connection,
                               log_level=log_level,
                               boto2_api_version=boto2_api_version,
                               https=https)
        if credpath:
            return UserContext(credpath=credpath,
                               region=region,
                               domain=domain,
                               machine=machine,
                               log_level=log_level,
                               boto2_api_version=boto2_api_version)

        info = self.admin.iam.create_account(account_name=aws_account_name,
                                                  ignore_existing=True)
        if info:
            user = self.admin.iam.create_user(user_name=aws_user_name,
                                              delegate_account=info.get('account_name'),
                                              path=path)
            info.update(user)
        else:
            raise RuntimeError('Failed to create and/or fetch Account:"{0}", for User:"******"'
                               .format(aws_account_name, aws_user_name))
        ak = self.admin.iam.get_aws_access_key(user_name=info.get('user_name'),
                                               delegate_account=info.get('account_name'))
        if not ak:
            ak = self.admin.iam.create_access_key(user_name=info.get('user_name'),
                                                  delegate_account=info.get('account_name'))
        try:
            info['access_key_id'] = ak['access_key_id']
        except KeyError:
            err_msg = ('Failed to fetch access key for USER:"******", ACCOUNT:"{1}"'
                       .format(aws_user_name, aws_account_name))
            self.log.error('{0}\n{1}'.format(get_traceback(), err_msg))
            raise RuntimeError(err_msg)
        if self.admin.iam.get_all_signing_certs(user_name=info.get('user_name'),
                                                delegate_account=info.get('account_name')):
            certs = True
        else:
            certs = False
        user =  UserContext(aws_access_key=info.get('access_key_id'),
                            aws_secret_key=info.get('secret_access_key'),
                            aws_account_name=info.get('account_name'),
                            aws_user_name=info.get('user_name'),
                            region=region,
                            domain=domain,
                            existing_certs=certs,
                            machine=self.sysadmin.clc_machine,
                            service_connection=self.sysadmin,
                            log_level=log_level,
                            boto2_api_version=boto2_api_version,
                            https=https)
        user._user_info = self.admin.iam.get_user_info(user_name=user.user_name,
                                                       delegate_account=user.account_id)
        return user

    def dump_conn_debug(self, info):
        """
        Helper method to format and display the connection info contained in a specific dict.
        Example: self.dump_conn_debug(self._system_connection_info)
        :param info:  connection dict.
        """
        try:
            self.log.debug(
                    'Connection info:\n{0}'
                    .format("\n".join("{0}:{1}".format(x, y) for x,y in info.iteritems())))
        except Exception as doh:
            self.log.error('{0}\nError attempting to dump connection info:{1}'
                           .format(get_traceback(), doh))


    def set_boto_logger_level(self, level='NOTSET', format_string=None):
        """
        Set the global boto loggers levels to 'level'. ie "DEBUG", "INFO", "CRITICAL"
        default is "NOTSET"
        :param level: string matching logging class levels, or integer representing the equiv value
        :param format_string: logging class formatter string
        """
        return set_boto_logger_level(level=level, format_string=format_string)

    def get_component_from_topology(self, environment_file, component_type=None):
        """
        Reads eucalyptus topology from environment file and returns value of expected component.

        Args:
            environment_file - environment file to extract Eucalyptus topology
            component_type - type of the component that needs to be extracted
        Returns:
            a dict with component_type as key and value from the environment file
        """
        try:
            with open(environment_file) as myenv:
                env_dict = yaml.load(myenv)
        except Exception as EE:
            self.log.error('Failed to read env file:"{0}", err:{1}'.format(environment_file, EE))
            raise EE

        result = env_dict['default_attributes']['eucalyptus']['topology'][component_type]

        return {component_type: result}
Exemple #43
0
    def __init__(self,
                 hostname=None,
                 username='******',
                 password=None,
                 keypath=None,
                 region=None,
                 domain=None,
                 proxy_hostname=None,
                 proxy_password=None,
                 clouduser_account='nephotest',
                 clouduser_name='sys_admin',
                 clouduser_credpath=None,
                 clouduser_accesskey=None,
                 clouduser_secretkey=None,
                 cloudadmin_credpath=None,
                 cloudadmin_accesskey=None,
                 cloudadmin_secretkey=None,
                 timeout=10,
                 log_level='DEBUG',
                 log_file=None,
                 log_file_level='DEBUG',
                 environment_file=None,
                 https=False,
                 validate_certs=False,
                 cred_depot_hostname=None,
                 cred_depot_username='******',
                 cred_depot_password=None,
                 boto2_api_version=None):
        """

        :param hostname: CLC ssh hostname
        :param username: CLC ssh username
        :param password: CLC ssh password
        :param proxy_hostname: CLC ssh proxy hostname
        :param proxy_password: CLC ssh proxy password
        :param clouduser_account:
        :param clouduser_name:
        :param clouduser_credpath:
        :param clouduser_accesskey:
        :param clouduser_secretkey:
        :param cloudadmin_credpath:
        :param cloudadmin_accesskey:
        :param cloudadmin_secretkey:
        :param timeout:
        """
        if isinstance(log_level, basestring):
            log_level = getattr(logging, log_level.upper(), logging.DEBUG)
        self.log = Eulogger("TESTER:{0}".format(hostname),
                            stdout_level=log_level,
                            logfile=log_file,
                            logfile_level=log_file_level)
        if not hostname and environment_file:
            try:
                component = self.get_component_from_topology(
                    environment_file, 'clc-1')
                hostname = component['clc-1']
            except KeyError:
                component = self.get_component_from_topology(
                    environment_file, 'clc')
                hostname = component['clc'][0]
        self.log.identifier = "TESTER:{0}".format(hostname)
        self.log = Eulogger("TESTER:{0}".format(hostname),
                            stdout_level=log_level)
        self._region = region
        self._sysadmin = None
        self._cloudadmin = None
        self._test_user = None
        self._cred_depot = None
        self._default_timeout = timeout
        self._domain = domain
        self._https = https
        self._validate_certs = validate_certs
        self._cloud_admin_connection_info = {}
        self._test_user_connection_info = {}
        boto2_api_version = boto2_api_version or __DEFAULT_API_VERSION__
        self._system_connection_info = {
            'hostname': hostname,
            'username': username,
            'password': password,
            'keypath': keypath,
            'proxy_hostname': proxy_hostname,
            'proxy_password': proxy_password,
            'proxy_username': None,
            'config_qa': None,
            'credpath': cloudadmin_credpath,
            'aws_access_key': cloudadmin_accesskey,
            'aws_secret_key': cloudadmin_secretkey,
            'log_level': log_level,
            'boto_debug_level': 0,
            'euca_user': '******',
            'euca_account': 'eucalyptus',
            'https': https,
            'domain': domain
        }

        self._cloud_admin_connection_info = {
            'aws_account_name': 'eucalyptus',
            'aws_user_name': 'admin',
            'credpath': cloudadmin_credpath,
            'region': self.region,
            'domain': self.domain,
            'aws_access_key': cloudadmin_accesskey,
            'aws_secret_key': cloudadmin_secretkey,
            'service_connection': self.sysadmin,
            'log_level': log_level,
            'validate_certs': validate_certs,
            'boto2_api_version': boto2_api_version,
            'https': https
        }

        self._test_user_connection_info = {
            'aws_account_name': clouduser_account,
            'aws_user_name': clouduser_name,
            'credpath': clouduser_credpath,
            'aws_access_key': clouduser_accesskey,
            'aws_secret_key': clouduser_secretkey,
            'region': self.region,
            'domain': self.domain,
            'log_level': log_level,
            'validate_certs': validate_certs,
            'boto2_api_version': boto2_api_version,
            'https': https
        }

        self._cred_depot_connection_info = {
            'hostname': cred_depot_hostname,
            'username': cred_depot_username,
            'password': cred_depot_password or password,
            'log_level': log_level
        }

        # TODO ??
        self.test_resources = \
            {
                '_instances': [],
                '_volumes': []
            }
Exemple #44
0
class TestController(object):
    def __init__(self,
                 hostname=None, username='******', password=None,
                 proxy_hostname=None, proxy_password=None,
                 clouduser_account='nephotest', clouduser_name='admin', clouduser_credpath=None,
                 clouduser_accesskey=None, clouduser_secretkey=None,
                 cloudadmin_credpath=None, cloudadmin_accesskey=None, cloudadmin_secretkey=None,
                 timeout=10, log_level='DEBUG',
                 cred_depot_hostname=None, cred_depot_username='******', cred_depot_password=None):

        """

        :param hostname: CLC ssh hostname
        :param username: CLC ssh username
        :param password: CLC ssh password
        :param proxy_hostname: CLC ssh proxy hostname
        :param proxy_password: CLC ssh proxy password
        :param clouduser_account:
        :param clouduser_name:
        :param clouduser_credpath:
        :param clouduser_accesskey:
        :param clouduser_secretkey:
        :param cloudadmin_credpath:
        :param cloudadmin_accesskey:
        :param cloudadmin_secretkey:
        :param timeout:
        """
        self.log = Eulogger("TESTER:{0}".format(hostname), stdout_level=log_level)
        self._sysadmin = None
        self._cloudadmin = None
        self._test_user = None
        self._cred_depot = None
        self._default_timeout = timeout
        self._system_connection_info = {'hostname': hostname,
                                        'username': username,
                                        'password': password,
                                        'proxy_hostname': proxy_hostname,
                                        'proxy_password': proxy_password,
                                        'proxy_username': None,
                                        'config_qa': None,
                                        'credpath': cloudadmin_credpath,
                                        'aws_access_key': cloudadmin_accesskey,
                                        'aws_secret_key': cloudadmin_secretkey,
                                        'log_level': log_level,
                                        'boto_debug_level': 0,
                                        'euca_user': '******',
                                        'euca_account': 'eucalyptus'}

        self._cloud_admin_connection_info = {'account_name': 'eucalyptus',
                                             'user_name': 'admin',
                                             'credpath': cloudadmin_credpath,
                                             'access_key': cloudadmin_accesskey,
                                             'secret_key': cloudadmin_secretkey,
                                             'log_level': log_level}

        self._test_user_connection_info = {'aws_account_name': clouduser_account,
                                           'aws_user_name': clouduser_name,
                                           'credpath': clouduser_credpath,
                                           'aws_access_key': clouduser_accesskey,
                                           'aws_secret_key': clouduser_secretkey,
                                           'log_level': log_level}
        self._cred_depot_connection_info = {'hostname': cred_depot_hostname,
                                            'username': cred_depot_username,
                                            'password': cred_depot_password or password,
                                            'log_level': log_level}
    def __repr__(self):
        try:
            myrepr = "{0}:{1}({2}:{3},{4}:{5})".format(
                self.__class__.__name__,
                self._system_connection_info.get('hostname', ""),
                self._cloud_admin_connection_info.get('account_name', ""),
                self._cloud_admin_connection_info.get('user_name', ""),
                self._test_user_connection_info.get('aws_account_name', ""),
                self._test_user_connection_info.get('aws_user_name', ""))
            return myrepr
        except Exception as E:
            self.log.debug(E)
            return str(self.__class__.__name__)

    @property
    def cred_depot(self):
        if not self._cred_depot and self._cred_depot_connection_info.get('hostname'):
            self._cred_depot = Machine(**self._cred_depot_connection_info)
        return self._cred_depot

    @property
    def sysadmin(self):
        if not self._sysadmin:
            try:

                self._sysadmin = SystemConnection(**self._system_connection_info)
            except Exception as TE:
                self.log.error('{0}\nCould not create sysadmin interface, timed out: "{1}"'
                                  .format(get_traceback(), TE))
                raise TE
        return self._sysadmin

    @property
    def admin(self):
        if not self._cloudadmin:
            conn_info = self._cloud_admin_connection_info
            if (conn_info.get('credpath') or
                (conn_info.get('aws_access_key') and conn_info.get('aws_secret_key'))):
                if conn_info.get('credpath'):
                    conn_info['machine'] = self.cred_depot
                self._cloudadmin = UserContext(**conn_info)
            else:
                self._cloudadmin = UserContext(eucarc=self.sysadmin.creds)
        return self._cloudadmin

    @property
    def user(self):
        if not self._test_user:
            self._test_user = self.create_user_using_cloudadmin(**self._test_user_connection_info)
        return self._test_user

    @user.setter
    def user(self, user):
        if user is None:
            self._test_user = None
        if isinstance(user, UserContext):
            self._test_user = user
            return
        raise ValueError('Unsupported type for test_user:"******", "{1}"'.format(user, type(user)))

    def reset_connections(self):
        self._sysadmin = None
        self._cloudadmin = None
        self._test_user = None

    def get_user_by_name(self, aws_account_name, aws_user_name,
                         machine=None, service_connection=None, path='/',
                         log_level=None):
        """
        Fetch an existing cloud user and convert into a usercontext object.
        For checking basic existence of a cloud user, use the iam interface instead.
        """
        try:
            user = self.admin.iam.get_user_info(user_name=aws_user_name,
                                                delegate_account=aws_account_name)
        except Exception:
            self.log.error('Error fetching "account:{0}, user:{1}" has this user been created '
                           'already?'.format(aws_account_name, aws_user_name))
            raise
        if user:
            return self.create_user_using_cloudadmin(aws_account_name=aws_account_name,
                                                     aws_user_name=aws_user_name,
                                                     machine=machine,
                                                     service_connection=service_connection,
                                                     path=path, log_level=log_level)
        else:
            raise ValueError('User info not returned for "account:{0}, user:{1}"'
                             .format(aws_account_name, aws_user_name))



    def create_user_using_cloudadmin(self, aws_account_name=None, aws_user_name='admin',
                                     aws_access_key=None, aws_secret_key=None,
                                     credpath=None, eucarc=None,
                                     machine=None, service_connection=None, path='/',
                                     log_level=None):
        if log_level is None:
            log_level = self.log.stdout_level or 'DEBUG'
        self.log.debug('Attempting to create user with params: account:{0}, name:{1}'
                          'access_key:{2}, secret_key:{3}, credpath:{4}, eucarc:{5}'
                          ', machine:{6}, service_connection:{7}, path:{8}, loglevel:{9}'
                          .format(aws_account_name, aws_user_name, aws_access_key, aws_secret_key,
                                  credpath, eucarc, machine, service_connection, path, log_level))
        service_connection = service_connection or self.sysadmin
        if eucarc:
            if aws_access_key:
                eucarc.access_key = aws_access_key
            if aws_secret_key:
                eucarc.secret_key = aws_secret_key
            if aws_user_name:
                eucarc.user_name = aws_user_name
            if aws_account_name:
                eucarc.account_name = aws_account_name
            return UserContext(eucarc=eucarc,
                               service_connection=service_connection,
                               log_level=log_level)
        if aws_access_key and aws_secret_key:
            return UserContext(aws_access_key=aws_access_key,
                               aws_secret_key=aws_secret_key,
                               aws_account_name=aws_account_name,
                               aws_user_name=aws_user_name,
                               service_connection=service_connection,
                               log_level=log_level)
        if credpath:
            return UserContext(credpath=credpath,
                               machine=machine,
                               log_level=log_level)

        info = self.admin.iam.create_account(account_name=aws_account_name,
                                                  ignore_existing=True)
        if info:
            user = self.admin.iam.create_user(user_name=aws_user_name,
                                              delegate_account=info.get('account_name'),
                                              path=path)
            info.update(user)
        else:
            raise RuntimeError('Failed to create and/or fetch Account:"{0}", for User:"******"'
                               .format(aws_account_name, aws_user_name))
        ak = self.admin.iam.get_aws_access_key(user_name=info.get('user_name'),
                                               delegate_account=info.get('account_name'))
        if not ak:
            ak = self.admin.iam.create_access_key(user_name=info.get('user_name'),
                                                  delegate_account=info.get('account_name'))
        try:
            info['access_key_id'] = ak['access_key_id']
        except KeyError:
            err_msg = ('Failed to fetch access key for USER:"******", ACCOUNT:"{1}"'
                       .format(aws_user_name, aws_account_name))
            self.log.error('{0}\n{1}'.format(get_traceback(), err_msg))
            raise RuntimeError(err_msg)
        if self.admin.iam.get_all_signing_certs(user_name=info.get('user_name'),
                                                delegate_account=info.get('account_name')):
            certs = True
        else:
            certs = False
        user =  UserContext(aws_access_key=info.get('access_key_id'),
                            aws_secret_key=info.get('secret_access_key'),
                            aws_account_name=info.get('account_name'),
                            aws_user_name=info.get('user_name'),
                            existing_certs=certs,
                            machine=self.sysadmin.clc_machine,
                            service_connection=self.sysadmin,
                            log_level=log_level)
        user._user_info = self.admin.iam.get_user_info(user_name=user.user_name,
                                                       delegate_account=user.account_id)
        return user

    def wait_for_result(self, *args, **kwargs):
        return wait_for_result(*args, **kwargs)