示例#1
0
    def support_get_logs(self, servicenames, hostname, dirpath):
        # type: (List[str], str, str) -> None
        """get container logs

        Fetch the container log files of services from the specified hosts.
        The log files will be placed in the named directory. All the containers
        for the host will be placed in a directory named hostname. The file
        names for each log will be servicename_id.log.

        :param servicenames: names of services (ie nova, glance, etc)
        :type servicenames: list of strings
        :param hostname: name of host to look for logs on
        :type hostname: string
        :param dirpath: path of directory where log files will be written
        :type dirpath: string
        """
        check_arg(dirpath, u._('Directory path'), str)
        dirpath = safe_decode(dirpath)
        if not os.path.exists(dirpath):
            raise InvalidArgument(
                u._('Directory path: {path} does not exist').format(
                    path=dirpath))

        check_arg(servicenames, u._('Service names'), list)
        servicenames = safe_decode(servicenames)
        check_arg(hostname, u._('Host names'), str)
        hostname = safe_decode(hostname)

        get_logs(servicenames, hostname, dirpath)
示例#2
0
    def check(verbose_level=1, hostnames=[], servicenames=[]):
        # type: (int, List[str], List[str]) -> Job
        """Do post-deployment smoke tests.

        :param hostnames: host names
        :type hostnames: list
        :param verbose_level: the higher the number, the more verbose
        :type verbose_level: integer
        :param servicenames: services to check. If empty, then check all.
        :type servicenames: list of strings
        :return: Job object
        :rtype: Job
        """
        check_arg(verbose_level, u._('Verbose level'), int)
        check_arg(hostnames,
                  u._('Host names'),
                  list,
                  empty_ok=True,
                  none_ok=True)
        check_arg(servicenames,
                  u._('Service names'),
                  list,
                  empty_ok=True,
                  none_ok=True)

        check_kolla_args(servicenames=servicenames)

        hostnames = safe_decode(hostnames)
        servicenames = safe_decode(servicenames)
        action = KollaAction(verbose_level=verbose_level,
                             playbook_name='site.yml')
        ansible_job = action.check(hostnames, servicenames)
        return Job(ansible_job)
示例#3
0
    def run_command(self, cmd):
        """run bash command

        return (retval, msg)
        """
        # self.log.debug('run cmd: %s' % cmd)
        msg = ''

        # pipe encoding defaults to None which will cause output encode errors
        # if non-ascii chars are attempted to be written to stdout.
        env = {'PYTHONIOENCODING': 'utf-8'}
        process = subprocess.Popen(cmd,
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE,
                                   env=env,
                                   shell=True)
        (out, err) = process.communicate()
        retval = process.returncode

        # the py dev debugger adds a string at the line start, remove it
        if err:
            msg = utils.safe_decode(err)
        if out:
            msg = msg + '\n' + utils.safe_decode(out)
        if msg.startswith('pydev debugger'):
            msg = msg.split('\n', 1)[1]
        return (retval, msg)
示例#4
0
    def property_clear(self,
                       property_list,
                       property_type=GLOBAL_TYPE,
                       change_set=None):
        # type: (List[str], str, List[str]) -> None
        """Clear a property

        :param property_list: property list
        :type property_list: list
        :param property_type: one of 'global', 'group' or 'host'
        :type property_type: string
        :param change_set: for group or host clears this is the list of
                           groups or hosts to clear the property for
        :type change_set: list of strings

        """
        check_arg(property_list, u._('Property List'), list)
        property_list = safe_decode(property_list)

        self._check_type(property_type)
        if property_type is not GLOBAL_TYPE:
            check_arg(change_set, u._('Change Set'), list, none_ok=True)
            change_set = safe_decode(change_set)

        ansible_properties = AnsibleProperties()

        if property_type == GLOBAL_TYPE:
            ansible_properties.clear_property(property_list)
        elif property_type == GROUP_TYPE:
            ansible_properties.clear_group_property(property_list, change_set)
        else:
            ansible_properties.clear_host_property(property_list, change_set)
