示例#1
0
 def _get_installed_candidate_version(package_name, client):
     installed = None
     candidate = None
     for line in client.run(['apt-cache', 'policy', package_name, DebianPackage.APT_CONFIG_STRING]).splitlines():
         line = line.strip()
         if line.startswith('Installed:'):
             installed = Toolbox.remove_prefix(line, 'Installed:').strip()
         elif line.startswith('Candidate:'):
             candidate = Toolbox.remove_prefix(line, 'Candidate:').strip()
         if installed is not None and candidate is not None:
             break
     return installed if installed != '(none)' else None, candidate if candidate != '(none)' else None
示例#2
0
 def _get_installed_candidate_version(package_name, client):
     installed = None
     candidate = None
     for line in client.run([
             'apt-cache', 'policy', package_name,
             DebianPackage.APT_CONFIG_STRING
     ]).splitlines():
         line = line.strip()
         if line.startswith('Installed:'):
             installed = Toolbox.remove_prefix(line, 'Installed:').strip()
         elif line.startswith('Candidate:'):
             candidate = Toolbox.remove_prefix(line, 'Candidate:').strip()
         if installed is not None and candidate is not None:
             break
     return installed if installed != '(none)' else None, candidate if candidate != '(none)' else None
示例#3
0
 def extract_dir_structure(directory):
     """
     Builds a dict representing a given directory
     """
     data = {'dirs': {}, 'files': []}
     for current_dir, dirs, files in os.walk(directory):
         current_dir = Toolbox.remove_prefix(current_dir, directory)
         if current_dir == '':
             data['dirs'] = dict((entry, {
                 'dirs': {},
                 'files': []
             }) for entry in dirs)
             data['files'] = files
         else:
             dir_entries = current_dir.strip('/').split('/')
             pointer = data['dirs']
             for entry in dir_entries[:-1]:
                 pointer = pointer[entry]['dirs']
             pointer = pointer[dir_entries[-1]]
             pointer['dirs'] = dict((entry, {
                 'dirs': {},
                 'files': []
             }) for entry in dirs)
             pointer['files'] = files
     return data
示例#4
0
    def add_service(name, client, params=None, target_name=None, additional_dependencies=None):
        """
        Add a service
        :param name: Name of the service to add
        :type name: str
        :param client: Client on which to add the service
        :type client: SSHClient
        :param params: Additional information about the service
        :type params: dict
        :param target_name: Overrule default name of the service with this name
        :type target_name: str
        :param additional_dependencies: Additional dependencies for this service
        :type additional_dependencies: list
        :return: None
        """
        if params is None:
            params = {}

        name = Systemd._get_name(name, client, "/opt/OpenvStorage/config/templates/systemd/")
        template_service = "/opt/OpenvStorage/config/templates/systemd/{0}.service"

        if not client.file_exists(template_service.format(name)):
            # Given template doesn't exist so we are probably using system
            # init scripts
            return

        template_file = client.file_read(template_service.format(name))

        for key, value in params.iteritems():
            template_file = template_file.replace("<{0}>".format(key), value)
        if "<SERVICE_NAME>" in template_file:
            service_name = name if target_name is None else target_name
            template_file = template_file.replace("<SERVICE_NAME>", Toolbox.remove_prefix(service_name, "ovs-"))
        template_file = template_file.replace("<_SERVICE_SUFFIX_>", "")

        dependencies = ""
        if additional_dependencies:
            for service in additional_dependencies:
                dependencies += "{0}.service ".format(service)
        template_file = template_file.replace("<ADDITIONAL_DEPENDENCIES>", dependencies)

        if target_name is None:
            client.file_write("/lib/systemd/system/{0}.service".format(name), template_file)
        else:
            client.file_write("/lib/systemd/system/{0}.service".format(target_name), template_file)
            name = target_name

        try:
            client.run(["systemctl", "daemon-reload"])
            client.run(["systemctl", "enable", "{0}.service".format(name)])
        except CalledProcessError as cpe:
            output = cpe.output
            Systemd._logger.exception("Add {0}.service failed, {1}".format(name, output))
            raise Exception("Add {0}.service failed, {1}".format(name, output))
