def verify(self, ftp):
        errors = ValidationException()
        node = ConfigNode('service.ftp', self.configstore).__getstate__()
        node.update(ftp)

        pmin = node['passive_ports_min']
        if 'passive_ports_min' in ftp:
            if pmin and (pmin < 1024 or pmin > 65535):
                errors.add((0, 'passive_ports_min'), 'This value must be between 1024 and 65535, inclusive.')

        pmax = node['passive_ports_max']
        if 'passive_ports_max' in ftp:
            if pmax and (pmax < 1024 or pmax > 65535):
                errors.add((0, 'passive_ports_max'), 'This value must be between 1024 and 65535, inclusive.')
            elif pmax and pmin and pmin >= pmax:
                errors.add((0, 'passive_ports_max'),  'This value must be higher than minimum passive port.')

        if node['only_anonymous'] and not node['anonymous_path']:
            errors.add(
                ((0, 'anonymous_path'), errno.EINVAL, 'This field is required for anonymous login.')
            )

        if node['tls'] is True and not node['tls_ssl_certificate']:
            errors.add((0, 'tls_ssl_certificate'), 'TLS specified without certificate.')

        if node['tls_ssl_certificate']:
            cert = self.dispatcher.call_sync('crypto.certificate.query', [('id', '=', node['tls_ssl_certificate'])])
            if not cert:
                errors.add((0, 'tls_ssl_certificate'), 'SSL Certificate not found.')

        if errors:
            raise errors

        return ['system']
Example #2
0
    def run(self, nfs):
        config = self.dispatcher.call_sync('service.query',
                                           [('name', '=', 'nfs')],
                                           {'single': True})['config']
        for n in ('mountd_port', 'rpcstatd_port', 'rpclockd_port'):
            port = nfs.get(n)
            if port and port != config[n] and is_port_open(port, 'inet'):
                raise TaskException(
                    errno.EBUSY,
                    'Port number : {0} is already in use'.format(port))

        try:
            node = ConfigNode('service.nfs', self.configstore)
            node.update(nfs)
            self.dispatcher.call_sync('etcd.generation.generate_group',
                                      'services')
            self.dispatcher.call_sync('etcd.generation.generate_group', 'nfs')
            self.dispatcher.dispatch_event('service.nfs.changed', {
                'operation': 'updated',
                'ids': None,
            })
        except RpcException as e:
            raise TaskException(errno.ENXIO,
                                'Cannot reconfigure NFS: {0}'.format(str(e)))

        return 'RESTART'
Example #3
0
    def run(self, ftp):
        if ftp.get('filemask'):
            ftp['filemask'] = get_integer(ftp['filemask'])

        if ftp.get('dirmask'):
            ftp['dirmask'] = get_integer(ftp['dirmask'])

        if ftp.get('anonymous_path'):
            if not os.path.exists(ftp['anonymous_path']):
                raise TaskException(
                    errno.ENOENT, 'Directory {0} does not exists'.format(
                        ftp['anonymous_path']))

        try:
            node = ConfigNode('service.ftp', self.configstore)
            node.update(ftp)
            self.dispatcher.call_sync('etcd.generation.generate_group', 'ftp')
            self.dispatcher.dispatch_event('service.ftp.changed', {
                'operation': 'updated',
                'ids': None,
            })
        except RpcException as e:
            raise TaskException(errno.ENXIO,
                                'Cannot reconfigure FTP: {0}'.format(str(e)))

        return 'RESTART'
Example #4
0
    def run(self, smb):
        try:
            action = 'NONE'
            node = ConfigNode('service.smb', self.configstore)
            if smb.get('filemask'):
                smb['filemask'] = get_integer(smb['filemask'])
            if smb.get('dirmask'):
                smb['dirmask'] = get_integer(smb['dirmask'])
            node.update(smb)
            configure_params(node.__getstate__(), self.dispatcher.call_sync('service.smb.ad_enabled'))

            try:
                rpc = smbconf.SambaMessagingContext()
                rpc.reload_config()
            except OSError:
                action = 'RESTART'

            # XXX: Is restart to change netbios name/workgroup *really* needed?
            if 'netbiosname' in smb or 'workgroup' in smb:
                action = 'RESTART'

            self.dispatcher.dispatch_event('service.smb.changed', {
                'operation': 'updated',
                'ids': None,
            })
        except RpcException as e:
            raise TaskException(
                errno.ENXIO, 'Cannot reconfigure SMB: {0}'.format(str(e))
            )

        return action
Example #5
0
    def verify(self, snmp):
        errors = []

        node = ConfigNode('service.snmp', self.configstore).__getstate__()
        node.update(snmp)

        if node['contact']:
            if '@' in node['contact']:
                if not jsonschema._format.is_email(node['contact']):
                    errors.append(('contact', errno.EINVAL, 'Invalid e-mail address'))
            elif not re.match(r'^[-_a-zA-Z0-9\s]+$', node['contact']):
                errors.append(('contact', errno.EINVAL, (
                    'Must contain only alphanumeric characters, _, - or a valid e-mail address')
                ))

        if not node['community']:
            if not node['v3']:
                errors.append(('community', errno.ENOENT, 'This field is required'))
        elif not re.match(r'^[-_a-zA-Z0-9\s]+$', node['community']):
            errors.append(('community', errno.EINVAL, (
                'The community must contain only alphanumeric characters, _ or -')
            ))

        if node['v3_password'] and len(node['v3_password']) < 8:
            errors.append(('v3_password', errno.EINVAL, 'Password must contain at least 8 characters'))

        if node['v3_privacy_passphrase'] and len(node['v3_privacy_passphrase']) < 8:
            errors.append(('v3_password', errno.EINVAL, 'Passphrase must contain at least 8 characters'))

        if errors:
            raise ValidationException(errors)

        return ['system']
Example #6
0
    def run(self, afp):
        paths = [PosixPath(afp.get(y)) if afp.get(y) else None for y in ('dbpath', 'homedir_path')]
        for p in paths:
            if p and not p.exists():
                raise TaskException(errno.ENOENT, 'Path : {0} does not exist'.format(p.as_posix()))
            if p and not p.is_dir():
                raise TaskException(errno.ENOTDIR, 'Path : {0} is not a directory'.format(p.as_posix()))

        if afp.get('guest_user'):
            if not self.dispatcher.call_sync('user.query', [('username', '=', afp['guest_user'])], {'single': True}):
                raise TaskException(errno.EINVAL, 'User: {0} does not exist'.format(afp['guest_user']))

        try:
            node = ConfigNode('service.afp', self.configstore)
            node.update(afp)
            self.dispatcher.call_sync('etcd.generation.generate_group', 'services')
            self.dispatcher.call_sync('etcd.generation.generate_group', 'afp')
            self.dispatcher.dispatch_event('service.afp.changed', {
                'operation': 'updated',
                'ids': None,
            })
        except RpcException as e:
            raise TaskException(
                errno.ENXIO, 'Cannot reconfigure AFP: {0}'.format(str(e))
            )

        return 'RELOAD'
