Skip to content

Commit

Permalink
Update secrets CLI to match REST API endpoint changes (#119)
Browse files Browse the repository at this point in the history
  • Loading branch information
ericwang-db authored and andrewmchen committed May 7, 2018
1 parent 2fbd7c0 commit 60b9be8
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 50 deletions.
26 changes: 13 additions & 13 deletions databricks_cli/sdk/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -532,20 +532,20 @@ def create_scope(self, scope, initial_manage_principal=None):
_data['scope'] = scope
if initial_manage_principal is not None:
_data['initial_manage_principal'] = initial_manage_principal
return self.client.perform_query('POST', '/secret/scopes/create', data=_data)
return self.client.perform_query('POST', '/secrets/scopes/create', data=_data)

def delete_scope(self, scope):
_data = {}
if scope is not None:
_data['scope'] = scope
return self.client.perform_query('POST', '/secret/scopes/delete', data=_data)
return self.client.perform_query('POST', '/secrets/scopes/delete', data=_data)

def list_scopes(self):
_data = {}

return self.client.perform_query('GET', '/secret/scopes/list', data=_data)
return self.client.perform_query('GET', '/secrets/scopes/list', data=_data)

def write_secret(self, scope, key, string_value=None, bytes_value=None):
def put_secret(self, scope, key, string_value=None, bytes_value=None):
_data = {}
if scope is not None:
_data['scope'] = scope
Expand All @@ -555,53 +555,53 @@ def write_secret(self, scope, key, string_value=None, bytes_value=None):
_data['string_value'] = string_value
if bytes_value is not None:
_data['bytes_value'] = bytes_value
return self.client.perform_query('POST', '/secret/secrets/write', data=_data)
return self.client.perform_query('POST', '/secrets/put', data=_data)

def delete_secret(self, scope, key):
_data = {}
if scope is not None:
_data['scope'] = scope
if key is not None:
_data['key'] = key
return self.client.perform_query('POST', '/secret/secrets/delete', data=_data)
return self.client.perform_query('POST', '/secrets/delete', data=_data)

def list_secrets(self, scope):
_data = {}
if scope is not None:
_data['scope'] = scope
return self.client.perform_query('GET', '/secret/secrets/list', data=_data)
return self.client.perform_query('GET', '/secrets/list', data=_data)

def write_acl(self, scope, principal, permission):
def put_acl(self, scope, principal, permission):
_data = {}
if scope is not None:
_data['scope'] = scope
if principal is not None:
_data['principal'] = principal
if permission is not None:
_data['permission'] = permission
return self.client.perform_query('POST', '/secret/acls/write', data=_data)
return self.client.perform_query('POST', '/secrets/acls/put', data=_data)

def delete_acl(self, scope, principal):
_data = {}
if scope is not None:
_data['scope'] = scope
if principal is not None:
_data['principal'] = principal
return self.client.perform_query('POST', '/secret/acls/delete', data=_data)
return self.client.perform_query('POST', '/secrets/acls/delete', data=_data)

def list_acls(self, scope):
_data = {}
if scope is not None:
_data['scope'] = scope
return self.client.perform_query('GET', '/secret/acls/list', data=_data)
return self.client.perform_query('GET', '/secrets/acls/list', data=_data)

def get_acl(self, scope, principal):
_data = {}
if scope is not None:
_data['scope'] = scope
if principal is not None:
_data['principal'] = principal
return self.client.perform_query('GET', '/secret/acls/get', data=_data)
return self.client.perform_query('GET', '/secrets/acls/get', data=_data)


class GroupsService(object):
Expand Down Expand Up @@ -658,4 +658,4 @@ def get_groups_for_principal(self, user_name=None, group_name=None):
if group_name is not None:
_data['group_name'] = group_name
return self.client.perform_query('GET', '/groups/list-parents', data=_data)

8 changes: 4 additions & 4 deletions databricks_cli/secrets/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,17 @@ def delete_scope(self, scope):
def list_scopes(self):
return self.client.list_scopes()

def write_secret(self, scope, key, string_value, bytes_value):
return self.client.write_secret(scope, key, string_value, bytes_value)
def put_secret(self, scope, key, string_value, bytes_value):
return self.client.put_secret(scope, key, string_value, bytes_value)

def delete_secret(self, scope, key):
return self.client.delete_secret(scope, key)

def list_secrets(self, scope):
return self.client.list_secrets(scope)

def write_acl(self, scope, principal, permission):
return self.client.write_acl(scope, principal, permission)
def put_acl(self, scope, principal, permission):
return self.client.put_acl(scope, principal, permission)

def delete_acl(self, scope, principal):
return self.client.delete_acl(scope, principal)
Expand Down
29 changes: 19 additions & 10 deletions databricks_cli/secrets/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ def _verify_and_translate_options(string_value, binary_file):


@click.command(context_settings=CONTEXT_SETTINGS,
short_help='Writes a secret to a scope.')
short_help='Puts a secret in a scope. "write" is an alias for "put".')
@click.option('--scope', required=True, type=SecretScopeClickType(), help=SecretScopeClickType.help)
@click.option('--key', required=True, type=SecretKeyClickType(), help=SecretKeyClickType.help)
@click.option('--string-value', default=None,
Expand All @@ -148,9 +148,10 @@ def _verify_and_translate_options(string_value, binary_file):
@profile_option
@eat_exceptions
@provide_api_client
def write_secret(api_client, scope, key, string_value, binary_file):
def put_secret(api_client, scope, key, string_value, binary_file):
"""
Writes a secret to the provided scope with the given name. Overwrites if the name exists.
Puts a secret in the provided scope with the given name.
Overwrites any existing value if the name exists.
You should specify at most one option in "string-value" and "binary-file".
Expand All @@ -161,9 +162,12 @@ def write_secret(api_client, scope, key, string_value, binary_file):
If none of "string-value" and "binary-file" specified, an editor will be opened for
inputting secret value. The value will be stored in UTF-8 (MB4) form.
"databricks secrets write" is an alias for "databricks secrets put", and will be
deprecated in a future release.
"""
string_param, bytes_param = _verify_and_translate_options(string_value, binary_file)
SecretApi(api_client).write_secret(scope, key, string_param, bytes_param)
SecretApi(api_client).put_secret(scope, key, string_param, bytes_param)


@click.command(context_settings=CONTEXT_SETTINGS,
Expand Down Expand Up @@ -207,8 +211,8 @@ def list_secrets(api_client, scope, output):


@click.command(context_settings=CONTEXT_SETTINGS,
short_help='Writes an access control rule for a principal applied to '
' a given secret scope.')
short_help='Creates or overwrites an access control rule for a principal applied to '
'a given secret scope. "write-acl" is an alias for "put-acl".')
@click.option('--scope', required=True, type=SecretScopeClickType(), help=SecretScopeClickType.help)
@click.option('--principal', required=True, type=SecretPrincipalClickType(),
help=SecretPrincipalClickType.help)
Expand All @@ -217,12 +221,15 @@ def list_secrets(api_client, scope, output):
@profile_option
@eat_exceptions
@provide_api_client
def write_acl(api_client, scope, principal, permission):
def put_acl(api_client, scope, principal, permission):
"""
Creates or overwrites the ACL associated with the given principal (user or group) on the
specified secret scope.
"databricks secrets write-acl" is an alias for "databricks secrets put-acl",
and will be deprecated in a future release.
"""
SecretApi(api_client).write_acl(scope, principal, permission)
SecretApi(api_client).put_acl(scope, principal, permission)


@click.command(context_settings=CONTEXT_SETTINGS,
Expand Down Expand Up @@ -304,10 +311,12 @@ def secrets_group():
secrets_group.add_command(create_scope, name='create-scope')
secrets_group.add_command(list_scopes, name='list-scopes')
secrets_group.add_command(delete_scope, name='delete-scope')
secrets_group.add_command(write_secret, name='write')
secrets_group.add_command(put_secret, name='put')
secrets_group.add_command(put_secret, name='write')
secrets_group.add_command(delete_secret, name='delete')
secrets_group.add_command(list_secrets, name='list')
secrets_group.add_command(write_acl, name='write-acl')
secrets_group.add_command(put_acl, name='put-acl')
secrets_group.add_command(put_acl, name='write-acl')
secrets_group.add_command(delete_acl, name='delete-acl')
secrets_group.add_command(list_acls, name='list-acls')
secrets_group.add_command(get_acl, name='get-acl')
46 changes: 23 additions & 23 deletions tests/secrets/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,56 +82,56 @@ def test_list_scope(secrets_api_mock):


@provide_conf
def test_write_secret_string_value(secrets_api_mock):
def test_put_secret_string_value(secrets_api_mock):
runner = CliRunner()
runner.invoke(cli.write_secret, ['--scope', SCOPE, '--key', KEY, '--string-value', VALUE])
assert secrets_api_mock.write_secret.call_args[0] == (SCOPE, KEY, VALUE, None)
runner.invoke(cli.put_secret, ['--scope', SCOPE, '--key', KEY, '--string-value', VALUE])
assert secrets_api_mock.put_secret.call_args[0] == (SCOPE, KEY, VALUE, None)


@provide_conf
def test_write_secret_multiple_value(secrets_api_mock):
def test_put_secret_multiple_value(secrets_api_mock):
runner = CliRunner()
result = runner.invoke(cli.write_secret,
result = runner.invoke(cli.put_secret,
['--scope', SCOPE, '--key', KEY,
'--string-value', VALUE, '--binary-file', VALUE])
assert result.exit_code != 0
assert secrets_api_mock.write_secret.call_count == 0
assert secrets_api_mock.put_secret.call_count == 0


@provide_conf
def test_write_secret_editor_input_correct_split(secrets_api_mock):
def test_put_secret_editor_input_correct_split(secrets_api_mock):
with mock.patch('databricks_cli.secrets.cli.click.edit') as edit_mock:
# normal input with trailing new lines
edit_mock.return_value = VALUE + '\n' + DASH_MARKER
runner = CliRunner()
runner.invoke(cli.write_secret, ['--scope', SCOPE, '--key', KEY])
assert secrets_api_mock.write_secret.call_args[0] == (SCOPE, KEY, VALUE, None)
runner.invoke(cli.put_secret, ['--scope', SCOPE, '--key', KEY])
assert secrets_api_mock.put_secret.call_args[0] == (SCOPE, KEY, VALUE, None)


@provide_conf
def test_write_secret_editor_input_no_value(secrets_api_mock):
def test_put_secret_editor_input_no_value(secrets_api_mock):
with mock.patch('databricks_cli.secrets.cli.click.edit') as edit_mock:
# file not saved
edit_mock.return_value = None
runner = CliRunner()
result = runner.invoke(cli.write_secret, ['--scope', SCOPE, '--key', KEY])
result = runner.invoke(cli.put_secret, ['--scope', SCOPE, '--key', KEY])
assert result.exit_code != 0
assert secrets_api_mock.write_secret.call_count == 0
assert secrets_api_mock.put_secret.call_count == 0


@provide_conf
def test_write_secret_editor_input_edited_marker(secrets_api_mock):
def test_put_secret_editor_input_edited_marker(secrets_api_mock):
with mock.patch('databricks_cli.secrets.cli.click.edit') as edit_mock:
# input with marker line edited
edit_mock.return_value = VALUE + '\n' + '# ----------\n'
runner = CliRunner()
result = runner.invoke(cli.write_secret, ['--scope', SCOPE, '--key', KEY])
result = runner.invoke(cli.put_secret, ['--scope', SCOPE, '--key', KEY])
assert result.exit_code != 0
assert secrets_api_mock.write_secret.call_count == 0
assert secrets_api_mock.put_secret.call_count == 0


@provide_conf
def test_write_secrets_binary_file(secrets_api_mock):
def test_put_secrets_binary_file(secrets_api_mock):
import os
import tempfile

Expand All @@ -143,9 +143,9 @@ def test_write_secrets_binary_file(secrets_api_mock):
f.close()

runner = CliRunner()
runner.invoke(cli.write_secret,
runner.invoke(cli.put_secret,
['--scope', SCOPE, '--key', KEY, '--binary-file', name])
assert secrets_api_mock.write_secret.call_args[0] == (SCOPE, KEY, None, 'dGVzdF92YWx1ZQoK')
assert secrets_api_mock.put_secret.call_args[0] == (SCOPE, KEY, None, 'dGVzdF92YWx1ZQoK')
finally:
os.unlink(name)

Expand Down Expand Up @@ -231,10 +231,10 @@ def test_delete_acl(secrets_api_mock):


@provide_conf
def test_write_acl(secrets_api_mock):
def test_put_acl(secrets_api_mock):
runner = CliRunner()
runner.invoke(cli.write_acl,
runner.invoke(cli.put_acl,
['--scope', SCOPE, '--principal', PRINCIPAL, '--permission', PERMISSION])
assert secrets_api_mock.write_acl.call_args[0][0] == SCOPE
assert secrets_api_mock.write_acl.call_args[0][1] == PRINCIPAL
assert secrets_api_mock.write_acl.call_args[0][2] == PERMISSION
assert secrets_api_mock.put_acl.call_args[0][0] == SCOPE
assert secrets_api_mock.put_acl.call_args[0][1] == PRINCIPAL
assert secrets_api_mock.put_acl.call_args[0][2] == PERMISSION

0 comments on commit 60b9be8

Please sign in to comment.