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, 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'
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'
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
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']
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'
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'
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']
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'
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)))
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'
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'
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']] })
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 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']
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'
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, 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']] })
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)))
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
def verify(self, stanchion): errors = [] node = ConfigNode("service.stanchion", self.configstore).__getstate__() node.update(stanchion) if errors: raise ValidationException(errors) return ["system"]
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 verify(self, haproxy): errors = [] node = ConfigNode('service.haproxy', self.configstore).__getstate__() node.update(haproxy) if errors: raise ValidationException(errors) return ['system']
def verify(self, riakcs): errors = [] node = ConfigNode('service.riak_cs', self.configstore).__getstate__() node.update(riakcs) if errors: raise ValidationException(errors) return ['system']
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"
def verify(self, glusterd): errors = [] node = ConfigNode('service.glusterd', self.configstore).__getstate__() node.update(glusterd) if errors: raise ValidationException(errors) return ['system']
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)))
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']
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)))
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)))
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)) )
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'
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"]
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'
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'
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'
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)
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')
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
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'
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
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'
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)))
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
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'
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