Beispiel #1
0
class DeviceInfoProvider(Provider):
    @description("Returns list of available device classes")
    @returns(h.array(str))
    def get_classes(self):
        return ["disk", "network", "cpu", "usb", "serial_port"]

    @description("Returns list of devices from given class")
    @accepts(str)
    @returns(
        h.any_of(h.ref('DiskDevice'), h.ref('NetworkDevice'),
                 h.ref('CpuDevice'), h.ref('SerialPortDevice'),
                 h.ref('UsbDevice')))
    def get_devices(self, dev_class):
        method = "_get_class_{0}".format(dev_class)
        if hasattr(self, method):
            return getattr(self, method)()

        return None

    def _get_class_disk(self):
        result = []
        geom.scan()
        for child in geom.class_by_name('DISK').geoms:
            result.append({
                "path": os.path.join("/dev", child.name),
                "name": child.name,
                "mediasize": child.provider.mediasize,
                "description": child.provider.config['descr']
            })

        return result

    def _get_class_multipath(self):
        result = []
        geom.scan()
        cls = geom.class_by_name('MULTIPATH')
        if not cls:
            return []

        for child in cls.geoms:
            result.append({
                "path": os.path.join("/dev", child.name),
                "name": child.name,
                "mediasize": child.provider.mediasize,
                "members": [c.provider.name for c in child.consumers]
            })

        return result

    def _get_class_network(self):
        result = []
        for i in list(netif.list_interfaces().keys()):
            if i.startswith(tuple(netif.CLONED_PREFIXES)):
                continue

            try:
                desc = get_sysctl(
                    re.sub('(\\w+)([0-9]+)', 'dev.\\1.\\2.%desc', i))
                result.append({'name': i, 'description': desc})
            except FileNotFoundError:
                continue

        return result

    def _get_class_serial_port(self):
        result = []
        for devices in devinfo.DevInfo().resource_managers['I/O ports'].values(
        ):
            for dev in devices:
                if not dev.name.startswith('uart'):
                    continue
                result.append({
                    'name': dev.name,
                    'description': dev.desc,
                    'drivername': dev.drivername,
                    'location': dev.location,
                    'start': hex(dev.start),
                    'size': dev.size
                })

        return result

    def _get_class_cpu(self):
        result = []
        ncpus = get_sysctl('hw.ncpu')
        model = get_sysctl('hw.model').strip('\x00')
        for i in range(0, ncpus):
            freq = None
            temp = None

            with contextlib.suppress(OSError):
                freq = get_sysctl('dev.cpu.{0}.freq'.format(i)),

            with contextlib.suppress(OSError):
                temp = get_sysctl('dev.cpu.{0}.temperature'.format(i))

            result.append({'name': model, 'freq': freq, 'temperature': temp})

        return result

    def _get_class_usb(self):
        result = []
        context = usb1.USBContext()

        for device in context.getDeviceList():
            result.append({
                'bus': device.getBusNumber(),
                'address': device.getDeviceAddress(),
                'manufacturer': device.getManufacturer(),
                'product': device.getProduct(),
                'vid': device.getVendorID(),
                'pid': device.getProductID(),
                'class': device.getDeviceClass()
            })

        context.exit()
        return result
            raise TaskException(
                errno.EAGAIN, 'Got exception while verifying install: {0}'.format(str(e))
            )
        return {
            'checksum': ed['checksum'],
            'notfound': ed['notfound'],
            'wrongtype': ed['wrongtype'],
            'perm': wl,
            'error': error_flag,
            'warn': warn_flag,
        }


@description("Checks for updates from the update server and downloads them if available")
@accepts(h.any_of(
    bool,
    None,
))
@returns(bool)
class CheckFetchUpdateTask(MasterProgressTask):
    def describe(self):
        return "Checks for updates from the update server and downloads them if available. " +\
               "Returns Ture if updates were found and applied else False"

    def verify(self, mail=False):
        block = self.dispatcher.resource_graph.get_resource(update_resource_string)
        if block is not None and block.busy:
            raise VerifyException(errno.EBUSY, (
                'An Update Operation (Configuration/ Download/ Applying'
                'the Updates) is already in the queue, please retry later'
            ))
Beispiel #3
0
    @returns('zfs-pool')
    def get_config(self):
        return self.dispatcher.call_sync('zfs.pool.get_boot_pool')


@description("Provides information on Boot Environments")
class BootEnvironmentsProvider(Provider):
    @query('boot-environment')
    def query(self, filter=None, params=None):
        return bootenvs.query(*(filter or []), **(params or {}))