示例#5
0
    def collapse_arakoon():
        """
        Collapse Arakoon's Tlogs
        :return: None
        """
        GenericController._logger.info('Starting arakoon collapse')
        storagerouters = StorageRouterList.get_storagerouters()
        cluster_info = [('cacc', storagerouters[0], True)]
        cluster_names = []
        for service in ServiceList.get_services():
            if service.is_internal is True and service.type.name in (ServiceType.SERVICE_TYPES.ARAKOON,
                                                                     ServiceType.SERVICE_TYPES.NS_MGR,
                                                                     ServiceType.SERVICE_TYPES.ALBA_MGR):
                cluster = ExtensionToolbox.remove_prefix(service.name, 'arakoon-')
                if cluster in cluster_names:
                    continue
                cluster_names.append(cluster)
                cluster_info.append((cluster, service.storagerouter, False))
        workload = {}
        for cluster, storagerouter, filesystem in cluster_info:
            GenericController._logger.debug('  Collecting info for cluster {0}'.format(cluster))
            config = ArakoonClusterConfig(cluster, filesystem=filesystem)
            config.load_config(storagerouter.ip)
            for node in config.nodes:
                if node.ip not in workload:
                    workload[node.ip] = {'node_id': node.name,
                                         'clusters': []}
                workload[node.ip]['clusters'].append((cluster, filesystem))
        for storagerouter in storagerouters:
            try:
                if storagerouter.ip not in workload:
                    continue
                node_workload = workload[storagerouter.ip]
                client = SSHClient(storagerouter)
                for cluster, filesystem in node_workload['clusters']:
                    try:
                        GenericController._logger.debug('  Collapsing cluster {0} on {1}'.format(cluster, storagerouter.ip))
                        if filesystem is True:
                            config_path = ArakoonClusterConfig.CONFIG_FILE.format(cluster)
                        else:
                            config_path = Configuration.get_configuration_path(ArakoonClusterConfig.CONFIG_KEY.format(cluster))
                        client.run(['arakoon', '--collapse-local', node_workload['node_id'], '2', '-config', config_path])
                        GenericController._logger.info('  Collapsing cluster {0} on {1} completed'.format(cluster, storagerouter.ip))
                    except:
                        GenericController._logger.exception('  Collapsing cluster {0} on {1} failed'.format(cluster, storagerouter.ip))
            except UnableToConnectException:
                GenericController._logger.error('  Could not collapse any cluster on {0} (not reachable)'.format(storagerouter.name))

        GenericController._logger.info('Arakoon collapse finished')
示例#6
0
    def add_service(name, client, params=None, target_name=None, startup_dependency=None, delay_registration=False):
        """
        Add a service
        :param name: Template name of the service to add
        :type name: str
        :param client: Client on which to add the service
        :type client: ovs.extensions.generic.sshclient.SSHClient
        :param params: Additional information about the service
        :type params: dict or None
        :param target_name: Overrule default name of the service with this name
        :type target_name: str or None
        :param startup_dependency: Additional startup dependency
        :type startup_dependency: str or None
        :param delay_registration: Register the service parameters in the config management right away or not
        :type delay_registration: bool
        :return: Parameters used by the service
        :rtype: dict
        """
        if params is None:
            params = {}

        service_name = Systemd._get_name(name, client, '/opt/OpenvStorage/config/templates/systemd/')
        template_file = '/opt/OpenvStorage/config/templates/systemd/{0}.service'.format(service_name)

        if not client.file_exists(template_file):
            # Given template doesn't exist so we are probably using system init scripts
            return

        if target_name is not None:
            service_name = target_name

        params.update({'SERVICE_NAME': Toolbox.remove_prefix(service_name, 'ovs-'),
                       'STARTUP_DEPENDENCY': '' if startup_dependency is None else '{0}.service'.format(startup_dependency)})
        template_content = client.file_read(template_file)
        for key, value in params.iteritems():
            template_content = template_content.replace('<{0}>'.format(key), value)
        client.file_write('/lib/systemd/system/{0}.service'.format(service_name), template_content)

        try:
            client.run(['systemctl', 'daemon-reload'])
            client.run(['systemctl', 'enable', '{0}.service'.format(service_name)])
        except CalledProcessError as cpe:
            Systemd._logger.exception('Add {0}.service failed, {1}'.format(service_name, cpe.output))
            raise Exception('Add {0}.service failed, {1}'.format(service_name, cpe.output))

        if delay_registration is False:
            Systemd.register_service(service_metadata=params, node_name=System.get_my_machine_id(client))
        return params
