Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
4232865
Fixes based on bugbash
kalyanaj Sep 7, 2018
fe349e2
Support for new set of domain commands, updates to event subscription…
kalyanaj Sep 13, 2018
f358dfc
Improved the usability of event-subscription operations by standardiz…
kalyanaj Sep 21, 2018
bd228ac
Bug fixes from bugbash
Sep 24, 2018
2d55e87
Merge branch 'master' of https://github.com/Azure/azure-cli-extensions
kalyanaj Sep 24, 2018
3ddd370
Merge branch 'master' of https://github.com/kalyanaj/azure-cli-extens…
kalyanaj Sep 24, 2018
d0cfe99
Updated test recordings.
kalyanaj Oct 3, 2018
82f2015
Merge remote-tracking branch 'upstream/master'
kalyanaj Oct 3, 2018
23b57ee
Linter fixes
kalyanaj Oct 3, 2018
1d71a20
Merge remote-tracking branch 'upstream/master'
kalyanaj Oct 10, 2018
c39ab22
Deprecated topic-name, RG name, resourceid for EventSubscription crud…
kalyanaj Oct 10, 2018
af461e0
Adding back deprecated arguments to eventsubscription list.
kalyanaj Oct 11, 2018
97ab9fb
Linter fixes.
kalyanaj Oct 11, 2018
df3c9e0
Re-recorded the tests after adding back the tests for deprecated argu…
kalyanaj Oct 12, 2018
50739d8
Linter fixes
kalyanaj Oct 12, 2018
48e2e7d
Updated recordings.
kalyanaj Oct 12, 2018
d6c0468
Ignore import error for dateutil since static checking is happening w…
kalyanaj Oct 13, 2018
26dd000
flake8 fixes.
kalyanaj Oct 13, 2018
915169f
Removed duplication in _params.py per PR feedback.
kalyanaj Oct 15, 2018
f3417f2
Fixed a flake8 issue.
kalyanaj Oct 15, 2018
023e6da
Add a missing hide=True deprecation info for one parameter.
kalyanaj Oct 16, 2018
6a051cf
Updated minCliCoreVersion to 2.0.48 due to the Knack 0.4.4 dependency.
kalyanaj Oct 16, 2018
c8c3188
Updating minCliCoreVersion to 2.0.49
kalyanaj Oct 16, 2018
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
8 changes: 8 additions & 0 deletions src/eventgrid/azext_eventgrid/_client_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ def topics_factory(cli_ctx, _):
return cf_eventgrid(cli_ctx).topics


def domains_factory(cli_ctx, _):
return cf_eventgrid(cli_ctx).domains


def domain_topics_factory(cli_ctx, _):
return cf_eventgrid(cli_ctx).domain_topics


def event_subscriptions_factory(cli_ctx, _):
return cf_eventgrid(cli_ctx).event_subscriptions

Expand Down
357 changes: 307 additions & 50 deletions src/eventgrid/azext_eventgrid/_help.py

Large diffs are not rendered by default.

52 changes: 39 additions & 13 deletions src/eventgrid/azext_eventgrid/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@
name_type
)

from .advanced_filter import EventSubscriptionAddFilter

included_event_types_type = CLIArgumentType(
help="A space-separated list of event types. To subscribe to all event types, the string \"All\" should be specified.",
help="A space-separated list of event types. Example: Microsoft.Storage.BlobCreated Microsoft.Storage.BlobDeleted. To subscribe to all event types, the string \"All\" should be specified.",
nargs='+'
)

Expand All @@ -27,6 +29,21 @@
nargs='+'
)

input_schema_type = CLIArgumentType(
help="Schema in which incoming events will be published to this topic/domain. If you specify customeventschema as the value for this parameter, you must also provide values for at least one of --input_mapping_default_values / --input_mapping_fields.",
arg_type=get_enum_type(['eventgridschema', 'customeventschema', 'cloudeventv01schema'], default='eventgridschema')
)

input_mapping_fields_type = CLIArgumentType(
help="When input-schema is specified as customeventschema, this parameter is used to specify input mappings based on field names. Specify space separated mappings in 'key=value' format. Allowed key names are 'id', 'topic', 'eventtime', 'subject', 'eventtype', 'dataversion'. The corresponding value names should specify the names of the fields in the custom input schema. If a mapping for either 'id' or 'eventtime' is not provided, Event Grid will auto-generate a default value for these two fields.",
arg_type=tags_type
)

input_mapping_default_values_type = CLIArgumentType(
help="When input-schema is specified as customeventschema, this parameter can be used to specify input mappings based on default values. You can use this parameter when your custom schema does not include a field that corresponds to one of the three fields supported by this parameter. Specify space separated mappings in 'key=value' format. Allowed key names are 'subject', 'eventtype', 'dataversion'. The corresponding value names should specify the default values to be used for the mapping and they will be used only when the published event doesn't have a valid mapping for a particular field.",
arg_type=tags_type
)


