def upgrade(ctx: click.Context): """ Upgrade users after Nauta upgrade. """ with spinner(text=Texts.UPGRADE_IN_PROGRESS): # noinspection PyBroadException try: # noinspection PyTypeChecker users: List[User] = User.list() with K8sProxy(NAUTAAppNames.GIT_REPO_MANAGER, number_of_retries_wait_for_readiness=60) as proxy: grm_client = GitRepoManagerClient(host='127.0.0.1', port=proxy.tunnel_port) for user in users: grm_user = grm_client.get_user(user.name) if not grm_user: grm_client.add_nauta_user(user.name) except Exception: handle_error(logger, Texts.UPGRADE_FAILED, Texts.UPGRADE_FAILED, add_verbosity_msg=ctx.obj.verbosity == 0) sys.exit(1) click.echo(Texts.UPGRADE_SUCCEEDED)
def purge_user(username: str): """ Removes all system's artifacts that belong to a removed user. K8s objects are removed during removal of a namespace. :param username: name of a user for which artifacts should be removed It throws exception in case of any problems detected during removal of a user """ try: # remove data from elasticsearch with spinner(text=TextsDel.DELETION_DELETING_USERS_EXPERIMENTS): es_client = K8sElasticSearchClient( host=f'{get_kubectl_host(with_port=True)}' f'/api/v1/namespaces/nauta/services/nauta-elasticsearch:nauta/proxy', verify_certs=False, use_ssl=True, headers={'Authorization': get_api_key()}) es_client.delete_logs_for_namespace(username) # remove data from git repo manager with k8s_proxy_context_manager.K8sProxy(NAUTAAppNames.GIT_REPO_MANAGER) as proxy,\ spinner(text=TextsDel.DELETION_DELETING_USERS_REPOSITORY): grm_client = GitRepoManagerClient(host='127.0.0.1', port=proxy.tunnel_port) grm_client.delete_nauta_user(username=username) except K8sProxyCloseError as exe: logger.exception("Error during closing of a proxy.") raise exe except Exception as exe: logger.exception(f"Error during removal of {username} user data") raise exe
def test_delete_nauta_user(mocker, git_repo_manager: GitRepoManagerClient): delete_user = mocker.patch.object(git_repo_manager, 'delete_user') delete_repo = mocker.patch.object(git_repo_manager, 'delete_repository') git_repo_manager.delete_nauta_user(username='******') assert delete_user.call_count == 1 assert delete_repo.call_count == 1
def add_user_to_git_repo_manager(username: str, state): try: with K8sProxy(NAUTAAppNames.GIT_REPO_MANAGER, number_of_retries_wait_for_readiness=30) as proxy: grm_client = GitRepoManagerClient(host='127.0.0.1', port=proxy.tunnel_port) grm_client.add_nauta_user(username=username) except Exception: handle_error(logger, Texts.GIT_REPO_MANAGER_ERROR_MSG, Texts.GIT_REPO_MANAGER_ERROR_MSG, add_verbosity_msg=state.verbosity == 0) raise
def test_get_user_error(requests_mock: Mocker, git_repo_manager: GitRepoManagerClient): get_user_mock = requests_mock.get( f'{git_repo_manager.base_url}/api/v1/users/{FAKE_USER}', status_code=500) with pytest.raises(HTTPError): git_repo_manager.get_user(FAKE_USER) assert get_user_mock.call_count == 1
def test_create_user_error(requests_mock: Mocker, git_repo_manager: GitRepoManagerClient): requests_mock.get(f'{git_repo_manager.base_url}/api/v1/users/{FAKE_USER}', status_code=404) post_user_mock = requests_mock.post( f'{git_repo_manager.base_url}/api/v1/admin/users', status_code=500) with pytest.raises(HTTPError): git_repo_manager.create_user(username=FAKE_USER, email='*****@*****.**') assert post_user_mock.call_count == 1
def test_add_public_key_for_user_error(requests_mock: Mocker, git_repo_manager: GitRepoManagerClient): add_key_mock = requests_mock.post( f'{git_repo_manager.base_url}/api/v1/admin/users/{FAKE_USER}/keys', status_code=422) with pytest.raises(HTTPError): git_repo_manager.add_public_key_for_user(username=FAKE_USER, public_key='fake-key') assert add_key_mock.call_count == 1
def test_get_repository_error(requests_mock: Mocker, git_repo_manager: GitRepoManagerClient): repo_name = 'fake_repo' get_repo_mock = requests_mock.get( f'{git_repo_manager.base_url}/api/v1/repos/{FAKE_USER}/{repo_name}', status_code=500) with pytest.raises(HTTPError): git_repo_manager.get_repository(username=FAKE_USER, repository_name=repo_name) assert get_repo_mock.call_count == 1
def test_delete_nauta_user_failure(mocker, git_repo_manager: GitRepoManagerClient): delete_user = mocker.patch.object(git_repo_manager, 'delete_user', side_effect=RuntimeError) delete_repo = mocker.patch.object(git_repo_manager, 'delete_repository') with pytest.raises(RuntimeError): git_repo_manager.delete_nauta_user(username='******') assert delete_user.call_count == 1 assert delete_repo.call_count == 1
def test_add_nauta_user(mocker, git_repo_manager: GitRepoManagerClient): generate_key = mocker.patch.object(git_repo_manager, '_generate_ssh_key', return_value=('private-key', 'public-key')) create_user = mocker.patch.object(git_repo_manager, 'create_user') add_key = mocker.patch.object(git_repo_manager, 'add_public_key_for_user') create_repo = mocker.patch.object(git_repo_manager, 'create_repository') create_secret = mocker.patch('git_repo_manager.client.create_secret') git_repo_manager.add_nauta_user(username='******') assert generate_key.call_count == 1 assert create_user.call_count == 1 assert add_key.call_count == 1 assert create_repo.call_count == 1 assert create_secret.call_count == 1
def test_add_public_key_for_user(requests_mock: Mocker, git_repo_manager: GitRepoManagerClient): add_key_mock = requests_mock.post( f'{git_repo_manager.base_url}/api/v1/admin/users/{FAKE_USER}/keys') response = git_repo_manager.add_public_key_for_user(username=FAKE_USER, public_key='fake-key') assert response assert add_key_mock.call_count == 1
def test_get_user_not_found(requests_mock: Mocker, git_repo_manager: GitRepoManagerClient): get_user_mock = requests_mock.get( f'{git_repo_manager.base_url}/api/v1/users/{FAKE_USER}', status_code=404) response = git_repo_manager.get_user(FAKE_USER) assert not response assert get_user_mock.call_count == 1
def test_delete_user_does_not_exist(requests_mock: Mocker, git_repo_manager: GitRepoManagerClient): requests_mock.get(f'{git_repo_manager.base_url}/api/v1/users/{FAKE_USER}', status_code=404) delete_user_mock = requests_mock.delete( f'{git_repo_manager.base_url}/api/v1/admin/users/{FAKE_USER}') response = git_repo_manager.delete_user(username=FAKE_USER) assert response is None assert delete_user_mock.call_count == 0
def test_create_user_new(requests_mock: Mocker, git_repo_manager: GitRepoManagerClient): requests_mock.get(f'{git_repo_manager.base_url}/api/v1/users/{FAKE_USER}', status_code=404) post_user_mock = requests_mock.post( f'{git_repo_manager.base_url}/api/v1/admin/users') response = git_repo_manager.create_user(username=FAKE_USER, email='*****@*****.**') assert response assert post_user_mock.call_count == 1
def test_get_repository_not_found(requests_mock: Mocker, git_repo_manager: GitRepoManagerClient): repo_name = 'fake_repo' get_repo_mock = requests_mock.get( f'{git_repo_manager.base_url}/api/v1/repos/{FAKE_USER}/{repo_name}', status_code=404) response = git_repo_manager.get_repository(username=FAKE_USER, repository_name=repo_name) assert not response assert get_repo_mock.call_count == 1
def test_add_nauta_user_failure(mocker, git_repo_manager: GitRepoManagerClient): generate_key = mocker.patch.object(git_repo_manager, '_generate_ssh_key', return_value=('private-key', 'public-key')) create_user = mocker.patch.object(git_repo_manager, 'create_user', side_effect=RuntimeError) add_key = mocker.patch.object(git_repo_manager, 'add_public_key_for_user') create_repo = mocker.patch.object(git_repo_manager, 'create_repository') create_secret = mocker.patch('git_repo_manager.client.create_secret') with pytest.raises(RuntimeError): git_repo_manager.add_nauta_user(username='******') assert generate_key.call_count == 1 assert create_user.call_count == 1 assert add_key.call_count == 0 assert create_repo.call_count == 0 assert create_secret.call_count == 0
def test_create_repository_exists(requests_mock: Mocker, git_repo_manager: GitRepoManagerClient): repo_name = 'fake_repo' get_repo_mock = requests_mock.get( f'{git_repo_manager.base_url}/api/v1/repos/{FAKE_USER}/{repo_name}', status_code=200) post_repo_mock = requests_mock.post( f'{git_repo_manager.base_url}/api/v1/admin/users/{FAKE_USER}/repos') response = git_repo_manager.create_repository(username=FAKE_USER, repository_name=repo_name) assert response assert get_repo_mock.call_count == 1 assert post_repo_mock.call_count == 0
def test_token_saved(mocker): fake_token = 'fake_token' secret_mock = MagicMock() secret_mock.data = {'token': fake_token} get_secret_mock = mocker.patch('git_repo_manager.client.get_secret', return_value=secret_mock) create_token_mock = mocker.patch( 'git_repo_manager.client.GitRepoManagerClient._create_admin_token') save_token_mock = mocker.patch( 'git_repo_manager.client.GitRepoManagerClient._save_admin_token') grm = GitRepoManagerClient(host='fake.host') assert grm.token == f'token {fake_token}' assert get_secret_mock.call_count == 1 assert create_token_mock.call_count == 0 assert save_token_mock.call_count == 0
def create(state: State, username: str, list_only: bool, filename: str): """ Adds a new user with a name given as a parameter. :param username: name of a new user """ if list_only and filename: handle_error(user_msg=Texts.F_L_OPTIONS_EXCLUSION_ERROR_MSG) exit(1) try: try: validate_user_name(username) except ValueError as exe: handle_error( logger, Texts.NAME_VALIDATION_ERROR_MSG.format(username=username), str(exe), add_verbosity_msg=state.verbosity == 0) exit(1) user_state = check_users_presence(username) if user_state == UserState.ACTIVE: handle_error( logger, Texts.USER_ALREADY_EXISTS_ERROR_MSG.format(username=username), Texts.USER_ALREADY_EXISTS_ERROR_MSG.format(username=username)) exit(1) if user_state == UserState.TERMINATING: handle_error( logger, Texts.USER_BEING_REMOVED_ERROR_MSG.format(username=username), Texts.USER_BEING_REMOVED_ERROR_MSG.format(username=username)) exit(1) except Exception: handle_error( logger, Texts.USER_VERIFICATION_ERROR_MSG.format(username=username), Texts.USER_VERIFICATION_ERROR_MSG.format(username=username), add_verbosity_msg=state.verbosity == 0) exit(1) try: with spinner(text=Texts.CREATING_USER_PROGRESS_MSG.format( username=username)): chart_location = os.path.join(Config().config_path, ADD_USER_CHART_NAME) nauta_config_map = NAUTAConfigMap() tiller_location = nauta_config_map.image_tiller tensorboard_service_location = nauta_config_map.image_tensorboard_service add_user_command = [ "helm", "install", "--wait", "--namespace", username, "--name", username, chart_location, "--set", "global.nauta=nauta", "--set", f"username={username}", "--set", "TillerImage={}".format(tiller_location), "--set", f"TensorboardServiceImage={tensorboard_service_location}" ] env = os.environ.copy() env['PATH'] = Config().config_path + os.pathsep + env['PATH'] _, err_code, log_output = execute_system_command( ' '.join(add_user_command), env=env, shell=True) if err_code: handle_error(logger, log_output, Texts.USER_ADD_ERROR_MSG, add_verbosity_msg=state.verbosity == 0) if not delete_user(username): handle_error(user_msg=Texts.REMOVE_USER_ERROR_MSG.format( username=username)) sys.exit(1) try: users_password = get_users_token(username) except Exception: handle_error(logger, Texts.PASSWORD_GATHER_ERROR_MSG, Texts.PASSWORD_GATHER_ERROR_MSG, add_verbosity_msg=state.verbosity == 0) users_password = "" try: cert = get_certificate(username) except Exception: handle_error(logger, Texts.CERT_GATHER_ERROR_MSG, Texts.CERT_GATHER_ERROR_MSG, add_verbosity_msg=state.verbosity == 0) cert = "" try: with K8sProxy( NAUTAAppNames.GIT_REPO_MANAGER, number_of_retries_wait_for_readiness=60) as proxy: grm_client = GitRepoManagerClient(host='127.0.0.1', port=proxy.tunnel_port) grm_client.add_nauta_user(username=username) except Exception: handle_error(logger, Texts.GIT_REPO_MANAGER_ERROR_MSG, Texts.GIT_REPO_MANAGER_ERROR_MSG, add_verbosity_msg=state.verbosity == 0) sys.exit(1) except Exception: handle_error(logger, Texts.USER_ADD_ERROR_MSG.format(username=username), Texts.USER_ADD_ERROR_MSG.format(username=username), add_verbosity_msg=state.verbosity == 0) if not delete_user(username): handle_error(user_msg=Texts.REMOVE_USER_ERROR_MSG.format( username=username)) sys.exit(1) if is_user_created(username, 90): click.echo(Texts.USER_CREATION_SUCCESS_MSG.format(username=username)) else: # if during 90 seconds a user hasn't been created - app displays information about it # but doesn't stop processing the command - config file generated here may be useful later # when user has been created click.echo(Texts.USER_NOT_READY_ERROR_MSG.format(username=username)) try: kubeconfig = generate_kubeconfig(username, username, get_kubectl_host(), users_password, cert) except Exception: handle_error(logger, Texts.CONFIG_CREATION_ERROR_MSG, Texts.CONFIG_CREATION_ERROR_MSG, add_verbosity_msg=state.verbosity == 0) exit(1) if list_only: click.echo(Texts.LIST_ONLY_HEADER) click.echo(kubeconfig) else: if not filename: filename = DEFAULT_FILENAME.format(username) try: with open(filename, "w") as file: file.write(kubeconfig) click.echo(Texts.CONFIG_SAVE_SUCCESS_MSG.format(filename=filename)) except Exception: handle_error(logger, Texts.CONFIG_SAVE_FAIL_MSG, Texts.CONFIG_SAVE_FAIL_MSG, add_verbosity_msg=state.verbosity == 0) click.echo(Texts.CONFIG_SAVE_FAIL_INSTRUCTIONS_MSG) click.echo(kubeconfig) sys.exit(1)
def git_repo_manager(mocker) -> GitRepoManagerClient: grm = GitRepoManagerClient(host='fake.host') mocker.patch.object(grm, '_get_admin_token', return_value='token fake') return grm