@description(
    "Creates a clone of the current Boot Environment or of the specified source (optional)"
)
@accepts(str, h.any_of(str, None))
class BootEnvironmentCreate(Task):
    @classmethod
    def early_describe(cls):
        return "Cloning Boot Environment"

    def describe(self, newname, source=None):
        return TaskDescription("Cloning Boot Environment {source} - new name {name}", name=newname, source=source or '')

    def verify(self, newname, source=None):
        return ['system']

    def run(self, newname, source=None):
        if not CreateClone(newname, bename=source):
            raise TaskException(errno.EIO, 'Cannot create the {0} boot environment'.format(newname))
Beispiel #4
0
        if not gid:
            raise RpcException(errno.ENOSPC, 'No free GIDs available')

        return gid


@description("Create an user in the system")
@accepts(h.all_of(
    h.ref('user'),
    h.required('username'),
    h.forbidden('builtin'),
    h.object(properties={'password': {'type': ['string', 'null']}}),
    h.any_of(
        h.required('password'),
        h.required('unixhash', 'nthash'),
        h.required('password_disabled')
    )
))
class UserCreateTask(Task):
    def __init__(self, dispatcher, datastore):
        super(UserCreateTask, self).__init__(dispatcher, datastore)
        self.id = None
        self.created_group = False

    @classmethod
    def early_describe(cls):
        return "Creating user"

    def describe(self, user):
        return TaskDescription("Adding user {name}", name=user['username'])
        if 'system_time' in props:
            timestamp = time.mktime(parser.parse(props['system_time']))
            bsd.clock_settime(bsd.ClockType.REALTIME, timestamp)

        if 'timezone' in props:
            self.configstore.set('system.timezone', props['timezone'])
            try:
                self.dispatcher.call_sync('etcd.generation.generate_group', 'localtime')
            except RpcException as e:
                raise TaskException(
                    errno.ENXIO,
                    'Cannot reconfigure system time: {0}'.format(str(e))
                )


@accepts(h.any_of(int, None))
@description("Reboots the System")
class SystemRebootTask(Task):
    def __init__(self, dispatcher, datastore):
        super(SystemRebootTask, self).__init__(dispatcher, datastore)
        self.finish_event = Event()
        self.abort_flag = False

    def describe(self, delay=None):
        return "System Reboot"

    def verify(self, delay=None):
        return ['root']

    def reboot_now(self):
        time.sleep(1)
        if 'system_time' in props:
            timestamp = time.mktime(parser.parse(props['system_time']))
            bsd.clock_settime(bsd.ClockType.REALTIME, timestamp)

        if 'timezone' in props:
            self.configstore.set('system.timezone', props['timezone'])
            try:
                self.dispatcher.call_sync('etcd.generation.generate_group',
                                          'localtime')
            except RpcException as e:
                raise TaskException(
                    errno.ENXIO,
                    'Cannot reconfigure system time: {0}'.format(str(e)))


@accepts(h.any_of(int, None))
@description("Reboots the System")
class SystemRebootTask(Task):
    def __init__(self, dispatcher):
        super(SystemRebootTask, self).__init__(dispatcher)
        self.finish_event = Event()
        self.abort_flag = False

    @classmethod
    def early_describe(cls):
        return 'Rebooting system'

    def describe(self, delay=None):
        return TaskDescription('Rebooting system with delay {delay} seconds',
                               delay=delay or 0)
Beispiel #7
0
            node.update(openvpn)
			
            self.dispatcher.call_sync('etcd.generation.generate_group', 'openvpn')
            self.dispatcher.dispatch_event('service.openvpn.changed', {
                'operation': 'update',
                'ids': None,
            })

        except RpcException as e:
            raise TaskException(errno.ENXIO,
                                'Cannot reconfigure OpenVPN: {0}'.format(str(e)))

        return 'RESTART'


@accepts(str, h.any_of(int, None))
@description('Generates Diffie-Hellman parameters and tls-auth key file')
class OpenVPNGenerateKeys(Task):
    ''' To get it working properly you need to set appropriate timeout on dipatcher client.
        Generation of 2048 bit dh parameters can take a long time.
        Maybe this task should be ProgressTask type? - need consultation on that 
    '''
    @classmethod
    def early_describe(cls):
        return 'Generating OpenVPN cryptographic parameters'

    def describe(self, key_type, key_length):
        return TaskDescription('Generating {key_type} OpenVPN cryptographic values', key_type=key_type)

    def verify(self, key_type, key_length):
        if key_type not in ['dh-parameters', 'tls-auth-key']:
Beispiel #8
0

@accepts(str)
class ZpoolDestroyTask(ZpoolBaseTask):
    def run(self, name):
        try:
            zfs = libzfs.ZFS()
            zfs.destroy(name)
        except libzfs.ZFSException as err:
            raise TaskException(errno.EFAULT, str(err))


