Skip to content
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
a9ce3d0
Azure EventGrid: 2020-10-15-preview-Identity support for System MSI
VidyaKukke Mar 18, 2021
3f9239c
[EventGrid] Add support for System Topic MSI
VidyaKukke Mar 19, 2021
fde65b2
Remove secret and replace with <HIDDEN>
VidyaKukke Mar 19, 2021
6844cb3
Remove secret
VidyaKukke Mar 19, 2021
0f913e3
Add support for storage-queue-msg-ttl
VidyaKukke Mar 21, 2021
d2007e1
Merge branch 'dev' of https://github.com/Azure/azure-cli into vkukke/…
VidyaKukke Mar 23, 2021
c296efc
Merge branch 'dev' of https://github.com/Azure/azure-cli into vkukke/…
VidyaKukke Mar 23, 2021
b973504
Add EnableAdvancedFilteringOnArrays + New AdvancedFilters
VidyaKukke Mar 23, 2021
f059fbc
Merge branch 'dev' of https://github.com/Azure/azure-cli into vkukke/…
VidyaKukke Mar 24, 2021
1e772c1
enable_advanced_filtering_on_arrays arg type
evelyn-ys Mar 24, 2021
9e2ec0e
Fix broken tests
VidyaKukke Mar 24, 2021
ec797cf
Fix style error
VidyaKukke Mar 24, 2021
7cd749b
Address review comments
VidyaKukke Mar 25, 2021
e4f5977
Merge branch 'dev' of https://github.com/Azure/azure-cli into vkukke/…
VidyaKukke Mar 25, 2021
1bc47be
address review comments
VidyaKukke Mar 25, 2021
4644ec2
Merge branch 'dev' of https://github.com/Azure/azure-cli into vkukke/…
VidyaKukke Mar 25, 2021
0ed551b
Add linter exclusion
VidyaKukke Mar 25, 2021
2df72b2
Fix linter issue
VidyaKukke Mar 25, 2021
310efdf
Address review comments
VidyaKukke Mar 26, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 118 additions & 3 deletions src/azure-cli/azure/cli/command_modules/eventgrid/_help.py

Large diffs are not rendered by default.

28 changes: 20 additions & 8 deletions src/azure-cli/azure/cli/command_modules/eventgrid/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,24 +153,30 @@
phone_extension_type = CLIArgumentType(
help='The extension of the customer service number of the publisher. Only digits are allowed and number of digits should not exceed 10.')

storage_queue_msg_ttl = CLIArgumentType(
help="Storage queue message time to live in seconds.",
options_list=['--storage-queue-msg-ttl', '--qttl'],
is_preview=True
)
Comment thread
evelyn-ys marked this conversation as resolved.
Outdated


