def migrate(cls):
        # type: () -> None
        """
        Execute the migration logic.
        :return: None
        :rtype: NoneType
        """
        with file_mutex('package_update_pu'):
            local_client = SSHClient(endpoint='127.0.0.1', username='******')

            # Override the created openvstorage_sdm_id during package install, with currently available SDM ID
            if local_client.file_exists(BOOTSTRAP_FILE):
                with open(BOOTSTRAP_FILE) as bstr_file:
                    node_id = json.load(bstr_file)['node_id']
                local_client.file_write(filename='/etc/openvstorage_sdm_id',
                                        contents=node_id + '\n')
            else:
                with open('/etc/openvstorage_sdm_id', 'r') as id_file:
                    node_id = id_file.read().strip()

            key = '{0}/versions'.format(
                ASD_NODE_CONFIG_LOCATION.format(node_id))
            version = Configuration.get(key) if Configuration.exists(
                key) else 0

            asd_manager_service_name = 'asd-manager'
            if cls.service_manager.has_service(
                    asd_manager_service_name,
                    local_client) and cls.service_manager.get_service_status(
                        asd_manager_service_name, local_client) == 'active':
                cls.logger.info('Stopping asd-manager service')
                cls.service_manager.stop_service(asd_manager_service_name,
                                                 local_client)

            # @TODO: Move these migrations to alba_node.client.update_execute_migration_code()
            if version < cls.CURRENT_VERSION:
                try:
                    # DB migrations
                    from source.controllers.asd import ASDController
                    from source.controllers.disk import DiskController
                    from source.dal.asdbase import ASDBase
                    from source.dal.lists.asdlist import ASDList
                    from source.dal.lists.disklist import DiskList
                    from source.dal.objects.asd import ASD

                    if not local_client.file_exists('{0}/main.db'.format(
                            ASDBase.DATABASE_FOLDER)):
                        local_client.dir_create([ASDBase.DATABASE_FOLDER])

                    asd_map = dict(
                        (asd.asd_id, asd) for asd in ASDList.get_asds())
                    DiskController.sync_disks()
                    for disk in DiskList.get_usable_disks():
                        if disk.state == 'MISSING' or disk.mountpoint is None:
                            continue
                        for asd_id in local_client.dir_list(disk.mountpoint):
                            if asd_id in asd_map:
                                asd = asd_map[asd_id]
                            else:
                                asd = ASD()

                            asd.disk = disk
                            asd.asd_id = asd_id
                            asd.folder = asd_id
                            if asd.has_config:
                                if asd.port is None or asd.hosts is None:
                                    config = Configuration.get(
                                        key=asd.config_key)
                                    asd.port = config['port']
                                    asd.hosts = config.get('ips', [])
                                asd.save()

                    # Adjustment of open file descriptors for ASD/maintenance services to 8192
                    asd_service_names = list(ASDController.list_asd_services())
                    maintenance_service_names = list(
                        MaintenanceController.get_services())
                    for service_name in asd_service_names + maintenance_service_names:
                        if cls.service_manager.has_service(
                                name=service_name, client=local_client):
                            if cls.service_manager.__class__ == Systemd:
                                path = '/lib/systemd/system/{0}.service'.format(
                                    service_name)
                                check = 'LimitNOFILE=8192'
                            else:
                                path = '/etc/init/{0}.conf'.format(
                                    service_name)
                                check = 'limit nofile 8192 8192'

                            restart_required = False
                            if os.path.exists(path):
                                with open(path, 'r') as system_file:
                                    if check not in system_file.read():
                                        restart_required = True

                            if restart_required is False:
                                continue

                            configuration_key = ServiceFactory.SERVICE_CONFIG_KEY.format(
                                node_id, service_name)
                            if Configuration.exists(configuration_key):
                                # Rewrite the service file
                                cls.service_manager.add_service(
                                    name=ASDController.ASD_PREFIX
                                    if service_name in asd_service_names else
                                    MaintenanceController.MAINTENANCE_PREFIX,
                                    client=local_client,
                                    params=Configuration.get(
                                        configuration_key),
                                    target_name=service_name)

                                # Let the update know that the ASD / maintenance services need to be restarted
                                # Inside `if Configuration.exists`, because useless to rapport restart if we haven't rewritten service file
                                ExtensionsToolbox.edit_version_file(
                                    client=local_client,
                                    package_name='alba',
                                    old_run_file='{0}/{1}.version'.format(
                                        ServiceFactory.RUN_FILE_DIR,
                                        service_name))
                        if cls.service_manager.__class__ == Systemd:
                            local_client.run(['systemctl', 'daemon-reload'])

                    # Version 3: Addition of 'ExecReload' for ASD/maintenance SystemD services
                    if cls.service_manager.__class__ == Systemd:  # Upstart does not have functionality to reload a process' configuration
                        reload_daemon = False
                        asd_service_names = list(
                            ASDController.list_asd_services())
                        maintenance_service_names = list(
                            MaintenanceController.get_services())
                        for service_name in asd_service_names + maintenance_service_names:
                            if not cls.service_manager.has_service(
                                    name=service_name, client=local_client):
                                continue

                            path = '/lib/systemd/system/{0}.service'.format(
                                service_name)
                            if os.path.exists(path):
                                with open(path, 'r') as system_file:
                                    if 'ExecReload' not in system_file.read():
                                        reload_daemon = True
                                        configuration_key = ServiceFactory.SERVICE_CONFIG_KEY.format(
                                            node_id, service_name)
                                        if Configuration.exists(
                                                configuration_key):
                                            # No need to edit the service version file, since this change only requires a daemon-reload
                                            cls.service_manager.add_service(
                                                name=ASDController.ASD_PREFIX
                                                if service_name
                                                in asd_service_names else
                                                MaintenanceController.
                                                MAINTENANCE_PREFIX,
                                                client=local_client,
                                                params=Configuration.get(
                                                    configuration_key),
                                                target_name=service_name)
                        if reload_daemon is True:
                            local_client.run(['systemctl', 'daemon-reload'])

                    # Version 6: Introduction of Active Drive
                    all_local_ips = OSFactory.get_manager().get_ip_addresses(
                        client=local_client)
                    for asd in ASDList.get_asds():
                        if asd.has_config:
                            asd_config = Configuration.get(asd.config_key)
                            if 'multicast' not in asd_config:
                                asd_config['multicast'] = None
                            if 'ips' in asd_config:
                                asd_ips = asd_config['ips'] or all_local_ips
                            else:
                                asd_ips = all_local_ips
                            asd.hosts = asd_ips
                            asd_config['ips'] = asd_ips
                            Configuration.set(asd.config_key, asd_config)
                            asd.save()

                    # Version 7: Moving flask certificate files to config dir
                    for file_name in [
                            'passphrase', 'server.crt', 'server.csr',
                            'server.key'
                    ]:
                        if local_client.file_exists(
                                '/opt/asd-manager/source/{0}'.format(
                                    file_name)):
                            local_client.file_move(
                                source_file_name='/opt/asd-manager/source/{0}'.
                                format(file_name),
                                destination_file_name=
                                '/opt/asd-manager/config/{0}'.format(
                                    file_name))
                except:
                    cls.logger.exception(
                        'Error while executing post-update code on node {0}'.
                        format(node_id))
            Configuration.set(key, cls.CURRENT_VERSION)

            if cls.service_manager.has_service(
                    asd_manager_service_name,
                    local_client) and cls.service_manager.get_service_status(
                        asd_manager_service_name, local_client) != 'active':
                cls.logger.info('Starting asd-manager service')
                cls.service_manager.start_service(asd_manager_service_name,
                                                  local_client)

        cls.logger.info('Post-update logic executed')