示例#5
0
    def stop(verbose_level=1, hostnames=[], servicenames=[]):
        # type: (int, List[str], List[str]) -> Job
        """Stop Hosts.

        Stops all kolla related docker containers on the specified hosts.

        :param hostnames: host names
        :type hostnames: list
        :param verbose_level: the higher the number, the more verbose
        :type verbose_level: integer
        :param servicenames: services to stop. If empty, then stop all.
        :type servicenames: list of strings
        :return: Job object
        :rtype: Job
        """
        check_arg(verbose_level, u._('Verbose level'), int)
        check_arg(hostnames,
                  u._('Host names'),
                  list,
                  empty_ok=True,
                  none_ok=True)
        check_arg(servicenames,
                  u._('Service names'),
                  list,
                  empty_ok=True,
                  none_ok=True)

        check_kolla_args(hostnames=hostnames, servicenames=servicenames)

        hostnames = safe_decode(hostnames)
        servicenames = safe_decode(servicenames)
        action = KollaAction(verbose_level=verbose_level,
                             playbook_name='site.yml')
        ansible_job = action.stop(hostnames, servicenames)
        return Job(ansible_job)
示例#6
0
    def pull(verbose_level=1, hostnames=[], servicenames=[]):
        """Pull.

        Pull all images for containers (only pulls, no running container).

        :param verbose_level: the higher the number, the more verbose
        :param hostnames: hosts to pull to. If empty, then pull to all.
        :type hostnames: list of strings
        :type verbose_level: integer
        :param servicenames: services to pull. If empty, then pull all.
        :return: Job object
        :rtype: Job
        """
        check_arg(hostnames,
                  u._('Host names'),
                  list,
                  empty_ok=True,
                  none_ok=True)
        check_arg(verbose_level, u._('Verbose level'), int)
        check_arg(servicenames,
                  u._('Service names'),
                  list,
                  empty_ok=True,
                  none_ok=True)

        check_kolla_args(hostnames=hostnames, servicenames=servicenames)

        hostnames = safe_decode(hostnames)
        servicenames = safe_decode(servicenames)
        action = KollaAction(verbose_level=verbose_level,
                             playbook_name='site.yml')
        ansible_job = action.pull(hostnames, servicenames)
        return Job(ansible_job)
示例#7
0
    def property_get(self, property_type=GLOBAL_TYPE, get_set=None):
        # type: (str, List[str]) -> List[Property]
        """Returns a list of Property objects

        :param property_type: one of 'global', 'group', or 'host'
        :type property_type: string
        :param get_set: optional list of hosts or groups to be used when
                         getting group or host related property lists
        :type get_set: list of strings
        :return: properties
        :rtype: list of Property objects
        """
        self._check_type(property_type)
        get_set = safe_decode(get_set)

        ansible_properties = AnsibleProperties()

        result_list = []
        if property_type == GLOBAL_TYPE:
            property_list = ansible_properties.get_all_unique()
        elif property_type == GROUP_TYPE:
            property_list = ansible_properties.get_group_list(get_set)
        else:
            property_list = ansible_properties.get_host_list(get_set)

        override_flags = ansible_properties.get_all_override_flags()

        for prop in property_list:
            result = Property(prop, override_flags.get(prop.name, None))
            result_list.append(result)

        return result_list
示例#8
0
    def property_set(self,
                     property_dict,
                     property_type=GLOBAL_TYPE,
                     change_set=None):
        # type: (Dict[str,str], str, List[str]) -> None
        """Set a property

        :param property_dict: property dictionary containing key / values
        :type property_dict: dictionary
        :param property_type: one of 'global', 'group' or 'host'
        :type property_type: string
        :param change_set: for group or host sets this is the list of groups
                           or hosts to set the property for
        :type change_set: list of strings

        """
        ansible_properties = AnsibleProperties()
        for key, value in property_dict.items():
            check_arg(key, u._('Property Key'), str)
            current_property = ansible_properties.get_property(key)
            if current_property is not None:
                current_property_type = current_property.value_type
                if current_property_type is not str:
                    original_value = value
                    value = yaml.safe_load(value)

                    # this check is to make sure that we can assign an empty
                    # string to a property.  without this safe_load will turn
                    # an empty string into a None which is different than an
                    # empty string.
                    if isinstance(original_value, six.string_types)\
                            and value is None:
                        value = ''
                    if current_property.value is None:
                        current_property_type = None
                    check_arg(value,
                              u._('Property Value'),
                              current_property_type,
                              empty_ok=True)
                    property_dict[key] = value
            else:
                check_arg(value, u._('Property Value'), str, empty_ok=True)
            if type(value) is str and '"' in value:
                raise InvalidArgument(
                    u._('Cannot use double quotes in '
                        'a property value.'))

        self._check_type(property_type)
        if property_type is not GLOBAL_TYPE:
            check_arg(change_set, u._('Change Set'), list, none_ok=True)
            change_set = safe_decode(change_set)

        if property_type == GLOBAL_TYPE:
            ansible_properties.set_property(property_dict)
        elif property_type == GROUP_TYPE:
            ansible_properties.set_group_property(property_dict, change_set)
        else:
            ansible_properties.set_host_property(property_dict, change_set)