def load_arguments(self, _): # pylint: disable=too-many-statements
with self.argument_context('eventgrid') as c:
c.argument('resource_group_name', arg_type=resource_group_name_type)
c.argument('location', arg_type=get_location_type(self.cli_ctx))
c.argument('tags', arg_type=tags_type)
c.argument('included_event_types', arg_type=included_event_types_type)
c.argument('included_event_types', arg_group="Filtering", arg_type=included_event_types_type)
c.argument('labels', arg_type=labels_type)
c.argument('endpoint_type', arg_type=get_enum_type(['webhook', 'eventhub', 'storagequeue', 'hybridconnection', 'servicebusqueue', 'servicebustopic', 'azurefunction'], default='webhook'))
c.argument('delivery_identity_endpoint_type', arg_type=get_enum_type(['webhook', 'eventhub', 'storagequeue', 'hybridconnection', 'servicebusqueue', 'servicebustopic', 'azurefunction'], default=None), is_preview=True)
c.argument('source_resource_id', help="Fully qualified identifier of the source Azure resource.")
c.argument('endpoint', help="Endpoint where EventGrid should deliver events matching this event subscription. For webhook endpoint type, this should be the corresponding webhook URL. For other endpoint types, this should be the Azure resource identifier of the endpoint. It is expected that the destination endpoint to be already created and available for use before executing any Event Grid command.")
c.argument('delivery_identity_endpoint', help="Endpoint with identity where EventGrid should deliver events matching this event subscription. For webhook endpoint type, this should be the corresponding webhook URL. For other endpoint types, this should be the Azure resource identifier of the endpoint.", is_preview=True)
c.argument('event_subscription_name', help="Name of the event subscription.")
c.argument('subject_begins_with', help="An optional string to filter events for an event subscription based on a prefix. Wildcard characters are not supported.")
c.argument('subject_ends_with', help="An optional string to filter events for an event subscription based on a suffix. Wildcard characters are not supported.")
c.argument('subject_begins_with', arg_group="Filtering", help="An optional string to filter events for an event subscription based on a prefix. Wildcard characters are not supported.")
c.argument('subject_ends_with', arg_group="Filtering", help="An optional string to filter events for an event subscription based on a suffix. Wildcard characters are not supported.")
c.argument('topic_type_name', help="Name of the topic type.")
c.argument('is_subject_case_sensitive', arg_type=get_three_state_flag(), options_list=['--subject-case-sensitive'], help="Specify to indicate whether the subject fields should be compared in a case sensitive manner. True if flag present.", )
c.argument('is_subject_case_sensitive', arg_group="Filtering", arg_type=get_three_state_flag(), options_list=['--subject-case-sensitive'], help="Specify to indicate whether the subject fields should be compared in a case sensitive manner. True if flag present.", )
c.argument('input_mapping_fields', arg_type=input_mapping_fields_type)
c.argument('input_mapping_default_values', arg_type=input_mapping_default_values_type)
c.argument('input_schema', arg_type=input_schema_type)
Expand Down Expand Up @@ -198,10 +204,13 @@ def load_arguments(self, _): # pylint: disable=too-many-statements
c.argument('setup_uri', help="URI of the partner website that can be used by Azure customers to setup Event Grid integration on an event source.")
c.argument('partner_registration_id', help="The fully qualified ARM Id of the partner registration that should be associated with this partner namespace. This takes the following format: /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.EventGrid/partnerRegistrations/{partnerRegistrationName}.")
c.argument('partner_topic_source', arg_type=partner_topic_source_type)
c.argument('desination_topic_name', help="Name of the partner topic associated with the event channel.")
c.argument('destination_topic_name', help="Name of the partner topic associated with the event channel.")
Comment thread
evelyn-ys marked this conversation as resolved.
c.argument('destination_resource_group_name', help="Azure Resource Group of the customer creating the event channel. The partner topic associated with the event channel will be created under this resource group.")
c.argument('destination_subscription_id', help="Azure subscription Id of the customer creating the event channel. The partner topic associated with the event channel will be created under this Azure subscription.")
c.argument('topic_type', help="Name of the topic type.", completer=get_resource_name_completion_list('Microsoft.EventGrid/topictypes'))
c.argument('enable_advanced_filtering_on_arrays', is_preview=True, arg_type=get_three_state_flag(),
options_list=['--enable-advanced-filtering-on-arrays', '--enable-af-arr'], arg_group="Filtering",
help="Allows advanced filters to be evaluated against an array of values instead of expecting a singular value.")