Example #2
0
def setup():
    """
    Interactive setup part for initial asd manager configuration
    """
    _print_and_log(message=Interactive.boxed_message(['ASD Manager setup']))

    # Gather information
    ipaddresses = OSFactory.get_manager().get_ip_addresses()
    if not ipaddresses:
        _print_and_log(
            level='error',
            message='\n' + Interactive.boxed_message(
                ['Could not retrieve IP information on local node']))
        sys.exit(1)
    validation_ip_addresses = copy.deepcopy(ipaddresses)

    local_client = SSHClient(endpoint='127.0.0.1', username='******')
    service_manager = ServiceFactory.get_manager()
    if service_manager.has_service(MANAGER_SERVICE, local_client):
        _print_and_log(level='error',
                       message='\n' + Interactive.boxed_message(
                           ['The ASD Manager is already installed.']))
        sys.exit(1)

    config = _validate_and_retrieve_pre_config()
    interactive = len(config) == 0
    ipmi_info = {'ip': None, 'username': None, 'pwd': None}

    if interactive is False:
        api_ip = config['api_ip']
        api_port = config.get('api_port', 8500)
        asd_ips = config.get('asd_ips', [])
        asd_start_port = config.get('asd_start_port', 8600)
        configuration_store = config.get('configuration_store', 'arakoon')
        ipmi_info = config.get('ipmi', ipmi_info)
    else:
        api_ip = Interactive.ask_choice(
            choice_options=ipaddresses,
            question='Select the public IP address to be used for the API',
            sort_choices=True)
        api_port = Interactive.ask_integer(
            question="Select the port to be used for the API",
            min_value=1025,
            max_value=65535,
            default_value=8500)
        asd_ips = []
        add_ips = True
        ipaddresses.append('All')
        while add_ips:
            current_ips = ' - Current selected IPs: {0}'.format(asd_ips)
            new_asd_ip = Interactive.ask_choice(
                choice_options=ipaddresses,
                question=
                "Select an IP address to be used for the ASDs or 'All' (All current and future interfaces: 0.0.0.0){0}"
                .format(current_ips if len(asd_ips) > 0 else ''),
                default_value='All')
            if new_asd_ip == 'All':
                ipaddresses.remove('All')
                asd_ips = [
                ]  # Empty list maps to all IPs - checked when configuring ASDs
                add_ips = False
            else:
                asd_ips.append(new_asd_ip)
                ipaddresses.remove(new_asd_ip)
                add_ips = Interactive.ask_yesno(
                    "Do you want to add another IP?")
        asd_start_port = Interactive.ask_integer(
            question="Select the port to be used for the ASDs",
            min_value=1025,
            max_value=65435,
            default_value=8600)
        configuration_store = 'arakoon'

        message = 'Do you want to set IPMI configuration keys?'
        proceed = Interactive.ask_yesno(message=message, default_value=False)
        if proceed is True:
            ipmi_info['ip'] = Interactive.ask_string(
                message='Enter the IPMI IP address',
                regex_info={'regex': ExtensionsToolbox.regex_ip})
            ipmi_info['username'] = Interactive.ask_string(
                message='Enter the IPMI username')
            ipmi_info['pwd'] = Interactive.ask_password(
                message='Enter the IPMI password')

    if api_ip not in validation_ip_addresses:
        _print_and_log(
            level='error',
            message='\n' + Interactive.boxed_message(lines=[
                'Invalid API IP {0} specified. Please choose from:'.format(
                    api_ip)
            ] + ['  * {0}'.format(ip) for ip in ipaddresses]))
        sys.exit(1)
    different_ips = set(asd_ips).difference(set(validation_ip_addresses))
    if different_ips:
        _print_and_log(
            level='error',
            message='\n' + Interactive.boxed_message(lines=[
                'Invalid ASD IPs {0} specified. Please choose from:'.format(
                    asd_ips)
            ] + ['  * {0}'.format(ip) for ip in ipaddresses]))
        sys.exit(1)

    if api_port in range(asd_start_port, asd_start_port + 100):
        _print_and_log(
            level='error',
            message='\n' + Interactive.boxed_message(
                ['API port cannot be in the range of the ASD port + 100']))
        sys.exit(1)

    if interactive is True:
        while not local_client.file_exists(CACC_LOCATION):
            _print_and_log(
                level='warning',
                message=
                ' - Please place a copy of the Arakoon\'s client configuration file at: {0}'
                .format(CACC_LOCATION))
            Interactive.ask_continue()

    local_client.file_write(filename=CONFIG_STORE_LOCATION,
                            contents=json.dumps(
                                {'configuration_store': configuration_store},
                                indent=4))

    node_id = Configuration.initialize(
        config={
            'api_ip': api_ip,
            'asd_ips': asd_ips,
            'api_port': api_port,
            'asd_start_port': asd_start_port,
            'ipmi': ipmi_info
        })

    # Model settings
    _print_and_log(message=' - Store settings in DB')
    for code, value in {
            'api_ip': api_ip,
            'api_port': api_port,
            'configuration_store': configuration_store,
            'node_id': node_id
    }.iteritems():
        setting = Setting()
        setting.code = code
        setting.value = value
        setting.save()

    # Deploy/start services
    _print_and_log(message=' - Deploying and starting services')
    service_manager.add_service(name=MANAGER_SERVICE, client=local_client)
    service_manager.add_service(name=WATCHER_SERVICE, client=local_client)
    _print_and_log(message=' - Starting watcher service')
    try:
        service_manager.start_service(name=WATCHER_SERVICE,
                                      client=local_client)
    except Exception:
        Configuration.uninitialize()
        _print_and_log(level='exception',
                       message='\n' +
                       Interactive.boxed_message(['Starting watcher failed']))
        sys.exit(1)

    _print_and_log(message='\n' +
                   Interactive.boxed_message(['ASD Manager setup completed']))