示例#9
0
 def _read_stream(self, stream):
     out = ''
     if stream and not stream.closed:
         try:
             out = safe_decode(stream.read())
         except IOError:  # nosec
             # error can happen if stream is empty
             pass
         if out is None:
             out = ''
     return out
示例#10
0
    def deploy(hostnames=[],
               serial_flag=False,
               verbose_level=1,
               servicenames=[]):
        # type: (List[str], bool, int, List[str]) -> Job
        """Deploy.

        Deploy and start all kolla containers.

        :param hostnames: hosts to deploy to. If empty, then deploy to all.
        :type hostnames: list of strings
        :param serial_flag: if true, deploy will be done one host at a time
        :type serial_flag: boolean
        :param verbose_level: the higher the number, the more verbose
        :type verbose_level: integer
        :param servicenames: services to deploy. If empty, then deploy all.
        :type servicenames: list of strings
        :return: Job object
        :rtype: Job
        """
        check_arg(hostnames,
                  u._('Host names'),
                  list,
                  empty_ok=True,
                  none_ok=True)
        check_arg(serial_flag, u._('Serial flag'), bool)
        check_arg(verbose_level, u._('Verbose level'), int)
        check_arg(servicenames,
                  u._('Service names'),
                  list,
                  empty_ok=True,
                  none_ok=True)

        check_kolla_args(hostnames=hostnames, servicenames=servicenames)

        hostnames = safe_decode(hostnames)
        servicenames = safe_decode(servicenames)
        action = KollaAction(verbose_level=verbose_level,
                             playbook_name='site.yml')
        ansible_job = action.deploy(hostnames, serial_flag, servicenames)
        return Job(ansible_job)
示例#11
0
    def service_get(self, servicenames):
        # type: (List[str]) -> List[Service]
        """Get selected services in the inventory

        :param servicenames: names of services to be read
        :type servicenames: list of strings
        :return: services
        :rtype: list of Service objects
        """
        check_arg(servicenames, u._('Service names'), list)
        servicenames = safe_decode(servicenames)
        return self._get_services(servicenames)
示例#12
0
    def group_get(self, groupnames):
        # type: (List[str]) -> List[Group]
        """Get selected groups in the inventory

        :param groupnames: names of groups to be read
        :type groupnames: list of strings
        :return: groups
        :rtype: list of Group objects
        """
        check_arg(groupnames, u._('Group names'), list)
        groupnames = safe_decode(groupnames)
        return self._get_groups(groupnames)
示例#13
0
    def run_command(self, cmd):
        """run bash command

        return (retval, msg)
        """
        # self.log.debug('run cmd: %s' % cmd)
        msg = ''
        process = subprocess.Popen(cmd,
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE,
                                   shell=True)
        (out, err) = process.communicate()
        retval = process.returncode

        # the py dev debugger adds a string at the line start, remove it
        if err:
            msg = utils.safe_decode(err)
        if out:
            msg = msg + '\n' + utils.safe_decode(out)
        if msg.startswith('pydev debugger'):
            msg = msg.split('\n', 1)[1]
        return (retval, msg)