def load_arguments(self, _):
with self.argument_context('eventgrid') as c:
Expand All @@ -36,7 +53,8 @@ def load_arguments(self, _):
c.argument('included_event_types', 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'], default='webhook'))
c.argument('resource_id', help="Fully qualified identifier of the Azure resource.")
c.argument('source_resource_id', help="Fully qualified identifier of the source Azure resource.")
c.argument('resource_id', deprecate_info=c.deprecate(redirect="--source-resource-id", expiration='2.1.0', hide=True), help="Fully qualified identifier of the 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.")
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.")
Expand All @@ -46,29 +64,37 @@ def load_arguments(self, _):

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'))
c.argument('input_mapping_fields', arg_type=tags_type, help="When input-schema is specified as customeventschema, this parameter is used to specify input mappings based on field names. Specify space separated mappings in 'key=value' format. Allowed key names are 'id', 'topic', 'eventtime', 'subject', 'eventtype', 'dataversion'. The corresponding value names should specify the names of the fields in the custom input schema.")
c.argument('input_mapping_default_values', arg_type=tags_type, help="When input-schema is specified as customeventschema, this parameter is used to specify input mappings based on default values. Specify space separated mappings in 'key=value' format. Allowed key names are 'subject', 'eventtype', 'dataversion'. The corresponding value names should specify the default values to be used for the mapping.")
c.argument('input_schema', arg_type=get_enum_type(['eventgridschema', 'customeventschema', 'cloudeventv01schema'], default='eventgridschema'), help='Schema in which incoming events will be published for this topic. If customeventschema is specified, either input_mapping_default_values or input_mapping_fields must be specified as well.')
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)

with self.argument_context('eventgrid domain') as c:
c.argument('domain_name', arg_type=name_type, help='Name of the domain', id_part='name', completer=get_resource_name_completion_list('Microsoft.EventGrid/domains'))
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)

with self.argument_context('eventgrid event-subscription') as c:
c.argument('topic_name', help='Name of the Event Grid topic', options_list=['--topic-name'], completer=get_resource_name_completion_list('Microsoft.EventGrid/topics'))
c.argument('topic_name', deprecate_info=c.deprecate(expiration='2.1.0', hide=True), help='Name of Event Grid topic', options_list=['--topic-name'], completer=get_resource_name_completion_list('Microsoft.EventGrid/topics'))
c.argument('event_subscription_name', arg_type=name_type, help='Name of the event subscription')
c.argument('event_delivery_schema', arg_type=get_enum_type(['eventgridschema', 'inputeventschema', 'cloudeventv01schema'], default='inputeventschema'), help='The schema in which events should be delivered for this event subscription. By default, events are delivered in the same schema in which they are published (inputeventschema).')
c.argument('event_delivery_schema', arg_type=get_enum_type(['eventgridschema', 'custominputschema', 'cloudeventv01schema']), help='The schema in which events should be delivered for this event subscription. By default, events will be delivered in the same schema in which they are published (based on the corresponding topic\'s input schema).')
c.argument('max_delivery_attempts', help="Maximum number of delivery attempts. Must be a number between 1 and 30.")
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('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.")

with self.argument_context('eventgrid event-subscription create') as c:
c.argument('topic_name', help='Name of the Event Grid topic to which the event subscription needs to be created.', options_list=['--topic-name'], completer=get_resource_name_completion_list('Microsoft.EventGrid/topics'))
c.argument('event_subscription_name', arg_type=name_type, help='Name of the new event subscription')
c.argument('resource_id', help="Fully qualified identifier of the Azure resource to which the event subscription needs to be created.")
c.argument('resource_group_name', deprecate_info=c.deprecate(expiration='2.1.0', hide=True), arg_type=resource_group_name_type)

with self.argument_context('eventgrid event-subscription delete') as c:
c.argument('topic_name', help='Name of the Event Grid topic whose event subscription needs to be deleted.', options_list=['--topic-name'], completer=get_resource_name_completion_list('Microsoft.EventGrid/topics'))
c.argument('event_subscription_name', arg_type=name_type, help='Name of the event subscription')
c.argument('resource_id', help="Fully qualified identifier of the Azure resource whose event subscription needs to be deleted.")
c.argument('resource_group_name', deprecate_info=c.deprecate(expiration='2.1.0', hide=True), arg_type=resource_group_name_type)

with self.argument_context('eventgrid event-subscription update') as c:
c.argument('resource_group_name', deprecate_info=c.deprecate(expiration='2.1.0', hide=True), arg_type=resource_group_name_type)

with self.argument_context('eventgrid event-subscription show') as c:
c.argument('resource_group_name', deprecate_info=c.deprecate(expiration='2.1.0', hide=True), arg_type=resource_group_name_type)
c.argument('include_full_endpoint_url', arg_type=get_three_state_flag(), options_list=['--include-full-endpoint-url'], help="Specify to indicate whether the full endpoint URL should be returned. True if flag present.", )

with self.argument_context('eventgrid topic-type') as c:
Expand Down
97 changes: 97 additions & 0 deletions src/eventgrid/azext_eventgrid/advanced_filter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

import argparse
from knack.util import CLIError

from azext_eventgrid.mgmt.eventgrid.models import (
NumberGreaterThanAdvancedFilter,
NumberGreaterThanOrEqualsAdvancedFilter,
NumberInAdvancedFilter,
NumberLessThanAdvancedFilter,
NumberLessThanOrEqualsAdvancedFilter,
NumberNotInAdvancedFilter,
StringBeginsWithAdvancedFilter,
StringContainsAdvancedFilter,
StringEndsWithAdvancedFilter,
StringInAdvancedFilter,
StringNotInAdvancedFilter,
BoolEqualsAdvancedFilter)

NUMBERIN = "NumberIn"
NUMBERNOTIN = "NumberNotIn"
STRINGIN = "StringIn"
STRINGNOTIN = "StringNotIn"
STRINGBEGINSWITH = "StringBeginsWith"
STRINGCONTAINS = "StringContains"
STRINGENDSWITH = "StringEndsWith"
NUMBERGREATERTHAN = "NumberGreaterThan"
NUMBERGREATERTHANOREQUALS = "NumberGreaterThanOrEquals"
NUMBERLESSTHAN = "NumberLessThan"
NUMBERLESSTHANOREQUALS = "NumberLessThanOrEquals"
BOOLEQUALS = "BoolEquals"


# 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 ...]')

key = values[0]
operator = values[1]

# operators that support single value
if 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():
_validate_only_single_value_is_specified(NUMBERLESSTHANOREQUALS, values)
advanced_filter = NumberLessThanOrEqualsAdvancedFilter(key=key, value=float(values[2]))
elif operator.lower() == NUMBERGREATERTHAN.lower():
_validate_only_single_value_is_specified(NUMBERGREATERTHAN, values)
advanced_filter = NumberGreaterThanAdvancedFilter(key=key, value=float(values[2]))
elif operator.lower() == NUMBERGREATERTHANOREQUALS.lower():
_validate_only_single_value_is_specified(NUMBERGREATERTHANOREQUALS, values)
advanced_filter = NumberGreaterThanOrEqualsAdvancedFilter(key=key, value=float(values[2]))
elif operator.lower() == BOOLEQUALS.lower():
_validate_only_single_value_is_specified(BOOLEQUALS, values)
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() == 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() == STRINGENDSWITH.lower():
advanced_filter = StringEndsWithAdvancedFilter(key=key, values=values[2:])
elif operator.lower() == STRINGCONTAINS.lower():
advanced_filter = StringContainsAdvancedFilter(key=key, values=values[2:])
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 + ".")
if namespace.advanced_filter is None:
namespace.advanced_filter = []
namespace.advanced_filter.append(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))
2 changes: 1 addition & 1 deletion src/eventgrid/azext_eventgrid/azext_metadata.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"azext.minCliCoreVersion": "2.0.24",
"azext.minCliCoreVersion": "2.0.49",
"azext.isPreview": true
}
30 changes: 29 additions & 1 deletion src/eventgrid/azext_eventgrid/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# pylint: disable=line-too-long