Example #7
0
    def run(self, ipfs):
        try:
            node = ConfigNode('service.ipfs', self.configstore)
            old_path = node['path'].value
            if 'path' in ipfs and ipfs['path'] != old_path:
                if not os.path.exists(ipfs['path']):
                    os.makedirs(ipfs['path'])
                    # jkh says that the ipfs path should be owned by root
                    os.chown(ipfs['path'], 0, 0)
                # Only move the contents and not the entire folder
                # there could be other stuff in that folder
                # (a careless user might have merged this with his other files)
                # also this folder could be a dataset in which case a simple move will fail
                # so lets just move the internal contents of this folder over
                if old_path is not None and os.path.exists(old_path):
                    try:
                        for item in os.listdir(old_path):
                            shutil.move(old_path + '/' + item, ipfs['path'])
                    except shutil.Error as serr:
                        raise TaskException(
                            errno.EIO,
                            "Migrating ipfs path resulted in error: {0}".format(serr))
            node.update(ipfs)
            self.dispatcher.call_sync('etcd.generation.generate_group', 'services')
            self.dispatcher.dispatch_event('service.ipfs.changed', {
                'operation': 'updated',
                'ids': None,
            })
        except RpcException as e:
            raise TaskException(
                errno.ENXIO, 'Cannot reconfigure IPFS: {0}'.format(str(e))
            )

        return 'RELOAD'
Example #8
0
    def verify(self, openvpn):
        interface_pattern = '(tap|tun)[0-9]'
        node = ConfigNode('service.openvpn', self.configstore).__getstate__()
        node.update(openvpn)
        
        if not re.search(interface_pattern, node['dev']):
            raise VerifyException(errno.EINVAL,
                                  '{0} Bad interface name. Allowed values tap/tun[0-9].'.format(node['dev']))
	
        if node['server_bridge_extended']:
            try:
                bridge_ip = ipaddress.ip_address(node['server_bridge_ip'])
                netmask = node['server_bridge_netmask']									
                ip_range_begin = ipaddress.ip_address(node['server_bridge_range_begin'])
                ip_range_end = ipaddress.ip_address(node['server_bridge_range_end'])
                subnet = ipaddress.ip_network('{0}/{1}'.format(bridge_ip, netmask), strict=False) 
      
            except ValueError as e:
                raise VerifyException(errno.EINVAL, str(e))

            if (ip_range_begin not in subnet) or (ip_range_end not in subnet):
                raise VerifyException(errno.EINVAL, 
                                      'Provided range of remote client IP adresses is invalid.')			
			
            if (bridge_ip >= ip_range_begin) and (bridge_ip <= ip_range_end):
                raise VerifyException(errno.EINVAL, 
                                      'Provided bridge IP address is in the client ip range.')

        if (node['keepalive_ping_interval'] * 2) >= node['keepalive_peer_down']:
            raise VerifyException(errno.EINVAL, 'The second parameter to keepalive must be'
                                  'at least twice the value of the first parameter.'
                                  'Recommended setting is keepalive 10 60.')
				
        return ['system']
Example #9
0
    def run(self, ipfs):
        try:
            node = ConfigNode('service.ipfs', self.configstore)
            old_path = node['path'].value
            if 'path' in ipfs and ipfs['path'] != old_path:
                if not os.path.exists(ipfs['path']):
                    os.makedirs(ipfs['path'])
                    # jkh says that the ipfs path should be owned by root
                    os.chown(ipfs['path'], 0, 0)
                # Only move the contents and not the entire folder
                # there could be other stuff in that folder
                # (a careless user might have merged this with his other files)
                # also this folder could be a dataset in which case a simple move will fail
                # so lets just move the internal contents of this folder over
                if old_path is not None and os.path.exists(old_path):
                    try:
                        for item in os.listdir(old_path):
                            shutil.move(old_path + '/' + item, ipfs['path'])
                    except shutil.Error as serr:
                        raise TaskException(
                            errno.EIO,
                            "Migrating ipfs path resulted in error: {0}".format(serr))
            node.update(ipfs)
            self.dispatcher.call_sync('etcd.generation.generate_group', 'ipfs')
            self.dispatcher.dispatch_event('service.ipfs.changed', {
                'operation': 'updated',
                'ids': None,
            })
        except RpcException as e:
            raise TaskException(
                errno.ENXIO, 'Cannot reconfigure IPFS: {0}'.format(str(e))
            )

        return 'RESTART'
Example #10
0
    def run(self, rsyncd):
        config = ConfigNode('service.rsyncd', self.configstore).__getstate__()

        if rsyncd.get('port') and is_port_open(rsyncd['port']):
            service_state = self.dispatcher.call_sync(
                'service.query', [('name', '=', 'rsyncd')], {
                    'single': True,
                    'select': 'state'
                })

            if not (service_state == "RUNNING"
                    and rsyncd['port'] == config['port']):
                raise TaskException(errno.EINVAL,
                                    'Provided port is already in use')

        try:
            node = ConfigNode('service.rsyncd', self.configstore)
            node.update(rsyncd)
            self.dispatcher.call_sync('etcd.generation.generate_group',
                                      'rsyncd')
            self.dispatcher.dispatch_event('service.rsyncd.changed', {
                'operation': 'updated',
                'ids': None,
            })
        except RpcException as e:
            raise TaskException(
                errno.ENXIO, 'Cannot reconfigure Rsyncd: {0}'.format(str(e)))
Example #11
0
    def run(self, ftp):
        if ftp.get('filemask'):
            ftp['filemask'] = get_integer(ftp['filemask'])

        if ftp.get('dirmask'):
            ftp['dirmask'] = get_integer(ftp['dirmask'])

        if ftp.get('anonymous_path'):
            if not os.path.exists(ftp['anonymous_path']):
                raise TaskException(errno.ENOENT,
                    'Directory {0} does not exists'.format(ftp['anonymous_path']))

        try:
            node = ConfigNode('service.ftp', self.configstore)
            node.update(ftp)
            self.dispatcher.call_sync('etcd.generation.generate_group', 'ftp')
            self.dispatcher.dispatch_event('service.ftp.changed', {
                'operation': 'updated',
                'ids': None,
            })
        except RpcException as e:
            raise TaskException(
                errno.ENXIO, 'Cannot reconfigure FTP: {0}'.format(str(e))
            )

        return 'RESTART'