@accepts(
    str,
    h.any_of(
        h.ref('zfs-topology'),
        None
    ),
    h.any_of(
        h.array(h.ref('zfs-vdev-extension')),
        None
    )
)
class ZpoolExtendTask(ZpoolBaseTask):
    def __init__(self, dispatcher, datastore):
        super(ZpoolExtendTask, self).__init__(dispatcher, datastore)
        self.pool = None
        self.started = False

    def run(self, pool, new_vdevs, updated_vdevs):
        try:
            self.pool = pool
Beispiel #9
0
class UpdateProvider(Provider):
    @accepts()
    @returns(str)
    def is_update_available(self):
        temp_available = update_cache.get('available', timeout=1)
        if temp_available is not None:
            return temp_available
        elif update_cache.is_valid('available'):
            return temp_available
        else:
            raise RpcException(
                errno.EBUSY,
                ('Update Availability flag is invalidated, an Update Check'
                 ' might be underway. Try again in some time.'))

    @accepts()
    @returns(h.array(str))
    def obtain_changelog(self):
        temp_changelog = update_cache.get('changelog', timeout=1)
        if temp_changelog is not None:
            return temp_changelog
        elif update_cache.is_valid('changelog'):
            return temp_changelog
        else:
            raise RpcException(
                errno.EBUSY, ('Changelog list is invalidated, an Update Check '
                              'might be underway. Try again in some time.'))

    @accepts()
    @returns(h.array(h.ref('update-ops')))
    def get_update_ops(self):
        temp_operations = update_cache.get('operations', timeout=1)
        if temp_operations is not None:
            return temp_operations
        elif update_cache.is_valid('operations'):
            return temp_operations
        else:
            raise RpcException(
                errno.EBUSY,
                ('Update Operations Dict is invalidated, an Update Check '
                 'might be underway. Try again in some time.'))

    @accepts()
    @returns(h.ref('update-info'))
    def update_info(self):
        if not update_cache.is_valid('available'):
            raise RpcException(
                errno.EBUSY,
                ('Update Availability flag is invalidated, an Update Check'
                 ' might be underway. Try again in some time.'))
        info_item_list = [
            'available', 'changelog', 'notes', 'notice', 'operations',
            'downloaded', 'version', 'installed', 'installed_version'
        ]
        return {
            key: update_cache.get(key, timeout=1)
            for key in info_item_list
        }

    @returns(h.any_of(
        h.array(h.ref('update-train')),
        None,
    ))
    def trains(self):
        conf = Configuration.Configuration()
        conf.LoadTrainsConfig()
        trains = conf.AvailableTrains()

        if trains is None:
            logger.debug(
                'The AvailableTrains call returned None. Check your network connection'
            )
            return None
        seltrain = self.dispatcher.configstore.get('update.train')

        data = []
        for name in list(trains.keys()):
            if name in conf._trains:
                train = conf._trains.get(name)
            else:
                train = Train.Train(name)
            data.append({
                'name': train.Name(),
                'description': train.Description(),
                'sequence': train.LastSequence(),
                'current': True if name == seltrain else False,
            })
        return data

    @accepts()
    @returns(str)
    def get_current_train(self):
        conf = Configuration.Configuration()
        conf.LoadTrainsConfig()
        return conf.CurrentTrain()

    @accepts()
    @returns(h.ref('update'))
    def get_config(self):
        return {
            'train': self.dispatcher.configstore.get('update.train'),
            'check_auto': self.dispatcher.configstore.get('update.check_auto'),
            'update_server': Configuration.Configuration().UpdateServerURL(),
        }

    @private
    @accepts(h.array(str))
    def update_cache_invalidate(self, value_list):
        for item in value_list:
            update_cache.invalidate(item)

    @private
    @accepts(h.object())
    def update_cache_putter(self, value_dict):
        for key, value in value_dict.items():
            update_cache.put(key, value)
        self.dispatcher.dispatch_event('update.update_info.updated',
                                       {'operation': 'update'})

    @private
    @accepts(str)
    @returns(h.any_of(None, str, bool, h.array(str)))
    def update_cache_getter(self, key):
        return update_cache.get(key, timeout=1)

    @private
    @accepts(str, str, h.any_of(None, h.object(additionalProperties=True)))
    def update_alert_set(self, update_class, update_version, kwargs=None):
        # Formulating a query to find any alerts in the current `update_class`
        # which could be either of ('UpdateAvailable', 'UpdateDownloaded', 'UpdateInstalled')
        # as well as any alerts for the specified update version string.
        # The reason I do this is because say an Update is Downloaded (FreeNAS-10-2016051047)
        # and there is either a previous alert for an older downloaded update OR there is a
        # previous alert for the same version itself but for it being available instead of being
        # downloaded already, both of these previous alerts would need to be cancelled and
        # replaced by 'UpdateDownloaded' for FreeNAS-10-2016051047.
        if kwargs is None:
            kwargs = {}
        existing_update_alerts = self.dispatcher.call_sync(
            'alert.query', [('and', [('active', '=', True),
                                     ('dismissed', '=', False)]),
                            ('or', [('class', '=', update_class),
                                    ('target', '=', update_version)])])
        title = UPDATE_ALERT_TITLE_MAP.get(update_class, 'Update Alert')
        desc = kwargs.get('desc')
        if desc is None:
            if update_class == 'UpdateAvailable':
                desc = 'Latest Update: {0} is available for download'.format(
                    update_version)
            elif update_class == 'UpdateDownloaded':
                desc = 'Update containing {0} is downloaded and ready for install'.format(
                    update_version)
            elif update_class == 'UpdateInstalled':
                update_installed_bootenv = kwargs.get(
                    'update_installed_bootenv')
                if update_installed_bootenv and not update_installed_bootenv[
                        0]['on_reboot']:
                    desc = 'Update containing {0} is installed.'.format(
                        update_version)
                    desc += ' Please activate {0} and Reboot to use this updated version'.format(
                        update_installed_bootenv[0]['realname'])
                else:
                    desc = 'Update containing {0} is installed and activated for next boot'.format(
                        update_version)
            else:
                # what state is this?
                raise RpcException(
                    errno.EINVAL,
                    'Unknown update alert class: {0}'.format(update_class))
        alert_payload = {
            'class': update_class,
            'title': title,
            'target': update_version,
            'description': desc
        }

        alert_exists = False
        # Purposely deleting stale alerts later on since if anything (in constructing the payload)
        # above this fails the exception prevents alert.cancel from being called.
        for update_alert in existing_update_alerts:
            if (update_alert['class'] == update_class
                    and update_alert["target"] == update_version
                    and update_alert["description"] == desc):
                alert_exists = True
                continue
            self.dispatcher.call_sync('alert.cancel', update_alert['id'])

        if not alert_exists:
            self.dispatcher.call_sync('alert.emit', alert_payload)