with self.argument_context('eventgrid topic') as c:
c.argument('topic_name', arg_type=name_type, help='Name of the topic.', id_part='name', completer=get_resource_name_completion_list('Microsoft.EventGrid/topics'))
Expand Down Expand Up @@ -290,14 +299,15 @@ def load_arguments(self, _): # pylint: disable=too-many-statements
c.argument('event_ttl', help="Event time to live (in minutes). Must be a number between 1 and 1440.")
c.argument('deadletter_endpoint', help="The Azure resource ID of an Azure Storage blob container destination where EventGrid should deadletter undeliverable events for this event subscription.")
c.argument('deadletter_identity_endpoint', help="The Azure resource ID of an Azure Storage blob container destination with identity where EventGrid should deadletter undeliverable events for this event subscription.")
c.argument('advanced_filter', action=EventSubscriptionAddFilter, nargs='+')
c.argument('advanced_filter', arg_group="Filtering", action=EventSubscriptionAddFilter, nargs='+')
c.argument('expiration_date', help="Date or datetime (in UTC, e.g. '2018-11-30T11:59:59+00:00' or '2018-11-30') after which the event subscription would expire. By default, there is no expiration for the event subscription.")
c.argument('azure_active_directory_tenant_id', help="The Azure Active Directory Tenant Id to get the access token that will be included as the bearer token in delivery requests. Applicable only for webhook as a destination")
c.argument('azure_active_directory_application_id_or_uri', help="The Azure Active Directory Application Id or Uri to get the access token that will be included as the bearer token in delivery requests. Applicable only for webhook as a destination")
c.argument('delivery_identity', arg_type=delivery_identity_type)
c.argument('deadletter_identity', arg_type=deadletter_identity_type)
c.argument('delivery_identity_endpoint', help="Endpoint with identity where EventGrid should deliver events matching this event subscription. For webhook endpoint type, this should be the corresponding webhook URL. For other endpoint types, this should be the Azure resource identifier of the endpoint.", is_preview=True)
c.argument('delivery_identity_endpoint_type', arg_type=get_enum_type(['webhook', 'eventhub', 'storagequeue', 'hybridconnection', 'servicebusqueue', 'servicebustopic', 'azurefunction'], default=None), is_preview=True)
c.argument('storage_queue_msg_ttl', arg_type=storage_queue_msg_ttl)

with self.argument_context('eventgrid event-subscription list') as c:
c.argument('odata_query', arg_type=odata_query_type, id_part=None)
Expand All @@ -315,11 +325,12 @@ def load_arguments(self, _): # pylint: disable=too-many-statements
c.argument('preferred_batch_size_in_kilobytes', help="Preferred batch size in kilobytes. Must be a number between 1 and 1024.")
c.argument('event_ttl', help="Event time to live (in minutes). Must be a number between 1 and 1440.")
c.argument('deadletter_endpoint', help="The Azure resource ID of an Azure Storage blob container destination where EventGrid should deadletter undeliverable events for this event subscription.")
c.argument('advanced_filter', action=EventSubscriptionAddFilter, nargs='+')
c.argument('advanced_filter', arg_group="Filtering", action=EventSubscriptionAddFilter, nargs='+')
c.argument('expiration_date', help="Date or datetime (in UTC, e.g. '2018-11-30T11:59:59+00:00' or '2018-11-30') after which the event subscription would expire. By default, there is no expiration for the event subscription.")
c.argument('azure_active_directory_tenant_id', help="The Azure Active Directory Tenant Id to get the access token that will be included as the bearer token in delivery requests. Applicable only for webhook as a destination")
c.argument('azure_active_directory_application_id_or_uri', help="The Azure Active Directory Application Id or Uri to get the access token that will be included as the bearer token in delivery requests. Applicable only for webhook as a destination")
c.argument('resource_group_name', arg_type=resource_group_name_type)
c.argument('storage_queue_msg_ttl', arg_type=storage_queue_msg_ttl)

with self.argument_context('eventgrid system-topic event-subscription list') as c:
c.argument('odata_query', arg_type=odata_query_type, id_part=None)
Expand All @@ -338,11 +349,12 @@ def load_arguments(self, _): # pylint: disable=too-many-statements
c.argument('preferred_batch_size_in_kilobytes', help="Preferred batch size in kilobytes. Must be a number between 1 and 1024.")
c.argument('event_ttl', help="Event time to live (in minutes). Must be a number between 1 and 1440.")
c.argument('deadletter_endpoint', help="The Azure resource ID of an Azure Storage blob container destination where EventGrid should deadletter undeliverable events for this event subscription.")
c.argument('advanced_filter', action=EventSubscriptionAddFilter, nargs='+')
c.argument('advanced_filter', arg_group="Filtering", action=EventSubscriptionAddFilter, nargs='+')
c.argument('expiration_date', help="Date or datetime (in UTC, e.g. '2018-11-30T11:59:59+00:00' or '2018-11-30') after which the event subscription would expire. By default, there is no expiration for the event subscription.")
c.argument('azure_active_directory_tenant_id', help="The Azure Active Directory Tenant Id to get the access token that will be included as the bearer token in delivery requests. Applicable only for webhook as a destination")
c.argument('azure_active_directory_application_id_or_uri', help="The Azure Active Directory Application Id or Uri to get the access token that will be included as the bearer token in delivery requests. Applicable only for webhook as a destination")
c.argument('resource_group_name', arg_type=resource_group_name_type)
c.argument('storage_queue_msg_ttl', arg_type=storage_queue_msg_ttl)