Example #12
0
    def run(self, ssh):
        config = self.dispatcher.call_sync('service.query',
                                           [('name', '=', 'sshd')], {
                                               'single': True,
                                               'select': 'config'
                                           })
        port = ssh.get('port')
        if port and port != config['port'] and is_port_open(port):
            raise TaskException(
                errno.EBUSY,
                'Port number : {0} is already in use'.format(port))

        try:
            node = ConfigNode('service.sshd', self.configstore)
            node.update(ssh)
            self.dispatcher.call_sync('etcd.generation.generate_group', 'sshd')
            self.dispatcher.dispatch_event('service.sshd.changed', {
                'operation': 'updated',
                'ids': None,
            })
        except RpcException as e:
            raise TaskException(errno.ENXIO,
                                'Cannot reconfigure SSH: {0}'.format(str(e)))

        return 'RELOAD'
Example #13
0
    def run(self, settings):
        node = ConfigNode('network', self.configstore)
        node.update(settings)

        if node['dhcp.assign_gateway']:
            # Clear out gateway settings
            node['gateway.ipv4'] = None

        if node['dhcp.assign_dns']:
            # Clear out DNS settings
            node['dns.addresses'] = []
            node['dns.search'] = []

        configure_proxy(self.dispatcher, node['http_proxy'].value)

        try:
            for code, message in self.dispatcher.call_sync(
                    'networkd.configuration.configure_network', timeout=60):
                self.add_warning(TaskWarning(code, message))

            self.dispatcher.call_sync('etcd.generation.generate_group',
                                      'network')
        except RpcException as e:
            raise TaskException(
                errno.ENXIO,
                'Cannot reconfigure interface: {0}'.format(str(e)))
    def run(self, id, updated_fields):
        service_def = self.datastore.get_by_id('service_definitions', id)
        node = ConfigNode('service.{0}'.format(service_def['name']), self.configstore)
        restart = False
        reload = False
        updated_config = updated_fields.get('config')

        if updated_config is None:
            return

        del updated_config['type']

        if service_def.get('task'):
            enable = updated_config.pop('enable', None)

            try:
                self.verify_subtask(service_def['task'], updated_config)
            except RpcException as err:
                new_err = ValidationException()
                new_err.propagate(err, [0], [1, 'config'])
                raise new_err

            result = self.join_subtasks(self.run_subtask(service_def['task'], updated_config))
            restart = result[0] == 'RESTART'
            reload = result[0] == 'RELOAD'

            if enable is not None:
                node['enable'] = enable
        else:
            node.update(updated_config)

            if service_def.get('etcd-group'):
                self.dispatcher.call_sync('etcd.generation.generate_group', service_def.get('etcd-group'))

            if 'enable' in updated_config:
                # Propagate to dependent services
                for i in service_def.get('dependencies', []):
                    svc_dep = self.datastore.get_by_id('service_definitions', i)
                    self.join_subtasks(self.run_subtask('service.update', i, {
                        'config': {
                            'type': 'service-{0}'.format(svc_dep['name']),
                            'enable': updated_config['enable']
                        }
                    }))

                if service_def.get('auto_enable'):
                    # Consult state of services dependent on us
                    for i in self.datastore.query('service_definitions', ('dependencies', 'in', service_def['name'])):
                        enb = self.configstore.get('service.{0}.enable', i['name'])
                        if enb != updated_config['enable']:
                            del updated_config['enable']
                            break

        self.dispatcher.call_sync('etcd.generation.generate_group', 'services')
        self.dispatcher.call_sync('service.apply_state', service_def['name'], restart, reload, timeout=30)
        self.dispatcher.dispatch_event('service.changed', {
            'operation': 'update',
            'ids': [service_def['id']]
        })
Example #15
0
    def get_config(self):
        node = ConfigNode('network', self.configstore).__getstate__()
        node.update({
            'gateway': self.dispatcher.call_sync('networkd.configuration.get_default_routes'),
            'dns': self.dispatcher.call_sync('networkd.configuration.get_dns_config')
        })

        return node
Example #16
0
    def get_config(self):
        node = ConfigNode('network', self.configstore).__getstate__()
        node.update({
            'gateway': self.dispatcher.call_sync('networkd.configuration.get_default_routes'),
            'dns': self.dispatcher.call_sync('networkd.configuration.get_dns_config')
        })

        return node
    def run(self, updated_params):
        node = ConfigNode('directory', self.configstore)
        node.update(updated_params)

        try:
            self.dispatcher.call_sync('dscached.management.reload_config')
        except RpcException as e:
            raise TaskException(errno.ENXIO, 'Cannot reconfigure directory services: {0}'.format(str(e)))
    def run(self, updated_params):
        node = ConfigNode('directory', self.configstore)
        node.update(updated_params)

        try:
            self.dispatcher.call_sync('dscached.management.reload_config')
        except RpcException as e:
            raise TaskException(errno.ENXIO, 'Cannot reconfigure directory services: {0}'.format(str(e)))
Example #19
0
    def verify(self, openvpn_updated):
        node = ConfigNode('service.openvpn', self.configstore).__getstate__()
        node.update(openvpn_updated)

        if node['dev'] not in ['tap', 'tun']:
            raise VerifyException(errno.EINVAL,
                                  '{0} Bad interface name. Allowed values tap/tun.'.format(node['dev']))
        if ((node['mode'] == 'pki' and node['dev'].startswith('tun'))
                or (node['mode'] == 'psk' and node['dev'].startswith('tap'))):
            raise VerifyException(errno.EINVAL,
                                  'tap interfaces can be used with pki scenario and tun with psk mode')

        if node['mode'] == 'pki' and (not node['ca'] or not node['cert']):
            raise VerifyException(errno.EINVAL,
                                  'For pki VPN mode ca and certyficate values are required')

        if node['mode'] == 'psk':
            try:
                ipaddress.ip_address(node['psk_server_ip'])
                ipaddress.ip_address(node['psk_remote_ip'])
            except ValueError as e:
                raise VerifyException(errno.EINVAL, str(e))

        if (node['server_bridge_extended']
            and not (node['server_bridge_ip'] or node['server_bridge_netmask']
                     or node['server_bridge_range_begin'] or node['server_bridge_range_end'])):

            raise VerifyException(errno.EINVAL,
                                  'For pki server_bridge_extended mode all server_bridge values are required')




        if node['mode'] == 'pki' and node['server_bridge_extended']:
            try:
                bridge_ip = ipaddress.ip_address(node['server_bridge_ip'])
                netmask = node['server_bridge_netmask']
                ip_range_begin = ipaddress.ip_address(node['server_bridge_range_begin'])
                ip_range_end = ipaddress.ip_address(node['server_bridge_range_end'])
                subnet = ipaddress.ip_network('{0}/{1}'.format(bridge_ip, netmask), strict=False)

            except ValueError as e:
                raise VerifyException(errno.EINVAL, str(e))

            if (ip_range_begin not in subnet) or (ip_range_end not in subnet):
                raise VerifyException(errno.EINVAL,
                                      'Provided range of remote client IP adresses is invalid.')

            if (bridge_ip >= ip_range_begin) and (bridge_ip <= ip_range_end):
                raise VerifyException(errno.EINVAL,
                                      'Provided bridge IP address is in the client ip range.')
        if node['mode'] == 'pki':
            if (node['keepalive_ping_interval'] * 2) >= node['keepalive_peer_down']:
                raise VerifyException(errno.EINVAL, 'The second parameter to keepalive must be'
                                      'at least twice the value of the first parameter.'
                                      'Recommended setting is keepalive 10 60.')

        return ['system']
