def test_storage_volume_config(tmpdir): """Test storage volume configuration objects.""" # Default config. conf = config.env() assert isinstance(conf.get(config.FLOWSERV_FILESTORE), dict) doc = {'type': 'fs'} conf.volume(config=doc) assert conf.get(config.FLOWSERV_FILESTORE) == doc # Configure from file. filename = os.path.join(tmpdir, 'config.json') util.write_object(filename=filename, obj=doc) os.environ[config.FLOWSERV_FILESTORE] = filename conf = config.env() assert conf.get(config.FLOWSERV_FILESTORE) == doc del os.environ[config.FLOWSERV_FILESTORE]
def configuration(): """Print configuration variables for flowServ.""" envvar = 'export {}={}' click.echo('Configuration settings:\n') for var, value in env().items(): click.echo(envvar.format(var, value)) click.echo()
def ClientAPI( env: Optional[Dict] = None, basedir: Optional[str] = None, database: Optional[str] = None, open_access: Optional[bool] = None, run_async: Optional[bool] = None, user_id: Optional[str] = None ) -> APIFactory: """Create an instance of the API factory that is responsible for generating API instances for a flowserv client. The main distinction here is whether a connection is made to a local instance of the service or to a remote instance. This distinction is made based on the value of the FLOWSERV_CLIENT environment variable that takes the values 'local' or 'remote'. The default is 'local'. Provides the option to alter the default settings of environment variables. Parameters ---------- env: dict, default=None Dictionary with configuration parameter values. basedir: string, default=None Base directory for all workflow files. If no directory is given or specified in the environment a temporary directory will be created. database: string, default=None Optional database connect url. open_access: bool, default=None Use an open access policy if set to True. run_async: bool, default=False Run workflows in asynchronous mode. user_id: string, default=None Optional identifier for the authenticated API user. Returns ------- flowserv.service.api.APIFactory """ # Get the base configuration settings from the environment if not given. env = env if env is not None else config.env() if not isinstance(env, Config): env = Config(env) # Update configuration based on the given optional arguments. if basedir is not None: env.basedir(basedir) if database is not None: env.database(database) if open_access is not None and open_access: env.open_access() # By default, the client runs all workflows synchronously. if run_async is not None and run_async: env.run_async() elif env.get(config.FLOWSERV_ASYNC) is None: env.run_sync() # Create local or remote API factory depending on the FLOWSERV_CLIENT value. client = env.get(config.FLOWSERV_CLIENT, config.LOCAL_CLIENT) if client == config.LOCAL_CLIENT: return LocalAPIFactory(env=env, user_id=user_id) elif client == config.REMOTE_CLIENT: # Not implemented yet. pass raise ValueError("inalid client type '{}'".format(client))
def test_service_descriptor_urls(): """Test getting Urls from the service descriptor.""" service = ServiceDescriptor.from_config(env=config.env()) doc = service.to_dict() doc['url'] = 'http://localhost//' service = ServiceDescriptor(doc=doc) assert service.urls( route.USERS_ACTIVATE) == 'http://localhost/users/activate' url = service.urls(route.FILES_DELETE, fileId='F1', userGroupId='G0') assert url == 'http://localhost/uploads/G0/files/F1'
def remote_service(): """Get a test instance for the remote service API.""" doc = ServiceDescriptor.from_config(env=config.env()).to_dict() doc['url'] = 'test' service = ServiceDescriptor(doc) return API(service=service, workflow_service=RemoteWorkflowService(descriptor=service), group_service=RemoteWorkflowGroupService(descriptor=service), upload_service=RemoteUploadFileService(descriptor=service), run_service=RemoteRunService(descriptor=service), user_service=RemoteUserService(descriptor=service))
def init(force=False): """Initialize database and base directories for the API.""" if not force: click.echo('This will erase an existing database.') click.confirm('Continue?', default=True, abort=True) # Create a new instance of the database. Raise errors if the database URL # is not set. config = env() connect_url = config.get(FLOWSERV_DB) if connect_url is None: raise err.MissingConfigurationError('database Url') DB(connect_url=connect_url).init()
def __init__(self, env: Optional[Dict] = None, basedir: Optional[str] = None, database: Optional[str] = None, open_access: Optional[bool] = None, run_async: Optional[bool] = None, clear: Optional[bool] = False, user_id: Optional[str] = None): """Initialize the client API factory. Provides the option to alter the default settings of environment variables and for using custom instance of the database and workflow engine. Parameters ---------- env: dict, default=None Dictionary with configuration parameter values. basedir: string, default=None Base directory for all workflow files. If no directory is given or specified in the environment a temporary directory will be created. database: str, default=None Databse connection Url. open_access: bool, default=None Use an open access policy if set to True. run_async: bool, default=False Run workflows in asynchronous mode. clear: bool, default=False Remove all existing files and folders in the base directory if the clear flag is True. user_id: string, default=None Identifier for an authenticated default user. """ # Get the base configuration settings from the environment if not given. self.env = env if env is not None else config.env() # Set the base directory and ensure that it exists. Create a temporary # directory if no base directory is specified. If a base directory was # specified by the user it will override the settings from the global # environment. basedir = basedir if basedir is not None else self.env.get( config.FLOWSERV_BASEDIR) self.basedir = basedir if basedir is not None else tempfile.mkdtemp() self.env[config.FLOWSERV_BASEDIR] = self.basedir # Remove all existing files and folders in the base directory if the # clear flag is True. if clear: util.cleardir(self.basedir) self.service = ClientAPI(env=self.env, basedir=self.basedir, database=database, open_access=open_access, run_async=run_async, user_id=user_id)
def test_service_descriptor(): """Test the service descriptor object.""" schema = validator('ServiceDescriptor') # Local service descriptor (no arguments). service = ServiceDescriptor.from_config(env=config.env()) schema.validate(service.to_dict()) assert service.routes().get(SERVICE_DESCRIPTOR) is not None assert service.routes().get('foo') is None # Remote service descriptor (init from local serialization). service = ServiceDescriptor(doc=service.to_dict(), routes={'foo': 'bar'}) schema.validate(service.to_dict()) assert service.routes().get(SERVICE_DESCRIPTOR) is not None schema.validate(service.to_dict()) assert service.routes().get('foo') == 'bar'
def get_app(app_key: Optional[str] = None) -> Workflow: """Get the application handle for the specified application identifier. If no application identifier is given it is expected in the environment variable FLOWSERV_APP. Parameters ---------- app_key: string Unique identifier referencing the workflow that defines the application that is being run. Returns ------- flowserv.client.app.workflow.Workflow """ return open_app(env=config.env().open_access(), identifier=app_key)
def __init__(self, env: Optional[Dict] = None, db: Optional[DB] = None, engine: Optional[WorkflowController] = None, user_id: Optional[str] = None): """Initialize the API factory from a given set of configuration parameters and their values. If the configuration dictionary is not provided the current values from the respective environment variables are used. The option to initialize the associated database and workflow engine is promarily intended for test purposes. Parameters ---------- env: dict, default=None Dictionary that provides access to configuration parameter values. db: flowserv.model.database.DB, default=None Optional default database. engine: flowserv.controller.base.WorkflowController, default=None Optional workflow controller (for test purposes). user_id: string, default=None Optional identifier for the authenticated API user. """ # Use the current environment settings if the configuration dictionary # is not given. env = env if env is not None else config.env() super(LocalAPIFactory, self).__init__(env) # Ensure that the base directory is set and exists. self[BASEDIR] = self.get(BASEDIR, config.API_DEFAULTDIR()) os.makedirs(self[BASEDIR], exist_ok=True) # Initialize that database. self._db = db if db is not None else init_db(self) # Initialize the workflow engine. self._engine = engine if engine is not None else init_backend(self) # Initialize the file store. self._fs = FS(self) # Ensure that the authentication policy identifier is set. self[AUTH] = self.get(AUTH, config.AUTH_OPEN) # Authenticated default user. The initial value depends on the given # value for the user_id or authentication policy. self._user_id = config.DEFAULT_USER if not user_id and self[ AUTH] == config.AUTH_OPEN else user_id
def init_service(basedir: Optional[str] = None, database: Optional[str] = None) -> APIFactory: """Configure the API factory that is used by the Flask application. Parameters ---------- basedir: string, default=None Base directory for all workflow files. If no directory is given or specified in the environment a temporary directory will be created. database: string, default=None Optional database connect url. Returns ------- flowserv.service.api.APIFactory """ global service service = ClientAPI( env=env().auth().run_async().webapp(), basedir=basedir, database=database ) return service
def open_app(env: Optional[Dict] = None, identifier: Optional[str] = None) -> Workflow: """Shortcut to open an instance for a workflow application from the environment configuration settings. Parameters ---------- env: dict, default=None Dictionary with configuration parameters to use instaed of the values in the global environment. identifier: string, default=None Identifier of the workflow application. Returns ------- flowserv.client.app.workflow.Workflow """ # Get the base configuration settings from the environment if not given. env = env if env is not None else config.env() # Return an instance of the specified application workflow. Get the # application identifier from the app if not given. return Flowserv(env=env).open( identifier=env.get(config.FLOWSERV_APP, identifier))
def test_config_env(var, value, result): """Test getting configuration values from environment variables.""" os.environ[var] = value conf = config.env() assert conf[var] == result del os.environ[var]