from azure.cli.core.commands import CliCommandType
from ._client_factory import (topics_factory, event_subscriptions_factory, topic_types_factory)
from ._client_factory import (topics_factory, domains_factory, domain_topics_factory, event_subscriptions_factory, topic_types_factory)


def load_command_table(self, _):
Expand All @@ -16,6 +16,18 @@ def load_command_table(self, _):
client_arg_name='self'
)

domains_mgmt_util = CliCommandType(
operations_tmpl='azext_eventgrid.mgmt.eventgrid.operations.domains_operations#DomainsOperations.{}',
client_factory=domains_factory,
client_arg_name='self'
)

domain_topics_mgmt_util = CliCommandType(
operations_tmpl='azext_eventgrid.mgmt.eventgrid.operations.domain_topics_operations#DomainTopicsOperations.{}',
client_factory=domain_topics_factory,
client_arg_name='self'
)

topic_type_mgmt_util = CliCommandType(
operations_tmpl='azext_eventgrid.mgmt.eventgrid.operations.topic_types_operations#TopicTypesOperations.{}',
client_factory=topic_types_factory,
Expand All @@ -34,6 +46,22 @@ def load_command_table(self, _):
setter_name='update',
client_factory=topics_factory)

with self.command_group('eventgrid domain topic', domain_topics_mgmt_util, client_factory=domain_topics_factory) as g:
g.command('show', 'get')
g.command('list', 'list_by_domain')

with self.command_group('eventgrid domain', domains_mgmt_util, client_factory=domains_factory) as g:
g.command('show', 'get')
g.command('key list', 'list_shared_access_keys')
g.command('key regenerate', 'regenerate_key')
g.command('delete', 'delete')
g.custom_command('list', 'cli_domain_list')
g.custom_command('create', 'cli_domain_create_or_update')
g.generic_update_command('update',
getter_name='get',
setter_name='update',
client_factory=domains_factory)

custom_tmpl = 'azext_eventgrid.custom#{}'
eventgrid_custom = CliCommandType(operations_tmpl=custom_tmpl)

Expand Down
Loading