示例#7
0
 def list(key):
     """
     List all keys starting with specified key
     :param key: Key to list
     :type key: str
     :return: Generator with all keys
     :rtype: generator
     """
     key = ArakoonConfiguration._clean_key(key)
     client = ArakoonConfiguration._get_client()
     entries = []
     for entry in client.prefix(key):
         if key == '' or entry.startswith(key.rstrip('/') + '/'):
             cleaned = Toolbox.remove_prefix(entry, key).strip('/').split('/')[0]
             if cleaned not in entries:
                 entries.append(cleaned)
                 yield cleaned
示例#8
0
    def add_service(name, client, params=None, target_name=None, additional_dependencies=None):
        """
        Add a service
        :param name: Name of the service to add
        :type name: str
        :param client: Client on which to add the service
        :type client: SSHClient
        :param params: Additional information about the service
        :type params: dict
        :param target_name: Overrule default name of the service with this name
        :type target_name: str
        :param additional_dependencies: Additional dependencies for this service
        :type additional_dependencies: list
        :return: None
        """
        if params is None:
            params = {}

        name = Upstart._get_name(name, client, '/opt/OpenvStorage/config/templates/upstart/')
        template_conf = '/opt/OpenvStorage/config/templates/upstart/{0}.conf'

        if not client.file_exists(template_conf.format(name)):
            # Given template doesn't exist so we are probably using system
            # init scripts
            return

        template_file = client.file_read(template_conf.format(name))

        for key, value in params.iteritems():
            template_file = template_file.replace('<{0}>'.format(key), value)
        if '<SERVICE_NAME>' in template_file:
            service_name = name if target_name is None else target_name
            template_file = template_file.replace('<SERVICE_NAME>', Toolbox.remove_prefix(service_name, 'ovs-'))
        template_file = template_file.replace('<_SERVICE_SUFFIX_>', '')

        dependencies = ''
        if additional_dependencies:
            for service in additional_dependencies:
                dependencies += '{0} '.format(service)
        template_file = template_file.replace('<ADDITIONAL_DEPENDENCIES>', dependencies)

        if target_name is None:
            client.file_write('/etc/init/{0}.conf'.format(name), template_file)
        else:
            client.file_write('/etc/init/{0}.conf'.format(target_name), template_file)
示例#9
0
 def extract_dir_structure(directory):
     """
     Builds a dict representing a given directory
     """
     data = {"dirs": {}, "files": []}
     for current_dir, dirs, files in os.walk(directory):
         current_dir = Toolbox.remove_prefix(current_dir, directory)
         if current_dir == "":
             data["dirs"] = dict((entry, {"dirs": {}, "files": []}) for entry in dirs)
             data["files"] = files
         else:
             dir_entries = current_dir.strip("/").split("/")
             pointer = data["dirs"]
             for entry in dir_entries[:-1]:
                 pointer = pointer[entry]["dirs"]
             pointer = pointer[dir_entries[-1]]
             pointer["dirs"] = dict((entry, {"dirs": {}, "files": []}) for entry in dirs)
             pointer["files"] = files
     return data
示例#10
0
    def remove_service(name, client, delay_unregistration=False):
        """
        Remove a service
        :param name: Name of the service to remove
        :type name: str
        :param client: Client on which to remove the service
        :type client: ovs.extensions.generic.sshclient.SSHClient
        :param delay_unregistration: Un-register the service parameters in the config management right away or not
        :type delay_unregistration: bool
        :return: None
        """
        name = Upstart._get_name(name, client)
        run_file_name = '/opt/OpenvStorage/run/{0}.version'.format(Toolbox.remove_prefix(name, 'ovs-'))
        if client.file_exists(run_file_name):
            client.file_delete(run_file_name)
        client.file_delete('/etc/init/{0}.conf'.format(name))

        if delay_unregistration is False:
            Upstart.unregister_service(service_name=name, node_name=System.get_my_machine_id(client))