with self.argument_context('eventgrid partner topic event-subscription list') as c:
c.argument('odata_query', arg_type=odata_query_type, id_part=None)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,14 @@
StringEndsWithAdvancedFilter,
StringInAdvancedFilter,
StringNotInAdvancedFilter,
BoolEqualsAdvancedFilter)
BoolEqualsAdvancedFilter,
StringNotBeginsWithAdvancedFilter,
StringNotContainsAdvancedFilter,
StringNotEndsWithAdvancedFilter,
IsNullOrUndefinedAdvancedFilter,
IsNotNullAdvancedFilter,
NumberInRangeAdvancedFilter,
NumberNotInRangeAdvancedFilter)

NUMBERIN = "NumberIn"
NUMBERNOTIN = "NumberNotIn"
Expand All @@ -32,20 +39,34 @@
NUMBERLESSTHAN = "NumberLessThan"
NUMBERLESSTHANOREQUALS = "NumberLessThanOrEquals"
BOOLEQUALS = "BoolEquals"
NUMBERINRANGE = "NumberInRange"
NUMBERNOTINRANGE = "NumberNotInRange"
STRINGNOTBEGINSWITH = "StringNotBeginsWith"
STRINGNOTENDSWITH = "StringNotEndsWith"
STRINGNOTCONTAINS = "StringNotContains"
ISNULLORUNDEFINED = "IsNullOrUndefined"
ISNOTNULL = "IsNotNull"


# pylint: disable=protected-access
# pylint: disable=too-few-public-methods
class EventSubscriptionAddFilter(argparse._AppendAction):
def __call__(self, parser, namespace, values, option_string=None):
if len(values) < 3:
raise CLIError('usage error: --advanced-filter KEY[.INNERKEY] FILTEROPERATOR VALUE [VALUE ...]')

_validate_values_len(values)
key = values[0]
operator = values[1]

# operators that support no value
if operator.lower() == ISNULLORUNDEFINED.lower():
_validate_no_value_is_specified(ISNULLORUNDEFINED, values)
advanced_filter = IsNullOrUndefinedAdvancedFilter(key=key)
elif operator.lower() == ISNOTNULL.lower():
_validate_no_value_is_specified(ISNOTNULL, values)
advanced_filter = IsNotNullAdvancedFilter(key=key)

# operators that support single value
if operator.lower() == NUMBERLESSTHAN.lower():
elif operator.lower() == NUMBERLESSTHAN.lower():
_validate_only_single_value_is_specified(NUMBERLESSTHAN, values)
advanced_filter = NumberLessThanAdvancedFilter(key=key, value=float(values[2]))
elif operator.lower() == NUMBERLESSTHANOREQUALS.lower():
Expand All @@ -62,36 +83,89 @@ def __call__(self, parser, namespace, values, option_string=None):
advanced_filter = BoolEqualsAdvancedFilter(key=key, value=bool(values[2]))