Example #20
0
    def verify(self, openvpn_updated):
        node = ConfigNode('service.openvpn', self.configstore).__getstate__()
        node.update(openvpn_updated)

        if node['dev'] not in ['tap', 'tun']:
            raise VerifyException(errno.EINVAL,
                                  '{0} Bad interface name. Allowed values tap/tun.'.format(node['dev']))
        if ((node['mode'] == 'pki' and node['dev'].startswith('tun'))
                or (node['mode'] == 'psk' and node['dev'].startswith('tap'))):
            raise VerifyException(errno.EINVAL,
                                  'tap interfaces can be used with pki scenario and tun with psk mode')

        if node['mode'] == 'pki' and (not node['ca'] or not node['cert']):
            raise VerifyException(errno.EINVAL,
                                  'For pki VPN mode ca and certyficate values are required')

        if node['mode'] == 'psk':
            try:
                ipaddress.ip_address(node['psk_server_ip'])
                ipaddress.ip_address(node['psk_remote_ip'])
            except ValueError as e:
                raise VerifyException(errno.EINVAL, str(e))

        if (node['server_bridge_extended']
            and not (node['server_bridge_ip'] or node['server_bridge_netmask']
                     or node['server_bridge_range_begin'] or node['server_bridge_range_end'])):

            raise VerifyException(errno.EINVAL,
                                  'For pki server_bridge_extended mode all server_bridge values are required')




        if node['mode'] == 'pki' and node['server_bridge_extended']:
            try:
                bridge_ip = ipaddress.ip_address(node['server_bridge_ip'])
                netmask = node['server_bridge_netmask']
                ip_range_begin = ipaddress.ip_address(node['server_bridge_range_begin'])
                ip_range_end = ipaddress.ip_address(node['server_bridge_range_end'])
                subnet = ipaddress.ip_network('{0}/{1}'.format(bridge_ip, netmask), strict=False)

            except ValueError as e:
                raise VerifyException(errno.EINVAL, str(e))

            if (ip_range_begin not in subnet) or (ip_range_end not in subnet):
                raise VerifyException(errno.EINVAL,
                                      'Provided range of remote client IP adresses is invalid.')

            if (bridge_ip >= ip_range_begin) and (bridge_ip <= ip_range_end):
                raise VerifyException(errno.EINVAL,
                                      'Provided bridge IP address is in the client ip range.')
        if node['mode'] == 'pki':
            if (node['keepalive_ping_interval'] * 2) >= node['keepalive_peer_down']:
                raise VerifyException(errno.EINVAL, 'The second parameter to keepalive must be'
                                      'at least twice the value of the first parameter.'
                                      'Recommended setting is keepalive 10 60.')

        return ['system']
Example #21
0
    def run(self, iscsi):
        try:
            node = ConfigNode('service.iscsi', self.configstore)
            node.update(iscsi)
            self.dispatcher.call_sync('etcd.generation.generate_group', 'ctl')
        except RpcException as e:
            raise TaskException(errno.ENXIO, 'Cannot reconfigure iSCSI: {0}'.format(str(e)))

        return 'RELOAD'
Example #22
0
 def run(self, iscsi):
     try:
         node = ConfigNode('service.iscsi', self.configstore)
         node.update(iscsi)
         self.dispatcher.call_sync('etcd.generation.generate_group', 'ctl')
     except RpcException as e:
         raise TaskException(errno.ENXIO, 'Cannot reconfigure iSCSI: {0}'.format(str(e)))
         
     return 'RELOAD'
Example #23
0
    def run(self, mail):
        node = ConfigNode('mail', self.dispatcher.configstore)
        node.update(mail)

        try:
            self.dispatcher.call_sync('etcd.generation.generate_group', 'mail')
        except RpcException, e:
            raise TaskException(errno.ENXIO,
                                'Cannot reconfigure mail: {0}'.format(str(e)))
Example #24
0
    def run(self, service, updated_fields):
        service_def = self.datastore.get_one('service_definitions', ('name', '=', service))
        node = ConfigNode('service.{0}'.format(service), self.dispatcher.configstore)
        node.update(updated_fields)

        self.dispatcher.dispatch_event('service.changed', {
            'operation': 'update',
            'ids': [service_def['id']]
        })
Example #25
0
    def run(self, settings):
        node = ConfigNode('network', self.configstore)
        node.update(settings)

        try:
            self.dispatcher.call_sync('networkd.configuration.configure_network')
            self.dispatcher.call_sync('etcd.generation.generate_group', 'network')
        except RpcException as e:
            raise TaskException(errno.ENXIO, 'Cannot reconfigure interface: {0}'.format(str(e)))
