Skip to content

Commit c3f9640

Browse files
zhuansunxtpietern
andauthored
CLI support for setting Delta Sharing recipient properties (#584)
Co-authored-by: Xiaotong Sun <Xiaotong Sun> Co-authored-by: Pieter Noordhuis <[email protected]>
1 parent 8b62607 commit c3f9640

File tree

4 files changed

+74
-10
lines changed

4 files changed

+74
-10
lines changed

databricks_cli/unity_catalog/api.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,8 +193,10 @@ def update_share_permissions(self, name, perm_spec):
193193

194194
# Recipient APIs
195195

196-
def create_recipient(self, name, comment, sharing_id, allowed_ip_addresses):
197-
return self.client.create_recipient(name, comment, sharing_id, allowed_ip_addresses)
196+
def create_recipient(self, name, comment, sharing_id,
197+
allowed_ip_addresses, custom_properties):
198+
return self.client.create_recipient(name, comment, sharing_id,
199+
allowed_ip_addresses, custom_properties)
198200

199201
def list_recipients(self):
200202
return self.client.list_recipients()

databricks_cli/unity_catalog/delta_sharing_cli.py

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,17 @@ def delete_share_cli(api_client, name):
383383

384384
############## Recipient Commands ##############
385385

386+
def parse_recipient_custom_properties(custom_property_list):
387+
custom_properties = []
388+
for property_str in custom_property_list:
389+
tokens = property_str.split('=', 2)
390+
if len(tokens) != 2:
391+
raise ValueError('Invalid format for property. '
392+
+ 'The format should be <key>=<value>.')
393+
custom_properties.append({"key": tokens[0], "value": tokens[1]})
394+
return custom_properties
395+
396+
386397
@click.command(context_settings=CONTEXT_SETTINGS,
387398
short_help='Create a new recipient.')
388399
@click.option('--name', required=True, help='Name of new recipient.')
@@ -394,16 +405,23 @@ def delete_share_cli(api_client, name):
394405
help=(
395406
'IP address in CIDR notation that is allowed to use delta sharing. '
396407
'(can be specified multiple times).'))
408+
@click.option('--property', 'custom_property', default=None, required=False, multiple=True,
409+
help=(
410+
'Properties of the recipient. Key and value should be provided '
411+
'at the same time separated by an equal sign. '
412+
'Example: --property country=US.'))
397413
@debug_option
398414
@profile_option
399415
@eat_exceptions
400416
@provide_api_client
401-
def create_recipient_cli(api_client, name, comment, sharing_id, allowed_ip_address):
417+
def create_recipient_cli(api_client, name, comment, sharing_id,
418+
allowed_ip_address, custom_property):
402419
"""
403420
Create a new recipient.
404421
"""
405422
recipient_json = UnityCatalogApi(api_client).create_recipient(
406-
name, comment, sharing_id, allowed_ip_address)
423+
name, comment, sharing_id,
424+
allowed_ip_address, parse_recipient_custom_properties(custom_property))
407425
click.echo(mc_pretty_format(recipient_json))
408426

409427

@@ -451,6 +469,12 @@ def get_recipient_cli(api_client, name):
451469
'IP address in CIDR notation that is allowed to use delta sharing '
452470
'(can be specified multiple times). Specify a single empty string to disable '
453471
'IP allowlist.'))
472+
@click.option('--property', 'custom_property', default=None, required=False, multiple=True,
473+
help=(
474+
'Properties of the recipient. Key and value should be provided '
475+
'at the same time separated by an equal sign. '
476+
'Example: --property country=US. '
477+
'Specify a single empty string to remove all properties.'))
454478
@click.option('--json-file', default=None, type=click.Path(),
455479
help=json_file_help(method='PATCH', path='/recipients/{name}'))
456480
@click.option('--json', default=None, type=JsonClickType(),
@@ -460,21 +484,26 @@ def get_recipient_cli(api_client, name):
460484
@eat_exceptions
461485
@provide_api_client
462486
def update_recipient_cli(api_client, name, new_name, comment, owner,
463-
allowed_ip_address, json_file, json):
487+
allowed_ip_address, custom_property, json_file, json):
464488
"""
465489
Update a recipient.
466490
467491
The public specification for the JSON request is in development.
468492
"""
469493
if ((new_name is not None) or (comment is not None) or (owner is not None) or
470-
len(allowed_ip_address) > 0):
494+
len(allowed_ip_address) or len(custom_property) > 0):
471495
if (json_file is not None) or (json is not None):
472496
raise ValueError('Cannot specify JSON if any other update flags are specified')
473497
data = {'name': new_name, 'comment': comment, 'owner': owner}
474498
if len(allowed_ip_address) > 0:
475499
data['ip_access_list'] = {}
476500
if len(allowed_ip_address) != 1 or allowed_ip_address[0] != '':
477501
data['ip_access_list']['allowed_ip_addresses'] = allowed_ip_address
502+
if len(custom_property) > 0:
503+
data['properties_kvpairs'] = {}
504+
if len(custom_property) != 1 or custom_property[0] != '':
505+
data['properties_kvpairs']['properties'] = parse_recipient_custom_properties(
506+
custom_property)
478507
recipient_json = UnityCatalogApi(api_client).update_recipient(name, data)
479508
click.echo(mc_pretty_format(recipient_json))
480509
else:

databricks_cli/unity_catalog/uc_service.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@ def update_share_permissions(self, name, perm_spec, headers=None):
379379
# Recipient Operations
380380

381381
def create_recipient(self, name, comment=None, sharing_id=None,
382-
allowed_ip_addresses=None, headers=None):
382+
allowed_ip_addresses=None, custom_properties=None, headers=None):
383383
_data = {
384384
'name': name,
385385
}
@@ -394,6 +394,10 @@ def create_recipient(self, name, comment=None, sharing_id=None,
394394
_data['ip_access_list'] = {
395395
'allowed_ip_addresses': allowed_ip_addresses,
396396
}
397+
if custom_properties is not None:
398+
_data['properties_kvpairs'] = {
399+
'properties': custom_properties
400+
}
397401

398402
return self.client.perform_query('POST', '/unity-catalog/recipients', data=_data,
399403
headers=headers)

tests/unity_catalog/test_delta_sharing_cli.py

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -463,12 +463,33 @@ def test_create_recipient_cli(api_mock, echo_mock):
463463
'--comment', 'comment',
464464
'--allowed-ip-address', '8.8.8.8',
465465
'--allowed-ip-address', '8.8.4.4',
466+
'--property', 'k1=v1',
467+
'--property', 'k2=v2'
466468
])
467469
api_mock.create_recipient.assert_called_once_with(
468-
RECIPIENT_NAME, 'comment', None, ('8.8.8.8', '8.8.4.4'))
470+
RECIPIENT_NAME,
471+
'comment',
472+
None,
473+
('8.8.8.8', '8.8.4.4'),
474+
[{"key": "k1", "value": "v1"}, {"key": "k2", "value": "v2"}]
475+
)
469476
echo_mock.assert_called_once_with(mc_pretty_format(RECIPIENT))
470477

471478

479+
@provide_conf
480+
def test_create_recipient_cli_invalid_custom_property(api_mock):
481+
api_mock.create_recipient.return_value = RECIPIENT
482+
runner = CliRunner()
483+
runner.invoke(
484+
delta_sharing_cli.create_recipient_cli,
485+
args=[
486+
'--name', RECIPIENT_NAME,
487+
'--property', 'k1=v1=v2'
488+
])
489+
490+
assert not api_mock.create_recipient.called
491+
492+
472493
@provide_conf
473494
def test_create_recipient_cli_with_sharing_id(api_mock, echo_mock):
474495
api_mock.create_recipient.return_value = RECIPIENT
@@ -480,7 +501,7 @@ def test_create_recipient_cli_with_sharing_id(api_mock, echo_mock):
480501
'--sharing-id', '123e4567-e89b-12d3-a456-426614174000'
481502
])
482503
api_mock.create_recipient.assert_called_once_with(
483-
RECIPIENT_NAME, None, '123e4567-e89b-12d3-a456-426614174000', ())
504+
RECIPIENT_NAME, None, '123e4567-e89b-12d3-a456-426614174000', (), [])
484505
echo_mock.assert_called_once_with(mc_pretty_format(RECIPIENT))
485506

486507

@@ -516,7 +537,9 @@ def test_update_recipient_cli(api_mock, echo_mock):
516537
'--comment', 'comment',
517538
'--owner', 'owner',
518539
'--allowed-ip-address', '8.8.8.8',
519-
'--allowed-ip-address', '8.8.4.4'
540+
'--allowed-ip-address', '8.8.4.4',
541+
'--property', 'k1=v1',
542+
'--property', 'k2=v2'
520543
])
521544
expected_data = {
522545
'name': 'new_recipient_name',
@@ -527,6 +550,12 @@ def test_update_recipient_cli(api_mock, echo_mock):
527550
'8.8.8.8',
528551
'8.8.4.4'
529552
)
553+
},
554+
'properties_kvpairs': {
555+
'properties': [
556+
{"key": "k1", "value": "v1"},
557+
{"key": "k2", "value": "v2"}
558+
]
530559
}
531560
}
532561
api_mock.update_recipient.assert_called_once_with(RECIPIENT_NAME, expected_data)

0 commit comments

Comments
 (0)