示例#11
0
    def post_update_core(client, components):
        """
        Execute functionality after the openvstorage core packages have been updated
        For framework:
            * Restart support-agent on every client
            * Restart arakoon-ovsdb on every client (if present and required)
        For storagedriver:
            * ALBA proxies on every client
            * Restart arakoon-voldrv on every client (if present and required)
        :param client: Client on which to execute this post update functionality
        :type client: SSHClient
        :param components: Update components which have been executed
        :type components: list
        :return: None
        """
        if 'framework' not in components and 'storagedriver' not in components:
            return

        update_information = UpdateController.get_update_information_core({})
        services_to_restart = set()
        if 'storagedriver' in components:
            services_to_restart.update(update_information.get('storagedriver', {}).get('services_post_update', set()))
        if 'framework' in components:
            services_to_restart.update(update_information.get('framework', {}).get('services_post_update', set()))
            services_to_restart.add('support-agent')

        if services_to_restart:
            UpdateController._logger.debug('{0}: Executing hook {1}'.format(client.ip, inspect.currentframe().f_code.co_name))
            for service_name in sorted(services_to_restart):
                if not service_name.startswith('ovs-arakoon-'):
                    UpdateController.change_services_state(services=[service_name], ssh_clients=[client], action='restart')
                else:
                    cluster_name = ArakoonClusterConfig.get_cluster_name(ExtensionToolbox.remove_prefix(service_name, 'ovs-arakoon-'))
                    if cluster_name == 'config':
                        arakoon_metadata = ArakoonInstaller.get_arakoon_metadata_by_cluster_name(cluster_name='cacc', filesystem=True, ip=System.get_my_storagerouter().ip)
                    else:
                        arakoon_metadata = ArakoonInstaller.get_arakoon_metadata_by_cluster_name(cluster_name=cluster_name)
                    if arakoon_metadata['internal'] is True:
                        UpdateController._logger.debug('{0}: Restarting arakoon node {1}'.format(client.ip, cluster_name))
                        ArakoonInstaller.restart_node(cluster_name=cluster_name,
                                                      client=client)
            UpdateController._logger.debug('{0}: Executed hook {1}'.format(client.ip, inspect.currentframe().f_code.co_name))
示例#12
0
 def get_candidate_versions(client, package_names):
     """
     Retrieve the versions candidate for installation of the packages provided
     :param client: Root client on which to check the candidate versions
     :type client: ovs.extensions.generic.sshclient.SSHClient
     :param package_names: Name of the packages to check
     :type package_names: list
     :return: Package candidate versions
     :rtype: dict
     """
     DebianPackage.update(client=client)
     versions = {}
     for package_name in package_names:
         versions[package_name] = ''
         for line in client.run(['apt-cache', 'policy', package_name, DebianPackage.APT_CONFIG_STRING]).splitlines():
             line = line.strip()
             if line.startswith('Candidate:'):
                 candidate = Toolbox.remove_prefix(line, 'Candidate:').strip()
                 if candidate == '(none)':
                     candidate = ''
                 versions[package_name] = candidate
                 break
     return versions
示例#13
0
    def remove_service(name, client, delay_unregistration=False):
        """
        Remove a service
        :param name: Name of the service to remove
        :type name: str
        :param client: Client on which to remove the service
        :type client: ovs.extensions.generic.sshclient.SSHClient
        :param delay_unregistration: Un-register the service parameters in the config management right away or not
        :type delay_unregistration: bool
        :return: None
        """
        name = Systemd._get_name(name, client)
        run_file_name = '/opt/OpenvStorage/run/{0}.version'.format(Toolbox.remove_prefix(name, 'ovs-'))
        if client.file_exists(run_file_name):
            client.file_delete(run_file_name)
        try:
            client.run(['systemctl', 'disable', '{0}.service'.format(name)])
        except CalledProcessError:
            pass  # Service already disabled
        client.file_delete('/lib/systemd/system/{0}.service'.format(name))
        client.run(['systemctl', 'daemon-reload'])

        if delay_unregistration is False:
            Systemd.unregister_service(service_name=name, node_name=System.get_my_machine_id(client))
示例#14
0
 def __getattr__(self, item):
     if item.startswith('configure_'):
         section = Toolbox.remove_prefix(item, 'configure_')
         return lambda **kwargs: self._add(section, **kwargs)