示例#14
0
    def reconfigure(verbose_level=1, hostnames=[], servicenames=[]):
        # type: (int, List[str], List[str]) -> Job
        """Reconfigure.

        Reconfigure OpenStack service.

        :param hostnames: host names
        :type hostnames: list
        :param verbose_level: the higher the number, the more verbose
        :type verbose_level: integer
        :param servicenames: services to prechecks.
        :type servicenames: list of strings
        :return: Job object
        :rtype: Job
        """
        check_arg(hostnames,
                  u._('Host names'),
                  list,
                  empty_ok=True,
                  none_ok=True)
        check_arg(verbose_level, u._('Verbose level'), int)
        check_arg(servicenames,
                  u._('Service names'),
                  list,
                  empty_ok=True,
                  none_ok=True)

        check_kolla_args(hostnames=hostnames, servicenames=servicenames)

        hostnames = safe_decode(hostnames)
        servicenames = safe_decode(servicenames)

        check_kolla_args(hostnames=hostnames, servicenames=servicenames)

        action = KollaAction(verbose_level=verbose_level,
                             playbook_name='site.yml')
        ansible_job = action.reconfigure(hostnames, servicenames)
        return Job(ansible_job)
示例#15
0
    def upgrade(verbose_level=1, hostnames=[], servicenames=[]):
        # type: (int, List[str], List[str]) -> Job
        """Upgrade.

        Upgrades existing OpenStack Environment.

        :param verbose_level: the higher the number, the more verbose
        :type verbose_level: integer
        :param hostnames: hostnames to upgrade.
        :type hostnames: list of strings.
        :param servicenames: services to upgrade. If empty, then upgrade all.
        :type servicenames: list of strings
        :return: Job object
        :rtype: Job

        Upgrade containers to new version specified by the property
        "openstack_release."
        """
        check_arg(verbose_level, u._('Verbose level'), int)
        check_arg(hostnames,
                  u._('Host names'),
                  list,
                  empty_ok=True,
                  none_ok=True)
        check_arg(servicenames,
                  u._('Service names'),
                  list,
                  empty_ok=True,
                  none_ok=True)

        check_kolla_args(servicenames=servicenames)

        hostnames = safe_decode(hostnames)
        servicenames = safe_decode(servicenames)
        action = KollaAction(verbose_level=verbose_level,
                             playbook_name='site.yml')
        ansible_job = action.upgrade(hostnames, servicenames)
        return Job(ansible_job)
示例#16
0
    def group_remove(self, groupnames):
        # type: (List[str]) -> None
        """Remove groups from the inventory

        :param groupnames: names of the groups to remove from the inventory
        :type groupnames: list of strings
        """
        check_arg(groupnames, u._('Group names'), list)
        groupnames = safe_decode(groupnames)

        inventory = Inventory.load()
        for groupname in groupnames:
            inventory.remove_group(groupname)
        Inventory.save(inventory)
示例#17
0
    def group_add(self, groupnames):
        # type: (List[str]) -> None
        """Add groups to the inventory

        :param groupnames: names of the groups to add to the inventory
        :type groupnames: list of strings

        """
        check_arg(groupnames, u._('Group names'), list)
        groupnames = safe_decode(groupnames)

        inventory = Inventory.load()
        for groupname in groupnames:
            inventory.add_group(groupname)
        Inventory.save(inventory)
示例#18
0
    def prechecks(verbose_level=1, hostnames=[], servicenames=[]):
        # type: (int, List[str], List[str]) -> Job
        """Check pre-deployment configuration of hosts.

        Check if host is ready for a new deployment. This will fail if
        any of the hosts are not configured correctly or if they have
        already been deployed to.
        :param hostnames: host names
        :type hostnames: list
        :param verbose_level: the higher the number, the more verbose
        :type verbose_level: integer
        :param servicenames: services to prechecks.
        :type servicenames: list of strings
        :return: Job object
        :rtype: Job
        """
        check_arg(hostnames,
                  u._('Host names'),
                  list,
                  empty_ok=True,
                  none_ok=True)
        check_arg(verbose_level, u._('Verbose level'), int)
        check_arg(servicenames,
                  u._('Service names'),
                  list,
                  empty_ok=True,
                  none_ok=True)

        check_kolla_args(hostnames=hostnames, servicenames=servicenames)

        hostnames = safe_decode(hostnames)
        servicenames = safe_decode(servicenames)
        action = KollaAction(verbose_level=verbose_level,
                             playbook_name='site.yml')
        ansible_job = action.precheck(hostnames, servicenames)
        return Job(ansible_job)
示例#19
0
    def host_remove(hostnames):
        # type: (List[str]) -> None
        """Remove hosts from the inventory

        :param hostnames: list of strings
        """
        check_arg(hostnames, u._('Host names'), list)
        hostnames = safe_decode(hostnames)

        inventory = Inventory.load()
        any_changed = False
        for hostname in hostnames:
            changed = inventory.remove_host(hostname)
            if changed:
                any_changed = True
        if any_changed:
            Inventory.save(inventory)