Beispiel #10
0
            node.update(openvpn_updated)

            self.dispatcher.call_sync('etcd.generation.generate_group', 'openvpn')
            self.dispatcher.dispatch_event('service.openvpn.changed', {
                'operation': 'update',
                'ids': None,
            })

        except RpcException as e:
            raise TaskException(errno.ENXIO,
                                'Cannot reconfigure OpenVPN: {0}'.format(str(e)))

        return 'RESTART'


@accepts(str, h.any_of(int, None))
@description('Generates Diffie-Hellman parameters and tls-auth key file')
class OpenVPNGenerateKeys(Task):
    """ To get it working properly you need to set appropriate timeout on dipatcher client.
        Generation of 2048 bit dh parameters can take a long time.
        Maybe this task should be ProgressTask type? - need consultation on that
    """
    @classmethod
    def early_describe(cls):
        return 'Generating OpenVPN cryptographic parameters'

    def describe(self, key_type, key_length):
        return TaskDescription('Generating {key_type} OpenVPN cryptographic values', key_type=key_type)

    def verify(self, key_type, key_length):
        if key_type not in ['dh-parameters', 'tls-auth-key']:
Beispiel #11
0
        return True


@description("Provides information on Boot Environments")
class BootEnvironmentsProvider(Provider):
    @query('BootEnvironment')
    @generator
    def query(self, filter=None, params=None):
        return bootenvs.query(*(filter or []), stream=True, **(params or {}))


@description(
    "Creates a clone of the current Boot Environment or of the specified source (optional)"
)
@accepts(str, h.any_of(str, None))
class BootEnvironmentCreate(Task):
    @classmethod
    def early_describe(cls):
        return "Cloning Boot Environment"

    def describe(self, newname, source=None):
        return TaskDescription(
            "Cloning Boot Environment {source} - new name {name}",
            name=newname,
            source=source or '')

    def verify(self, newname, source=None):
        return ['system']

    def run(self, newname, source=None):
Beispiel #12
0
        if not gid:
            raise RpcException(errno.ENOSPC, 'No free GIDs available')

        return gid


@description("Create an user in the system")
@accepts(h.all_of(
    h.ref('User'),
    h.required('username'),
    h.forbidden('builtin'),
    h.object(properties={'password': {'type': ['password', 'null']}}),
    h.any_of(
        h.required('password'),
        h.required('unixhash', 'nthash'),
        h.required('password_disabled')
    )
))
class UserCreateTask(Task):
    def __init__(self, dispatcher):
        super(UserCreateTask, self).__init__(dispatcher)
        self.id = None
        self.created_group = False

    @classmethod
    def early_describe(cls):
        return "Creating user"

    def describe(self, user):
        return TaskDescription("Adding user {name}", name=user['username'])