示例#15
0
 def __getattr__(self, item):
     if item.startswith('configure_'):
         section = Toolbox.remove_prefix(item, 'configure_')
         return lambda **kwargs: self._add(section, **kwargs)
示例#16
0
    def get_package_information_core(client, package_info):
        """
        Called by GenericController.refresh_package_information() every hour

        Retrieve information about the currently installed versions of the core packages
        Retrieve information about the versions to which each package can potentially be updated
        If installed version is different from candidate version --> store this information in model

        Additionally check the services with a 'run' file
        Verify whether the running version is up-to-date with the candidate version
        If different --> store this information in the model

        Result: Every package with updates or which requires services to be restarted is stored in the model

        :param client: Client on which to collect the version information
        :type client: SSHClient
        :param package_info: Dictionary passed in by the thread calling this function
        :type package_info: dict
        :return: Package information
        :rtype: dict
        """
        try:
            if client.username != 'root':
                raise RuntimeError('Only the "root" user can retrieve the package information')

            binaries = PackageManager.get_binary_versions(client=client, package_names=UpdateController.core_packages_with_binaries)
            installed = PackageManager.get_installed_versions(client=client, package_names=UpdateController.all_core_packages)
            candidate = PackageManager.get_candidate_versions(client=client, package_names=UpdateController.all_core_packages)
            if set(installed.keys()) != set(UpdateController.all_core_packages) or set(candidate.keys()) != set(UpdateController.all_core_packages):
                raise RuntimeError('Failed to retrieve the installed and candidate versions for packages: {0}'.format(', '.join(UpdateController.all_core_packages)))

            # Retrieve Arakoon information
            framework_arakoons = []
            storagedriver_arakoons = []
            for cluster, arakoon_list in {'cacc': framework_arakoons,
                                          'ovsdb': framework_arakoons,
                                          'voldrv': storagedriver_arakoons}.iteritems():
                cluster_name = ArakoonClusterConfig.get_cluster_name(cluster)
                if cluster_name is None:
                    continue

                if cluster == 'cacc':
                    arakoon_metadata = ArakoonInstaller.get_arakoon_metadata_by_cluster_name(cluster_name=cluster_name, filesystem=True, ip=client.ip)
                else:
                    arakoon_metadata = ArakoonInstaller.get_arakoon_metadata_by_cluster_name(cluster_name=cluster_name)

                if arakoon_metadata['internal'] is True:
                    arakoon_list.append(ArakoonInstaller.get_service_name_for_cluster(cluster_name=arakoon_metadata['cluster_name']))

            storagerouter = StorageRouterList.get_by_ip(client.ip)
            alba_proxies = []
            for service in storagerouter.services:
                if service.type.name == ServiceType.SERVICE_TYPES.ALBA_PROXY:
                    alba_proxies.append(service.name)

            storagedriver_services = []
            for sd in storagerouter.storagedrivers:
                storagedriver_services.append('ovs-dtl_{0}'.format(sd.vpool.name))
                storagedriver_services.append('ovs-volumedriver_{0}'.format(sd.vpool.name))

            default_entry = {'candidate': None,
                             'installed': None,
                             'services_to_restart': []}

            #                       component:   package_name: services_with_run_file
            for component, info in {'framework': {'arakoon': framework_arakoons,
                                                  'openvstorage': []},
                                    'storagedriver': {'alba': alba_proxies,
                                                      'arakoon': storagedriver_arakoons,
                                                      'volumedriver-no-dedup-base': [],
                                                      'volumedriver-no-dedup-server': storagedriver_services}}.iteritems():
                component_info = {}
                for package, services in info.iteritems():
                    for service in services:
                        service = ExtensionToolbox.remove_prefix(service, 'ovs-')
                        version_file = '/opt/OpenvStorage/run/{0}.version'.format(service)
                        if not client.file_exists(version_file):
                            UpdateController._logger.warning('{0}: Failed to find a version file in /opt/OpenvStorage/run for service {1}'.format(client.ip, service))
                            continue
                        package_name = package
                        running_versions = client.file_read(version_file).strip()
                        for version in running_versions.split(';'):
                            version = version.strip()
                            running_version = None
                            if '=' in version:
                                package_name = version.split('=')[0]
                                running_version = version.split('=')[1]
                            elif version:
                                running_version = version

                            if package_name not in UpdateController.all_core_packages:
                                raise ValueError('Unknown package dependency found in {0}'.format(version_file))
                            if package_name not in binaries:
                                raise RuntimeError('Binary version for package {0} was not retrieved'.format(package_name))

                            if running_version is not None and running_version != binaries[package_name]:
                                if package_name not in component_info:
                                    component_info[package_name] = copy.deepcopy(default_entry)
                                component_info[package_name]['installed'] = running_version
                                component_info[package_name]['candidate'] = binaries[package_name]
                                component_info[package_name]['services_to_restart'].append('ovs-{0}'.format(service))

                    if installed[package] != candidate[package] and package not in component_info:
                        component_info[package] = copy.deepcopy(default_entry)
                        component_info[package]['installed'] = installed[package]
                        component_info[package]['candidate'] = candidate[package]
                if component_info:
                    if component not in package_info[client.ip]:
                        package_info[client.ip][component] = {}
                    package_info[client.ip][component].update(component_info)
        except Exception as ex:
            if 'errors' not in package_info[client.ip]:
                package_info[client.ip]['errors'] = []
            package_info[client.ip]['errors'].append(ex)
        return package_info