Example #26
0
    def run(self, smb):
        node = ConfigNode('service.smb', self.configstore).__getstate__()
        netbiosname = smb.get('netbiosname')
        if netbiosname is not None:
            for n in netbiosname:
                if not validate_netbios_name(n):
                    raise TaskException(errno.EINVAL, 'Invalid name {0}'.format(n))
        else:
            netbiosname = node['netbiosname']

        workgroup = smb.get('workgroup')
        if workgroup is not None:
            if not validate_netbios_name(workgroup):
                raise TaskException(errno.EINVAL, 'Invalid name')
        else:
            workgroup = node['workgroup']

        if workgroup.lower() in [i.lower() for i in netbiosname]:
            raise TaskException(errno.EINVAL, 'NetBIOS and Workgroup must be unique')

        if smb.get('guest_user'):
            if not self.dispatcher.call_sync('user.query', [('username', '=', smb['guest_user'])], {'single': True}):
                raise TaskException(errno.EINVAL, 'User: {0} does not exist'.format(smb['guest_user']))

        try:
            action = 'NONE'
            node = ConfigNode('service.smb', self.configstore)
            if smb.get('filemask'):
                smb['filemask'] = get_integer(smb['filemask'])

            if smb.get('dirmask'):
                smb['dirmask'] = get_integer(smb['dirmask'])

            node.update(smb)
            configure_params(node.__getstate__(), self.dispatcher.call_sync('service.smb.ad_enabled'))

            try:
                rpc = smbconf.SambaMessagingContext()
                rpc.reload_config()
            except OSError:
                action = 'RESTART'

            # XXX: Is restart to change netbios name/workgroup *really* needed?
            if 'netbiosname' in smb or 'workgroup' in smb:
                action = 'RESTART'

            self.dispatcher.dispatch_event('service.smb.changed', {
                'operation': 'updated',
                'ids': None,
            })
        except RpcException as e:
            raise TaskException(
                errno.ENXIO, 'Cannot reconfigure SMB: {0}'.format(str(e))
            )

        return action
Example #27
0
    def verify(self, stanchion):
        errors = []

        node = ConfigNode("service.stanchion", self.configstore).__getstate__()
        node.update(stanchion)

        if errors:
            raise ValidationException(errors)

        return ["system"]
Example #28
0
    def run(self, dyndns):
        try:
            node = ConfigNode("service.dyndns", self.configstore)
            node.update(dyndns)
            self.dispatcher.call_sync("etcd.generation.generate_group", "dyndns")
            self.dispatcher.dispatch_event("service.dyndns.changed", {"operation": "updated", "ids": None})
        except RpcException as e:
            raise TaskException(errno.ENXIO, "Cannot reconfigure DynamicDNS: {0}".format(str(e)))

        return "RELOAD"
Example #29
0
    def verify(self, haproxy):
        errors = []

        node = ConfigNode('service.haproxy', self.configstore).__getstate__()
        node.update(haproxy)

        if errors:
            raise ValidationException(errors)

        return ['system']
Example #30
0
    def verify(self, riakcs):
        errors = []

        node = ConfigNode('service.riak_cs', self.configstore).__getstate__()
        node.update(riakcs)

        if errors:
            raise ValidationException(errors)

        return ['system']
Example #31
0
    def run(self, ftp):
        try:
            node = ConfigNode("service.ftp", self.configstore)
            node.update(ftp)
            self.dispatcher.call_sync("etcd.generation.generate_group", "ftp")
            self.dispatcher.dispatch_event("service.ftp.changed", {"operation": "updated", "ids": None})
        except RpcException as e:
            raise TaskException(errno.ENXIO, "Cannot reconfigure FTP: {0}".format(str(e)))

        return "RESTART"
Example #32
0
    def verify(self, glusterd):
        errors = []

        node = ConfigNode('service.glusterd', self.configstore).__getstate__()
        node.update(glusterd)

        if errors:
            raise ValidationException(errors)

        return ['system']
Example #33
0
    def run(self, mail):
        node = ConfigNode('mail', self.dispatcher.configstore)
        node.update(mail)

        try:
            self.dispatcher.call_sync('etcd.generation.generate_group', 'mail')
        except RpcException, e:
            raise TaskException(
                errno.ENXIO, 'Cannot reconfigure mail: {0}'.format(str(e))
            )
    def run(self, dc):
        self.set_progress(0, 'Checking Domain Controller service state')
        node = ConfigNode('service.dc', self.configstore).__getstate__()
        node.update(dc)
        if not node.get('volume'):
            raise TaskException(
                errno.ENXIO,
                'Domain controller service is hosted by the virtual machine.'
                'Please provide the valid zfs pool name for the virtual machine volume creation.'
            )

        else:
            try:
                self.dispatcher.call_sync(
                    'service.dc.check_dc_vm_availability')
            except RpcException:
                dc['vm_id'] = self.run_subtask_sync(
                    'vm.create', {
                        'name': 'zentyal_domain_controller',
                        'template': {
                            'name': 'zentyal-4.2'
                        },
                        'target': node['volume'],
                        'config': {
                            'autostart': True
                        }
                    },
                    progress_callback=lambda p, m, e=None: self.chunk_progress(
                        5, 100, 'Creating Domain Controller virtual machine: ',
                        p, m, e))
            finally:
                vm_config = self.dispatcher.call_sync(
                    'vm.query', [('id', '=', dc.get('vm_id', node['vm_id']))],
                    {
                        'select': 'config',
                        'single': True
                    })
                if not node['enable'] and vm_config['autostart']:
                    vm_config['autostart'] = False
                elif node['enable'] and not vm_config['autostart']:
                    vm_config['autostart'] = True

                self.run_subtask_sync(
                    'vm.update',
                    dc['vm_id'] if dc.get('vm_id') else node['vm_id'],
                    {'config': vm_config})

        try:
            node = ConfigNode('service.dc', self.configstore)
            node.update(dc)

            self.dispatcher.dispatch_event('service.dc.changed', {
                'operation': 'update',
                'ids': None,
            })

        except RpcException as e:
            raise TaskException(
                errno.ENXIO,
                'Cannot reconfigure DC vm service: {0}'.format(str(e)))
Example #35
0
    def verify(self, ftp):
        errors = ValidationException()
        node = ConfigNode('service.ftp', self.configstore).__getstate__()
        node.update(ftp)

        pmin = node['passive_ports_min']
        if 'passive_ports_min' in ftp:
            if pmin and (pmin < 1024 or pmin > 65535):
                errors.add(
                    (0, 'passive_ports_min'),
                    'This value must be between 1024 and 65535, inclusive.')

        pmax = node['passive_ports_max']
        if 'passive_ports_max' in ftp:
            if pmax and (pmax < 1024 or pmax > 65535):
                errors.add(
                    (0, 'passive_ports_max'),
                    'This value must be between 1024 and 65535, inclusive.')
            elif pmax and pmin and pmin >= pmax:
                errors.add(
                    (0, 'passive_ports_max'),
                    'This value must be higher than minimum passive port.')

        if not all((pmax, pmin)) and any((pmax, pmin)):
            errors.add(
                (0, 'passive_ports_max' if pmin else 'passive_ports_min'),
                'You cannot just supply only one of "passive_ports_max" or "passive_ports_min"'
                + 'Either both stay none or both have valid values in them')

        if node['only_anonymous'] and not node['anonymous_path']:
            errors.add((0, 'anonymous_path'),
                       'This field is required for anonymous login.')

        if node['tls'] is True and not node['tls_ssl_certificate']:
            errors.add((0, 'tls_ssl_certificate'),
                       'TLS specified without certificate.')

        if node['tls_ssl_certificate']:
            cert = self.dispatcher.call_sync(
                'crypto.certificate.query',
                [('id', '=', node['tls_ssl_certificate'])])
            if not cert:
                errors.add((0, 'tls_ssl_certificate'),
                           'SSL Certificate not found.')

        if node['only_anonymous'] and node['only_local']:
            errors.add((
                0, 'only_anonymous'
            ), 'Anonymous only and local only types of authentication cannot be enabled together.'
                       )

        if errors:
            raise errors

        return ['system']