示例#20
0
    def host_get(hostnames):
        # type: (List[str]) -> List[Host]
        """Get selected hosts in the inventory

        :param hostnames: list of strings
        :return: hosts
        :rtype: list of Host objects
        """
        check_arg(hostnames, u._('Host names'), list)
        hostnames = safe_decode(hostnames)
        inventory = Inventory.load()
        inventory.validate_hostnames(hostnames)

        hosts = []
        host_groups = inventory.get_host_groups()
        for hostname in hostnames:
            hosts.append(Host(hostname, host_groups[hostname]))
        return hosts
示例#21
0
    def host_destroy(hostnames,
                     destroy_type,
                     verbose_level=1,
                     include_data=False,
                     remove_images=False):
        # type: (List[str], str, int, bool, bool) -> Job
        """Destroy Hosts.

        Stops and removes all kolla related docker containers on the
        specified hosts.

        :param hostnames: host names
        :type hostnames: list
        :param destroy_type: either 'kill' or 'stop'
        :type destroy_type: string
        :param verbose_level: the higher the number, the more verbose
        :type verbose_level: integer
        :param include_data: if true, destroy data containers too.
        :type include_data: boolean
        :param remove_images: if true, destroy will remove the docker images
        :type remove_images: boolean
        :return: Job object
        :rtype: Job
        """
        check_arg(hostnames, u._('Host names'), list)
        check_arg(destroy_type, u._('Destroy type'), str)
        check_arg(verbose_level, u._('Verbose level'), int)
        check_arg(include_data, u._('Include data'), bool)
        check_arg(remove_images, u._('Remove images'), bool)
        if destroy_type not in ['stop', 'kill']:
            raise InvalidArgument(
                u._('Invalid destroy type ({type}). Must be either '
                    '"stop" or "kill".').format(type=destroy_type))

        hostnames = safe_decode(hostnames)
        inventory = Inventory.load()
        inventory.validate_hostnames(hostnames)

        action = KollaAction(verbose_level=verbose_level,
                             playbook_name='destroy.yml')
        ansible_job = action.destroy_hosts(hostnames, destroy_type,
                                           include_data, remove_images)
        return Job(ansible_job)
示例#22
0
    def add_service(self, servicename):
        # type: (str) -> None
        """Add service to group

        :param servicename: name of the service to add to the group
        :type servicename: string
        """
        check_arg(servicename, u._('Service name'), str)
        servicename = safe_decode(servicename)
        inventory = Inventory.load()
        inventory.validate_servicenames([servicename], client_filter=True)

        group_services = inventory.get_group_services()
        self._servicenames = group_services[self.name]
        if servicename not in self._servicenames:
            # service not associated with group, add it
            inventory.add_group_to_service(self.name, servicename)
            self._servicenames.append(servicename)
            Inventory.save(inventory)
示例#23
0
    def add_host(self, hostname):
        # type: (str) -> None
        """Add host to group

        :param hostname: name of the host to add to the group
        :type hostname: string

        """
        check_arg(hostname, u._('Host name'), str)
        hostname = safe_decode(hostname)
        inventory = Inventory.load()
        inventory.validate_hostnames([hostname])

        group = inventory.get_group(self.name)
        self._hostnames = group.get_hostnames()
        if hostname not in self._hostnames:
            # host not associated with group, add it
            inventory.add_host(hostname, self.name)
            self._hostnames.append(hostname)
            Inventory.save(inventory)
示例#24
0
    def remove_service(self, servicename):
        # type: (str) -> None
        """Remove service from group

        :param servicename: name of the service to remove from the group
        :type servicename: string

        """
        check_arg(servicename, u._('Service name'), str)
        servicename = safe_decode(servicename)
        inventory = Inventory.load()
        inventory.validate_servicenames([servicename], client_filter=True)

        group_services = inventory.get_group_services()
        self._servicenames = group_services[self.name]
        if servicename in self._servicenames:
            # service is associated with group, remove it
            inventory.remove_group_from_service(self.name, servicename)
            self._servicenames.remove(servicename)
            Inventory.save(inventory)