示例#17
0
 def unregister_service(node_name, service_name):
     """
     Un-register the metadata of a service from the configuration management
     :param node_name: Name of the node on which to un-register the service
     :type node_name: str
     :param service_name: Name of the service to clean from the configuration management
     :type service_name: str
     :return: None
     """
     Configuration.delete(key='/ovs/framework/hosts/{0}/services/{1}'.format(node_name, Toolbox.remove_prefix(service_name, 'ovs-')))
示例#18
0
 def register_service(node_name, service_metadata):
     """
     Register the metadata of the service to the configuration management
     :param node_name: Name of the node on which the service is running
     :type node_name: str
     :param service_metadata: Metadata of the service
     :type service_metadata: dict
     :return: None
     """
     service_name = service_metadata['SERVICE_NAME']
     Configuration.set(key='/ovs/framework/hosts/{0}/services/{1}'.format(node_name, Toolbox.remove_prefix(service_name, 'ovs-')),
                       value=service_metadata)
示例#19
0
    def add_service(name,
                    client,
                    params=None,
                    target_name=None,
                    additional_dependencies=None):
        """
        Add a service
        :param name: Name of the service to add
        :type name: str
        :param client: Client on which to add the service
        :type client: SSHClient
        :param params: Additional information about the service
        :type params: dict
        :param target_name: Overrule default name of the service with this name
        :type target_name: str
        :param additional_dependencies: Additional dependencies for this service
        :type additional_dependencies: list
        :return: None
        """
        if params is None:
            params = {}

        name = Systemd._get_name(
            name, client, '/opt/OpenvStorage/config/templates/systemd/')
        template_service = '/opt/OpenvStorage/config/templates/systemd/{0}.service'

        if not client.file_exists(template_service.format(name)):
            # Given template doesn't exist so we are probably using system
            # init scripts
            return

        template_file = client.file_read(template_service.format(name))

        for key, value in params.iteritems():
            template_file = template_file.replace('<{0}>'.format(key), value)
        if '<SERVICE_NAME>' in template_file:
            service_name = name if target_name is None else target_name
            template_file = template_file.replace(
                '<SERVICE_NAME>', Toolbox.remove_prefix(service_name, 'ovs-'))
        template_file = template_file.replace('<_SERVICE_SUFFIX_>', '')

        dependencies = ''
        if additional_dependencies:
            for service in additional_dependencies:
                dependencies += '{0}.service '.format(service)
        template_file = template_file.replace('<ADDITIONAL_DEPENDENCIES>',
                                              dependencies)

        if target_name is None:
            client.file_write('/lib/systemd/system/{0}.service'.format(name),
                              template_file)
        else:
            client.file_write(
                '/lib/systemd/system/{0}.service'.format(target_name),
                template_file)
            name = target_name

        try:
            client.run(['systemctl', 'daemon-reload'])
            client.run(['systemctl', 'enable', '{0}.service'.format(name)])
        except CalledProcessError as cpe:
            output = cpe.output
            Systemd._logger.exception('Add {0}.service failed, {1}'.format(
                name, output))
            raise Exception('Add {0}.service failed, {1}'.format(name, output))