# operators that support multiple values
elif operator.lower() == NUMBERIN.lower():
float_values = [float(i) for i in values[2:]]
advanced_filter = NumberInAdvancedFilter(key=key, values=float_values)
elif operator.lower() == NUMBERNOTIN.lower():
float_values = [float(i) for i in values[2:]]
advanced_filter = NumberNotInAdvancedFilter(key=key, values=float_values)
elif operator.lower() == NUMBERIN.lower() or operator.lower() == NUMBERNOTIN.lower():
advanced_filter = _get_in_advanced_filter(key, operator, values)
elif operator.lower() == STRINGIN.lower():
advanced_filter = StringInAdvancedFilter(key=key, values=values[2:])
elif operator.lower() == STRINGNOTIN.lower():
advanced_filter = StringNotInAdvancedFilter(key=key, values=values[2:])
elif operator.lower() == STRINGBEGINSWITH.lower():
advanced_filter = StringBeginsWithAdvancedFilter(key=key, values=values[2:])
elif operator.lower() == STRINGNOTBEGINSWITH.lower():
advanced_filter = StringNotBeginsWithAdvancedFilter(key=key, values=values[2:])
elif operator.lower() == STRINGENDSWITH.lower():
advanced_filter = StringEndsWithAdvancedFilter(key=key, values=values[2:])
elif operator.lower() == STRINGNOTENDSWITH.lower():
advanced_filter = StringNotEndsWithAdvancedFilter(key=key, values=values[2:])
elif operator.lower() == STRINGCONTAINS.lower():
advanced_filter = StringContainsAdvancedFilter(key=key, values=values[2:])
elif operator.lower() == STRINGNOTCONTAINS.lower():
advanced_filter = StringNotContainsAdvancedFilter(key=key, values=values[2:])

# operators that support range of values
elif operator.lower() == NUMBERINRANGE.lower() or operator.lower() == NUMBERNOTINRANGE.lower():
advanced_filter = _get_in_range_advanced_filter(key, operator, values)
else:
raise CLIError("--advanced-filter: The specified filter operator '{}' is not"
" a valid operator. Supported values are ".format(operator) +
NUMBERIN + "," + NUMBERNOTIN + "," + STRINGIN + "," +
STRINGNOTIN + "," + STRINGBEGINSWITH + "," +
STRINGCONTAINS + "," + STRINGENDSWITH + "," +
NUMBERGREATERTHAN + "," + NUMBERGREATERTHANOREQUALS + "," +
NUMBERLESSTHAN + "," + NUMBERLESSTHANOREQUALS + "," + BOOLEQUALS + ".")
NUMBERLESSTHAN + "," + NUMBERLESSTHANOREQUALS + "," + BOOLEQUALS + "," +
NUMBERINRANGE + "," + NUMBERNOTINRANGE + "," +
ISNULLORUNDEFINED + "," + ISNOTNULL + "," +
STRINGNOTBEGINSWITH + "," + STRINGNOTENDSWITH + "," +
STRINGNOTCONTAINS + ".")
if namespace.advanced_filter is None:
namespace.advanced_filter = []
namespace.advanced_filter.append(advanced_filter)


def _get_in_advanced_filter(key, operator, values):
_validate_at_least_single_value_is_specified(operator, values)
float_values = [float(i) for i in values[2:]]

if operator.lower() == NUMBERIN.lower():
advanced_filter = NumberInAdvancedFilter(key=key, values=float_values)
elif operator.lower() == NUMBERNOTIN.lower():
advanced_filter = NumberNotInAdvancedFilter(key=key, values=float_values)

return advanced_filter


def _get_in_range_advanced_filter(key, operator, values):
result = []
for value in values[2:]:
float_value = [float(i) for i in value.split(',')]
result.append(float_value)

if operator.lower() == NUMBERINRANGE.lower():
advanced_filter = NumberInRangeAdvancedFilter(key=key, values=result)
elif operator.lower() == NUMBERNOTINRANGE.lower():
advanced_filter = NumberNotInRangeAdvancedFilter(key=key, values=result)
return advanced_filter


def _validate_only_single_value_is_specified(operator_type, values):
if len(values) != 3:
raise CLIError("--advanced-filter: For '{}' operator, only one filter value "
"must be specified.".format(operator_type))


def _validate_no_value_is_specified(operator_type, values):
if len(values) != 2:
raise CLIError("--advanced-filter: For '{}' operator, no filter value "
"must be specified.".format(operator_type))


def _validate_at_least_single_value_is_specified(operator_type, values):
if len(values) < 3:
raise CLIError("--advanced-filter: For '{}' operator at least one filter value "
"must be specified.".format(operator_type))


def _validate_values_len(values):
valuesLen = len(values)
if valuesLen < 2:
raise CLIError('usage error: --advanced-filter KEY[.INNERKEY] FILTEROPERATOR VALUE [VALUE...]')
Comment thread
evelyn-ys marked this conversation as resolved.
Outdated
Loading