def test_is_authenticated_token(self, mock_config_file_with_auth): """test checking if the user is authenticated via a token""" config = Configuration(mock_config_file_with_auth[0]) mgr = get_identity_manager(config) assert type(mgr) == LocalIdentityManager # Don't check at_hash claim due to password grant not setting it in the token mgr.validate_at_hash_claim = False # Invalid with no token assert mgr.is_authenticated() is False assert mgr.is_authenticated(None) is False assert mgr.is_authenticated("asdfasdfa") is False assert mgr.is_authenticated("asdfasdfa", "asdfasdffdgfgh") is False assert mgr.is_authenticated( mock_config_file_with_auth[1]['access_token'], mock_config_file_with_auth[1]['id_token']) is True # Second access should load from disk and not need a token mgr2 = get_identity_manager(config) assert mgr2.is_authenticated() is True assert mgr2.is_authenticated( "asdfasdfa") is True # An "expired" token will essentially do this # Double check logging out un-authenticates mgr2.logout() assert mgr.is_authenticated() is False assert mgr2.is_authenticated() is False clean_local_cache(mgr)
def test_get_user_profile(self, mock_config_file_with_auth_browser): """test getting a user profile from Auth0""" config = Configuration(mock_config_file_with_auth_browser[0]) mgr = get_identity_manager(config) assert type(mgr) == BrowserIdentityManager # Don't check at_hash claim due to password grant not setting it in the token mgr.validate_at_hash_claim = False # Load User with pytest.raises(AuthenticationError): # Should fail without a token mgr.get_user_profile() # Load User u = mgr.get_user_profile(mock_config_file_with_auth_browser[2]['access_token'], mock_config_file_with_auth_browser[2]['id_token']) assert type(u) == User assert u.username == "johndoe" assert u.email == "*****@*****.**" assert u.given_name == "John" assert u.family_name == "Doe" # Second access should fail since not cached mgr2 = get_identity_manager(config) with pytest.raises(AuthenticationError): # Should fail without a token mgr2.get_user_profile()
def test_authenticate_user_exists_token(self, mock_config_file_with_auth): """test getting a user after stored locally already""" config = Configuration(mock_config_file_with_auth[0]) mgr = get_identity_manager(config) assert type(mgr) == LocalIdentityManager # Save User assert os.path.exists(os.path.join(mgr.auth_dir, 'cached_id_jwt')) is False mgr._safe_cached_id_access(mock_config_file_with_auth[1]['id_token']) assert os.path.exists(os.path.join(mgr.auth_dir, 'cached_id_jwt')) is True # Load User u2 = mgr.get_user_profile( mock_config_file_with_auth[1]['access_token'], mock_config_file_with_auth[1]['id_token']) assert type(u2) == User assert "johndoe" == u2.username assert "*****@*****.**" == u2.email assert "John" == u2.given_name assert "Doe" == u2.family_name clean_local_cache(mgr)
def test_load_user_refresh(self, mock_config_file_with_auth): """handling a new token for the same user""" config = Configuration(mock_config_file_with_auth[0]) with mock.patch.object(jose.jwt, 'get_unverified_claims', lambda x: mock_jwt_claims(x)): with mock.patch.object(LocalIdentityManager, 'validate_jwt_token', mock_jwt_validate): mgr = get_identity_manager(config) assert type(mgr) == LocalIdentityManager # Save User assert os.path.exists(os.path.join(mgr.auth_dir, 'cached_id_jwt')) is False mgr._safe_cached_id_access(json.dumps({'nickname': 'testuser', 'dummy': '1'})) assert os.path.exists(os.path.join(mgr.auth_dir, 'cached_id_jwt')) is True with open(os.path.join(mgr.auth_dir, 'cached_id_jwt'), 'rt') as cf: data = json.loads(json.load(cf)) assert data['dummy'] == '1' # Load User u2 = mgr._load_user(json.dumps({'nickname': 'testuser', 'dummy': '2'})) assert type(u2) == User assert "testuser" == u2.username assert "*****@*****.**" == u2.email assert "test" == u2.given_name assert "user" == u2.family_name with open(os.path.join(mgr.auth_dir, 'cached_id_jwt'), 'rt') as cf: data = json.loads(json.load(cf)) assert data['dummy'] == '2' clean_local_cache(mgr)
def test_get_profile_attribute(self, mock_config_file_with_auth): """test getting profile attributes safely from the profile dictionary""" config = Configuration(mock_config_file_with_auth[0]) mgr = get_identity_manager(config) profile_data = {"username": "", "email": "*****@*****.**"} assert mgr._get_profile_attribute(profile_data, "email") == "*****@*****.**" assert mgr._get_profile_attribute(profile_data, "email", False) == "*****@*****.**" assert mgr._get_profile_attribute(profile_data, "username", False) is None with pytest.raises(AuthenticationError): mgr._get_profile_attribute(profile_data, "username") with pytest.raises(AuthenticationError): mgr._get_profile_attribute(profile_data, "username", True) with pytest.raises(AuthenticationError): mgr._get_profile_attribute(profile_data, "first_name") assert mgr._get_profile_attribute(profile_data, "first_name", False) is None clean_local_cache(mgr)
def fixture_working_dir_lfs_disabled(): """A pytest fixture that creates a temporary working directory, config file, schema, and local user identity """ # Create temp dir config_file, temp_dir = _create_temp_work_dir(lfs_enabled=False) # Create user identity insert_cached_identity(temp_dir) # Create test client schema = graphene.Schema(query=LabbookQuery, mutation=LabbookMutations) with patch.object(Configuration, 'find_default_config', lambda self: config_file): # Load User identity into app context app = Flask("lmsrvlabbook") app.config["LABMGR_CONFIG"] = Configuration() app.config["LABMGR_ID_MGR"] = get_identity_manager(Configuration()) with app.app_context(): # within this block, current_app points to app. Set current usert explicitly(this is done in the middleware) flask.g.user_obj = app.config["LABMGR_ID_MGR"].get_user_profile() # Create a test client client = Client(schema, middleware=[DataloaderMiddleware()], context_value=ContextMock()) yield config_file, temp_dir, client, schema # name of the config file, temporary working directory, the schema # Remove the temp_dir shutil.rmtree(temp_dir)
def test_load_user_mismatch(self, mock_config_file_with_auth): """handling a new token for the same user""" config = Configuration(mock_config_file_with_auth[0]) with mock.patch.object(jose.jwt, 'get_unverified_claims', lambda x: mock_jwt_claims(x)): with mock.patch.object(LocalIdentityManager, 'validate_jwt_token', mock_jwt_validate): mgr = get_identity_manager(config) assert type(mgr) == LocalIdentityManager # Save User assert os.path.exists( os.path.join(mgr.auth_dir, 'cached_id_jwt')) is False mgr._safe_cached_id_access( json.dumps({ 'nickname': 'olduser', 'dummy': '1' })) assert os.path.exists( os.path.join(mgr.auth_dir, 'cached_id_jwt')) is True # Load User u2 = mgr._load_user( json.dumps({ 'nickname': 'testuser', 'dummy': '1' })) assert os.path.exists( os.path.join(mgr.auth_dir, 'cached_id_jwt')) is False clean_local_cache(mgr)
def test_check_first_login_no_user_locally_no_repo( self, mock_import, mock_config_file_with_auth_first_login, cleanup_auto_import): """Test login with the user in the repo alread""" # Add mock for call to auth service responses.add(responses.GET, 'https://usersrv.gigantum.io/user', json={'exists': False}, status=404) responses.add(responses.POST, 'https://usersrv.gigantum.io/user', status=201) config = Configuration(mock_config_file_with_auth_first_login[0]) mgr = get_identity_manager(config) # Don't check at_hash claim due to password grant not setting it in the token mgr.validate_at_hash_claim = False mgr._check_first_login( "johndoe", access_token=mock_config_file_with_auth_first_login[2] ['access_token']) # Should import labbook - note we aren't mocking all the way to the workers time.sleep(5) assert os.path.exists( os.path.join('/mnt', 'gigantum', "johndoe", "johndoe", "labbooks", "my-first-project")) is True
def mock_create_labbooks(fixture_working_dir): # Create a labbook in the temporary directory config_file = fixture_working_dir[0] im = InventoryManager(fixture_working_dir[0]) lb = im.create_labbook(UT_USERNAME, UT_USERNAME, UT_LBNAME, description="Cats labbook 1") # Create a file in the dir with open(os.path.join(fixture_working_dir[1], 'unittest-examplefile'), 'w') as sf: sf.write("test data") sf.seek(0) FileOperations.insert_file(lb, 'code', sf.name) assert os.path.isfile( os.path.join(lb.root_dir, 'code', 'unittest-examplefile')) # Create test client schema = graphene.Schema(query=LabbookQuery, mutation=LabbookMutations) with patch.object(Configuration, 'find_default_config', lambda self: config_file): app = Flask("lmsrvlabbook") app.config["LABMGR_CONFIG"] = Configuration() app.config["LABMGR_ID_MGR"] = get_identity_manager(Configuration()) with app.app_context(): flask.g.user_obj = app.config["LABMGR_ID_MGR"].get_user_profile() client = Client( schema, middleware=[DataloaderMiddleware(), error_middleware], context_value=ContextMock()) yield lb, client, schema shutil.rmtree(fixture_working_dir, ignore_errors=True)
def test_get_user_profile(self, mock_config_file_with_auth): """test getting a user profile from Auth0""" config = Configuration(mock_config_file_with_auth[0]) mgr = get_identity_manager(config) assert type(mgr) == LocalIdentityManager # Don't check at_hash claim due to password grant not setting it in the token mgr.validate_at_hash_claim = False # Load User with pytest.raises(AuthenticationError): # Should fail without a token mgr.get_user_profile() # Load User u = mgr.get_user_profile(mock_config_file_with_auth[1]['access_token'], mock_config_file_with_auth[1]['id_token']) assert type(u) == User assert os.path.exists(os.path.join(mgr.auth_dir, 'cached_id_jwt')) is True assert u.username == "johndoe" assert u.email == "*****@*****.**" assert u.given_name == "John" assert u.family_name == "Doe" # Seccond access should load from disk and not need a token mgr2 = get_identity_manager(config) u2 = mgr2.get_user_profile() assert type(u) == User assert os.path.exists(os.path.join(mgr.auth_dir, 'cached_id_jwt')) is True assert u2.username == "johndoe" assert u2.email == "*****@*****.**" assert u2.given_name == "John" assert u2.family_name == "Doe" # Double check logging out un-authenticates mgr2.logout() with pytest.raises(AuthenticationError): # Should fail without a token mgr.get_user_profile() with pytest.raises(AuthenticationError): # Should fail without a token mgr2.get_user_profile() clean_local_cache(mgr)
def fixture_single_dataset(): """A pytest fixture that creates a temporary working directory, a config file to match, creates the schema, and populates the environment component repository. Class scope modifier attached """ # Create temp dir config_file, temp_dir = _create_temp_work_dir() # Create user identity insert_cached_identity(temp_dir) # Create test client schema = graphene.Schema(query=LabbookQuery, mutation=LabbookMutations) # Create a bunch of lab books im = InventoryManager(config_file) ds = im.create_dataset('default', 'default', "test-dataset", storage_type="gigantum_object_v1", description="Cats 2") m = Manifest(ds, 'default') cm_class = get_cache_manager_class(ds.client_config) cache_mgr = cm_class(ds, 'default') revision = ds.git.repo.head.commit.hexsha os.makedirs(os.path.join(cache_mgr.cache_root, revision, "other_dir")) helper_append_file(cache_mgr.cache_root, revision, "test1.txt", "asdfasdf") helper_append_file(cache_mgr.cache_root, revision, "test2.txt", "rtg") helper_append_file(cache_mgr.cache_root, revision, "test3.txt", "wer") helper_append_file(cache_mgr.cache_root, revision, "other_dir/test4.txt", "dfasdfhfgjhg") helper_append_file(cache_mgr.cache_root, revision, "other_dir/test5.txt", "fdghdfgsa") m.update() with patch.object(Configuration, 'find_default_config', lambda self: config_file): # Load User identity into app context app = Flask("lmsrvlabbook") app.config["LABMGR_CONFIG"] = Configuration() app.config["LABMGR_ID_MGR"] = get_identity_manager(Configuration()) with app.app_context(): # within this block, current_app points to app. Set current user explicitly (this is done in the middleware) flask.g.user_obj = app.config["LABMGR_ID_MGR"].get_user_profile() # Create a test client client = Client(schema, middleware=[DataloaderMiddleware()], context_value=ContextMock()) yield config_file, temp_dir, client, ds, cache_mgr # Remove the temp_dir shutil.rmtree(temp_dir)
def test_is_authenticated_token(self, mock_config_file_with_auth_browser): """test checking if the user is authenticated via a token""" # TODO: Possibly move to integration tests or fully mock since this makes a call out to Auth0 config = Configuration(mock_config_file_with_auth_browser[0]) mgr = get_identity_manager(config) assert type(mgr) == BrowserIdentityManager # Invalid with no token assert mgr.is_authenticated() is False assert mgr.is_authenticated(None) is False assert mgr.is_authenticated("asdfasdfa") is False assert mgr.is_authenticated(mock_config_file_with_auth_browser[2]['access_token']) is True # Second access should fail since not cached mgr2 = get_identity_manager(config) assert mgr2.is_authenticated() is False assert mgr2.is_authenticated("asdfasdfa") is False # An "expired" token will essentially do this
def test_load_user_no_user(self, mock_config_file_with_auth): """test getting an identity manager""" config = Configuration(mock_config_file_with_auth[0]) mgr = get_identity_manager(config) assert type(mgr) == LocalIdentityManager # Load User assert mgr._load_user(None) is None clean_local_cache(mgr)
def test_get_identity_manager(self, mock_config_file_with_auth): """test getting an identity manager""" config = Configuration(mock_config_file_with_auth[0]) mgr = get_identity_manager(config) assert type(mgr) == LocalIdentityManager assert mgr.config == config assert mgr.auth_dir == os.path.join(mock_config_file_with_auth[2], '.labmanager', 'identity') assert mgr.user is None assert mgr.rsa_key is None assert mgr._user is None
def test_is_session_valid(self, mock_config_file_with_auth_browser): """test check for valid session""" config = Configuration(mock_config_file_with_auth_browser[0]) mgr = get_identity_manager(config) assert type(mgr) == BrowserIdentityManager # Invalid with no token assert mgr.is_token_valid() is False assert mgr.is_token_valid(None) is False assert mgr.is_token_valid("asdfasdfasdf") is False assert mgr.is_token_valid(mock_config_file_with_auth_browser[2]['access_token']) is True assert mgr.rsa_key is not None
def test_check_first_login_user_locally(self, mock_config_file_with_auth_first_login, cleanup_auto_import): """Test login, but the user already logged into this instance""" # fake the user already existing by creating the user directory working_dir = mock_config_file_with_auth_first_login[1] os.makedirs(os.path.join(working_dir, "johndoe")) config = Configuration(mock_config_file_with_auth_first_login[0]) mgr = get_identity_manager(config) mgr._check_first_login("johndoe", access_token=mock_config_file_with_auth_first_login[2]['access_token']) # Should not import labbook - note we aren't mocking all the way to the workers time.sleep(5) assert os.path.exists(os.path.join('/mnt', 'gigantum', "johndoe", "johndoe", "labbooks", "awful-intersections-demo")) is False
def test_check_first_login_errors(self, mock_config_file_with_auth_first_login, cleanup_auto_import): """Test login, but the user already logged into this instance""" # fake the user already existing by creating the user directory working_dir = mock_config_file_with_auth_first_login[1] os.makedirs(os.path.join(working_dir, "johndoe")) config = Configuration(mock_config_file_with_auth_first_login[0]) mgr = get_identity_manager(config) with pytest.raises(ValueError): mgr._check_first_login("", "") with pytest.raises(ValueError): mgr._check_first_login("johndoe", "") with pytest.raises(ValueError): mgr._check_first_login("", "asdf")
def test_load_corrupt(self, mock_config_file_with_auth): """handling a corrupted cached id token""" config = Configuration(mock_config_file_with_auth[0]) mgr = get_identity_manager(config) assert type(mgr) == LocalIdentityManager os.makedirs(mgr.auth_dir, exist_ok=True) with open(os.path.join(mgr.auth_dir, 'cached_id_jwt'), 'wt') as cf: cf.write('"sdfsd"df"') assert os.path.exists(os.path.join(mgr.auth_dir, 'cached_id_jwt')) is True # Load User with pytest.raises(json.decoder.JSONDecodeError): mgr._load_user(None) assert os.path.exists(os.path.join(mgr.auth_dir, 'cached_id_jwt')) is False clean_local_cache(mgr)
def fixture_working_dir_env_repo_scoped(): """A pytest fixture that creates a temporary working directory, a config file to match, creates the schema, and populates the environment component repository. Class scope modifier attached """ # Create temp dir config_file, temp_dir = _create_temp_work_dir() # Create user identity insert_cached_identity(temp_dir) # Create test client schema = graphene.Schema(query=LabbookQuery, mutation=LabbookMutations) # get environment data and index erm = RepositoryManager(config_file) erm.update_repositories() erm.index_repositories() with patch.object(Configuration, 'find_default_config', lambda self: config_file): # Load User identity into app context app = Flask("lmsrvlabbook") app.config["LABMGR_CONFIG"] = Configuration() app.config["LABMGR_ID_MGR"] = get_identity_manager(Configuration()) with app.app_context(): # within this block, current_app points to app. Set current user explicitly (this is done in the middleware) flask.g.user_obj = app.config["LABMGR_ID_MGR"].get_user_profile() # Create a test client client = Client( schema, middleware=[DataloaderMiddleware(), error_middleware], context_value=ContextMock()) # name of the config file, temporary working directory, the schema yield config_file, temp_dir, client, schema # Remove the temp_dir shutil.rmtree(temp_dir)
def test_logout_user(self, mock_config_file_with_auth): """test getting an identity manager""" config = Configuration(mock_config_file_with_auth[0]) mgr = get_identity_manager(config) assert type(mgr) == LocalIdentityManager # Save User assert os.path.exists(os.path.join(mgr.auth_dir, 'cached_id_jwt')) is False mgr._safe_cached_id_access(mock_config_file_with_auth[1]['id_token']) assert os.path.exists(os.path.join(mgr.auth_dir, 'cached_id_jwt')) is True assert os.path.exists(os.path.join(mgr.auth_dir, 'jwks.json')) is True # Load User mgr.logout() assert os.path.exists(os.path.join(mgr.auth_dir, 'cached_id_jwt')) is False assert os.path.exists(os.path.join(mgr.auth_dir, 'jwks.json')) is False assert mgr.user is None assert mgr.rsa_key is None assert mgr._load_user(None) is None clean_local_cache(mgr)
def fixture_working_dir_with_cached_user(): """A pytest fixture that creates a temporary working directory, config file, schema, and local user identity """ # Create temp dir config_file, temp_dir = _create_temp_work_dir() insert_cached_identity(temp_dir) with patch.object(Configuration, 'find_default_config', lambda self: config_file): app = Flask("lmsrvlabbook") # Load configuration class into the flask application app.config["LABMGR_CONFIG"] = Configuration() app.config["LABMGR_ID_MGR"] = get_identity_manager(Configuration()) with app.app_context(): # within this block, current_app points to app. yield config_file, temp_dir # name of the config file, temporary working directory # Remove the temp_dir shutil.rmtree(temp_dir)
def test_get_identity_manager_errors(self, mock_config_file_with_auth): """Testing get_identity_manager error handling""" config = Configuration(mock_config_file_with_auth[0]) config.config['auth']['identity_manager'] = "asdfasdf" with pytest.raises(ValueError): get_identity_manager(config) del config.config['auth']['identity_manager'] with pytest.raises(ValueError): get_identity_manager(config) del config.config['auth'] with pytest.raises(ValueError): get_identity_manager(config)
logger.info(f"Using custom user configuration from {user_conf_path}") try: with open(user_conf_path) as user_file: yaml.safe_load(user_file) shutil.copyfile(user_conf_path, os.path.expanduser("~/user-config.yaml")) except Exception as e: logger.error("Error parsing user config, cannot proceed") raise else: logger.info("No custom user configuration found") random_bytes = os.urandom(32) app.config["SECRET_KEY"] = base64.b64encode(random_bytes).decode('utf-8') app.config["LABMGR_CONFIG"] = config = Configuration() app.config["LABMGR_ID_MGR"] = get_identity_manager(Configuration()) if config.config["flask"]["allow_cors"]: # Allow CORS CORS(app, max_age=7200) # Set Debug mode app.config['DEBUG'] = config.config["flask"]["DEBUG"] # Register LabBook service app.register_blueprint(blueprint.complete_labbook_service) # Configure CHP try: api_prefix = app.config["LABMGR_CONFIG"].config['proxy']["labmanager_api_prefix"] apparent_proxy_port = app.config["LABMGR_CONFIG"].config['proxy']["apparent_proxy_port"]
def fixture_working_dir_dataset_populated_scoped(): """A pytest fixture that creates a temporary working directory, a config file to match, creates the schema, and populates the environment component repository. Class scope modifier attached """ # Create temp dir config_file, temp_dir = _create_temp_work_dir() # Create user identity insert_cached_identity(temp_dir) # Create test client schema = graphene.Schema(query=LabbookQuery, mutation=LabbookMutations) # Create a bunch of lab books im = InventoryManager(config_file) im.create_dataset('default', 'default', "dataset2", storage_type="gigantum_object_v1", description="Cats 2") time.sleep(1.1) im.create_dataset('default', 'default', "dataset3", storage_type="gigantum_object_v1", description="Cats 3") time.sleep(1.1) im.create_dataset('default', 'default', "dataset4", storage_type="gigantum_object_v1", description="Cats 4") time.sleep(1.1) im.create_dataset('default', 'default', "dataset5", storage_type="gigantum_object_v1", description="Cats 5") time.sleep(1.1) im.create_dataset('default', 'default', "dataset6", storage_type="gigantum_object_v1", description="Cats 6") time.sleep(1.1) im.create_dataset('default', 'default', "dataset7", storage_type="gigantum_object_v1", description="Cats 7") time.sleep(1.1) im.create_dataset('default', 'default', "dataset8", storage_type="gigantum_object_v1", description="Cats 8") time.sleep(1.1) im.create_dataset('default', 'default', "dataset9", storage_type="gigantum_object_v1", description="Cats 9") time.sleep(1.1) im.create_dataset('default', 'test3', "dataset-other", storage_type="gigantum_object_v1", description="Cats other") time.sleep(1.1) im.create_labbook('test3', 'test3', "labbook-0", description="This should not show up.") im.create_dataset('default', 'default', "dataset1", storage_type="gigantum_object_v1", description="Cats 1") time.sleep(1.1) with patch.object(Configuration, 'find_default_config', lambda self: config_file): # Load User identity into app context app = Flask("lmsrvlabbook") app.config["LABMGR_CONFIG"] = Configuration() app.config["LABMGR_ID_MGR"] = get_identity_manager(Configuration()) with app.app_context(): # within this block, current_app points to app. Set current user explicitly (this is done in the middleware) flask.g.user_obj = app.config["LABMGR_ID_MGR"].get_user_profile() # Create a test client client = Client(schema, middleware=[DataloaderMiddleware()], context_value=ContextMock()) yield config_file, temp_dir, client, schema # Remove the temp_dir shutil.rmtree(temp_dir)
def build_image_for_jupyterlab(): # Create temp dir config_file, temp_dir = _create_temp_work_dir() # Create user identity insert_cached_identity(temp_dir) # Create test client schema = graphene.Schema(query=LabbookQuery, mutation=LabbookMutations) # get environment data and index erm = RepositoryManager(config_file) erm.update_repositories() erm.index_repositories() with patch.object(Configuration, 'find_default_config', lambda self: config_file): # Load User identity into app context app = Flask("lmsrvlabbook") app.config["LABMGR_CONFIG"] = Configuration() app.config["LABMGR_ID_MGR"] = get_identity_manager(Configuration()) with app.app_context(): # within this block, current_app points to app. Set current user explicitly (this is done in the middleware) flask.g.user_obj = app.config["LABMGR_ID_MGR"].get_user_profile() # Create a test client client = Client( schema, middleware=[DataloaderMiddleware(), error_middleware], context_value=ContextMock()) # Create a labook im = InventoryManager(config_file) lb = im.create_labbook('default', 'unittester', "containerunittestbook", description="Testing docker building.") cm = ComponentManager(lb) cm.add_base(ENV_UNIT_TEST_REPO, ENV_UNIT_TEST_BASE, ENV_UNIT_TEST_REV) cm.add_packages("pip3", [{ "manager": "pip3", "package": "requests", "version": "2.18.4" }]) bam = BundledAppManager(lb) bam.add_bundled_app(9999, 'share', 'A bundled app for testing', "cd /mnt; python3 -m http.server 9999") ib = ImageBuilder(lb) ib.assemble_dockerfile(write=True) docker_client = get_docker_client() try: lb, docker_image_id = ContainerOperations.build_image( labbook=lb, username="******") # Note: The final field is the owner yield lb, ib, docker_client, docker_image_id, client, "unittester" finally: try: docker_client.containers.get(docker_image_id).stop() docker_client.containers.get(docker_image_id).remove() except: pass try: docker_client.images.remove(docker_image_id, force=True, noprune=False) except: pass shutil.rmtree(lb.root_dir)