예제 #1
0
    def clean(self, data):
        data = super().clean(data)

        if data is None:
            if self.null:
                return None

            return copy.deepcopy(self.default)

        if not isinstance(data, dict):
            raise Error(self.name, 'A dict was expected')

        verrors = ValidationErrors()
        for key, value in list(data.items()):
            if not self.additional_attrs:
                if key not in self.attrs:
                    verrors.add(f'{self.name}.{key}', 'Field was not expected')
                    continue

            attr = self.attrs.get(key)
            if not attr:
                continue

            data[key] = self._clean_attr(attr, value, verrors)

        # Do not make any field and required and not populate default values
        if not self.update:
            data.update(self.get_defaults(data, self.get_attrs_to_skip(data), verrors))

        verrors.check()

        return data
예제 #2
0
 def validate(self, value):
     super().validate(value)
     verrors = ValidationErrors()
     uri = urlparse(value)
     if not all(getattr(uri, k) for k in ('scheme', 'netloc')):
         verrors.add(self.name, 'Not a valid URI')
     verrors.check()
예제 #3
0
    def _do_create(self, job, data):
        self.middleware.call_sync('jail.check_dataset_existence')
        verrors = ValidationErrors()
        branch = data.pop('branch') or self.get_version()
        install_notes = ''
        plugin_name = data.pop('plugin_name')
        jail_name = data.pop('jail_name')
        plugin_repository = data.pop('plugin_repository')
        post_install = False

        job.set_progress(0, f'Creating plugin: {plugin_name}')
        if jail_name in [
                j['id'] for j in self.middleware.call_sync('jail.query')
        ]:
            verrors.add('plugin_create.jail_name',
                        f'A jail with name {jail_name} already exists')
        else:
            verrors = common_validation(self.middleware,
                                        data,
                                        schema='plugin_create')

        verrors.check()

        job.set_progress(20, 'Initial validation complete')

        def progress_callback(content, exception):
            msg = content['message'].strip('\r\n')
            nonlocal install_notes, post_install

            if post_install and msg:
                install_notes += f'\n{msg}'

            if '  These pkgs will be installed:' in msg:
                job.set_progress(50, msg)
            elif 'Installing plugin packages:' in msg:
                job.set_progress(75, msg)
            elif 'Running post_install.sh' in msg:
                job.set_progress(90, msg)
                # Sets each message going forward as important to the user
                post_install = True
            else:
                job.set_progress(None, msg)

        ioc.IOCage(callback=progress_callback, silent=False).fetch(
            **{
                'accept': True,
                'name': jail_name,
                'plugin_name': plugin_name,
                'git_repository': plugin_repository,
                'props': data['props'],
                'branch': branch,
            })

        new_plugin = self.middleware.call_sync('plugin._get_instance',
                                               jail_name)
        new_plugin['install_notes'] = install_notes.strip()

        return new_plugin
예제 #4
0
    def validate(self, value):
        if value is None:
            return

        verrors = ValidationErrors()

        if not dn.is_dn(value):
            verrors.add(self.name, "Invalid LDAP DN specified.")

        verrors.check()
        return super().validate(value)
예제 #5
0
    def ping_remote(self, options):
        """
        Method that will send an ICMP echo request to "hostname"
        and will wait up to "timeout" for a reply.
        """
        ip = None
        ip_found = True
        verrors = ValidationErrors()
        try:
            ip = IpAddress()
            ip(options['hostname'])
            ip = options['hostname']
        except ValueError:
            ip_found = False
        if not ip_found:
            try:
                if options['type'] == 'ICMP':
                    ip = socket.getaddrinfo(options['hostname'], None)[0][4][0]
                elif options['type'] == 'ICMPV4':
                    ip = socket.getaddrinfo(options['hostname'], None,
                                            socket.AF_INET)[0][4][0]
                elif options['type'] == 'ICMPV6':
                    ip = socket.getaddrinfo(options['hostname'], None,
                                            socket.AF_INET6)[0][4][0]
            except socket.gaierror:
                verrors.add(
                    'options.hostname',
                    f'{options["hostname"]} cannot be resolved to an IP address.'
                )

        verrors.check()

        addr = ipaddress.ip_address(ip)
        if not addr.version == 4 and (options['type'] == 'ICMP'
                                      or options['type'] == 'ICMPV4'):
            verrors.add(
                'options.type',
                f'Requested ICMPv4 protocol, but the address provided "{addr}" is not a valid IPv4 address.'
            )
        if not addr.version == 6 and options['type'] == 'ICMPV6':
            verrors.add(
                'options.type',
                f'Requested ICMPv6 protocol, but the address provided "{addr}" is not a valid IPv6 address.'
            )
        verrors.check()

        ping_host = False
        if addr.version == 4:
            ping_host = self._ping_host(ip, options['timeout'])
        elif addr.version == 6:
            ping_host = self._ping6_host(ip, options['timeout'])

        return ping_host
예제 #6
0
    def validate(self, value):
        if value is None:
            return value

        verrors = ValidationErrors()

        if value and len(str(value)) > self.max_length:
            verrors.add(self.name, f'Value greater than {self.max_length} not allowed')

        verrors.check()

        return super().validate(value)
예제 #7
0
 async def validate(self, data, dev):
     verrors = ValidationErrors()
     unavail = [
         i for i in data['capabilities']
         if i not in dev.supported_capabilities
     ]
     if unavail:
         # gave us a capability that isn't supported on the device
         # or is "fixed" (meaning it can't be changed)
         verrors.add(
             f'capabilities_set.{data["action"]}',
             f'"{data["name"]}" does not support "{", ".join(unavail)}"')
     verrors.check()