Example #36
0
    def run(self, settings):
        node = ConfigNode('network', self.dispatcher.configstore)
        node.update(settings)

        try:
            self.dispatcher.call_sync(
                'networkd.configuration.configure_network')
            self.dispatcher.call_sync('etcd.generation.generate_group',
                                      'network')
        except RpcException, e:
            raise TaskException(
                errno.ENXIO,
                'Cannot reconfigure interface: {0}'.format(str(e)))
Example #37
0
 def run(self, rsyncd):
     try:
         node = ConfigNode('service.rsyncd', self.configstore)
         node.update(rsyncd)
         self.dispatcher.call_sync('etcd.generation.generate_group',
                                   'rsyncd')
         self.dispatcher.dispatch_event('service.rsyncd.changed', {
             'operation': 'updated',
             'ids': None,
         })
     except RpcException as e:
         raise TaskException(
             errno.ENXIO, 'Cannot reconfigure Rsyncd: {0}'.format(str(e)))
Example #38
0
 def run(self, rsyncd):
     try:
         node = ConfigNode('service.rsyncd', self.configstore)
         node.update(rsyncd)
         self.dispatcher.call_sync('etcd.generation.generate_group', 'rsyncd')
         self.dispatcher.dispatch_event('service.rsyncd.changed', {
             'operation': 'updated',
             'ids': None,
         })
     except RpcException as e:
         raise TaskException(
             errno.ENXIO, 'Cannot reconfigure Rsyncd: {0}'.format(str(e))
         )
Example #39
0
    def run(self, ups):
        node = ConfigNode('service.ups', self.configstore).__getstate__()
        if 'monitor_password' in ups:
            ups['monitor_password'] = ups['monitor_password'].secret

        node.update(ups)

        if node['mode'] == 'MASTER' and (not node['driver_port'] or not node['driver']):
            raise TaskException(errno.EINVAL, 'Please provide a valid port and driver for monitored UPS device')

        if node['mode'] == 'SLAVE' and not node['remote_host']:
            raise TaskException(errno.EINVAL, 'remote_host field is required in SLAVE mode')

        if not re.search(r'^[a-z0-9\.\-_]+$', node['identifier'], re.I):
            raise TaskException(errno.EINVAL, 'Use alphanumeric characters, ".", "-" and "_"')

        for i in ('monitor_user', 'monitor_password'):
            if re.search(r'[ #]', node[i], re.I):
                raise TaskException(errno.EINVAL, 'Spaces or number signs are not allowed')

        try:
            node = ConfigNode('service.ups', self.configstore)
            node.update(ups)
            self.dispatcher.call_sync('etcd.generation.generate_group', 'services')
            self.dispatcher.call_sync('etcd.generation.generate_group', 'ups')
            self.dispatcher.dispatch_event('service.ups.changed', {
                'operation': 'updated',
                'ids': None,
            })
        except RpcException as e:
            raise TaskException(
                errno.ENXIO, 'Cannot reconfigure UPS: {0}'.format(str(e))
            )

        return 'RESTART'
    def verify(self, lldp):
        errors = ValidationException()
        node = ConfigNode('service.lldp', self.configstore).__getstate__()
        node.update(lldp)

        # Lazy load pycountry due to extra verbose DEBUG logging
        import pycountry
        if node['country_code'] and node['country_code'] not in pycountry.countries.indices['alpha2']:
            errors.add((0, 'country_code'), 'Invalid ISO-3166 alpha 2 code')

        if errors:
            raise errors

        return ['system']
    def run(self, lldp):
        try:
            node = ConfigNode('service.lldp', self.configstore)
            node.update(lldp)
            self.dispatcher.dispatch_event('service.lldp.changed', {
                'operation': 'updated',
                'ids': None,
            })
        except RpcException as e:
            raise TaskException(
                errno.ENXIO, 'Cannot reconfigure LLDP: {0}'.format(str(e))
            )

        return 'RELOAD'
Example #42
0
    def verify(self, ipfs):
        errors = []

        node = ConfigNode("service.ipfs", self.configstore).__getstate__()
        node.update(ipfs)

        if "path" in ipfs:
            if ipfs["path"] in [None, ""] or ipfs["path"].isspace():
                errors.append(("path", errno.EINVAL, "The provided path: '{0}' is not valid".format(ipfs["path"])))

        if errors:
            raise ValidationException(errors)

        return ["system"]
Example #43
0
    def run(self, webdav):
        node = ConfigNode('service.webdav', self.configstore).__getstate__()
        node.update(webdav)

        if node['http_port'] == node['https_port']:
            raise TaskException(errno.EINVAL, 'HTTP and HTTPS ports cannot be the same')

        if 'HTTPS' in node['protocol'] and not node['certificate']:
            raise TaskException(errno.EINVAL, 'SSL protocol specified without choosing a certificate')

        if node['certificate']:
            cert = self.dispatcher.call_sync(
                'crypto.certificate.query',
                [('name', '=', node['certificate'])],
                {'single': True}
            )

            if not cert:
                raise TaskException(errno.ENOENT, 'SSL Certificate not found.')

        try:
            node = ConfigNode('service.webdav', self.configstore)
            node.update(webdav)
            self.dispatcher.call_sync('etcd.generation.generate_group', 'services')
            self.dispatcher.call_sync('etcd.generation.generate_group', 'webdav')
            self.dispatcher.dispatch_event('service.webdav.changed', {
                'operation': 'updated',
                'ids': None,
            })
        except RpcException as e:
            raise TaskException(
                errno.ENXIO, 'Cannot reconfigure WebDAV: {0}'.format(str(e))
            )

        return 'RESTART'
