class Main(object): def __init__(self): self.logger = logging.getLogger('dscached') self.config = None self.datastore = None self.configstore = None self.rpc = RpcContext() self.rpc.streaming_enabled = True self.rpc.streaming_burst = 16 self.client = None self.server = None self.plugin_dirs = [] self.plugins = {} self.directories = [] self.users_cache = TTLCacheStore() self.groups_cache = TTLCacheStore() self.hosts_cache = TTLCacheStore() self.cache_ttl = 7200 self.search_order = [] self.cache_enumerations = True self.cache_lookups = True self.home_directory_root = None self.account_service = AccountService(self) self.group_service = GroupService(self) self.rpc.register_service_instance('dscached.account', self.account_service) self.rpc.register_service_instance('dscached.group', self.group_service) self.rpc.register_service_instance('dscached.host', HostService(self)) self.rpc.register_service_instance('dscached.idmap', IdmapService(self)) self.rpc.register_service_instance('dscached.management', ManagementService(self)) self.rpc.register_service_instance('dscached.debug', DebugService()) def get_active_directories(self): return list( filter(lambda d: d and d.state == DirectoryState.BOUND, self.directories)) def get_searched_directories(self): return list( filter(lambda d: d and d.state == DirectoryState.BOUND, (self.get_directory_by_name(n) for n in self.get_search_order()))) def get_search_order(self): return self.search_order def get_directory_by_domain(self, domain_name): return first_or_default(lambda d: d.domain_name == domain_name, self.directories) def get_directory_by_name(self, name): return first_or_default(lambda d: d.name == name, self.directories) def get_directory_for_id(self, uid=None, gid=None): if uid is not None: if uid == 0: # Special case for root user return first_or_default(lambda d: d.plugin_type == 'local', self.directories) return first_or_default( lambda d: d.max_uid and d.max_uid >= uid >= d.min_uid, self.directories) if gid is not None: if gid == 0: # Special case for wheel group return first_or_default(lambda d: d.plugin_type == 'local', self.directories) return first_or_default( lambda d: d.max_gid and d.max_gid >= gid >= d.min_gid, self.directories) def get_home_directory(self, directory, username): if not self.home_directory_root: return '/nonexistent' return os.path.join(self.home_directory_root, f'{username}@{directory.domain_name}') def wait_for_etcd(self): self.client.test_or_wait_for_event( 'plugin.service_resume', lambda args: args['name'] == 'etcd.generation', lambda: 'etcd.generation' in self.client.call_sync( 'discovery.get_services')) def init_datastore(self): try: self.datastore = datastore.get_datastore() except datastore.DatastoreException as err: self.logger.error('Cannot initialize datastore: %s', str(err)) sys.exit(1) self.configstore = ConfigStore(self.datastore) def init_dispatcher(self): def on_error(reason, **kwargs): if reason in (ClientError.CONNECTION_CLOSED, ClientError.LOGOUT): self.logger.warning('Connection to dispatcher lost') self.connect() self.client = Client() self.client.on_error(on_error) self.connect() def init_server(self, address): self.server = Server(self) self.server.rpc = self.rpc self.server.streaming = True self.server.start(address, transport_options={'permissions': 0o777}) thread = Thread(target=self.server.serve_forever) thread.name = 'ServerThread' thread.daemon = True thread.start() def parse_config(self, filename): try: with open(filename, 'r') as f: self.config = json.load(f) except IOError as err: self.logger.error('Cannot read config file: %s', err.message) sys.exit(1) except ValueError: self.logger.error( 'Config file has unreadable format (not valid JSON)') sys.exit(1) self.plugin_dirs = self.config['dscached']['plugin-dirs'] def connect(self): while True: try: self.client.connect('unix:') self.client.login_service('dscached') self.client.enable_server(self.rpc) self.client.resume_service('dscached.account') self.client.resume_service('dscached.group') self.client.resume_service('dscached.host') self.client.resume_service('dscached.idmap') self.client.resume_service('dscached.management') self.client.resume_service('dscached.debug') return except (OSError, RpcException) as err: self.logger.warning( 'Cannot connect to dispatcher: {0}, retrying in 1 second'. format(str(err))) time.sleep(1) def scan_plugins(self): for i in self.plugin_dirs: self.scan_plugin_dir(i) def scan_plugin_dir(self, dir): self.logger.debug('Scanning plugin directory %s', dir) for f in os.listdir(dir): name, ext = os.path.splitext(os.path.basename(f)) if ext != '.py': continue try: plugin = load_module_from_file(name, os.path.join(dir, f)) plugin._init(self) except: self.logger.error('Cannot initialize plugin {0}'.format(f), exc_info=True) def register_plugin(self, name, cls): self.plugins[name] = cls self.logger.info('Registered plugin {0} (class {1})'.format(name, cls)) def register_schema(self, name, schema): self.client.register_schema(name, schema) def register_schemas(self): from freenas.dispatcher.model import context for name, schema in (s.__named_json_schema__() for s in context.local_json_schema_objects): self.logger.debug(f'Registering schema: {name}') self.client.register_schema(name, schema) def init_directories(self): for i in self.datastore.query('directories'): try: directory = Directory(self, i) self.directories.append(directory) directory.configure() except: continue def load_config(self): self.search_order = self.configstore.get('directory.search_order') self.cache_ttl = self.configstore.get('directory.cache_ttl') self.cache_enumerations = self.configstore.get( 'directory.cache_enumerations') self.cache_lookups = self.configstore.get('directory.cache_lookups') self.home_directory_root = self.configstore.get( 'system.home_directory_root') def checkin(self): checkin() def main(self): parser = argparse.ArgumentParser() parser.add_argument('-c', metavar='CONFIG', default=DEFAULT_CONFIGFILE, help='Middleware config file') parser.add_argument('-s', metavar='SOCKET', default=DEFAULT_SOCKET_ADDRESS, help='Socket address to listen on') args = parser.parse_args() configure_logging('dscached', 'DEBUG') setproctitle('dscached') self.config = args.c self.parse_config(self.config) self.init_datastore() self.init_dispatcher() self.load_config() self.init_server(args.s) self.scan_plugins() self.register_schemas() self.wait_for_etcd() self.init_directories() self.checkin() self.client.wait_forever()
class Main(object): def __init__(self): self.logger = logging.getLogger('dscached') self.config = None self.datastore = None self.configstore = None self.rpc = RpcContext() self.rpc.streaming_enabled = True self.rpc.streaming_burst = 16 self.client = None self.server = None self.plugin_dirs = [] self.plugins = {} self.directories = [] self.users_cache = TTLCacheStore() self.groups_cache = TTLCacheStore() self.hosts_cache = TTLCacheStore() self.cache_ttl = 7200 self.search_order = [] self.cache_enumerations = True self.cache_lookups = True self.rpc.register_service_instance('dscached.account', AccountService(self)) self.rpc.register_service_instance('dscached.group', GroupService(self)) self.rpc.register_service_instance('dscached.host', HostService(self)) self.rpc.register_service_instance('dscached.management', ManagementService(self)) self.rpc.register_service_instance('dscached.debug', DebugService()) def get_enabled_directories(self): return list(filter(None, (self.get_directory_by_name(n) for n in self.get_search_order()))) def get_search_order(self): return ['local', 'system'] + self.search_order def get_directory_by_domain(self, domain_name): return first_or_default(lambda d: d.domain_name == domain_name, self.directories) def get_directory_by_name(self, name): return first_or_default(lambda d: d.name == name, self.directories) def get_directory_for_id(self, uid=None, gid=None): if uid is not None: if uid == 0: # Special case for root user return first_or_default(lambda d: d.plugin_type == 'local', self.directories) return first_or_default( lambda d: d.max_uid and d.max_uid >= uid >= d.min_uid, self.directories ) if gid is not None: if gid == 0: # Special case for wheel group return first_or_default(lambda d: d.plugin_type == 'local', self.directories) return first_or_default( lambda d: d.max_gid and d.max_gid >= gid >= d.min_gid, self.directories ) def init_datastore(self): try: self.datastore = datastore.get_datastore() except datastore.DatastoreException as err: self.logger.error('Cannot initialize datastore: %s', str(err)) sys.exit(1) self.configstore = ConfigStore(self.datastore) def init_dispatcher(self): def on_error(reason, **kwargs): if reason in (ClientError.CONNECTION_CLOSED, ClientError.LOGOUT): self.logger.warning('Connection to dispatcher lost') self.connect() self.client = Client() self.client.on_error(on_error) self.connect() def init_server(self, address): self.server = Server(self) self.server.rpc = self.rpc self.server.start(address) thread = Thread(target=self.server.serve_forever) thread.name = 'ServerThread' thread.daemon = True thread.start() def parse_config(self, filename): try: with open(filename, 'r') as f: self.config = json.load(f) except IOError as err: self.logger.error('Cannot read config file: %s', err.message) sys.exit(1) except ValueError: self.logger.error('Config file has unreadable format (not valid JSON)') sys.exit(1) self.plugin_dirs = self.config['dscached']['plugin-dirs'] def connect(self): while True: try: self.client.connect('unix:') self.client.login_service('dscached') self.client.enable_server(self.rpc) self.client.resume_service('dscached.account') self.client.resume_service('dscached.group') self.client.resume_service('dscached.host') self.client.resume_service('dscached.management') self.client.resume_service('dscached.debug') return except (OSError, RpcException) as err: self.logger.warning('Cannot connect to dispatcher: {0}, retrying in 1 second'.format(str(err))) time.sleep(1) def scan_plugins(self): for i in self.plugin_dirs: self.scan_plugin_dir(i) def scan_plugin_dir(self, dir): self.logger.debug('Scanning plugin directory %s', dir) for f in os.listdir(dir): name, ext = os.path.splitext(os.path.basename(f)) if ext != '.py': continue try: plugin = imp.load_source(name, os.path.join(dir, f)) plugin._init(self) except: self.logger.error('Cannot initialize plugin {0}'.format(f), exc_info=True) def register_plugin(self, name, cls): self.plugins[name] = cls self.logger.info('Registered plugin {0} (class {1})'.format(name, cls)) def register_schema(self, name, schema): self.client.register_schema(name, schema) def init_directories(self): for i in self.datastore.query('directories'): try: directory = Directory(self, i) directory.configure() self.directories.append(directory) except BaseException as err: continue def load_config(self): self.search_order = self.configstore.get('directory.search_order') self.cache_ttl = self.configstore.get('directory.cache_ttl') self.cache_enumerations = self.configstore.get('directory.cache_enumerations') self.cache_lookups = self.configstore.get('directory.cache_lookups') def main(self): parser = argparse.ArgumentParser() parser.add_argument('-c', metavar='CONFIG', default=DEFAULT_CONFIGFILE, help='Middleware config file') parser.add_argument('-s', metavar='SOCKET', default=DEFAULT_SOCKET_ADDRESS, help='Socket address to listen on') args = parser.parse_args() configure_logging('/var/log/dscached.log', 'DEBUG') setproctitle.setproctitle('dscached') self.config = args.c self.parse_config(self.config) self.init_datastore() self.init_dispatcher() self.load_config() self.init_server(args.s) self.scan_plugins() self.init_directories() self.client.wait_forever()