예제 #8
0
    def validate(self, value):
        if value is None:
            return

        verrors = ValidationErrors()

        if value:
            if not os.path.exists(value):
                verrors.add(self.name, "This path does not exist.", errno.ENOENT)
            self.validate_internal(verrors, value)

        verrors.check()

        return super().validate(value)
예제 #9
0
def validate_return_type(func, result, schemas):
    if not schemas and result is None:
        return
    elif not schemas:
        raise ValueError(f'Return schema missing for {func.__name__!r}')

    result = copy.deepcopy(result)
    if not isinstance(result, tuple):
        result = [result]

    verrors = ValidationErrors()
    for res_entry, schema in zip(result, schemas):
        clean_and_validate_arg(verrors, schema, res_entry)
    verrors.check()
예제 #10
0
    def validate(self, value):
        verrors = ValidationErrors()
        attr_verrors = ValidationErrors()
        for attr in self.schemas:
            try:
                attr.validate(value)
            except TypeError:
                pass
            except ValidationErrors as e:
                attr_verrors.extend(e)
            else:
                break
        else:
            verrors.extend(attr_verrors)

        verrors.check()
예제 #11
0
    def clone(self, job, source_jail, options):
        verrors = ValidationErrors()
        try:
            self.check_jail_existence(source_jail, skip=False)
        except CallError:
            verrors.add('source_jail', f'{source_jail} does not exist.',
                        errno.ENOENT)
        else:
            try:
                self.check_jail_existence(options['uuid'], skip=False)
            except CallError:
                pass
            else:
                verrors.add(
                    'clone_jail.uuid',
                    f'Jail with "{options["uuid"]}" uuid already exists.',
                    errno.EEXIST)

        verrors.check()
        verrors = common_validation(self.middleware,
                                    options,
                                    schema='clone_jail')
        verrors.check()

        job.set_progress(25, 'Initial validation complete.')

        ioc.IOCage(jail=source_jail,
                   skip_jails=True).create(source_jail,
                                           options['props'],
                                           _uuid=options['uuid'],
                                           thickjail=options['thickjail'],
                                           clone=True)

        job.set_progress(100, 'Jail has been successfully cloned.')

        return self.middleware.call_sync('jail._get_instance', options['uuid'])
예제 #12
0
    def fstab(self, jail, options):
        """Manipulate a jails fstab"""
        uuid, _, iocage = self.check_jail_existence(jail, skip=False)
        status, jid = IOCList.list_get_jid(uuid)
        action = options['action'].lower()
        index = options.get('index')

        if status and action != 'list':
            raise CallError(
                f'{jail} should not be running when adding a mountpoint')

        verrors = ValidationErrors()

        if action in ('add', 'replace', 'remove'):
            if action != 'remove' or index is None:
                # For remove we allow removing by index or mount, so if index is not specified
                # we should validate that rest of the fields exist.
                for f in ('source', 'destination', 'fstype', 'fsoptions',
                          'dump', 'pass'):
                    if not options.get(f):
                        verrors.add(
                            f'options.{f}',
                            f'This field is required with "{action}" action.')

            if action == 'replace' and index is None:
                verrors.add(
                    'options.index',
                    'Index cannot be "None" when replacing an fstab entry.')

        verrors.check()

        source = options.get('source')
        if action in ('add', 'replace') and not os.path.exists(source):
            verrors.add('options.source',
                        'The provided path for the source does not exist.')

        destination = options.get('destination')
        if destination:
            destination = f'/{destination}' if destination[0] != '/' else \
                destination
            dst = f'{self.get_iocroot()}/jails/{jail}/root'
            if dst not in destination:
                destination = f'{dst}{destination}'

            if os.path.exists(destination):
                if not os.path.isdir(destination):
                    verrors.add(
                        'options.destination',
                        'Destination is not a directory. Please provide a '
                        'empty directory for the destination.')
                elif os.listdir(destination):
                    verrors.add('options.destination',
                                'Destination directory must be empty.')
            else:
                os.makedirs(destination)

        # Setup defaults for library
        source = source or ''
        destination = destination or ''
        fstype = options.get('fstype')
        fsoptions = options.get('fsoptions')
        dump = options.get('dump')
        _pass = options.get('pass')

        if verrors:
            raise verrors

        try:
            _list = iocage.fstab(action,
                                 source,
                                 destination,
                                 fstype,
                                 fsoptions,
                                 dump,
                                 _pass,
                                 index=index)
        except ioc_exceptions.ValidationFailed as e:
            # CallError uses strings, the exception message may not always be a
            # list.
            if not isinstance(e.message, str) and isinstance(
                    e.message, Iterable):
                e.message = '\n'.join(e.message)

            self.logger.error(f'{e!r}')
            raise CallError(e.message)

        if action == "list":
            split_list = {}
            system_mounts = ('/root/bin', '/root/boot', '/root/lib',
                             '/root/libexec', '/root/rescue', '/root/sbin',
                             '/root/usr/bin', '/root/usr/include',
                             '/root/usr/lib', '/root/usr/libexec',
                             '/root/usr/sbin', '/root/usr/share',
                             '/root/usr/libdata', '/root/usr/lib32')

            for i in _list:
                fstab_entry = i[1]
                _fstab_type = 'SYSTEM' if fstab_entry[0].endswith(
                    system_mounts) else 'USER'

                split_list[i[0]] = {'entry': fstab_entry, 'type': _fstab_type}

            return split_list

        return True