Example #44
0
    def run(self, glusterd):
        try:
            node = ConfigNode('service.glusterd', self.configstore)
            node.update(glusterd)
            self.dispatcher.dispatch_event('service.glusterd.changed', {
                'operation': 'updated',
                'ids': None,
            })
        except RpcException as e:
            raise TaskException(
                errno.ENXIO, 'Cannot reconfigure Glusterd: {0}'.format(str(e))
            )

        return 'RESTART'
Example #45
0
    def run(self, dyndns):
        try:
            node = ConfigNode('service.dyndns', self.configstore)
            node.update(dyndns)
            self.dispatcher.call_sync('etcd.generation.generate_group', 'dyndns')
            self.dispatcher.dispatch_event('service.dyndns.changed', {
                'operation': 'updated',
                'ids': None,
            })
        except RpcException as e:
            raise TaskException(
                errno.ENXIO, 'Cannot reconfigure DynamicDNS: {0}'.format(str(e))
            )

        return 'RELOAD'
Example #46
0
    def run(self, dyndns):
        try:
            node = ConfigNode('service.dyndns', self.configstore)
            node.update(dyndns)
            self.dispatcher.call_sync('etcd.generation.generate_group', 'dyndns')
            self.dispatcher.dispatch_event('service.dyndns.changed', {
                'operation': 'updated',
                'ids': None,
            })
        except RpcException as e:
            raise TaskException(
                errno.ENXIO, 'Cannot reconfigure DynamicDNS: {0}'.format(str(e))
            )

        return 'RELOAD'
    def run(self, ftp):
        try:
            node = ConfigNode('service.ftp', self.configstore)
            node.update(ftp)
            self.dispatcher.call_sync('etcd.generation.generate_group', 'ftp')
            self.dispatcher.dispatch_event('service.ftp.changed', {
                'operation': 'updated',
                'ids': None,
            })
        except RpcException as e:
            raise TaskException(
                errno.ENXIO, 'Cannot reconfigure FTP: {0}'.format(str(e))
            )

        return 'RESTART'
Example #48
0
    def apply_state(self, service, restart=False, reload=False):
        svc = self.datastore.get_one('service_definitions',
                                     ('name', '=', service))
        if not svc:
            raise RpcException(errno.ENOENT,
                               'Service {0} not found'.format(service))

        state, _, pid = get_status(self.dispatcher, self.datastore, svc)
        node = ConfigNode('service.{0}'.format(service), self.configstore)

        if node['enable'].value and state != 'RUNNING':
            logger.info('Starting service {0}'.format(service))
            self.dispatcher.call_sync('service.ensure_started',
                                      service,
                                      timeout=120)

        elif not node['enable'].value and state != 'STOPPED':
            logger.info('Stopping service {0}'.format(service))
            self.dispatcher.call_sync('service.ensure_stopped',
                                      service,
                                      timeout=120)

        else:
            if restart:
                logger.info('Restarting service {0}'.format(service))
                self.dispatcher.call_sync('service.restart',
                                          service,
                                          timeout=120)
            elif reload:
                logger.info('Reloading service {0}'.format(service))
                self.dispatcher.call_sync('service.reload',
                                          service,
                                          timeout=120)
Example #49
0
    def run(self, id, updated_params):
        directory = self.datastore.get_by_id('directories', id)
        old_name = None

        if directory['immutable']:
            raise TaskException(
                errno.EPERM,
                'Directory {0} is immutable'.format(directory['name']))

        if 'name' in updated_params:
            old_name = directory['name']
            if self.datastore.exists('directories',
                                     ('name', '=', updated_params['name'])):
                raise TaskException(
                    errno.EEXIST,
                    'Directory {0} already exists'.format(directory['name']))

        directory.update(updated_params)
        self.datastore.update('directories', id, directory)
        self.dispatcher.call_sync('dscached.management.configure_directory',
                                  id)
        self.dispatcher.dispatch_event('directory.changed', {
            'operation': 'update',
            'ids': [id]
        })

        if old_name:
            node = ConfigNode('directory', self.configstore)
            search_order = node['search_order'].value
            if old_name in search_order:
                search_order.remove(old_name)
                search_order.append(directory['name'])
                node['search_order'] = search_order

            self.dispatcher.call_sync('dscached.management.reload_config')
Example #50
0
    def get_service_config(self, service):
        svc = self.datastore.get_one('service_definitions', ('name', '=', service))
        if not svc:
            raise RpcException(errno.EINVAL, 'Invalid service name')

        node = ConfigNode('service.{0}'.format(service), self.configstore)
        return node
Example #51
0
    def run(self, tftp):
        try:
            node = ConfigNode('service.tftpd', self.configstore)
            tftp['umask'] = get_integer(tftp['umask'])
            node.update(tftp)
            self.dispatcher.call_sync('etcd.generation.generate_group',
                                      'services')
            self.dispatcher.dispatch_event('service.tftpd.changed', {
                'operation': 'updated',
                'ids': None,
            })
        except RpcException as e:
            raise TaskException(errno.ENXIO,
                                'Cannot reconfigure TFTP: {0}'.format(str(e)))

        return 'RESTART'
Example #52
0
    def run(self, smb):
        node = ConfigNode("service.smb", self.configstore).__getstate__()
        netbiosname = smb.get("netbiosname")
        if netbiosname is not None:
            for n in netbiosname:
                if not validate_netbios_name(n):
                    raise TaskException(errno.EINVAL, "Invalid name {0}".format(n))
        else:
            netbiosname = node["netbiosname"]

        workgroup = smb.get("workgroup")
        if workgroup is not None:
            if not validate_netbios_name(workgroup):
                raise TaskException(errno.EINVAL, "Invalid name")
        else:
            workgroup = node["workgroup"]

        if workgroup.lower() in [i.lower() for i in netbiosname]:
            raise TaskException(errno.EINVAL, "NetBIOS and Workgroup must be unique")

        try:
            action = "NONE"
            node = ConfigNode("service.smb", self.configstore)
            if smb.get("filemask"):
                smb["filemask"] = get_integer(smb["filemask"])

            if smb.get("dirmask"):
                smb["dirmask"] = get_integer(smb["dirmask"])

            node.update(smb)
            configure_params(node.__getstate__(), self.dispatcher.call_sync("service.smb.ad_enabled"))

            try:
                rpc = smbconf.SambaMessagingContext()
                rpc.reload_config()
            except OSError:
                action = "RESTART"

            # XXX: Is restart to change netbios name/workgroup *really* needed?
            if "netbiosname" in smb or "workgroup" in smb:
                action = "RESTART"

            self.dispatcher.dispatch_event("service.smb.changed", {"operation": "updated", "ids": None})
        except RpcException as e:
            raise TaskException(errno.ENXIO, "Cannot reconfigure SMB: {0}".format(str(e)))

        return action
