Пример #1
0
    def test_key_prefix_correct(self):
        kv = KVAdapter()
        kv.kv_put = MagicMock()

        storage = OffsetStorage('my-node' , key_prefix='bq-delivered', kv=kv)
        storage.mark_last_read(150)

        kv.kv_put.assert_called_with('bq-delivered/my-node', '150')
Пример #2
0
    def test_key_prefix_used_everywhere(self):
        kv = KVAdapter()
        kv.kv_put = MagicMock()
        kv.kv_get = MagicMock(side_effect=[{'Value': '120'}])

        storage = OffsetStorage('server1' , key_prefix='somequeue', kv=kv)
        storage.mark_last_read(120)
        epoch = storage.get_last_read_epoch()

        kv.kv_put.assert_called_with('somequeue/server1', '120')
        kv.kv_get.assert_called_with('somequeue/server1')
        self.assertEqual(120, epoch)
Пример #3
0
class Utils:
    def __init__(self, provider: ValueProvider):
        self.provider = provider
        self.kv = KVAdapter()

    @func_log(func_enter, func_leave)
    def get_hostname(self, machine_id: str) -> str:
        """
        Returns the hostname of the given machine_id according to the given
        ConfStore (ValueProvider).
        """

        store = self.provider
        hostname = store.get(
            f'node>{machine_id}>network>data>private_fqdn', allow_null=True)
        return hostname or store.get(f'node>{machine_id}>hostname')

    @func_log(func_enter, func_leave)
    def get_local_hostname(self) -> str:
        """
        Retrieves the machine-id of the node where the code runs and fetches
        its hostname from the ConfStore (ValueProvider).
        """
        store = self.provider
        machine_id = store.get_machine_id()
        return self.get_hostname(machine_id)

    @func_log(func_enter, func_leave)
    @repeat_if_fails()
    def save_node_facts(self):
        hostname = self.get_local_hostname()
        cmd = ['facter', '--json', 'processorcount', 'memorysize_mb']
        node_facts = execute(cmd)
        self.kv.kv_put(f'{hostname}/facts', node_facts)

    @func_log(func_enter, func_leave)
    @repeat_if_fails()
    def get_node_facts(self):
        hostname = self.get_local_hostname()
        node_facts = None
        node_facts_val = None
        while (not node_facts or node_facts is None):
            try:
                node_facts = self.kv.kv_get(f'{hostname}/facts')
                node_facts_val = json.loads(node_facts['Value'])
            except TypeError:
                logging.info('%s facts not available yet, retrying...',
                             hostname)
                sleep(2)
                continue
        return node_facts_val

    @func_log(func_enter, func_leave)
    def get_data_devices(self, machine_id: str, cvg: int) -> DList[Text]:
        data_devices = DList(
            [Text(device) for device in self.provider.get(
                f'node>{machine_id}>'
                f'storage>cvg[{cvg}]>devices>data')], 'List Text')
        return data_devices

    @func_log(func_enter, func_leave)
    def _get_drive_info_form_os(self, path: str) -> Disk:
        drive_size = 0
        with open(path, 'rb') as f:
            drive_size = f.seek(0, io.SEEK_END)
        return Disk(path=Maybe(Text(path), 'Text'),
                    size=Maybe(drive_size, 'Natural'),
                    blksize=Maybe(os.stat(path).st_blksize, 'Natural'))

    @func_log(func_enter, func_leave)
    @repeat_if_fails()
    def _save_drive_info(self, path: str):
        disk: Disk = self._get_drive_info_form_os(path)
        hostname = self.get_local_hostname()
        drive_info = json.dumps({'path': disk.path.get().s,
                                 'size': int(disk.size.get()),
                                 'blksize': int(disk.blksize.get())})
        disk_key = path.strip('/')
        self.kv.kv_put(f'{hostname}/drives/{disk_key}', drive_info)

    @func_log(func_enter, func_leave)
    @repeat_if_fails()
    def save_log_path(self):
        hostname = self.get_local_hostname()
        machine_id = self.provider.get_machine_id()
        log_key = self.provider.get('cortx>common>storage>log')
        log_path = log_key + LOG_DIR_EXT + machine_id
        self.kv.kv_put(f'{hostname}/log_path', log_path)

    @func_log(func_enter, func_leave)
    def is_motr_io_present(self, machine_id: str) -> bool:
        """
        Returns True if motr component is present in the components list
        for the given node>{machine_id}.
        """
        return self.is_component_and_service(machine_id,
                                             Const.COMPONENT_MOTR.value,
                                             Const.SERVICE_MOTR_IO.value)

    @func_log(func_enter, func_leave)
    def is_component(self, machine_id: str, name: str) -> bool:
        """
        Returns True if the given component is present in the components
        list for the given node>{machine_id} according to the
        ConfStore (ValueProvider).
        """
        comp_names = self.provider.get(f'node>{machine_id}>'
                                       f'components')
        found = False
        for component in comp_names:
            if(component.get('name') == name):
                found = True
                break
        return found

    @func_log(func_enter, func_leave)
    def is_component_and_service(self, machine_id: str,
                                 comp_name: str, svc_name: str) -> bool:
        """
        Returns True if the given service and component is present in the
        components list for the given node>{machine_id} according to the
        ConfStore (ValueProvider).
        """
        return self.is_component(machine_id, comp_name) and \
            self.is_service(machine_id, svc_name)

    @func_log(func_enter, func_leave)
    def is_component_or_service(self, machine_id: str, name: str) -> bool:
        """
        Returns True if the given service or component is present in the
        components list for the given node>{machine_id} according to the
        ConfStore (ValueProvider).
        """
        return self.is_component(machine_id, name) or \
            self.is_service(machine_id, name)

    @func_log(func_enter, func_leave)
    def is_service(self, machine_id: str, svc_name: str) -> bool:
        """
        Returns True if the given service is present in the components
        list for the given node>{machine_id} according to the
        ConfStore (ValueProvider).
        """
        comp_names = self.provider.get(f'node>{machine_id}>'
                                       f'components')
        found: bool = False
        for component in comp_names:
            svc_names = component.get('services')
            if svc_names:
                for service in svc_names:
                    if(service == svc_name):
                        found = True
                        break
        return found

    @func_log(func_enter, func_leave)
    def save_drives_info(self):
        machine_id = self.provider.get_machine_id()
        if(self.is_motr_io_present(machine_id)):
            cvgs_key: str = f'node>{machine_id}>storage>cvg'
            for cvg in range(len(self.provider.get(cvgs_key))):
                data_devs = self.get_data_devices(machine_id, cvg)
                for dev_path in data_devs.value:
                    self._save_drive_info(dev_path.s)

    @func_log(func_enter, func_leave)
    @repeat_if_fails()
    def get_drive_info_from_consul(self, path: Text, machine_id: str) -> Disk:
        hostname = self.get_hostname(machine_id)
        disk_path = json.loads(str(path)).lstrip(os.sep)
        drive_data = None
        drive_info = None
        while (not drive_data or drive_data is None):
            try:
                drive_data = self.kv.kv_get(f'{hostname}/drives/{disk_path}')
                drive_info = json.loads(drive_data['Value'])
            except TypeError:
                logging.info('%s details are not available yet, retrying...',
                             disk_path)
                sleep(2)
                continue
        return (Disk(path=Maybe(path, 'Text'),
                     size=Maybe(drive_info['size'], 'Natural'),
                     blksize=Maybe(drive_info['blksize'], 'Natural')))

    @func_log(func_enter, func_leave)
    def get_drives_info_for(self, cvg: int, machine_id: str) -> DList[Disk]:
        data_devs = self.get_data_devices(machine_id, cvg)
        return DList([self.get_drive_info_from_consul(dev_path, machine_id)
                      for dev_path in data_devs.value], 'List Disk')

    @func_log(func_enter, func_leave)
    def import_kv(self, conf_dir_path: str):
        with open(f'{conf_dir_path}/consul-kv.json') as f:
            data = json.load(f)
            for item in data:
                item_data = json.loads(json.dumps(item))
                self.kv.kv_put(item_data['key'],
                               str(item_data['value']))

    @func_log(func_enter, func_leave)
    def copy_conf_files(self, conf_dir_path: str):
        machine_id = self.provider.get_machine_id()
        global_config_path = self.provider.get('cortx>common>storage>local')

        dest_motr = f'{global_config_path}/motr/sysconfig/{machine_id}'
        os.makedirs(dest_motr, exist_ok=True)

        cmd = ['/opt/seagate/cortx/hare/libexec/node-name',
               '--conf-dir', conf_dir_path]
        node_name = execute(cmd)

        copy_tree(f'{conf_dir_path}/sysconfig/motr/{node_name}', dest_motr)

        with open(f'{conf_dir_path}/consul-kv.json') as f:
            data = json.load(f)
            for item in data:
                item_data = json.loads(json.dumps(item))
                if item_data['key'] == 'm0_client_types':
                    m0_client_types = item_data['value']
                    break

        for client_type in json.loads(m0_client_types):
            src = f'{conf_dir_path}/sysconfig/{client_type}/{node_name}'
            dest = f'{global_config_path}/{client_type}/sysconfig/{machine_id}'
            os.makedirs(dest, exist_ok=True)
            copy_tree(src, dest)

        shutil.copyfile(
            f'{conf_dir_path}/confd.xc',
            f'{dest_motr}/confd.xc')

    @func_log(func_enter, func_leave)
    def copy_consul_files(self, conf_dir_path: str, mode: str):
        shutil.copyfile(
            f'{conf_dir_path}/consul-{mode}-conf/consul-{mode}-conf.json',
            f'{conf_dir_path}/consul/config/consul-{mode}-conf.json')

    @func_log(func_enter, func_leave)
    def stop_hare(self):
        self.hare_stop = True

    @func_log(func_enter, func_leave)
    def is_hare_stopping(self) -> bool:
        return self.hare_stop

    @func_log(func_enter, func_leave)
    def get_transport_type(self) -> str:
        transport_type = self.provider.get(
            'cortx>motr>transport_type',
            allow_null=True)
        if transport_type is None:
            return 'libfab'
        return transport_type

    @func_log(func_enter, func_leave)
    @repeat_if_fails()
    def save_config_path(self, path: str):
        self.kv.kv_put('config_path', path)