示例#25
0
    def remove_host(self, hostname):
        # type: (str) -> None
        """Remove host from group

        :param hostname: name of the host to remove from the group
        :type hostname: string

        """
        check_arg(hostname, u._('Host name'), str)
        hostname = safe_decode(hostname)
        inventory = Inventory.load()
        inventory.validate_hostnames([hostname])

        group = inventory.get_group(self.name)
        self._hostnames = group.get_hostnames()
        if hostname in self._hostnames:
            # host is associated with group, remove it
            inventory.remove_host(hostname, self.name)
            self._hostnames.remove(hostname)
            Inventory.save(inventory)
示例#26
0
    def support_dump(self, dirpath):
        # type: (str) -> str
        """Dumps configuration data for debugging.

        Dumps most files in /etc/kolla and /usr/share/kolla into a
        tar file so be given to support / development to help with
        debugging problems.

        :param dirpath: path to directory where dump will be placed
        :type dirpath: string
        :return: path to dump file
        :rtype: string
        """
        check_arg(dirpath, u._('Directory path'), str)
        dirpath = safe_decode(dirpath)
        if not os.path.exists(dirpath):
            raise InvalidArgument(
                u._('Directory path: {path} does not exist').format(
                    path=dirpath))
        dumpfile_path = dump(dirpath)
        return dumpfile_path
示例#27
0
    def host_ssh_check(hostnames):
        # type: (List[str]) -> Dict[str,Dict[str,object]]
        """Check hosts for ssh connectivity

        Check status is a dictionary of form:
            - {hostname: {
              'success':<True|False>,
              'msg':message_string},
              ...
              }

        :param hostnames: list of strings
        :return: check status
        :rtype: dictionary
        """
        check_arg(hostnames, u._('Host names'), list)
        inventory = Inventory.load()
        hostnames = safe_decode(hostnames)
        inventory.validate_hostnames(hostnames)
        summary = inventory.ssh_check_hosts(hostnames)
        return summary
示例#28
0
    def host_precheck(hostnames, verbose_level=1):
        # type: (List[str], int) -> Job
        """Check pre-deployment configuration of hosts.

        Check if host is ready for a new deployment. This will fail if
        any of the hosts are not configured correctly or if they have
        already been deployed to.
        :param hostnames: host names
        :type hostnames: list
        :param verbose_level: the higher the number, the more verbose
        :type verbose_level: integer
        :return: Job object
        :rtype: Job
        """
        check_arg(hostnames, u._('Host names'), list)
        check_arg(verbose_level, u._('Verbose level'), int)
        hostnames = safe_decode(hostnames)
        inventory = Inventory.load()
        inventory.validate_hostnames(hostnames)

        ansible_job = actions.precheck(hostnames, verbose_level)
        return Job(ansible_job)
示例#29
0
    def host_stop(hostnames, verbose_level=1):
        # type: (List[str], int) -> Job
        """Stop Hosts.

        Stops all kolla related docker containers on the specified hosts.

        :param hostnames: host names
        :type hostnames: list
        :param verbose_level: the higher the number, the more verbose
        :type verbose_level: integer
        :return: Job object
        :rtype: Job
        """
        check_arg(hostnames, u._('Host names'), list)
        check_arg(verbose_level, u._('Verbose level'), int)

        hostnames = safe_decode(hostnames)
        inventory = Inventory.load()
        inventory.validate_hostnames(hostnames)

        ansible_job = actions.stop_hosts(hostnames, verbose_level)
        return Job(ansible_job)
示例#30
0
    def test_log_collector_api(self):
        if os.path.exists(LOGDIR):
            shutil.rmtree(LOGDIR)
        os.mkdir(LOGDIR)

        hostnames = ['test_host1']
        CLIENT.host_add(hostnames)

        services = CLIENT.service_get_all()
        service_names = []
        for service in services:
            service_names.append(service.name)
        try:
            for hostname in hostnames:
                CLIENT.support_get_logs(service_names, safe_decode(hostname),
                                        LOGDIR)
                raise Exception('get_logs command succeeded without physical '
                                'hosts')
        except Exception as e:
            self.assertIn('UNREACHABLE', str(e),
                          'unexpected failure in get_logs: %s' % str(e))
        finally:
            if os.path.exists(LOGDIR):
                shutil.rmtree(LOGDIR)