Example #53
0
    def run(self, openvpn_updated):
        node = ConfigNode('service.openvpn', self.configstore).__getstate__()
        node.update(openvpn_updated)

        if node['mode'] == 'pki':

                ca_cert_id = self.datastore.query('crypto.certificates',
                                                  ('name', '=', node['ca']), select=('id'))
                ca_cert_name = self.datastore.query('crypto.certificates',
                                                    ('id', '=', node['ca']), select=('name'))

                if not ca_cert_id:
                    if not ca_cert_name:
                        raise TaskException(errno.EINVAL,
                                            'Provided CA certificate does not exist in config database.')

                else:
                        openvpn_updated['ca'] = ca_cert_id[0]

                cert_id = self.datastore.query('crypto.certificates',
                                               ('name', '=', node['cert']), select=('id'))
                cert_name = self.datastore.query('crypto.certificates',
                                                 ('id', '=', node['cert']), select=('name'))

                if not cert_id:
                    if not cert_name:
                        raise TaskException(errno.EINVAL,
                                            'Provided certificate does not exist in config database.')
                else:
                    openvpn_updated['cert'] = cert_id[0]
                    openvpn_updated['key'] = cert_id[0]

                openvpn_user = self.datastore.exists('users', ('username', '=', node['user']))
                if not openvpn_user:
                    raise TaskException(errno.EINVAL, 'Provided user does not exist.')

                openvpn_group = self.datastore.exists('groups', ('name', '=', node['group']))
                if not openvpn_group:
                    raise TaskException(errno.EINVAL, 'Provided user does not exist.')

        try:
            node = ConfigNode('service.openvpn', self.configstore)
            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'
Example #54
0
    def run(self, rsyncd):

        if rsyncd.get('port') and is_port_open(rsyncd['port']):
            raise TaskException(errno.EINVAL,
                                'Provided port is already in use')

        try:
            node = ConfigNode('service.rsyncd', self.configstore)
            node.update(rsyncd)
            self.dispatcher.call_sync('etcd.generation.generate_group',
                                      'rsyncd')
            self.dispatcher.dispatch_event('service.rsyncd.changed', {
                'operation': 'updated',
                'ids': None,
            })
        except RpcException as e:
            raise TaskException(
                errno.ENXIO, 'Cannot reconfigure Rsyncd: {0}'.format(str(e)))
Example #55
0
 def get_config(self):
     config = ConfigNode('service.smb', self.configstore).__getstate__()
     if 'filemask' in config:
         if config['filemask'] is not None:
             config['filemask'] = get_unix_permissions(config['filemask'])
     if 'dirmask' in config:
         if config['dirmask'] is not None:
             config['dirmask'] = get_unix_permissions(config['dirmask'])
     return config
Example #56
0
    def run(self, lldp):
        node = ConfigNode('service.lldp', self.configstore).__getstate__()
        node.update(lldp)
        import pycountry
        if node['country_code'] and node[
                'country_code'] not in pycountry.countries.indices['alpha2']:
            raise TaskException(errno.EINVAL, 'Invalid ISO-3166 alpha 2 code')

        try:
            self.dispatcher.dispatch_event('service.lldp.changed', {
                'operation': 'updated',
                'ids': None,
            })
        except RpcException as e:
            raise TaskException(errno.ENXIO,
                                'Cannot reconfigure LLDP: {0}'.format(str(e)))

        return 'RELOAD'
Example #57
0
    def verify(self, ftp):
        errors = ValidationException()
        node = ConfigNode('service.ftp', self.configstore).__getstate__()
        node.update(ftp)

        pmin = node['passive_ports_min']
        if 'passive_ports_min' in ftp:
            if pmin and (pmin < 1024 or pmin > 65535):
                errors.add(
                    (0, 'passive_ports_min'),
                    'This value must be between 1024 and 65535, inclusive.')

        pmax = node['passive_ports_max']
        if 'passive_ports_max' in ftp:
            if pmax and (pmax < 1024 or pmax > 65535):
                errors.add(
                    (0, 'passive_ports_max'),
                    'This value must be between 1024 and 65535, inclusive.')
            elif pmax and pmin and pmin >= pmax:
                errors.add(
                    (0, 'passive_ports_max'),
                    'This value must be higher than minimum passive port.')

        if node['only_anonymous'] and not node['anonymous_path']:
            errors.add((0, 'anonymous_path'), errno.EINVAL,
                       'This field is required for anonymous login.')

        if node['tls'] is True and not node['tls_ssl_certificate']:
            errors.add((0, 'tls_ssl_certificate'),
                       'TLS specified without certificate.')

        if node['tls_ssl_certificate']:
            cert = self.dispatcher.call_sync(
                'crypto.certificate.query',
                [('id', '=', node['tls_ssl_certificate'])])
            if not cert:
                errors.add((0, 'tls_ssl_certificate'),
                           'SSL Certificate not found.')

        if errors:
            raise errors

        return ['system']
    def run(self, directory):
        try:
            params = self.dispatcher.call_sync(
                'dscached.management.normalize_parameters', directory['type'],
                directory.get('parameters', {}))
        except RpcException as err:
            raise TaskException(err.code, err.message)

        if self.datastore.exists('directories',
                                 ('name', '=', directory['name'])):
            raise TaskException(
                errno.EEXIST,
                'Directory {0} already exists'.format(directory['name']))

        normalize(
            directory, {
                'enabled': False,
                'enumerate': True,
                'immutable': False,
                'uid_range': None,
                'gid_range': None
            })

        # Replace passed in params with normalized ones
        directory['parameters'] = params

        for k, v in directory['parameters'].items():
            if k == 'password':
                directory['parameters'][k] = unpassword(v)

        if directory['type'] == 'winbind':
            normalize(directory, {
                'uid_range': [100000, 999999],
                'gid_range': [100000, 999999]
            })

            smb = self.dispatcher.call_sync('service.query',
                                            [('name', '=', 'smb')],
                                            {"single": True})
            if not q.get(smb, 'config.enable'):
                q.set(smb, 'config.enable', True)
                self.run_subtask_sync('service.update', smb['id'], smb)

        self.id = self.datastore.insert('directories', directory)
        self.dispatcher.call_sync('dscached.management.configure_directory',
                                  self.id)
        self.dispatcher.dispatch_event('directory.changed', {
            'operation': 'create',
            'ids': [self.id]
        })

        node = ConfigNode('directory', self.configstore)
        node['search_order'] = node['search_order'].value + [directory['name']]
        self.dispatcher.call_sync('dscached.management.reload_config')
        return self.id