Repository: incubator-airflow Updated Branches: refs/heads/master 163263b6a -> 859c8330d
[AIRFLOW-2750] Add subcommands to delete and list users Currently, adding user is the only operation that CLI has on RBAC. This PR adds functionality to delete and list users via CLI. Closes #3610 from sekikn/AIRFLOW-2750 Project: http://git-wip-us.apache.org/repos/asf/incubator-airflow/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-airflow/commit/859c8330 Tree: http://git-wip-us.apache.org/repos/asf/incubator-airflow/tree/859c8330 Diff: http://git-wip-us.apache.org/repos/asf/incubator-airflow/diff/859c8330 Branch: refs/heads/master Commit: 859c8330da7aff370a2d637c1581d21cdf6cac62 Parents: 163263b Author: Kengo Seki <[email protected]> Authored: Tue Jul 17 13:52:28 2018 +0100 Committer: Kaxil Naik <[email protected]> Committed: Tue Jul 17 13:52:28 2018 +0100 ---------------------------------------------------------------------- airflow/bin/cli.py | 49 ++++++++++++++++++++++++++++++++++++++++++++----- tests/core.py | 26 ++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 5 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-airflow/blob/859c8330/airflow/bin/cli.py ---------------------------------------------------------------------- diff --git a/airflow/bin/cli.py b/airflow/bin/cli.py index dc31d06..a245539 100644 --- a/airflow/bin/cli.py +++ b/airflow/bin/cli.py @@ -1294,6 +1294,37 @@ def create_user(args): @cli_utils.action_logging +def delete_user(args): + if not args.username: + raise SystemExit('Required arguments are missing: username') + + appbuilder = cached_appbuilder() + + try: + u = next(u for u in appbuilder.sm.get_all_users() if u.username == args.username) + except StopIteration: + raise SystemExit('{} is not a valid user.'.format(args.username)) + + if appbuilder.sm.del_register_user(u): + print('User {} deleted.'.format(args.username)) + else: + raise SystemExit('Failed to delete user.') + + +@cli_utils.action_logging +def list_users(args): + appbuilder = cached_appbuilder() + users = appbuilder.sm.get_all_users() + fields = ['id', 'username', 'email', 'first_name', 'last_name', 'roles'] + users = [[user.__getattribute__(field) for field in fields] for user in users] + msg = tabulate(users, [field.capitalize().replace('_', ' ') for field in fields], + tablefmt="fancy_grid") + if sys.version_info[0] < 3: + msg = msg.encode('utf-8') + print(msg) + + +@cli_utils.action_logging def list_dag_runs(args, dag=None): if dag: args.dag_id = dag.dag_id @@ -1401,6 +1432,10 @@ class CLIFactory(object): "Do not prompt to confirm reset. Use with care!", "store_true", default=False), + 'username': Arg( + ('-u', '--username',), + help='Username of the user', + type=str), # list_dag_runs 'no_backfill': Arg( @@ -1762,10 +1797,6 @@ class CLIFactory(object): ('-e', '--email',), help='Email of the user', type=str), - 'username': Arg( - ('-u', '--username',), - help='Username of the user', - type=str), 'password': Arg( ('-p', '--password',), help='Password of the user', @@ -1933,9 +1964,17 @@ class CLIFactory(object): 'conn_id', 'conn_uri', 'conn_extra') + tuple(alternative_conn_specs), }, { 'func': create_user, - 'help': "Create an admin account", + 'help': "Create an account for the Web UI", 'args': ('role', 'username', 'email', 'firstname', 'lastname', 'password', 'use_random_password'), + }, { + 'func': delete_user, + 'help': "Delete an account for the Web UI", + 'args': ('username',), + }, { + 'func': list_users, + 'help': "List accounts for the Web UI", + 'args': tuple(), }, { 'func': sync_perm, http://git-wip-us.apache.org/repos/asf/incubator-airflow/blob/859c8330/tests/core.py ---------------------------------------------------------------------- diff --git a/tests/core.py b/tests/core.py index e0504c6..513aacf 100644 --- a/tests/core.py +++ b/tests/core.py @@ -1029,6 +1029,32 @@ class CliTests(unittest.TestCase): ]) cli.create_user(args) + def test_cli_delete_user(self): + args = self.parser.parse_args([ + 'create_user', '-u', 'test3', '-l', 'doe', '-f', 'jon', + '-e', '[email protected]', '-r', 'Viewer', '--use_random_password' + ]) + cli.create_user(args) + args = self.parser.parse_args([ + 'delete_user', '-u', 'test3', + ]) + cli.delete_user(args) + + def test_cli_list_users(self): + for i in range(0, 3): + args = self.parser.parse_args([ + 'create_user', '-u', 'user{}'.format(i), '-l', 'doe', '-f', 'jon', + '-e', 'jdoe+{}@gmail.com'.format(i), '-r', 'Viewer', + '--use_random_password' + ]) + cli.create_user(args) + with mock.patch('sys.stdout', + new_callable=six.StringIO) as mock_stdout: + cli.list_users(self.parser.parse_args(['list_users'])) + stdout = mock_stdout.getvalue() + for i in range(0, 3): + self.assertIn('user{}'.format(i), stdout) + def test_cli_sync_perm(self): # test whether sync_perm cli will throw exceptions or not args = self.parser.parse_args([
