From 71bd202f5261e7ce8b2db38bb9b6802f1a55a5dc Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Mon, 1 Nov 2021 16:25:59 +0800 Subject: [PATCH] Revert "delete eventgrid" (#21512) * Revert "delete eventgrid (#21509)" This reverts commit 700dc5e334e868df4b61fba97cf183c31084bbd4. * Update ci.yml * Update CHANGELOG.md --- sdk/eventgrid/azure-eventgrid/CHANGELOG.md | 191 +++++++ sdk/eventgrid/azure-eventgrid/MANIFEST.in | 5 + sdk/eventgrid/azure-eventgrid/README.md | 478 ++++++++++++++++++ .../azure-eventgrid/azure/__init__.py | 1 + .../azure/eventgrid/__init__.py | 19 + .../azure/eventgrid/_constants.py | 10 + .../azure/eventgrid/_event_mappings.py | 336 ++++++++++++ .../azure/eventgrid/_generated/__init__.py | 16 + .../eventgrid/_generated/_configuration.py | 52 ++ .../_event_grid_publisher_client.py | 87 ++++ .../eventgrid/_generated/aio/__init__.py | 10 + .../_generated/aio/_configuration.py | 46 ++ .../_generated/aio/_configuration_async.py | 46 ++ .../aio/_event_grid_publisher_client.py | 81 +++ .../aio/_event_grid_publisher_client_async.py | 45 ++ .../eventgrid/_generated/models/__init__.py | 19 + .../eventgrid/_generated/models/_models.py | 143 ++++++ .../_generated/models/_models_py3.py | 166 ++++++ .../azure/eventgrid/_generated/py.typed | 1 + .../eventgrid/_generated/rest/__init__.py | 22 + .../_generated/rest/_request_builders.py | 201 ++++++++ .../_generated/rest/_request_builders_py3.py | 208 ++++++++ .../azure/eventgrid/_helpers.py | 167 ++++++ .../azure/eventgrid/_messaging_shared.py | 41 ++ .../azure/eventgrid/_models.py | 113 +++++ .../azure/eventgrid/_policies.py | 50 ++ .../azure/eventgrid/_publisher_client.py | 216 ++++++++ .../eventgrid/_signature_credential_policy.py | 36 ++ .../azure/eventgrid/_version.py | 12 + .../azure/eventgrid/aio/__init__.py | 9 + .../eventgrid/aio/_publisher_client_async.py | 213 ++++++++ .../azure-eventgrid/azure/eventgrid/py.typed | 0 .../azure-eventgrid/dev_requirements.txt | 7 + .../azure-eventgrid/migration_guide.md | 102 ++++ sdk/eventgrid/azure-eventgrid/mypy.ini | 13 + .../azure-eventgrid/samples/README.md | 76 +++ .../sample_authentication_async.py | 57 +++ ...le_publish_cloud_event_using_dict_async.py | 49 ++ ..._publish_custom_schema_to_a_topic_async.py | 53 ++ ...ample_publish_eg_event_using_dict_async.py | 61 +++ ...ple_publish_eg_events_to_a_domain_async.py | 54 ++ ...mple_publish_eg_events_to_a_topic_async.py | 45 ++ ...s_to_a_topic_using_sas_credential_async.py | 44 ++ ...nts_using_cloud_events_1.0_schema_async.py | 45 ++ .../consume_cloud_events_from_eventhub.py | 42 ++ ...consume_cloud_events_from_storage_queue.py | 36 ++ ...eventgrid_events_from_service_bus_queue.py | 36 ++ .../consume_samples/functionsapp/.funcignore | 5 + .../consume_samples/functionsapp/.gitignore | 130 +++++ .../EventGridTrigger1/__init__.py | 21 + .../EventGridTrigger1/function.json | 10 + .../functionsapp/EventGridTrigger1/host.json | 7 + .../functionsapp/EventGridTrigger1/sample.dat | 20 + .../consume_samples/functionsapp/host.json | 15 + .../consume_samples/functionsapp/proxies.json | 4 + .../functionsapp/requirements.txt | 1 + ...ish_cloud_events_to_custom_topic_sample.py | 56 ++ ...ish_cloud_events_to_domain_topic_sample.py | 58 +++ ...sh_custom_schema_events_to_topic_sample.py | 59 +++ ...vent_grid_events_to_custom_topic_sample.py | 55 ++ ...ish_with_shared_access_signature_sample.py | 60 +++ .../sync_samples/sample_authentication.py | 49 ++ .../sample_consume_custom_payload.py | 34 ++ .../sync_samples/sample_generate_sas.py | 32 ++ .../sample_publish_cloud_event_using_dict.py | 41 ++ ...sample_publish_custom_schema_to_a_topic.py | 49 ++ .../sample_publish_eg_event_using_dict.py | 57 +++ .../sample_publish_eg_events_to_a_domain.py | 46 ++ .../sample_publish_eg_events_to_a_topic.py | 38 ++ ..._events_to_a_topic_using_sas_credential.py | 37 ++ ...sh_events_using_cloud_events_1.0_schema.py | 39 ++ .../azure-eventgrid/sdk_packaging.toml | 7 + sdk/eventgrid/azure-eventgrid/setup.cfg | 2 + sdk/eventgrid/azure-eventgrid/setup.py | 91 ++++ .../swagger/README.PYTHON_T2.md | 24 + .../swagger/postprocess_eventnames.py | 56 ++ sdk/eventgrid/azure-eventgrid/tests/_mocks.py | 77 +++ .../azure-eventgrid/tests/conftest.py | 33 ++ .../tests/eventgrid_preparer.py | 109 ++++ .../tests/perfstress_tests/README.md | 48 ++ .../tests/perfstress_tests/__init__.py | 0 .../tests/perfstress_tests/send.py | 73 +++ ...nt.test_send_cloud_event_data_as_list.yaml | 38 ++ ...nd_cloud_event_data_base64_using_data.yaml | 38 ++ ...ient.test_send_cloud_event_data_bytes.yaml | 38 ++ ...lient.test_send_cloud_event_data_dict.yaml | 38 ++ ...lient.test_send_cloud_event_data_none.yaml | 38 ++ ...client.test_send_cloud_event_data_str.yaml | 38 ++ ...send_cloud_event_data_with_extensions.yaml | 38 ++ ...her_client.test_send_cloud_event_dict.yaml | 37 ++ ..._client.test_send_custom_schema_event.yaml | 38 ++ ...test_send_custom_schema_event_as_list.yaml | 40 ++ ...st_send_event_grid_event_data_as_list.yaml | 40 ++ ....test_send_event_grid_event_data_dict.yaml | 38 ++ ...t.test_send_event_grid_event_data_str.yaml | 38 ++ ..._send_event_grid_event_dict_data_dict.yaml | 38 ++ ...client.test_send_signature_credential.yaml | 38 ++ ...ync.test_send_and_close_async_session.yaml | 28 + ...nc.test_send_cloud_event_data_as_list.yaml | 28 + ...sync.test_send_cloud_event_data_bytes.yaml | 28 + ...async.test_send_cloud_event_data_dict.yaml | 28 + ...async.test_send_cloud_event_data_none.yaml | 28 + ..._async.test_send_cloud_event_data_str.yaml | 28 + ...send_cloud_event_data_with_extensions.yaml | 28 + ...ient_async.test_send_cloud_event_dict.yaml | 27 + ...t_async.test_send_custom_schema_event.yaml | 28 + ...test_send_custom_schema_event_as_list.yaml | 30 ++ ...st_send_event_grid_event_data_as_list.yaml | 30 ++ ....test_send_event_grid_event_data_dict.yaml | 28 + ...c.test_send_event_grid_event_data_str.yaml | 28 + ..._async.test_send_signature_credential.yaml | 28 + .../tests/test_cloud_event_tracing.py | 67 +++ .../tests/test_eg_event_get_bytes.py | 266 ++++++++++ .../tests/test_eg_publisher_client.py | 361 +++++++++++++ .../tests/test_eg_publisher_client_async.py | 347 +++++++++++++ .../tests/test_serialization.py | 140 +++++ sdk/eventgrid/ci.yml | 2 + sdk/eventgrid/test-resources.json | 127 +++++ sdk/eventgrid/tests.yml | 17 + 119 files changed, 7498 insertions(+) create mode 100644 sdk/eventgrid/azure-eventgrid/CHANGELOG.md create mode 100644 sdk/eventgrid/azure-eventgrid/MANIFEST.in create mode 100644 sdk/eventgrid/azure-eventgrid/README.md create mode 100644 sdk/eventgrid/azure-eventgrid/azure/__init__.py create mode 100644 sdk/eventgrid/azure-eventgrid/azure/eventgrid/__init__.py create mode 100644 sdk/eventgrid/azure-eventgrid/azure/eventgrid/_constants.py create mode 100644 sdk/eventgrid/azure-eventgrid/azure/eventgrid/_event_mappings.py create mode 100644 sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/__init__.py create mode 100644 sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/_configuration.py create mode 100644 sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/_event_grid_publisher_client.py create mode 100644 sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/aio/__init__.py create mode 100644 sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/aio/_configuration.py create mode 100644 sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/aio/_configuration_async.py create mode 100644 sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/aio/_event_grid_publisher_client.py create mode 100644 sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/aio/_event_grid_publisher_client_async.py create mode 100644 sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/models/__init__.py create mode 100644 sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/models/_models.py create mode 100644 sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/models/_models_py3.py create mode 100644 sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/py.typed create mode 100644 sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/rest/__init__.py create mode 100644 sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/rest/_request_builders.py create mode 100644 sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/rest/_request_builders_py3.py create mode 100644 sdk/eventgrid/azure-eventgrid/azure/eventgrid/_helpers.py create mode 100644 sdk/eventgrid/azure-eventgrid/azure/eventgrid/_messaging_shared.py create mode 100644 sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py create mode 100644 sdk/eventgrid/azure-eventgrid/azure/eventgrid/_policies.py create mode 100644 sdk/eventgrid/azure-eventgrid/azure/eventgrid/_publisher_client.py create mode 100644 sdk/eventgrid/azure-eventgrid/azure/eventgrid/_signature_credential_policy.py create mode 100644 sdk/eventgrid/azure-eventgrid/azure/eventgrid/_version.py create mode 100644 sdk/eventgrid/azure-eventgrid/azure/eventgrid/aio/__init__.py create mode 100644 sdk/eventgrid/azure-eventgrid/azure/eventgrid/aio/_publisher_client_async.py create mode 100644 sdk/eventgrid/azure-eventgrid/azure/eventgrid/py.typed create mode 100644 sdk/eventgrid/azure-eventgrid/dev_requirements.txt create mode 100644 sdk/eventgrid/azure-eventgrid/migration_guide.md create mode 100644 sdk/eventgrid/azure-eventgrid/mypy.ini create mode 100644 sdk/eventgrid/azure-eventgrid/samples/README.md create mode 100644 sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_authentication_async.py create mode 100644 sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_publish_cloud_event_using_dict_async.py create mode 100644 sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_publish_custom_schema_to_a_topic_async.py create mode 100644 sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_publish_eg_event_using_dict_async.py create mode 100644 sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_publish_eg_events_to_a_domain_async.py create mode 100644 sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_publish_eg_events_to_a_topic_async.py create mode 100644 sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_publish_events_to_a_topic_using_sas_credential_async.py create mode 100644 sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_publish_events_using_cloud_events_1.0_schema_async.py create mode 100644 sdk/eventgrid/azure-eventgrid/samples/consume_samples/consume_cloud_events_from_eventhub.py create mode 100644 sdk/eventgrid/azure-eventgrid/samples/consume_samples/consume_cloud_events_from_storage_queue.py create mode 100644 sdk/eventgrid/azure-eventgrid/samples/consume_samples/consume_eventgrid_events_from_service_bus_queue.py create mode 100644 sdk/eventgrid/azure-eventgrid/samples/consume_samples/functionsapp/.funcignore create mode 100644 sdk/eventgrid/azure-eventgrid/samples/consume_samples/functionsapp/.gitignore create mode 100644 sdk/eventgrid/azure-eventgrid/samples/consume_samples/functionsapp/EventGridTrigger1/__init__.py create mode 100644 sdk/eventgrid/azure-eventgrid/samples/consume_samples/functionsapp/EventGridTrigger1/function.json create mode 100644 sdk/eventgrid/azure-eventgrid/samples/consume_samples/functionsapp/EventGridTrigger1/host.json create mode 100644 sdk/eventgrid/azure-eventgrid/samples/consume_samples/functionsapp/EventGridTrigger1/sample.dat create mode 100644 sdk/eventgrid/azure-eventgrid/samples/consume_samples/functionsapp/host.json create mode 100644 sdk/eventgrid/azure-eventgrid/samples/consume_samples/functionsapp/proxies.json create mode 100644 sdk/eventgrid/azure-eventgrid/samples/consume_samples/functionsapp/requirements.txt create mode 100644 sdk/eventgrid/azure-eventgrid/samples/publish_samples/publish_cloud_events_to_custom_topic_sample.py create mode 100644 sdk/eventgrid/azure-eventgrid/samples/publish_samples/publish_cloud_events_to_domain_topic_sample.py create mode 100644 sdk/eventgrid/azure-eventgrid/samples/publish_samples/publish_custom_schema_events_to_topic_sample.py create mode 100644 sdk/eventgrid/azure-eventgrid/samples/publish_samples/publish_event_grid_events_to_custom_topic_sample.py create mode 100644 sdk/eventgrid/azure-eventgrid/samples/publish_samples/publish_with_shared_access_signature_sample.py create mode 100644 sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_authentication.py create mode 100644 sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_consume_custom_payload.py create mode 100644 sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_generate_sas.py create mode 100644 sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_cloud_event_using_dict.py create mode 100644 sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_custom_schema_to_a_topic.py create mode 100644 sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_eg_event_using_dict.py create mode 100644 sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_eg_events_to_a_domain.py create mode 100644 sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_eg_events_to_a_topic.py create mode 100644 sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_events_to_a_topic_using_sas_credential.py create mode 100644 sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_events_using_cloud_events_1.0_schema.py create mode 100644 sdk/eventgrid/azure-eventgrid/sdk_packaging.toml create mode 100644 sdk/eventgrid/azure-eventgrid/setup.cfg create mode 100644 sdk/eventgrid/azure-eventgrid/setup.py create mode 100644 sdk/eventgrid/azure-eventgrid/swagger/README.PYTHON_T2.md create mode 100644 sdk/eventgrid/azure-eventgrid/swagger/postprocess_eventnames.py create mode 100644 sdk/eventgrid/azure-eventgrid/tests/_mocks.py create mode 100644 sdk/eventgrid/azure-eventgrid/tests/conftest.py create mode 100644 sdk/eventgrid/azure-eventgrid/tests/eventgrid_preparer.py create mode 100644 sdk/eventgrid/azure-eventgrid/tests/perfstress_tests/README.md create mode 100644 sdk/eventgrid/azure-eventgrid/tests/perfstress_tests/__init__.py create mode 100644 sdk/eventgrid/azure-eventgrid/tests/perfstress_tests/send.py create mode 100644 sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_cloud_event_data_as_list.yaml create mode 100644 sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_cloud_event_data_base64_using_data.yaml create mode 100644 sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_cloud_event_data_bytes.yaml create mode 100644 sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_cloud_event_data_dict.yaml create mode 100644 sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_cloud_event_data_none.yaml create mode 100644 sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_cloud_event_data_str.yaml create mode 100644 sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_cloud_event_data_with_extensions.yaml create mode 100644 sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_cloud_event_dict.yaml create mode 100644 sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_custom_schema_event.yaml create mode 100644 sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_custom_schema_event_as_list.yaml create mode 100644 sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_event_grid_event_data_as_list.yaml create mode 100644 sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_event_grid_event_data_dict.yaml create mode 100644 sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_event_grid_event_data_str.yaml create mode 100644 sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_event_grid_event_dict_data_dict.yaml create mode 100644 sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_signature_credential.yaml create mode 100644 sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_and_close_async_session.yaml create mode 100644 sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_cloud_event_data_as_list.yaml create mode 100644 sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_cloud_event_data_bytes.yaml create mode 100644 sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_cloud_event_data_dict.yaml create mode 100644 sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_cloud_event_data_none.yaml create mode 100644 sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_cloud_event_data_str.yaml create mode 100644 sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_cloud_event_data_with_extensions.yaml create mode 100644 sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_cloud_event_dict.yaml create mode 100644 sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_custom_schema_event.yaml create mode 100644 sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_custom_schema_event_as_list.yaml create mode 100644 sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_event_grid_event_data_as_list.yaml create mode 100644 sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_event_grid_event_data_dict.yaml create mode 100644 sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_event_grid_event_data_str.yaml create mode 100644 sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_signature_credential.yaml create mode 100644 sdk/eventgrid/azure-eventgrid/tests/test_cloud_event_tracing.py create mode 100644 sdk/eventgrid/azure-eventgrid/tests/test_eg_event_get_bytes.py create mode 100644 sdk/eventgrid/azure-eventgrid/tests/test_eg_publisher_client.py create mode 100644 sdk/eventgrid/azure-eventgrid/tests/test_eg_publisher_client_async.py create mode 100644 sdk/eventgrid/azure-eventgrid/tests/test_serialization.py create mode 100644 sdk/eventgrid/test-resources.json create mode 100644 sdk/eventgrid/tests.yml diff --git a/sdk/eventgrid/azure-eventgrid/CHANGELOG.md b/sdk/eventgrid/azure-eventgrid/CHANGELOG.md new file mode 100644 index 00000000000..c0784135231 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/CHANGELOG.md @@ -0,0 +1,191 @@ +# Release History + +## 4.6.1 (Unreleased) + +### Features Added + +### Breaking Changes + +### Bugs Fixed + +### Other Changes + +## 4.6.0 (2021-10-05) + +### Features Added + +- Added new enum values to `SystemEvents`. + +## 4.5.0 (2021-08-10) + +### Features Added + +- Added a new enum value `Microsoft.ContainerService.NewKubernetesVersionAvailable` to `SystemEvents`. +- Added a `from_json` method which now accepts storage QueueMessage, eventhub's EventData or ServiceBusMessage or simply json bytes to return an `EventGridEvent` + +## 4.4.0 (2021-07-19) + +- Bumped `msrest` dependency to `0.6.21` to align with mgmt package. + +### Features Added + +- `EventGridPublisherClient` now supports Azure Active Directory (AAD) for authentication. + +## 4.3.0 (2021-06-09) + + **New Features** + - Added new event names related to blob inventory to the `SystemEventNames` enum. + + **Bug Fixes** + - Replaced the `ServiceBusDeadletterMessagesAvailableWithNoListenerEventName` with the right value. + +## 4.2.0 (2021-05-12) + + **New Features** + - Added new event names to the `SystemEventNames` enum. + +## 4.1.1 (2021-04-07) + + **Bug Fixes** + - Improved the `repr` on `EventGridEvent` to show more meaningful text. + +## 4.1.0 (2021-03-23) + + **New Features** + - Added new SystemEventNames `AcsChatThreadParticipantRemovedEventName`, `AcsChatThreadParticipantAddedEventName` and `AcsRecordingFileStatusUpdatedEventName`. + +## 4.0.0 (2021-03-09) + + **Note:** This is the first stable release of our efforts to create a user-friendly and Pythonic client library for Azure EventGrid. Users migrating from `v1.x` are advised to view the [migration guide](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/migration_guide.md). + + **New Features** + - `azure-eventgrid` package now supports `azure.core.messaging.CloudEvent` which honors the CNCF CloudEvent spec. + - `azure.eventgrid.SystemEventNames` can be used to get the event model type mapping for system events. + - Implements the `EventGridPublisherClient` for the publish flow for EventGrid Events, CloudEvents and Custom schema events. + + **Breaking Changes** + - `azure.eventgrid.models` namespace along with all the models in it are now removed.: + - JSON documentation on the events is available here: https://docs.microsoft.com/azure/event-grid/system-topics + - `azure.eventgrid.SystemEventNames` provides the list of available events name for easy switching. + - `azure.eventgrid.event_grid_client.EventGridClient` is now removed in favor of `azure.eventgrid.EventGridPublisherClient`. + - `azure.eventgrid.event_grid_client.EventGridClientConfiguration` is now removed. + + +## 2.0.0 (2021-03-09) + + **Disclaimer:** v2.0.0 is functionally equivalent to v4.0.0. Users are advised to use v4.0.0 instead of this. + + **Breaking Changes** + - `~azure.eventgrid.CloudEvent` is now removed in favor of `~azure.core.messaging.CloudEvent`. + - All the `SystemEventNames` related to Azure Communication Service starting with `ACS****` are renamed to `Acs***` to honor pascal case. + + **Features** + - Added support for two new `SystemEvents` - `ServiceBusDeadletterMessagesAvailablePeriodicNotificationsEventData` and `ServiceBusActiveMessagesAvailablePeriodicNotificationsEventData` + +## 2.0.0b5 (2021-02-10) + + **Breaking Changes** + - `EventGridSharedAccessSignatureCredential` is deprecated in favor of `AzureSasCredential`. + - `azure.eventgrid.models` namespace along with all the models in it are now removed. `azure.eventgrid.SystemEventNames` can be used to get the event model type mapping. + - `topic_hostname` is renamed to `endpoint` in the `EventGridPublisherClient`. + - `azure.eventgrid.generate_shared_access_signature` method is now renamed to `generate_sas`. + - `EventGridConsumer`is now removed. Please see the samples to see how events can be deserialized. + - `CustomEvent` model is removed. Dictionaries must be used to send a custom schema. + + **Bug Fixes** + - `EventGridEvent` has two additional required positional parameters namely, `data` and `data_version`. + - `EventGridPublisherClient` now appropriately throws a `ValueError` if an invalid credential is passed during initialization. + +## 2.0.0b4 (2020-11-11) + + **Bug Fixes** + - `TypeError` is raised when bytes are passed to an `EventGridEvent`. + +## 2.0.0b3 (2020-10-05) + + **Feature** + - Added support for Keyvault Event Types + - Added distributed tracing support for CloudEvents + +## 2.0.0b2 (2020-09-24) + + **Features** + - Added support for Azure Communication Services event types. + +## 2.0.0b1 (2020-09-08) + + **Features** + - Version (2.0.0b1) is the first preview of our efforts to create a user-friendly and Pythonic client library for Azure EventGrid. + For more information about this, and preview releases of other Azure SDK libraries, please visit https://azure.github.io/azure-sdk/releases/latest/python.html. + - Added Support for `CloudEvents`. + - Implements the `EventGridPublisherClient` for the publish flow for EventGrid Events, CloudEvents and CustomEvents. + - Implements the `EventGridConsumer` for the consume flow of the events. + +## 1.3.0 (2019-05-20) + + - Event Schemas for new event types from IotHub, Media Services, + Container Registry, Maps, and AppConfiguration services. + +## 1.2.0 (2018-08-28) + + - Event Schemas for new events (IotHub DeviceConnected and + DeviceDisconnected events, Resource events related to actions), and + breaking changes to the schema for IotHub DeviceCreated event and + IotHub DeviceDeleted event. + +## 1.1.0 (2018-05-24) + + - Event Schemas for EventGrid subscription validation event, Azure + Media events, and ServiceBus events. + +## 1.0.0 (2018-04-26) + +**General Breaking changes** + +This version uses a next-generation code generator that *might* +introduce breaking changes. + + - Model signatures now use only keyword-argument syntax. All + positional arguments must be re-written as keyword-arguments. To + keep auto-completion in most cases, models are now generated for + Python 2 and Python 3. Python 3 uses the "*" syntax for + keyword-only arguments. + - Enum types now use the "str" mixin (class AzureEnum(str, Enum)) to + improve the behavior when unrecognized enum values are encountered. + While this is not a breaking change, the distinctions are important, + and are documented here: + At a glance: + - "is" should not be used at all. + - "format" will return the string value, where "%s" string + formatting will return `NameOfEnum.stringvalue`. Format syntax + should be prefered. + - New Long Running Operation: + - Return type changes from + `msrestazure.azure_operation.AzureOperationPoller` to + `msrest.polling.LROPoller`. External API is the same. + - Return type is now **always** a `msrest.polling.LROPoller`, + regardless of the optional parameters used. + - The behavior has changed when using `raw=True`. Instead of + returning the initial call result as `ClientRawResponse`, + without polling, now this returns an LROPoller. After polling, + the final resource will be returned as a `ClientRawResponse`. + - New `polling` parameter. The default behavior is + `Polling=True` which will poll using ARM algorithm. When + `Polling=False`, the response of the initial call will be + returned without polling. + - `polling` parameter accepts instances of subclasses of + `msrest.polling.PollingMethod`. + - `add_done_callback` will no longer raise if called after + polling is finished, but will instead execute the callback right + away. + +**Features** + + - Client class can be used as a context manager to keep the underlying + HTTP session open for performance + - Support for consuming Azure Container Registry events and Azure IoT + Hub events published to Event Grid. + +## 0.1.0 (2018-01-30) + + - Initial Release diff --git a/sdk/eventgrid/azure-eventgrid/MANIFEST.in b/sdk/eventgrid/azure-eventgrid/MANIFEST.in new file mode 100644 index 00000000000..f7f367718db --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/MANIFEST.in @@ -0,0 +1,5 @@ +recursive-include tests *.py *.yaml +recursive-include samples *.py +include *.md +include azure/__init__.py +include azure/eventgrid/py.typed diff --git a/sdk/eventgrid/azure-eventgrid/README.md b/sdk/eventgrid/azure-eventgrid/README.md new file mode 100644 index 00000000000..b290ce62a50 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/README.md @@ -0,0 +1,478 @@ +# Azure Event Grid client library for Python + +Azure Event Grid is a fully-managed intelligent event routing service that allows for uniform event consumption using a publish-subscribe model. + +[Source code][python-eg-src] | [Package (PyPI)][python-eg-pypi] | [API reference documentation][python-eg-ref-docs] | [Product documentation][python-eg-product-docs] | [Samples][python-eg-samples] | [Changelog][python-eg-changelog] + +## _Disclaimer_ + +_Azure SDK Python packages support for Python 2.7 is ending 01 January 2022. For more information and questions, please refer to https://github.com/Azure/azure-sdk-for-python/issues/20691_ + +## Getting started + +### Prerequisites +* Python 2.7, or 3.6 or later is required to use this package. +* You must have an [Azure subscription][azure_subscription] and an Event Grid Topic resource to use this package. Follow this [step-by-step tutorial](https://docs.microsoft.com/azure/event-grid/custom-event-quickstart-portal) to register the Event Grid resource provider and create Event Grid topics using the [Azure portal](https://portal.azure.com/). There is a [similar tutorial](https://docs.microsoft.com/azure/event-grid/custom-event-quickstart) using [Azure CLI](https://docs.microsoft.com/cli/azure). + + +### Install the package +Install the Azure Event Grid client library for Python with [pip][pip]: + +```bash +pip install azure-eventgrid +``` + +* An existing Event Grid topic or domain is required. You can create the resource using [Azure Portal][azure_portal_create_EG_resource] or [Azure CLI][azure_cli_link] + +If you use Azure CLI, replace `` and `` with your own unique names. + +#### Create an Event Grid Topic + +``` +az eventgrid topic --create --location --resource-group --name +``` + +#### Create an Event Grid Domain + +``` +az eventgrid domain --create --location --resource-group --name +``` + +### Authenticate the client +In order to interact with the Event Grid service, you will need to create an instance of a client. +An **endpoint** and **credential** are necessary to instantiate the client object. + +#### Using Azure Active Directory (AAD) + +Azure Event Grid provides integration with Azure Active Directory (Azure AD) for identity-based authentication of requests. With Azure AD, you can use role-based access control (RBAC) to grant access to your Azure Event Grid resources to users, groups, or applications. + +To send events to a topic or domain with a `TokenCredential`, the authenticated identity should have the "EventGrid Data Sender" role assigned. + +With the `azure-identity` package, you can seamlessly authorize requests in both development and production environments. To learn more about Azure Active Directory, see the [`azure-identity` README](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/identity/azure-identity/README.md). + +For example, you can use `DefaultAzureCredential` to construct a client which will authenticate using Azure Active Directory: + +```Python +from azure.identity import DefaultAzureCredential +from azure.eventgrid import EventGridPublisherClient, EventGridEvent + +event = EventGridEvent( + data={"team": "azure-sdk"}, + subject="Door1", + event_type="Azure.Sdk.Demo", + data_version="2.0" +) + +credential = DefaultAzureCredential() +endpoint = os.environ["EG_TOPIC_HOSTNAME"] +client = EventGridPublisherClient(endpoint, credential) + +client.send(event) +``` + +#### Looking up the endpoint +You can find the topic endpoint within the Event Grid Topic resource on the Azure portal. This will look like: +`"https://..eventgrid.azure.net/api/events"` + +#### Create the client with AzureKeyCredential + +To use an Access key as the `credential` parameter, +pass the key as a string into an instance of [AzureKeyCredential][azure-key-credential]. + +> **Note:** The Access Key may be found in the azure portal in the "Access Keys" menu of the Event Grid Topic resource. They may also be obtained via the azure CLI, or the `azure-mgmt-eventgrid` library. A guide for getting access keys can be found [here](https://docs.microsoft.com/azure/event-grid/get-access-keys). + +```python +from azure.core.credentials import AzureKeyCredential +from azure.eventgrid import EventGridPublisherClient + +endpoint = "https://..eventgrid.azure.net/api/events" +credential = AzureKeyCredential("") +eg_publisher_client = EventGridPublisherClient(endpoint, credential) +``` +> **Note:** A client may also be authenticated via SAS signature, using the `AzureSasCredential`. A sample demonstrating this, is available [here][python-eg-sample-send-using-sas] ([async_version][python-eg-sample-send-using-sas-async]). + +> **Note:** The `generate_sas` method can be used to generate a shared access signature. A sample demonstrating this can be seen [here][python-eg-generate-sas]. + +## Key concepts + +### Topic +A **[topic](https://docs.microsoft.com/azure/event-grid/concepts#topics)** is a channel within the EventGrid service to send events. The event schema that a topic accepts is decided at topic creation time. If events of a schema type are sent to a topic that requires a different schema type, errors will be raised. + +### Domain +An event **[domain](https://docs.microsoft.com/azure/event-grid/event-domains)** is a management tool for large numbers of Event Grid topics related to the same application. They allow you to publish events to thousands of topics. Domains also give you authorization and authentication control over each topic. For more information, visit [Event domain overview](https://docs.microsoft.com/azure/event-grid/event-domains). + +When you create an event domain, a publishing endpoint for this domain is made available to you. This process is similar to creating an Event Grid Topic. The only difference is that, when publishing to a domain, you must specify the topic within the domain that you'd like the event to be delivered to. + +### Event schemas +An **[event](https://docs.microsoft.com/azure/event-grid/concepts#events)** is the smallest amount of information that fully describes something that happened in the system. When a custom topic or domain is created, you must specify the schema that will be used when publishing events. + +Event Grid supports multiple schemas for encoding events. + +#### Event Grid schema +While you may configure your topic to use a [custom schema](https://docs.microsoft.com/azure/event-grid/input-mappings), it is more common to use the already-defined Event Grid schema. See the specifications and requirements [here](https://docs.microsoft.com/azure/event-grid/event-schema). + +#### CloudEvents v1.0 schema +Another option is to use the CloudEvents v1.0 schema. [CloudEvents](https://cloudevents.io/) is a Cloud Native Computing Foundation project which produces a specification for describing event data in a common way. The service summary of CloudEvents can be found [here](https://docs.microsoft.com/azure/event-grid/cloud-event-schema). + +### EventGridPublisherClient +`EventGridPublisherClient` provides operations to send event data to a topic hostname specified during client initialization. + +Regardless of the schema that your topic or domain is configured to use, `EventGridPublisherClient` will be used to publish events to it. Use the `send` method publishing events. + +The following formats of events are allowed to be sent: +- A list or a single instance of strongly typed EventGridEvents. +- A dict representation of a serialized EventGridEvent object. +- A list or a single instance of strongly typed CloudEvents. +- A dict representation of a serialized CloudEvent object. + +- A dict representation of any Custom Schema. + +Please have a look at the [samples](https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/eventgrid/azure-eventgrid/samples) for detailed examples. + + + **Note:** It is important to know if your topic supports CloudEvents or EventGridEvents before publishing. If you send to a topic that does not support the schema of the event you are sending, send() will throw an exception. + +### System Topics +A **[system topic](https://docs.microsoft.com/azure/event-grid/system-topics)** in Event Grid represents one or more events published by Azure services such as Azure Storage or Azure Event Hubs. For example, a system topic may represent all blob events or only blob creation and blob deletion events published for a specific storage account. + +The names of the various event types for the system events published to Azure Event Grid are available in `azure.eventgrid.SystemEventNames`. +For complete list of recognizable system topics, visit [System Topics](https://docs.microsoft.com/azure/event-grid/system-topics). + + For more information about the key concepts on Event Grid, see [Concepts in Azure Event Grid][publisher-service-doc]. + +## Event Grid on Kubernetes with Azure Arc + +Event Grid on Kubernetes with Azure Arc is an offering that allows you to run Event Grid on your own Kubernetes cluster. This capability is enabled by the use of Azure Arc enabled Kubernetes. Through Azure Arc enabled Kubernetes, a supported Kubernetes cluster connects to Azure. Once connected, you are able to install Event Grid on it. Learn more about it [here](https://docs.microsoft.com/azure/event-grid/kubernetes/overview). + +## Examples + +The following sections provide several code snippets covering some of the most common Event Grid tasks, including: + +* [Send an Event Grid Event](#send-an-event-grid-event) +* [Send a Cloud Event](#send-a-cloud-event) +* [Send Multiple Events](#send-multiple-events) +* [Send events as Dictionaries](#send-events-as-dictionaries) +* [Consume a payload from storage queue](#consume-from-storage-queue) +* [Consume from ServiceBus](#consume-from-servicebus) + +### Send an Event Grid Event + +This example publishes an Event Grid event. + +```Python +import os +from azure.core.credentials import AzureKeyCredential +from azure.eventgrid import EventGridPublisherClient, EventGridEvent + +key = os.environ["EG_ACCESS_KEY"] +endpoint = os.environ["EG_TOPIC_HOSTNAME"] + +event = EventGridEvent( + data={"team": "azure-sdk"}, + subject="Door1", + event_type="Azure.Sdk.Demo", + data_version="2.0" +) + +credential = AzureKeyCredential(key) +client = EventGridPublisherClient(endpoint, credential) + +client.send(event) +``` + +### Send a Cloud Event + +This example publishes a Cloud event. + +```Python +import os +from azure.core.credentials import AzureKeyCredential +from azure.core.messaging import CloudEvent +from azure.eventgrid import EventGridPublisherClient + +key = os.environ["CLOUD_ACCESS_KEY"] +endpoint = os.environ["CLOUD_TOPIC_HOSTNAME"] + +event = CloudEvent( + type="Azure.Sdk.Sample", + source="https://egsample.dev/sampleevent", + data={"team": "azure-sdk"} +) + +credential = AzureKeyCredential(key) +client = EventGridPublisherClient(endpoint, credential) + +client.send(event) +``` + +### Send Multiple events + +It is possible to send events as a batch when sending multiple events to a topic or a domain. This example sends a list of CloudEvents using the send method. + +**WARNING:** When sending a list of multiple events at one time, iterating over and sending each event will not result in optimal performance. For best performance, it is highly recommended to send a list of events. + +```Python +import os +from azure.core.credentials import AzureKeyCredential +from azure.core.messaging import CloudEvent +from azure.eventgrid import EventGridPublisherClient + +key = os.environ["CLOUD_ACCESS_KEY"] +endpoint = os.environ["CLOUD_TOPIC_HOSTNAME"] + +event0 = CloudEvent( + type="Azure.Sdk.Sample", + source="https://egsample.dev/sampleevent", + data={"team": "azure-sdk"} +) +event1 = CloudEvent( + type="Azure.Sdk.Sample", + source="https://egsample.dev/sampleevent", + data={"team2": "azure-eventgrid"} +) + +events = [event0, event1] + +credential = AzureKeyCredential(key) +client = EventGridPublisherClient(endpoint, credential) + +client.send(events) +``` + +### Send events as dictionaries + +A dict representation of respective serialized models can also be used to publish CloudEvent(s) or EventGridEvent(s) apart from the strongly typed objects. + +Use a dict-like representation to send to a topic with custom schema as shown below. + +```Python +import os +import uuid +import datetime as dt +from msrest.serialization import UTC +from azure.core.credentials import AzureKeyCredential +from azure.eventgrid import EventGridPublisherClient + +key = os.environ["CUSTOM_SCHEMA_ACCESS_KEY"] +endpoint = os.environ["CUSTOM_SCHEMA_TOPIC_HOSTNAME"] + +event = custom_schema_event = { + "customSubject": "sample", + "customEventType": "sample.event", + "customDataVersion": "2.0", + "customId": uuid.uuid4(), + "customEventTime": dt.datetime.now(UTC()).isoformat(), + "customData": "sample data" + } + +credential = AzureKeyCredential(key) +client = EventGridPublisherClient(endpoint, credential) + +client.send(event) +``` + +### Consume from storage queue + +This example consumes a message received from storage queue and deserializes it to a CloudEvent object. + +```Python +from azure.core.messaging import CloudEvent +from azure.storage.queue import QueueServiceClient, BinaryBase64DecodePolicy +import os +import json + +# all types of CloudEvents below produce same DeserializedEvent +connection_str = os.environ['STORAGE_QUEUE_CONN_STR'] +queue_name = os.environ['STORAGE_QUEUE_NAME'] + +with QueueServiceClient.from_connection_string(connection_str) as qsc: + payload = qsc.get_queue_client( + queue=queue_name, + message_decode_policy=BinaryBase64DecodePolicy() + ).peek_messages() + + ## deserialize payload into a list of typed Events + events = [CloudEvent.from_dict(json.loads(msg.content)) for msg in payload] +``` + +### Consume from servicebus + +This example consumes a payload message received from ServiceBus and deserializes it to an EventGridEvent object. + +```Python +from azure.eventgrid import EventGridEvent +from azure.servicebus import ServiceBusClient +import os +import json + +# all types of EventGridEvents below produce same DeserializedEvent +connection_str = os.environ['SERVICE_BUS_CONN_STR'] +queue_name = os.environ['SERVICE_BUS_QUEUE_NAME'] + +with ServiceBusClient.from_connection_string(connection_str) as sb_client: + payload = sb_client.get_queue_receiver(queue_name).receive_messages() + + ## deserialize payload into a list of typed Events + events = [EventGridEvent.from_dict(json.loads(next(msg.body).decode('utf-8'))) for msg in payload] +``` + +## Distributed Tracing with EventGrid + +You can use opentelemetry for Python as usual with EventGrid since it's compatible with azure-core tracing integration. + +Here is an example of using OpenTelemetry to trace sending a CloudEvent. + +First, set OpenTelemetry as enabled tracing plugin for EventGrid. + +```python +from azure.core.settings import settings +from azure.core.tracing.ext.opentelemetry_span import OpenTelemetrySpan + +settings.tracing_implementation = OpenTelemetrySpan +``` + +Regular open telemetry usage from here. See [OpenTelemetry](https://github.com/open-telemetry/opentelemetry-python) for details. +This example uses a simple console exporter to export the traces. Any exporter can be used here including `azure-monitor-opentelemetry-exporter`, `jaeger`, `zipkin` etc. + +```python +from opentelemetry import trace +from opentelemetry.sdk.trace import TracerProvider +from opentelemetry.sdk.trace.export import ConsoleSpanExporter +from opentelemetry.sdk.trace.export import SimpleSpanProcessor # this requires opentelemtry >= 1.0.0 + +# Simple console exporter +exporter = ConsoleSpanExporter() + +trace.set_tracer_provider(TracerProvider()) +tracer = trace.get_tracer(__name__) +trace.get_tracer_provider().add_span_processor( + SimpleSpanProcessor(exporter) +) +``` + +Once the `tracer` and `exporter` are set, please follow the example below to start collecting traces while using the `send` method from the `EventGridPublisherClient` to send a CloudEvent object. + +```python +import os +from azure.eventgrid import EventGridPublisherClient +from azure.core.messaging import CloudEvent +from azure.core.credentials import AzureKeyCredential + +hostname = os.environ['CLOUD_TOPIC_HOSTNAME'] +key = AzureKeyCredential(os.environ['CLOUD_ACCESS_KEY']) +cloud_event = CloudEvent( + source = 'demo', + type = 'sdk.demo', + data = {'test': 'hello'}, +) +with tracer.start_as_current_span(name="MyApplication"): + client = EventGridPublisherClient(hostname, key) + client.send(cloud_event) +``` + +## Troubleshooting + +- Enable `azure.eventgrid` logger to collect traces from the library. + +### General +Event Grid client library will raise exceptions defined in [Azure Core][azure_core_exceptions]. + +### Logging +This library uses the standard +[logging][python_logging] library for logging. +Basic information about HTTP sessions (URLs, headers, etc.) is logged at INFO +level. + +### Optional Configuration + +Optional keyword arguments can be passed in at the client and per-operation level. +The azure-core [reference documentation][azure_core_ref_docs] +describes available configurations for retries, logging, transport protocols, and more. + +## Next steps + +The following section provides several code snippets illustrating common patterns used in the Event Grid Python API. + +### More sample code + +These code samples show common champion scenario operations with the Azure Event Grid client library. + +* Generate Shared Access Signature: [sample_generate_sas.py][python-eg-generate-sas] + +* Authenticate the client: [sample_authentication.py][python-eg-auth] ([async_version][python-eg-auth-async]) + +* Publish events to a topic using SAS: [sample_publish_events_to_a_topic_using_sas_credential_async.py][python-eg-sample-send-using-sas] ([async_version][python-eg-sample-send-using-sas-async]) +* Publish Event Grid Events to a topic: [sample_publish_eg_events_to_a_topic.py][python-eg-sample-eg-event] ([async_version][python-eg-sample-eg-event-async]) +* Publish EventGrid Events to a domain topic: [sample_publish_eg_events_to_a_domain_topic.py][python-eg-sample-eg-event-to-domain] ([async_version][python-eg-sample-eg-event-to-domain-async]) +* Publish a Cloud Event: [sample_publish_events_using_cloud_events_1.0_schema.py][python-eg-sample-send-cloudevent] ([async_version][python-eg-sample-send-cloudevent-async]) +* Publish a Custom Schema: [sample_publish_custom_schema_to_a_topic.py][python-eg-publish-custom-schema] ([async_version][python-eg-publish-custom-schema-async]) + +The following samples cover publishing and consuming `dict` representations of EventGridEvents and CloudEvents. +* Publish EventGridEvent as dict like representation: [sample_publish_eg_event_using_dict.py][python-eg-sample-send-eg-as-dict] ([async_version][python-eg-sample-send-eg-as-dict-async]) + +* Publish CloudEvent as dict like representation: [sample_publish_cloud_event_using_dict.py][python-eg-sample-send-cloudevent-as-dict] ([async_version][python-eg-sample-send-cloudevent-as-dict-async]) + +* Consume a Custom Payload of raw cloudevent data: [sample_consume_custom_payload.py][python-eg-sample-consume-custom-payload] + +More samples can be found [here][python-eg-samples]. + +* More samples related to the send scenario can be seen [here][python-eg-publish-samples]. +* To see more samples related to consuming a payload from different messaging services as a typed object, please visit [Consume Samples][python-eg-consume-samples] + +### Additional documentation + +For more extensive documentation on Azure Event Grid, see the [Event Grid documentation][python-eg-product-docs] on docs.microsoft.com. + +## Contributing +This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit [cla.microsoft.com][cla]. + +When you submit a pull request, a CLA-bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA. + +This project has adopted the [Microsoft Open Source Code of Conduct][code_of_conduct]. For more information see the [Code of Conduct FAQ][coc_faq] or contact [opencode@microsoft.com][coc_contact] with any additional questions or comments. + + + +[azure_cli_link]: https://pypi.org/project/azure-cli/ +[python-eg-src]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/ +[python-eg-pypi]: https://pypi.org/project/azure-eventgrid +[python-eg-product-docs]: https://docs.microsoft.com/azure/event-grid/overview +[python-eg-ref-docs]: https://azuresdkdocs.blob.core.windows.net/$web/python/azure-eventgrid/latest/index.html +[publisher-service-doc]: https://docs.microsoft.com/azure/event-grid/concepts +[python-eg-samples]: https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/eventgrid/azure-eventgrid/samples +[python-eg-changelog]: https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/eventgrid/azure-eventgrid/CHANGELOG.md +[pip]: https://pypi.org/project/pip/ + +[azure_portal_create_EG_resource]: https://ms.portal.azure.com/#blade/HubsExtension/BrowseResource/resourceType/Microsoft.EventGrid%2Ftopics +[azure-key-credential]: https://aka.ms/azsdk/python/core/azurekeycredential +[azure_core_exceptions]: https://aka.ms/azsdk/python/core/docs#module-azure.core.exceptions +[python_logging]: https://docs.python.org/3/library/logging.html +[azure_core_ref_docs]: https://aka.ms/azsdk/python/core/docs +[azure_subscription]: https://azure.microsoft.com/free/ + +[python-eg-auth]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_authentication.py +[python-eg-generate-sas]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_generate_sas.py +[python-eg-sample-send-using-sas]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_events_to_a_topic_using_sas_credential.py +[python-eg-sample-eg-event]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_eg_events_to_a_topic.py +[python-eg-sample-eg-event-to-domain]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_eg_events_to_a_domain.py +[python-eg-sample-send-cloudevent]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_events_using_cloud_events_1.0_schema.py +[python-eg-publish-custom-schema]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_custom_schema_to_a_topic.py +[python-eg-sample-send-eg-as-dict]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_eg_event_using_dict.py +[python-eg-sample-send-cloudevent-as-dict]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_cloud_event_using_dict.py + +[python-eg-auth-async]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_authentication_async.py +[python-eg-sample-send-using-sas-async]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_publish_events_to_a_topic_using_sas_credential_async.py +[python-eg-sample-eg-event-async]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_publish_eg_events_to_a_topic_async.py +[python-eg-sample-eg-event-to-domain-async]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_publish_eg_events_to_a_domain_async.py +[python-eg-sample-send-cloudevent-async]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_publish_events_using_cloud_events_1.0_schema_async.py +[python-eg-publish-custom-schema-async]:https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_publish_custom_schema_to_a_topic_async.py +[python-eg-sample-send-eg-as-dict-async]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_publish_eg_event_using_dict_async.py +[python-eg-sample-send-cloudevent-as-dict-async]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_publish_cloud_event_using_dict_async.py + +[python-eg-publish-samples]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/samples/publish_samples +[python-eg-consume-samples]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/samples/consume_samples +[python-eg-sample-consume-custom-payload]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_consume_custom_payload.py + +[cla]: https://cla.microsoft.com +[code_of_conduct]: https://opensource.microsoft.com/codeofconduct/ +[coc_faq]: https://opensource.microsoft.com/codeofconduct/faq/ +[coc_contact]: mailto:opencode@microsoft.com diff --git a/sdk/eventgrid/azure-eventgrid/azure/__init__.py b/sdk/eventgrid/azure-eventgrid/azure/__init__.py new file mode 100644 index 00000000000..0c36c2076ba --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/azure/__init__.py @@ -0,0 +1 @@ +__path__ = __import__('pkgutil').extend_path(__path__, __name__) # type: ignore diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/__init__.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/__init__.py new file mode 100644 index 00000000000..1dc3655a13b --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/__init__.py @@ -0,0 +1,19 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------- + +from ._publisher_client import EventGridPublisherClient +from ._event_mappings import SystemEventNames +from ._helpers import generate_sas +from ._models import EventGridEvent +from ._version import VERSION + +__all__ = [ + "EventGridPublisherClient", + "EventGridEvent", + "generate_sas", + "SystemEventNames", +] +__version__ = VERSION diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_constants.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_constants.py new file mode 100644 index 00000000000..c246323f947 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_constants.py @@ -0,0 +1,10 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +DEFAULT_EVENTGRID_SCOPE = "https://eventgrid.azure.net/.default" +EVENTGRID_KEY_HEADER = "aeg-sas-key" +EVENTGRID_TOKEN_HEADER = "aeg-sas-token" +DEFAULT_API_VERSION = "2018-01-01" +SAFE_ENCODE = "~()*!.'" diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_event_mappings.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_event_mappings.py new file mode 100644 index 00000000000..8edfe14b2e8 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_event_mappings.py @@ -0,0 +1,336 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- +from enum import Enum + +# pylint: disable=line-too-long + +class SystemEventNames(str, Enum): + """ + This enum represents the names of the various event types for the system events published to + Azure Event Grid. To check the list of recognizable system topics, + visit https://docs.microsoft.com/azure/event-grid/system-topics. + """ + # these names below are for backward compat only - refrain from using them. + AcsChatMemberAddedToThreadWithUserEventName = 'Microsoft.Communication.ChatMemberAddedToThreadWithUser' + + ResourceWriteFailureEventName = 'Microsoft.Resources.ResourceWriteFailure' + + IoTHubDeviceDeletedEventName = 'Microsoft.Devices.DeviceDeleted' + + IoTHubDeviceDisconnectedEventName = 'Microsoft.Devices.DeviceDisconnected' + + ResourceDeleteFailureEventName = 'Microsoft.Resources.ResourceDeleteFailure' + + ResourceDeleteCancelEventName = 'Microsoft.Resources.ResourceDeleteCancel' + + AcsChatThreadParticipantAddedEventName = 'Microsoft.Communication.ChatThreadParticipantAdded' + + ResourceDeleteSuccessEventName = 'Microsoft.Resources.ResourceDeleteSuccess' + + EventGridSubscriptionValidationEventName = 'Microsoft.EventGrid.SubscriptionValidationEvent' + + ResourceWriteSuccessEventName = 'Microsoft.Resources.ResourceWriteSuccess' + + ResourceActionSuccessEventName = 'Microsoft.Resources.ResourceActionSuccess' + + ResourceWriteCancelEventName = 'Microsoft.Resources.ResourceWriteCancel' + + ResourceActionFailureEventName = 'Microsoft.Resources.ResourceActionFailure' + + AcsChatMemberRemovedFromThreadWithUserEventName = 'Microsoft.Communication.ChatMemberRemovedFromThreadWithUser' + + IoTHubDeviceConnectedEventName = 'Microsoft.Devices.DeviceConnected' + + EventGridSubscriptionDeletedEventName = 'Microsoft.EventGrid.SubscriptionDeletedEvent' + + AcsChatThreadParticipantRemovedEventName = 'Microsoft.Communication.ChatThreadParticipantRemoved' + + ResourceActionCancelEventName = 'Microsoft.Resources.ResourceActionCancel' + + IoTHubDeviceCreatedEventName = 'Microsoft.Devices.DeviceCreated' + + # backward compat names end here. + AcsChatMessageDeletedEventName = 'Microsoft.Communication.ChatMessageDeleted' + + AcsChatMessageDeletedInThreadEventName = 'Microsoft.Communication.ChatMessageDeletedInThread' + + AcsChatMessageEditedEventName = 'Microsoft.Communication.ChatMessageEdited' + + AcsChatMessageEditedInThreadEventName = 'Microsoft.Communication.ChatMessageEditedInThread' + + AcsChatMessageReceivedEventName = 'Microsoft.Communication.ChatMessageReceived' + + AcsChatMessageReceivedInThreadEventName = 'Microsoft.Communication.ChatMessageReceivedInThread' + + AcsChatParticipantAddedToThreadEventName = 'Microsoft.Communication.ChatThreadParticipantAdded' + + AcsChatParticipantAddedToThreadWithUserEventName = 'Microsoft.Communication.ChatParticipantAddedToThreadWithUser' + + AcsChatParticipantRemovedFromThreadEventName = 'Microsoft.Communication.ChatThreadParticipantRemoved' + + AcsChatParticipantRemovedFromThreadWithUserEventName = 'Microsoft.Communication.ChatParticipantRemovedFromThreadWithUser' + + AcsChatThreadCreatedEventName = 'Microsoft.Communication.ChatThreadCreated' + + AcsChatThreadCreatedWithUserEventName = 'Microsoft.Communication.ChatThreadCreatedWithUser' + + AcsChatThreadDeletedEventName = 'Microsoft.Communication.ChatThreadDeleted' + + AcsChatThreadPropertiesUpdatedEventName = 'Microsoft.Communication.ChatThreadPropertiesUpdated' + + AcsChatThreadPropertiesUpdatedPerUserEventName = 'Microsoft.Communication.ChatThreadPropertiesUpdatedPerUser' + + AcsChatThreadWithUserDeletedEventName = 'Microsoft.Communication.ChatThreadWithUserDeleted' + + AcsRecordingFileStatusUpdatedEventName = 'Microsoft.Communication.RecordingFileStatusUpdated' + + AcsSmsDeliveryReportReceivedEventName = 'Microsoft.Communication.SMSDeliveryReportReceived' + + AcsSmsReceivedEventName = 'Microsoft.Communication.SMSReceived' + + AcsUserDisconnectedEventName = 'Microsoft.Communication.UserDisconnected' + + ApiManagementApiCreatedEventName = 'Microsoft.ApiManagement.ApiCreated' + + ApiManagementApiDeletedEventName = 'Microsoft.ApiManagement.ApiDeleted' + + ApiManagementApiReleaseCreatedEventName = 'Microsoft.ApiManagement.ApiReleaseCreated' + + ApiManagementApiReleaseDeletedEventName = 'Microsoft.ApiManagement.ApiReleaseDeleted' + + ApiManagementApiReleaseUpdatedEventName = 'Microsoft.ApiManagement.ApiReleaseUpdated' + + ApiManagementApiUpdatedEventName = 'Microsoft.ApiManagement.ApiUpdated' + + ApiManagementProductCreatedEventName = 'Microsoft.ApiManagement.ProductCreated' + + ApiManagementProductDeletedEventName = 'Microsoft.ApiManagement.ProductDeleted' + + ApiManagementProductUpdatedEventName = 'Microsoft.ApiManagement.ProductUpdated' + + ApiManagementSubscriptionCreatedEventName = 'Microsoft.ApiManagement.SubscriptionCreated' + + ApiManagementSubscriptionDeletedEventName = 'Microsoft.ApiManagement.SubscriptionDeleted' + + ApiManagementSubscriptionUpdatedEventName = 'Microsoft.ApiManagement.SubscriptionUpdated' + + ApiManagementUserCreatedEventName = 'Microsoft.ApiManagement.UserCreated' + + ApiManagementUserDeletedEventName = 'Microsoft.ApiManagement.UserDeleted' + + ApiManagementUserUpdatedEventName = 'Microsoft.ApiManagement.UserUpdated' + + AppConfigurationKeyValueDeletedEventName = 'Microsoft.AppConfiguration.KeyValueDeleted' + + AppConfigurationKeyValueModifiedEventName = 'Microsoft.AppConfiguration.KeyValueModified' + + ContainerRegistryArtifactEventName = 'Microsoft.AppConfiguration.KeyValueModified' + + ContainerRegistryChartDeletedEventName = 'Microsoft.ContainerRegistry.ChartDeleted' + + ContainerRegistryChartPushedEventName = 'Microsoft.ContainerRegistry.ChartPushed' + + ContainerRegistryEventName = 'Microsoft.ContainerRegistry.ChartPushed' + + ContainerRegistryImageDeletedEventName = 'Microsoft.ContainerRegistry.ImageDeleted' + + ContainerRegistryImagePushedEventName = 'Microsoft.ContainerRegistry.ImagePushed' + + ContainerServiceNewKubernetesVersionAvailableEventName = 'Microsoft.ContainerService.NewKubernetesVersionAvailable' + + EventHubCaptureFileCreatedEventName = 'Microsoft.EventHub.CaptureFileCreated' + + IotHubDeviceConnectedEventName = 'Microsoft.Devices.DeviceConnected' + + IotHubDeviceCreatedEventName = 'Microsoft.Devices.DeviceCreated' + + IotHubDeviceDeletedEventName = 'Microsoft.Devices.DeviceDeleted' + + IotHubDeviceDisconnectedEventName = 'Microsoft.Devices.DeviceDisconnected' + + IotHubDeviceTelemetryEventName = 'Microsoft.Devices.DeviceTelemetry' + + KeyVaultAccessPolicyChangedEventName = 'Microsoft.KeyVault.VaultAccessPolicyChanged' + + KeyVaultCertificateExpiredEventName = 'Microsoft.KeyVault.CertificateExpired' + + KeyVaultCertificateNearExpiryEventName = 'Microsoft.KeyVault.CertificateNearExpiry' + + KeyVaultCertificateNewVersionCreatedEventName = 'Microsoft.KeyVault.CertificateNewVersionCreated' + + KeyVaultKeyExpiredEventName = 'Microsoft.KeyVault.KeyExpired' + + KeyVaultKeyNearExpiryEventName = 'Microsoft.KeyVault.KeyNearExpiry' + + KeyVaultKeyNewVersionCreatedEventName = 'Microsoft.KeyVault.KeyNewVersionCreated' + + KeyVaultSecretExpiredEventName = 'Microsoft.KeyVault.SecretExpired' + + KeyVaultSecretNearExpiryEventName = 'Microsoft.KeyVault.SecretNearExpiry' + + KeyVaultSecretNewVersionCreatedEventName = 'Microsoft.KeyVault.SecretNewVersionCreated' + + MachineLearningServicesDatasetDriftDetectedEventName = 'Microsoft.MachineLearningServices.DatasetDriftDetected' + + MachineLearningServicesModelDeployedEventName = 'Microsoft.MachineLearningServices.ModelDeployed' + + MachineLearningServicesModelRegisteredEventName = 'Microsoft.MachineLearningServices.ModelRegistered' + + MachineLearningServicesRunCompletedEventName = 'Microsoft.MachineLearningServices.RunCompleted' + + MachineLearningServicesRunStatusChangedEventName = 'Microsoft.MachineLearningServices.RunStatusChanged' + + MapsGeofenceEnteredEventName = 'Microsoft.Maps.GeofenceEntered' + + MapsGeofenceExitedEventName = 'Microsoft.Maps.GeofenceExited' + + MapsGeofenceResultEventName = 'Microsoft.Maps.GeofenceResult' + + MediaJobCanceledEventName = 'Microsoft.Media.JobCanceled' + + MediaJobCancelingEventName = 'Microsoft.Media.JobCanceling' + + MediaJobErroredEventName = 'Microsoft.Media.JobErrored' + + MediaJobFinishedEventName = 'Microsoft.Media.JobFinished' + + MediaJobOutputCanceledEventName = 'Microsoft.Media.JobOutputCanceled' + + MediaJobOutputCancelingEventName = 'Microsoft.Media.JobOutputCanceling' + + MediaJobOutputErroredEventName = 'Microsoft.Media.JobOutputErrored' + + MediaJobOutputFinishedEventName = 'Microsoft.Media.JobOutputFinished' + + MediaJobOutputProcessingEventName = 'Microsoft.Media.JobOutputProcessing' + + MediaJobOutputProgressEventName = 'Microsoft.Media.JobOutputProgress' + + MediaJobOutputScheduledEventName = 'Microsoft.Media.JobOutputScheduled' + + MediaJobOutputStateChangeEventName = 'Microsoft.Media.JobOutputStateChange' + + MediaJobProcessingEventName = 'Microsoft.Media.JobProcessing' + + MediaJobScheduledEventName = 'Microsoft.Media.JobScheduled' + + MediaJobStateChangeEventName = 'Microsoft.Media.JobStateChange' + + MediaLiveEventChannelArchiveHeartbeatEventName = 'Microsoft.Media.LiveEventChannelArchiveHeartbeat' + + MediaLiveEventConnectionRejectedEventName = 'Microsoft.Media.LiveEventConnectionRejected' + + MediaLiveEventEncoderConnectedEventName = 'Microsoft.Media.LiveEventEncoderConnected' + + MediaLiveEventEncoderDisconnectedEventName = 'Microsoft.Media.LiveEventEncoderDisconnected' + + MediaLiveEventIncomingDataChunkDroppedEventName = 'Microsoft.Media.LiveEventIncomingDataChunkDropped' + + MediaLiveEventIncomingStreamReceivedEventName = 'Microsoft.Media.LiveEventIncomingStreamReceived' + + MediaLiveEventIncomingStreamsOutOfSyncEventName = 'Microsoft.Media.LiveEventIncomingStreamsOutOfSync' + + MediaLiveEventIncomingVideoStreamsOutOfSyncEventName = 'Microsoft.Media.LiveEventIncomingVideoStreamsOutOfSync' + + MediaLiveEventIngestHeartbeatEventName = 'Microsoft.Media.LiveEventIngestHeartbeat' + + MediaLiveEventTrackDiscontinuityDetectedEventName = 'Microsoft.Media.LiveEventTrackDiscontinuityDetected' + + PolicyInsightsPolicyStateChangedEventName = 'Microsoft.PolicyInsights.PolicyStateChanged' + + PolicyInsightsPolicyStateCreatedEventName = 'Microsoft.PolicyInsights.PolicyStateCreated' + + PolicyInsightsPolicyStateDeletedEventName = 'Microsoft.PolicyInsights.PolicyStateDeleted' + + RedisExportRDBCompletedEventName = 'Microsoft.Cache.ExportRDBCompleted' + + RedisImportRDBCompletedEventName = 'Microsoft.Cache.ImportRDBCompleted' + + RedisPatchingCompletedEventName = 'Microsoft.Cache.PatchingCompleted' + + RedisScalingCompletedEventName = 'Microsoft.Cache.ScalingCompleted' + + ResourceActionCancelName = 'Microsoft.Resources.ResourceActionCancel' + + ResourceActionFailureName = 'Microsoft.Resources.ResourceActionFailure' + + ResourceActionSuccessName = 'Microsoft.Resources.ResourceActionSuccess' + + ResourceDeleteCancelName = 'Microsoft.Resources.ResourceDeleteCancel' + + ResourceDeleteFailureName = 'Microsoft.Resources.ResourceDeleteFailure' + + ResourceDeleteSuccessName = 'Microsoft.Resources.ResourceDeleteSuccess' + + ResourceWriteCancelName = 'Microsoft.Resources.ResourceWriteCancel' + + ResourceWriteFailureName = 'Microsoft.Resources.ResourceWriteFailure' + + ResourceWriteSuccessName = 'Microsoft.Resources.ResourceWriteSuccess' + + ServiceBusActiveMessagesAvailablePeriodicNotificationsEventName = 'Microsoft.ServiceBus.ActiveMessagesAvailablePeriodicNotifications' + + ServiceBusActiveMessagesAvailableWithNoListenersEventName = 'Microsoft.ServiceBus.ActiveMessagesAvailableWithNoListeners' + + ServiceBusDeadletterMessagesAvailablePeriodicNotificationsEventName = 'Microsoft.ServiceBus.DeadletterMessagesAvailablePeriodicNotifications' + + ServiceBusDeadletterMessagesAvailableWithNoListenersEventName = 'Microsoft.ServiceBus.DeadletterMessagesAvailableWithNoListeners' + + SignalRServiceClientConnectionConnectedEventName = 'Microsoft.SignalRService.ClientConnectionConnected' + + SignalRServiceClientConnectionDisconnectedEventName = 'Microsoft.SignalRService.ClientConnectionDisconnected' + + StorageAsyncOperationInitiatedEventName = 'Microsoft.Storage.AsyncOperationInitiated' + + StorageBlobCreatedEventName = 'Microsoft.Storage.BlobCreated' + + StorageBlobDeletedEventName = 'Microsoft.Storage.BlobDeleted' + + StorageBlobInventoryPolicyCompletedEventName = 'Microsoft.Storage.BlobInventoryPolicyCompleted' + + StorageBlobRenamedEventName = 'Microsoft.Storage.BlobRenamed' + + StorageBlobTierChangedEventName = 'Microsoft.Storage.BlobTierChanged' + + StorageDirectoryCreatedEventName = 'Microsoft.Storage.DirectoryCreated' + + StorageDirectoryDeletedEventName = 'Microsoft.Storage.DirectoryDeleted' + + StorageDirectoryRenamedEventName = 'Microsoft.Storage.DirectoryRenamed' + + StorageLifecyclePolicyCompletedEventName = 'Microsoft.Storage.LifecyclePolicyCompleted' + + SubscriptionDeletedEventName = 'Microsoft.EventGrid.SubscriptionDeletedEvent' + + SubscriptionValidationEventName = 'Microsoft.EventGrid.SubscriptionValidationEvent' + + WebAppServicePlanUpdatedEventName = 'Microsoft.Web.AppServicePlanUpdated' + + WebAppUpdatedEventName = 'Microsoft.Web.AppUpdated' + + WebBackupOperationCompletedEventName = 'Microsoft.Web.BackupOperationCompleted' + + WebBackupOperationFailedEventName = 'Microsoft.Web.BackupOperationFailed' + + WebBackupOperationStartedEventName = 'Microsoft.Web.BackupOperationStarted' + + WebRestoreOperationCompletedEventName = 'Microsoft.Web.RestoreOperationCompleted' + + WebRestoreOperationFailedEventName = 'Microsoft.Web.RestoreOperationFailed' + + WebRestoreOperationStartedEventName = 'Microsoft.Web.RestoreOperationStarted' + + WebSlotSwapCompletedEventName = 'Microsoft.Web.SlotSwapCompleted' + + WebSlotSwapFailedEventName = 'Microsoft.Web.SlotSwapFailed' + + WebSlotSwapStartedEventName = 'Microsoft.Web.SlotSwapStarted' + + WebSlotSwapWithPreviewCancelledEventName = 'Microsoft.Web.SlotSwapWithPreviewCancelled' + + WebSlotSwapWithPreviewStartedEventName = 'Microsoft.Web.SlotSwapWithPreviewStarted' + + # servicebus alias + ServiceBusDeadletterMessagesAvailableWithNoListenerEventName = 'Microsoft.ServiceBus.DeadletterMessagesAvailableWithNoListeners' diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/__init__.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/__init__.py new file mode 100644 index 00000000000..54198998f87 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/__init__.py @@ -0,0 +1,16 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from ._event_grid_publisher_client import EventGridPublisherClient +__all__ = ['EventGridPublisherClient'] + +try: + from ._patch import patch_sdk # type: ignore + patch_sdk() +except ImportError: + pass diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/_configuration.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/_configuration.py new file mode 100644 index 00000000000..10b08816d1b --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/_configuration.py @@ -0,0 +1,52 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from typing import TYPE_CHECKING + +from azure.core.configuration import Configuration +from azure.core.pipeline import policies + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any + +VERSION = "unknown" + +class EventGridPublisherClientConfiguration(Configuration): + """Configuration for EventGridPublisherClient. + + Note that all parameters used to create this instance are saved as instance + attributes. + + """ + + def __init__( + self, + **kwargs # type: Any + ): + # type: (...) -> None + super(EventGridPublisherClientConfiguration, self).__init__(**kwargs) + + self.api_version = "2018-01-01" + kwargs.setdefault('sdk_moniker', 'eventgridpublisherclient/{}'.format(VERSION)) + self._configure(**kwargs) + + def _configure( + self, + **kwargs # type: Any + ): + # type: (...) -> None + self.user_agent_policy = kwargs.get('user_agent_policy') or policies.UserAgentPolicy(**kwargs) + self.headers_policy = kwargs.get('headers_policy') or policies.HeadersPolicy(**kwargs) + self.proxy_policy = kwargs.get('proxy_policy') or policies.ProxyPolicy(**kwargs) + self.logging_policy = kwargs.get('logging_policy') or policies.NetworkTraceLoggingPolicy(**kwargs) + self.http_logging_policy = kwargs.get('http_logging_policy') or policies.HttpLoggingPolicy(**kwargs) + self.retry_policy = kwargs.get('retry_policy') or policies.RetryPolicy(**kwargs) + self.custom_hook_policy = kwargs.get('custom_hook_policy') or policies.CustomHookPolicy(**kwargs) + self.redirect_policy = kwargs.get('redirect_policy') or policies.RedirectPolicy(**kwargs) + self.authentication_policy = kwargs.get('authentication_policy') diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/_event_grid_publisher_client.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/_event_grid_publisher_client.py new file mode 100644 index 00000000000..33ee8b1244a --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/_event_grid_publisher_client.py @@ -0,0 +1,87 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from copy import deepcopy +from typing import TYPE_CHECKING + +from azure.core import PipelineClient +from msrest import Deserializer, Serializer + +from ._configuration import EventGridPublisherClientConfiguration + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any, Dict + + from azure.core.rest import HttpRequest, HttpResponse + +class EventGridPublisherClient(object): + """EventGrid Python Publisher Client. + + """ + + def __init__( + self, + **kwargs # type: Any + ): + # type: (...) -> None + base_url = 'https://{topicHostname}' + self._config = EventGridPublisherClientConfiguration(**kwargs) + self._client = PipelineClient(base_url=base_url, config=self._config, **kwargs) + + client_models = {} # type: Dict[str, Any] + self._serialize = Serializer(client_models) + self._deserialize = Deserializer(client_models) + self._serialize.client_side_validation = False + + + def send_request( + self, + request, # type: HttpRequest + **kwargs # type: Any + ): + # type: (...) -> HttpResponse + """Runs the network request through the client's chained policies. + + We have helper methods to create requests specific to this service in `event_grid_publisher_client.rest`. + Use these helper methods to create the request you pass to this method. + + >>> from event_grid_publisher_client.rest import build_publish_events_request + >>> request = build_publish_events_request(json=json, content=content, **kwargs) + + >>> response = client.send_request(request) + + + For more information on this code flow, see https://aka.ms/azsdk/python/protocol/quickstart + + For advanced cases, you can also create your own :class:`~azure.core.rest.HttpRequest` + and pass it in. + + :param request: The network request you want to make. Required. + :type request: ~azure.core.rest.HttpRequest + :keyword bool stream: Whether the response payload will be streamed. Defaults to False. + :return: The response of your network call. Does not do error handling on your response. + :rtype: ~azure.core.rest.HttpResponse + """ + + request_copy = deepcopy(request) + request_copy.url = self._client.format_url(request_copy.url) + return self._client.send_request(request_copy, **kwargs) + + def close(self): + # type: () -> None + self._client.close() + + def __enter__(self): + # type: () -> EventGridPublisherClient + self._client.__enter__() + return self + + def __exit__(self, *exc_details): + # type: (Any) -> None + self._client.__exit__(*exc_details) diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/aio/__init__.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/aio/__init__.py new file mode 100644 index 00000000000..eeec885ee41 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/aio/__init__.py @@ -0,0 +1,10 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from ._event_grid_publisher_client import EventGridPublisherClient +__all__ = ['EventGridPublisherClient'] diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/aio/_configuration.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/aio/_configuration.py new file mode 100644 index 00000000000..2fe719e6da1 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/aio/_configuration.py @@ -0,0 +1,46 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from typing import Any + +from azure.core.configuration import Configuration +from azure.core.pipeline import policies + +VERSION = "unknown" + +class EventGridPublisherClientConfiguration(Configuration): + """Configuration for EventGridPublisherClient. + + Note that all parameters used to create this instance are saved as instance + attributes. + + """ + + def __init__( + self, + **kwargs: Any + ) -> None: + super(EventGridPublisherClientConfiguration, self).__init__(**kwargs) + + self.api_version = "2018-01-01" + kwargs.setdefault('sdk_moniker', 'eventgridpublisherclient/{}'.format(VERSION)) + self._configure(**kwargs) + + def _configure( + self, + **kwargs: Any + ) -> None: + self.user_agent_policy = kwargs.get('user_agent_policy') or policies.UserAgentPolicy(**kwargs) + self.headers_policy = kwargs.get('headers_policy') or policies.HeadersPolicy(**kwargs) + self.proxy_policy = kwargs.get('proxy_policy') or policies.ProxyPolicy(**kwargs) + self.logging_policy = kwargs.get('logging_policy') or policies.NetworkTraceLoggingPolicy(**kwargs) + self.http_logging_policy = kwargs.get('http_logging_policy') or policies.HttpLoggingPolicy(**kwargs) + self.retry_policy = kwargs.get('retry_policy') or policies.AsyncRetryPolicy(**kwargs) + self.custom_hook_policy = kwargs.get('custom_hook_policy') or policies.CustomHookPolicy(**kwargs) + self.redirect_policy = kwargs.get('redirect_policy') or policies.AsyncRedirectPolicy(**kwargs) + self.authentication_policy = kwargs.get('authentication_policy') diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/aio/_configuration_async.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/aio/_configuration_async.py new file mode 100644 index 00000000000..2fe719e6da1 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/aio/_configuration_async.py @@ -0,0 +1,46 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from typing import Any + +from azure.core.configuration import Configuration +from azure.core.pipeline import policies + +VERSION = "unknown" + +class EventGridPublisherClientConfiguration(Configuration): + """Configuration for EventGridPublisherClient. + + Note that all parameters used to create this instance are saved as instance + attributes. + + """ + + def __init__( + self, + **kwargs: Any + ) -> None: + super(EventGridPublisherClientConfiguration, self).__init__(**kwargs) + + self.api_version = "2018-01-01" + kwargs.setdefault('sdk_moniker', 'eventgridpublisherclient/{}'.format(VERSION)) + self._configure(**kwargs) + + def _configure( + self, + **kwargs: Any + ) -> None: + self.user_agent_policy = kwargs.get('user_agent_policy') or policies.UserAgentPolicy(**kwargs) + self.headers_policy = kwargs.get('headers_policy') or policies.HeadersPolicy(**kwargs) + self.proxy_policy = kwargs.get('proxy_policy') or policies.ProxyPolicy(**kwargs) + self.logging_policy = kwargs.get('logging_policy') or policies.NetworkTraceLoggingPolicy(**kwargs) + self.http_logging_policy = kwargs.get('http_logging_policy') or policies.HttpLoggingPolicy(**kwargs) + self.retry_policy = kwargs.get('retry_policy') or policies.AsyncRetryPolicy(**kwargs) + self.custom_hook_policy = kwargs.get('custom_hook_policy') or policies.CustomHookPolicy(**kwargs) + self.redirect_policy = kwargs.get('redirect_policy') or policies.AsyncRedirectPolicy(**kwargs) + self.authentication_policy = kwargs.get('authentication_policy') diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/aio/_event_grid_publisher_client.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/aio/_event_grid_publisher_client.py new file mode 100644 index 00000000000..24cb703a7ed --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/aio/_event_grid_publisher_client.py @@ -0,0 +1,81 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from copy import deepcopy +from typing import Any, Awaitable, TYPE_CHECKING + +from azure.core import AsyncPipelineClient +from azure.core.rest import AsyncHttpResponse, HttpRequest +from msrest import Deserializer, Serializer + +from ._configuration import EventGridPublisherClientConfiguration + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Dict + +class EventGridPublisherClient: + """EventGrid Python Publisher Client. + + """ + + def __init__( + self, + **kwargs: Any + ) -> None: + base_url = 'https://{topicHostname}' + self._config = EventGridPublisherClientConfiguration(**kwargs) + self._client = AsyncPipelineClient(base_url=base_url, config=self._config, **kwargs) + + client_models = {} # type: Dict[str, Any] + self._serialize = Serializer(client_models) + self._deserialize = Deserializer(client_models) + self._serialize.client_side_validation = False + + + def send_request( + self, + request: HttpRequest, + **kwargs: Any + ) -> Awaitable[AsyncHttpResponse]: + """Runs the network request through the client's chained policies. + + We have helper methods to create requests specific to this service in `event_grid_publisher_client.rest`. + Use these helper methods to create the request you pass to this method. + + >>> from event_grid_publisher_client.rest import build_publish_events_request + >>> request = build_publish_events_request(json=json, content=content, **kwargs) + + >>> response = await client.send_request(request) + + + For more information on this code flow, see https://aka.ms/azsdk/python/protocol/quickstart + + For advanced cases, you can also create your own :class:`~azure.core.rest.HttpRequest` + and pass it in. + + :param request: The network request you want to make. Required. + :type request: ~azure.core.rest.HttpRequest + :keyword bool stream: Whether the response payload will be streamed. Defaults to False. + :return: The response of your network call. Does not do error handling on your response. + :rtype: ~azure.core.rest.AsyncHttpResponse + """ + + request_copy = deepcopy(request) + request_copy.url = self._client.format_url(request_copy.url) + return self._client.send_request(request_copy, **kwargs) + + async def close(self) -> None: + await self._client.close() + + async def __aenter__(self) -> "EventGridPublisherClient": + await self._client.__aenter__() + return self + + async def __aexit__(self, *exc_details) -> None: + await self._client.__aexit__(*exc_details) diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/aio/_event_grid_publisher_client_async.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/aio/_event_grid_publisher_client_async.py new file mode 100644 index 00000000000..acd4bdd2a0e --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/aio/_event_grid_publisher_client_async.py @@ -0,0 +1,45 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from typing import Any + +from azure.core import AsyncPipelineClient +from msrest import Deserializer, Serializer + +from ._configuration_async import EventGridPublisherClientConfiguration +from .operations_async import EventGridPublisherClientOperationsMixin +from .. import models + + +class EventGridPublisherClient(EventGridPublisherClientOperationsMixin): + """EventGrid Python Publisher Client. + + """ + + def __init__( + self, + **kwargs: Any + ) -> None: + base_url = 'https://{topicHostname}' + self._config = EventGridPublisherClientConfiguration(**kwargs) + self._client = AsyncPipelineClient(base_url=base_url, config=self._config, **kwargs) + + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + self._serialize = Serializer(client_models) + self._deserialize = Deserializer(client_models) + + + async def close(self) -> None: + await self._client.close() + + async def __aenter__(self) -> "EventGridPublisherClient": + await self._client.__aenter__() + return self + + async def __aexit__(self, *exc_details) -> None: + await self._client.__aexit__(*exc_details) diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/models/__init__.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/models/__init__.py new file mode 100644 index 00000000000..78057eebbf3 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/models/__init__.py @@ -0,0 +1,19 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +try: + from ._models_py3 import CloudEvent + from ._models_py3 import EventGridEvent +except (SyntaxError, ImportError): + from ._models import CloudEvent # type: ignore + from ._models import EventGridEvent # type: ignore + +__all__ = [ + 'CloudEvent', + 'EventGridEvent', +] diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/models/_models.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/models/_models.py new file mode 100644 index 00000000000..32887d4fdff --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/models/_models.py @@ -0,0 +1,143 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +import msrest.serialization + + +class CloudEvent(msrest.serialization.Model): + """Properties of an event published to an Event Grid topic using the CloudEvent 1.0 Schema. + + All required parameters must be populated in order to send to Azure. + + :param additional_properties: Unmatched properties from the message are deserialized to this + collection. + :type additional_properties: dict[str, object] + :param id: Required. An identifier for the event. The combination of id and source must be + unique for each distinct event. + :type id: str + :param source: Required. Identifies the context in which an event happened. The combination of + id and source must be unique for each distinct event. + :type source: str + :param data: Event data specific to the event type. + :type data: object + :param data_base64: Event data specific to the event type, encoded as a base64 string. + :type data_base64: bytearray + :param type: Required. Type of event related to the originating occurrence. + :type type: str + :param time: The time (in UTC) the event was generated, in RFC3339 format. + :type time: ~datetime.datetime + :param specversion: Required. The version of the CloudEvents specification which the event + uses. + :type specversion: str + :param dataschema: Identifies the schema that data adheres to. + :type dataschema: str + :param datacontenttype: Content type of data value. + :type datacontenttype: str + :param subject: This describes the subject of the event in the context of the event producer + (identified by source). + :type subject: str + """ + + _validation = { + 'id': {'required': True}, + 'source': {'required': True}, + 'type': {'required': True}, + 'specversion': {'required': True}, + } + + _attribute_map = { + 'additional_properties': {'key': '', 'type': '{object}'}, + 'id': {'key': 'id', 'type': 'str'}, + 'source': {'key': 'source', 'type': 'str'}, + 'data': {'key': 'data', 'type': 'object'}, + 'data_base64': {'key': 'data_base64', 'type': 'bytearray'}, + 'type': {'key': 'type', 'type': 'str'}, + 'time': {'key': 'time', 'type': 'iso-8601'}, + 'specversion': {'key': 'specversion', 'type': 'str'}, + 'dataschema': {'key': 'dataschema', 'type': 'str'}, + 'datacontenttype': {'key': 'datacontenttype', 'type': 'str'}, + 'subject': {'key': 'subject', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(CloudEvent, self).__init__(**kwargs) + self.additional_properties = kwargs.get('additional_properties', None) + self.id = kwargs['id'] + self.source = kwargs['source'] + self.data = kwargs.get('data', None) + self.data_base64 = kwargs.get('data_base64', None) + self.type = kwargs['type'] + self.time = kwargs.get('time', None) + self.specversion = kwargs['specversion'] + self.dataschema = kwargs.get('dataschema', None) + self.datacontenttype = kwargs.get('datacontenttype', None) + self.subject = kwargs.get('subject', None) + + +class EventGridEvent(msrest.serialization.Model): + """Properties of an event published to an Event Grid topic using the EventGrid Schema. + + Variables are only populated by the server, and will be ignored when sending a request. + + All required parameters must be populated in order to send to Azure. + + :param id: Required. An unique identifier for the event. + :type id: str + :param topic: The resource path of the event source. + :type topic: str + :param subject: Required. A resource path relative to the topic path. + :type subject: str + :param data: Required. Event data specific to the event type. + :type data: object + :param event_type: Required. The type of the event that occurred. + :type event_type: str + :param event_time: Required. The time (in UTC) the event was generated. + :type event_time: ~datetime.datetime + :ivar metadata_version: The schema version of the event metadata. + :vartype metadata_version: str + :param data_version: Required. The schema version of the data object. + :type data_version: str + """ + + _validation = { + 'id': {'required': True}, + 'subject': {'required': True}, + 'data': {'required': True}, + 'event_type': {'required': True}, + 'event_time': {'required': True}, + 'metadata_version': {'readonly': True}, + 'data_version': {'required': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'topic': {'key': 'topic', 'type': 'str'}, + 'subject': {'key': 'subject', 'type': 'str'}, + 'data': {'key': 'data', 'type': 'object'}, + 'event_type': {'key': 'eventType', 'type': 'str'}, + 'event_time': {'key': 'eventTime', 'type': 'iso-8601'}, + 'metadata_version': {'key': 'metadataVersion', 'type': 'str'}, + 'data_version': {'key': 'dataVersion', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(EventGridEvent, self).__init__(**kwargs) + self.id = kwargs['id'] + self.topic = kwargs.get('topic', None) + self.subject = kwargs['subject'] + self.data = kwargs['data'] + self.event_type = kwargs['event_type'] + self.event_time = kwargs['event_time'] + self.metadata_version = None + self.data_version = kwargs['data_version'] diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/models/_models_py3.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/models/_models_py3.py new file mode 100644 index 00000000000..782a90f1ad0 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/models/_models_py3.py @@ -0,0 +1,166 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +import datetime +from typing import Dict, Optional + +import msrest.serialization + + +class CloudEvent(msrest.serialization.Model): + """Properties of an event published to an Event Grid topic using the CloudEvent 1.0 Schema. + + All required parameters must be populated in order to send to Azure. + + :param additional_properties: Unmatched properties from the message are deserialized to this + collection. + :type additional_properties: dict[str, object] + :param id: Required. An identifier for the event. The combination of id and source must be + unique for each distinct event. + :type id: str + :param source: Required. Identifies the context in which an event happened. The combination of + id and source must be unique for each distinct event. + :type source: str + :param data: Event data specific to the event type. + :type data: object + :param data_base64: Event data specific to the event type, encoded as a base64 string. + :type data_base64: bytearray + :param type: Required. Type of event related to the originating occurrence. + :type type: str + :param time: The time (in UTC) the event was generated, in RFC3339 format. + :type time: ~datetime.datetime + :param specversion: Required. The version of the CloudEvents specification which the event + uses. + :type specversion: str + :param dataschema: Identifies the schema that data adheres to. + :type dataschema: str + :param datacontenttype: Content type of data value. + :type datacontenttype: str + :param subject: This describes the subject of the event in the context of the event producer + (identified by source). + :type subject: str + """ + + _validation = { + 'id': {'required': True}, + 'source': {'required': True}, + 'type': {'required': True}, + 'specversion': {'required': True}, + } + + _attribute_map = { + 'additional_properties': {'key': '', 'type': '{object}'}, + 'id': {'key': 'id', 'type': 'str'}, + 'source': {'key': 'source', 'type': 'str'}, + 'data': {'key': 'data', 'type': 'object'}, + 'data_base64': {'key': 'data_base64', 'type': 'bytearray'}, + 'type': {'key': 'type', 'type': 'str'}, + 'time': {'key': 'time', 'type': 'iso-8601'}, + 'specversion': {'key': 'specversion', 'type': 'str'}, + 'dataschema': {'key': 'dataschema', 'type': 'str'}, + 'datacontenttype': {'key': 'datacontenttype', 'type': 'str'}, + 'subject': {'key': 'subject', 'type': 'str'}, + } + + def __init__( + self, + *, + id: str, + source: str, + type: str, + specversion: str, + additional_properties: Optional[Dict[str, object]] = None, + data: Optional[object] = None, + data_base64: Optional[bytearray] = None, + time: Optional[datetime.datetime] = None, + dataschema: Optional[str] = None, + datacontenttype: Optional[str] = None, + subject: Optional[str] = None, + **kwargs + ): + super(CloudEvent, self).__init__(**kwargs) + self.additional_properties = additional_properties + self.id = id + self.source = source + self.data = data + self.data_base64 = data_base64 + self.type = type + self.time = time + self.specversion = specversion + self.dataschema = dataschema + self.datacontenttype = datacontenttype + self.subject = subject + + +class EventGridEvent(msrest.serialization.Model): + """Properties of an event published to an Event Grid topic using the EventGrid Schema. + + Variables are only populated by the server, and will be ignored when sending a request. + + All required parameters must be populated in order to send to Azure. + + :param id: Required. An unique identifier for the event. + :type id: str + :param topic: The resource path of the event source. + :type topic: str + :param subject: Required. A resource path relative to the topic path. + :type subject: str + :param data: Required. Event data specific to the event type. + :type data: object + :param event_type: Required. The type of the event that occurred. + :type event_type: str + :param event_time: Required. The time (in UTC) the event was generated. + :type event_time: ~datetime.datetime + :ivar metadata_version: The schema version of the event metadata. + :vartype metadata_version: str + :param data_version: Required. The schema version of the data object. + :type data_version: str + """ + + _validation = { + 'id': {'required': True}, + 'subject': {'required': True}, + 'data': {'required': True}, + 'event_type': {'required': True}, + 'event_time': {'required': True}, + 'metadata_version': {'readonly': True}, + 'data_version': {'required': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'topic': {'key': 'topic', 'type': 'str'}, + 'subject': {'key': 'subject', 'type': 'str'}, + 'data': {'key': 'data', 'type': 'object'}, + 'event_type': {'key': 'eventType', 'type': 'str'}, + 'event_time': {'key': 'eventTime', 'type': 'iso-8601'}, + 'metadata_version': {'key': 'metadataVersion', 'type': 'str'}, + 'data_version': {'key': 'dataVersion', 'type': 'str'}, + } + + def __init__( + self, + *, + id: str, + subject: str, + data: object, + event_type: str, + event_time: datetime.datetime, + data_version: str, + topic: Optional[str] = None, + **kwargs + ): + super(EventGridEvent, self).__init__(**kwargs) + self.id = id + self.topic = topic + self.subject = subject + self.data = data + self.event_type = event_type + self.event_time = event_time + self.metadata_version = None + self.data_version = data_version diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/py.typed b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/py.typed new file mode 100644 index 00000000000..e5aff4f83af --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/py.typed @@ -0,0 +1 @@ +# Marker file for PEP 561. \ No newline at end of file diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/rest/__init__.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/rest/__init__.py new file mode 100644 index 00000000000..89faac69e03 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/rest/__init__.py @@ -0,0 +1,22 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +try: + from ._request_builders_py3 import build_publish_events_request + from ._request_builders_py3 import build_publish_cloud_event_events_request + from ._request_builders_py3 import build_publish_custom_event_events_request +except (SyntaxError, ImportError): + from ._request_builders import build_publish_events_request # type: ignore + from ._request_builders import build_publish_cloud_event_events_request # type: ignore + from ._request_builders import build_publish_custom_event_events_request # type: ignore + +__all__ = [ + 'build_publish_events_request', + 'build_publish_cloud_event_events_request', + 'build_publish_custom_event_events_request', +] diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/rest/_request_builders.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/rest/_request_builders.py new file mode 100644 index 00000000000..103a7bcce52 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/rest/_request_builders.py @@ -0,0 +1,201 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import TYPE_CHECKING + +from azure.core.rest import HttpRequest +from msrest import Serializer + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any, List, Optional + +_SERIALIZER = Serializer() + +# fmt: off + +def build_publish_events_request( + **kwargs # type: Any +): + # type: (...) -> HttpRequest + """Publishes a batch of events to an Azure Event Grid topic. + + See https://aka.ms/azsdk/python/protocol/quickstart for how to incorporate this request builder + into your code flow. + + :keyword json: Pass in a JSON-serializable object (usually a dictionary). See the template in + our example to find the input shape. An array of events to be published to Event Grid. + :paramtype json: any + :keyword content: Pass in binary content you want in the body of the request (typically bytes, + a byte iterator, or stream input). An array of events to be published to Event Grid. + :paramtype content: any + :return: Returns an :class:`~azure.core.rest.HttpRequest` that you will pass to the client's + `send_request` method. See https://aka.ms/azsdk/python/protocol/quickstart for how to + incorporate this response into your code flow. + :rtype: ~azure.core.rest.HttpRequest + + Example: + .. code-block:: python + + # JSON input template you can fill out and use as your `json` input. + json = [ + { + "data": "any", + "dataVersion": "str", + "eventTime": "datetime", + "eventType": "str", + "id": "str", + "metadataVersion": "str (optional)", + "subject": "str", + "topic": "str (optional)" + } + ] + """ + + content_type = kwargs.pop('content_type', None) # type: Optional[str] + + api_version = "2018-01-01" + # Construct URL + url = kwargs.pop("template_url", '/api/events') + + # Construct parameters + query_parameters = kwargs.pop("params", {}) # type: Dict[str, Any] + query_parameters['api-version'] = _SERIALIZER.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = kwargs.pop("headers", {}) # type: Dict[str, Any] + if content_type is not None: + header_parameters['Content-Type'] = _SERIALIZER.header("content_type", content_type, 'str') + + return HttpRequest( + method="POST", + url=url, + params=query_parameters, + headers=header_parameters, + **kwargs + ) + + +def build_publish_cloud_event_events_request( + **kwargs # type: Any +): + # type: (...) -> HttpRequest + """Publishes a batch of events to an Azure Event Grid topic. + + See https://aka.ms/azsdk/python/protocol/quickstart for how to incorporate this request builder + into your code flow. + + :keyword json: Pass in a JSON-serializable object (usually a dictionary). See the template in + our example to find the input shape. An array of events to be published to Event Grid. + :paramtype json: any + :keyword content: Pass in binary content you want in the body of the request (typically bytes, + a byte iterator, or stream input). An array of events to be published to Event Grid. + :paramtype content: any + :return: Returns an :class:`~azure.core.rest.HttpRequest` that you will pass to the client's + `send_request` method. See https://aka.ms/azsdk/python/protocol/quickstart for how to + incorporate this response into your code flow. + :rtype: ~azure.core.rest.HttpRequest + + Example: + .. code-block:: python + + # JSON input template you can fill out and use as your `json` input. + json = [ + { + "": { + "str": "any (optional)" + }, + "data": "any (optional)", + "data_base64": "bytearray (optional)", + "datacontenttype": "str (optional)", + "dataschema": "str (optional)", + "id": "str", + "source": "str", + "specversion": "str", + "subject": "str (optional)", + "time": "datetime (optional)", + "type": "str" + } + ] + """ + + content_type = kwargs.pop('content_type', None) # type: Optional[str] + + api_version = "2018-01-01" + # Construct URL + url = kwargs.pop("template_url", '/api/events') + + # Construct parameters + query_parameters = kwargs.pop("params", {}) # type: Dict[str, Any] + query_parameters['api-version'] = _SERIALIZER.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = kwargs.pop("headers", {}) # type: Dict[str, Any] + if content_type is not None: + header_parameters['Content-Type'] = _SERIALIZER.header("content_type", content_type, 'str') + + return HttpRequest( + method="POST", + url=url, + params=query_parameters, + headers=header_parameters, + **kwargs + ) + + +def build_publish_custom_event_events_request( + **kwargs # type: Any +): + # type: (...) -> HttpRequest + """Publishes a batch of events to an Azure Event Grid topic. + + See https://aka.ms/azsdk/python/protocol/quickstart for how to incorporate this request builder + into your code flow. + + :keyword json: Pass in a JSON-serializable object (usually a dictionary). See the template in + our example to find the input shape. An array of events to be published to Event Grid. + :paramtype json: any + :keyword content: Pass in binary content you want in the body of the request (typically bytes, + a byte iterator, or stream input). An array of events to be published to Event Grid. + :paramtype content: any + :return: Returns an :class:`~azure.core.rest.HttpRequest` that you will pass to the client's + `send_request` method. See https://aka.ms/azsdk/python/protocol/quickstart for how to + incorporate this response into your code flow. + :rtype: ~azure.core.rest.HttpRequest + + Example: + .. code-block:: python + + # JSON input template you can fill out and use as your `json` input. + json = [ + "any (optional)" + ] + """ + + content_type = kwargs.pop('content_type', None) # type: Optional[str] + + api_version = "2018-01-01" + # Construct URL + url = kwargs.pop("template_url", '/api/events') + + # Construct parameters + query_parameters = kwargs.pop("params", {}) # type: Dict[str, Any] + query_parameters['api-version'] = _SERIALIZER.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = kwargs.pop("headers", {}) # type: Dict[str, Any] + if content_type is not None: + header_parameters['Content-Type'] = _SERIALIZER.header("content_type", content_type, 'str') + + return HttpRequest( + method="POST", + url=url, + params=query_parameters, + headers=header_parameters, + **kwargs + ) + diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/rest/_request_builders_py3.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/rest/_request_builders_py3.py new file mode 100644 index 00000000000..b51dd09d7d9 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_generated/rest/_request_builders_py3.py @@ -0,0 +1,208 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import Any, List, Optional + +from azure.core.rest import HttpRequest +from msrest import Serializer + +_SERIALIZER = Serializer() + + +def build_publish_events_request( + *, + json: Any = None, + content: Any = None, + **kwargs: Any +) -> HttpRequest: + """Publishes a batch of events to an Azure Event Grid topic. + + See https://aka.ms/azsdk/python/protocol/quickstart for how to incorporate this request builder + into your code flow. + + :keyword json: Pass in a JSON-serializable object (usually a dictionary). See the template in + our example to find the input shape. An array of events to be published to Event Grid. + :paramtype json: any + :keyword content: Pass in binary content you want in the body of the request (typically bytes, + a byte iterator, or stream input). An array of events to be published to Event Grid. + :paramtype content: any + :return: Returns an :class:`~azure.core.rest.HttpRequest` that you will pass to the client's + `send_request` method. See https://aka.ms/azsdk/python/protocol/quickstart for how to + incorporate this response into your code flow. + :rtype: ~azure.core.rest.HttpRequest + + Example: + .. code-block:: python + + # JSON input template you can fill out and use as your `json` input. + json = [ + { + "data": "any", + "dataVersion": "str", + "eventTime": "datetime", + "eventType": "str", + "id": "str", + "metadataVersion": "str (optional)", + "subject": "str", + "topic": "str (optional)" + } + ] + """ + + content_type = kwargs.pop('content_type', None) # type: Optional[str] + + api_version = "2018-01-01" + # Construct URL + url = kwargs.pop("template_url", '/api/events') + + # Construct parameters + query_parameters = kwargs.pop("params", {}) # type: Dict[str, Any] + query_parameters['api-version'] = _SERIALIZER.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = kwargs.pop("headers", {}) # type: Dict[str, Any] + if content_type is not None: + header_parameters['Content-Type'] = _SERIALIZER.header("content_type", content_type, 'str') + + return HttpRequest( + method="POST", + url=url, + params=query_parameters, + headers=header_parameters, + json=json, + content=content, + **kwargs + ) + + +def build_publish_cloud_event_events_request( + *, + json: Any = None, + content: Any = None, + **kwargs: Any +) -> HttpRequest: + """Publishes a batch of events to an Azure Event Grid topic. + + See https://aka.ms/azsdk/python/protocol/quickstart for how to incorporate this request builder + into your code flow. + + :keyword json: Pass in a JSON-serializable object (usually a dictionary). See the template in + our example to find the input shape. An array of events to be published to Event Grid. + :paramtype json: any + :keyword content: Pass in binary content you want in the body of the request (typically bytes, + a byte iterator, or stream input). An array of events to be published to Event Grid. + :paramtype content: any + :return: Returns an :class:`~azure.core.rest.HttpRequest` that you will pass to the client's + `send_request` method. See https://aka.ms/azsdk/python/protocol/quickstart for how to + incorporate this response into your code flow. + :rtype: ~azure.core.rest.HttpRequest + + Example: + .. code-block:: python + + # JSON input template you can fill out and use as your `json` input. + json = [ + { + "": { + "str": "any (optional)" + }, + "data": "any (optional)", + "data_base64": "bytearray (optional)", + "datacontenttype": "str (optional)", + "dataschema": "str (optional)", + "id": "str", + "source": "str", + "specversion": "str", + "subject": "str (optional)", + "time": "datetime (optional)", + "type": "str" + } + ] + """ + + content_type = kwargs.pop('content_type', None) # type: Optional[str] + + api_version = "2018-01-01" + # Construct URL + url = kwargs.pop("template_url", '/api/events') + + # Construct parameters + query_parameters = kwargs.pop("params", {}) # type: Dict[str, Any] + query_parameters['api-version'] = _SERIALIZER.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = kwargs.pop("headers", {}) # type: Dict[str, Any] + if content_type is not None: + header_parameters['Content-Type'] = _SERIALIZER.header("content_type", content_type, 'str') + + return HttpRequest( + method="POST", + url=url, + params=query_parameters, + headers=header_parameters, + json=json, + content=content, + **kwargs + ) + + +def build_publish_custom_event_events_request( + *, + json: Any = None, + content: Any = None, + **kwargs: Any +) -> HttpRequest: + """Publishes a batch of events to an Azure Event Grid topic. + + See https://aka.ms/azsdk/python/protocol/quickstart for how to incorporate this request builder + into your code flow. + + :keyword json: Pass in a JSON-serializable object (usually a dictionary). See the template in + our example to find the input shape. An array of events to be published to Event Grid. + :paramtype json: any + :keyword content: Pass in binary content you want in the body of the request (typically bytes, + a byte iterator, or stream input). An array of events to be published to Event Grid. + :paramtype content: any + :return: Returns an :class:`~azure.core.rest.HttpRequest` that you will pass to the client's + `send_request` method. See https://aka.ms/azsdk/python/protocol/quickstart for how to + incorporate this response into your code flow. + :rtype: ~azure.core.rest.HttpRequest + + Example: + .. code-block:: python + + # JSON input template you can fill out and use as your `json` input. + json = [ + "any (optional)" + ] + """ + + content_type = kwargs.pop('content_type', None) # type: Optional[str] + + api_version = "2018-01-01" + # Construct URL + url = kwargs.pop("template_url", '/api/events') + + # Construct parameters + query_parameters = kwargs.pop("params", {}) # type: Dict[str, Any] + query_parameters['api-version'] = _SERIALIZER.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = kwargs.pop("headers", {}) # type: Dict[str, Any] + if content_type is not None: + header_parameters['Content-Type'] = _SERIALIZER.header("content_type", content_type, 'str') + + return HttpRequest( + method="POST", + url=url, + params=query_parameters, + headers=header_parameters, + json=json, + content=content, + **kwargs + ) + diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_helpers.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_helpers.py new file mode 100644 index 00000000000..8c51aafffaf --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_helpers.py @@ -0,0 +1,167 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- +from typing import TYPE_CHECKING, Any +import json +import hashlib +import hmac +import base64 +import six + +try: + from urllib.parse import quote +except ImportError: + from urllib2 import quote # type: ignore + +from msrest import Serializer +from azure.core.pipeline.transport import HttpRequest +from azure.core.pipeline.policies import AzureKeyCredentialPolicy, BearerTokenCredentialPolicy +from azure.core.credentials import AzureKeyCredential, AzureSasCredential +from ._signature_credential_policy import EventGridSasCredentialPolicy +from . import _constants as constants + +from ._generated.models import ( + CloudEvent as InternalCloudEvent, +) + +if TYPE_CHECKING: + from datetime import datetime + +def generate_sas(endpoint, shared_access_key, expiration_date_utc, **kwargs): + # type: (str, str, datetime, Any) -> str + """Helper method to generate shared access signature given hostname, key, and expiration date. + :param str endpoint: The topic endpoint to send the events to. + Similar to .-1.eventgrid.azure.net + :param str shared_access_key: The shared access key to be used for generating the token + :param datetime.datetime expiration_date_utc: The expiration datetime in UTC for the signature. + :keyword str api_version: The API Version to include in the signature. + If not provided, the default API version will be used. + :rtype: str + + .. admonition:: Example: + + .. literalinclude:: ../samples/sync_samples/sample_generate_sas.py + :start-after: [START generate_sas] + :end-before: [END generate_sas] + :language: python + :dedent: 0 + :caption: Generate a shared access signature. + """ + full_endpoint = "{}?apiVersion={}".format( + endpoint, kwargs.get("api_version", constants.DEFAULT_API_VERSION) + ) + encoded_resource = quote(full_endpoint, safe=constants.SAFE_ENCODE) + encoded_expiration_utc = quote(str(expiration_date_utc), safe=constants.SAFE_ENCODE) + + unsigned_sas = "r={}&e={}".format(encoded_resource, encoded_expiration_utc) + signature = quote( + _generate_hmac(shared_access_key, unsigned_sas), safe=constants.SAFE_ENCODE + ) + signed_sas = "{}&s={}".format(unsigned_sas, signature) + return signed_sas + +def _generate_hmac(key, message): + decoded_key = base64.b64decode(key) + bytes_message = message.encode("ascii") + hmac_new = hmac.new(decoded_key, bytes_message, hashlib.sha256).digest() + + return base64.b64encode(hmac_new) + + +def _get_authentication_policy(credential, bearer_token_policy=BearerTokenCredentialPolicy): + if credential is None: + raise ValueError("Parameter 'self._credential' must not be None.") + if hasattr(credential, "get_token"): + return bearer_token_policy( + credential, + constants.DEFAULT_EVENTGRID_SCOPE + ) + if isinstance(credential, AzureKeyCredential): + return AzureKeyCredentialPolicy( + credential=credential, name=constants.EVENTGRID_KEY_HEADER + ) + if isinstance(credential, AzureSasCredential): + return EventGridSasCredentialPolicy( + credential=credential, name=constants.EVENTGRID_TOKEN_HEADER + ) + raise ValueError( + "The provided credential should be an instance of a TokenCredential, AzureSasCredential or AzureKeyCredential" + ) + + +def _is_cloud_event(event): + # type: (Any) -> bool + required = ("id", "source", "specversion", "type") + try: + return all([_ in event for _ in required]) and event["specversion"] == "1.0" + except TypeError: + return False + + +def _is_eventgrid_event(event): + # type: (Any) -> bool + required = ("subject", "eventType", "data", "dataVersion", "id", "eventTime") + try: + return all([prop in event for prop in required]) + except TypeError: + return False + + +def _eventgrid_data_typecheck(event): + try: + data = event.get("data") + except AttributeError: + data = event.data + + if isinstance(data, six.binary_type): + raise TypeError( + "Data in EventGridEvent cannot be bytes. Please refer to" + "https://docs.microsoft.com/en-us/azure/event-grid/event-schema" + ) + +def _cloud_event_to_generated(cloud_event, **kwargs): + if isinstance(cloud_event.data, six.binary_type): + data_base64 = cloud_event.data + data = None + else: + data = cloud_event.data + data_base64 = None + return InternalCloudEvent( + id=cloud_event.id, + source=cloud_event.source, + type=cloud_event.type, + specversion=cloud_event.specversion, + data=data, + data_base64=data_base64, + time=cloud_event.time, + dataschema=cloud_event.dataschema, + datacontenttype=cloud_event.datacontenttype, + subject=cloud_event.subject, + additional_properties=cloud_event.extensions, + **kwargs + ) + +def _build_request(endpoint, content_type, events): + serialize = Serializer() + header_parameters = {} # type: Dict[str, Any] + header_parameters['Content-Type'] = serialize.header("content_type", content_type, 'str') + + query_parameters = {} # type: Dict[str, Any] + query_parameters['api-version'] = serialize.query("api_version", "2018-01-01", 'str') + + body = serialize.body(events, '[object]') + if body is None: + data = None + else: + data = json.dumps(body) + header_parameters['Content-Length'] = str(len(data)) + + request = HttpRequest( + method="POST", + url=endpoint, + headers=header_parameters, + data=data + ) + request.format_parameters(query_parameters) + return request diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_messaging_shared.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_messaging_shared.py new file mode 100644 index 00000000000..bc9307d0058 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_messaging_shared.py @@ -0,0 +1,41 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +# ========================================================================== +# This file contains duplicate code that is shared with azure-eventgrid. +# Both the files should always be identical. +# ========================================================================== + + + +import json +from azure.core.exceptions import raise_with_traceback + +def _get_json_content(obj): + """Event mixin to have methods that are common to different Event types + like CloudEvent, EventGridEvent etc. + """ + msg = "Failed to load JSON content from the object." + try: + # storage queue + return json.loads(obj.content) + except ValueError as err: + raise_with_traceback(ValueError, msg, err) + except AttributeError: + # eventhubs + try: + return json.loads(next(obj.body))[0] + except KeyError: + # servicebus + return json.loads(next(obj.body)) + except ValueError as err: + raise_with_traceback(ValueError, msg, err) + except: # pylint: disable=bare-except + try: + return json.loads(obj) + except ValueError as err: + raise_with_traceback(ValueError, msg, err) diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py new file mode 100644 index 00000000000..ecc74505a9d --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py @@ -0,0 +1,113 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- +# pylint:disable=protected-access +from typing import Any, cast +import datetime as dt +import uuid +from msrest.serialization import UTC +from ._messaging_shared import _get_json_content +from ._generated.models import ( + EventGridEvent as InternalEventGridEvent, +) + + +class EventGridEvent(InternalEventGridEvent): + """Properties of an event published to an Event Grid topic using the EventGrid Schema. + + Variables are only populated by the server, and will be ignored when sending a request. + + All required parameters must be populated in order to send to Azure. + + :param subject: Required. A resource path relative to the topic path. + :type subject: str + :param event_type: Required. The type of the event that occurred. + :type event_type: str + :param data: Required. Event data specific to the event type. + :type data: object + :param data_version: Required. The schema version of the data object. + If not provided, will be stamped with an empty value. + :type data_version: str + :keyword topic: The resource path of the event source. If not provided, Event Grid will + stamp onto the event. This is required when sending event(s) to a domain. + :paramtype topic: Optional[str] + :keyword metadata_version: The schema version of the event metadata. If provided, + must match Event Grid Schema exactly. If not provided, EventGrid will stamp onto event. + :paramtype metadata_version: Optional[str] + :keyword id: An identifier for the event. In not provided, a random UUID will be generated and used. + :paramtype id: Optional[str] + :keyword event_time: The time (in UTC) of the event. If not provided, + it will be the time (in UTC) the event was generated. + :paramtype event_time: Optional[~datetime.datetime] + :ivar subject: A resource path relative to the topic path. + :vartype subject: str + :ivar event_type: The type of the event that occurred. + :vartype event_type: str + :ivar data: Event data specific to the event type. + :vartype data: object + :ivar data_version: The schema version of the data object. + If not provided, will be stamped with an empty value. + :vartype data_version: str + :ivar topic: The resource path of the event source. If not provided, Event Grid will stamp onto the event. + :vartype topic: str + :ivar metadata_version: The schema version of the event metadata. If provided, must match Event Grid Schema exactly. + If not provided, EventGrid will stamp onto event. + :vartype metadata_version: str + :ivar id: An identifier for the event. In not provided, a random UUID will be generated and used. + :vartype id: str + :ivar event_time: The time (in UTC) of the event. If not provided, + it will be the time (in UTC) the event was generated. + :vartype event_time: ~datetime.datetime + """ + + _validation = { + "id": {"required": True}, + "subject": {"required": True}, + "data": {"required": True}, + "event_type": {"required": True}, + "event_time": {"required": True}, + "metadata_version": {"readonly": True}, + "data_version": {"required": True}, + } + + _attribute_map = { + "id": {"key": "id", "type": "str"}, + "topic": {"key": "topic", "type": "str"}, + "subject": {"key": "subject", "type": "str"}, + "data": {"key": "data", "type": "object"}, + "event_type": {"key": "eventType", "type": "str"}, + "event_time": {"key": "eventTime", "type": "iso-8601"}, + "metadata_version": {"key": "metadataVersion", "type": "str"}, + "data_version": {"key": "dataVersion", "type": "str"}, + } + + def __init__(self, subject, event_type, data, data_version, **kwargs): + # type: (str, str, object, str, Any) -> None + kwargs.setdefault("id", uuid.uuid4()) + kwargs.setdefault("subject", subject) + kwargs.setdefault("event_type", event_type) + kwargs.setdefault("event_time", dt.datetime.now(UTC()).isoformat()) + kwargs.setdefault("data", data) + kwargs.setdefault("data_version", data_version) + + super(EventGridEvent, self).__init__(**kwargs) + + def __repr__(self): + return "EventGridEvent(subject={}, event_type={}, id={}, event_time={})".format( + self.subject, self.event_type, self.id, self.event_time + )[:1024] + + @classmethod + def from_json(cls, event): + # type: (Any) -> EventGridEvent + """ + Returns the deserialized EventGridEvent object when a json payload is provided. + :param event: The json string that should be converted into a EventGridEvent. This can also be + a storage QueueMessage, eventhub's EventData or ServiceBusMessage + :type event: object + :rtype: EventGridEvent + :raises ValueError: If the provided JSON is invalid. + """ + dict_event = _get_json_content(event) + return cast(EventGridEvent, EventGridEvent.from_dict(dict_event)) diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_policies.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_policies.py new file mode 100644 index 00000000000..ee5cc7a4695 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_policies.py @@ -0,0 +1,50 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import json +from typing import TYPE_CHECKING +import logging +from azure.core.pipeline.policies import SansIOHTTPPolicy + +_LOGGER = logging.getLogger(__name__) + +if TYPE_CHECKING: + from azure.core.pipeline import PipelineRequest + + +class CloudEventDistributedTracingPolicy(SansIOHTTPPolicy): + """CloudEventDistributedTracingPolicy is a policy which adds distributed tracing informatiom + to a batch of cloud events. It does so by copying the `traceparent` and `tracestate` properties + from the HTTP request into the individual events as extension properties. + This will only happen in the case where an event does not have a `traceparent` defined already. This + allows events to explicitly set a traceparent and tracestate which would be respected during "multi-hop + transmission". + See https://github.com/cloudevents/spec/blob/master/extensions/distributed-tracing.md + for more information on distributed tracing and cloud events. + """ + + _CONTENT_TYPE = "application/cloudevents-batch+json; charset=utf-8" + + def on_request(self, request): + # type: (PipelineRequest) -> None + try: + traceparent = request.http_request.headers["traceparent"] + tracestate = request.http_request.headers["tracestate"] + except KeyError: + return + + if ( + request.http_request.headers["content-type"] + == CloudEventDistributedTracingPolicy._CONTENT_TYPE + and traceparent is not None + ): + + body = json.loads(request.http_request.body) + for item in body: + if "traceparent" not in item and "tracestate" not in item: + item["traceparent"] = traceparent + item["tracestate"] = tracestate + + request.http_request.body = json.dumps(body) diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_publisher_client.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_publisher_client.py new file mode 100644 index 00000000000..8878454999c --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_publisher_client.py @@ -0,0 +1,216 @@ +# +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +from typing import TYPE_CHECKING, cast, Dict, List, Any, Union + +from azure.core.tracing.decorator import distributed_trace +from azure.core.pipeline.policies import ( + RequestIdPolicy, + HeadersPolicy, + RedirectPolicy, + RetryPolicy, + ContentDecodePolicy, + CustomHookPolicy, + NetworkTraceLoggingPolicy, + ProxyPolicy, + DistributedTracingPolicy, + HttpLoggingPolicy, + UserAgentPolicy, +) +from azure.core.messaging import CloudEvent + +from ._models import EventGridEvent +from ._helpers import ( + _get_authentication_policy, + _is_cloud_event, + _is_eventgrid_event, + _eventgrid_data_typecheck, + _build_request, + _cloud_event_to_generated, +) +from ._generated._event_grid_publisher_client import ( + EventGridPublisherClient as EventGridPublisherClientImpl, +) +from ._policies import CloudEventDistributedTracingPolicy +from ._version import VERSION + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from azure.core.credentials import ( + AzureKeyCredential, + AzureSasCredential, + TokenCredential, + ) + + SendType = Union[ + CloudEvent, + EventGridEvent, + Dict, + List[CloudEvent], + List[EventGridEvent], + List[Dict], + ] + +ListEventType = Union[List[CloudEvent], List[EventGridEvent], List[Dict]] + + +class EventGridPublisherClient(object): + """EventGridPublisherClient publishes events to an EventGrid topic or domain. + It can be used to publish either an EventGridEvent, a CloudEvent or a Custom Schema. + + :param str endpoint: The topic endpoint to send the events to. + :param credential: The credential object used for authentication which + implements SAS key authentication or SAS token authentication or a TokenCredential. + :type credential: ~azure.core.credentials.AzureKeyCredential or ~azure.core.credentials.AzureSasCredential or + ~azure.core.credentials.TokenCredential + :rtype: None + + .. admonition:: Example: + + .. literalinclude:: ../samples/sync_samples/sample_authentication.py + :start-after: [START client_auth_with_key_cred] + :end-before: [END client_auth_with_key_cred] + :language: python + :dedent: 0 + :caption: Creating the EventGridPublisherClient with an endpoint and AzureKeyCredential. + + .. literalinclude:: ../samples/sync_samples/sample_authentication.py + :start-after: [START client_auth_with_sas_cred] + :end-before: [END client_auth_with_sas_cred] + :language: python + :dedent: 0 + :caption: Creating the EventGridPublisherClient with an endpoint and AzureSasCredential. + """ + + def __init__(self, endpoint, credential, **kwargs): + # type: (str, Union[AzureKeyCredential, AzureSasCredential, TokenCredential], Any) -> None + self._endpoint = endpoint + self._client = EventGridPublisherClientImpl( + policies=EventGridPublisherClient._policies(credential, **kwargs), **kwargs + ) + + @staticmethod + def _policies(credential, **kwargs): + # type: (Union[AzureKeyCredential, AzureSasCredential, TokenCredential], Any) -> List[Any] + auth_policy = _get_authentication_policy(credential) + sdk_moniker = "eventgrid/{}".format(VERSION) + policies = [ + RequestIdPolicy(**kwargs), + HeadersPolicy(**kwargs), + UserAgentPolicy(sdk_moniker=sdk_moniker, **kwargs), + ProxyPolicy(**kwargs), + ContentDecodePolicy(**kwargs), + RedirectPolicy(**kwargs), + RetryPolicy(**kwargs), + auth_policy, + CustomHookPolicy(**kwargs), + NetworkTraceLoggingPolicy(**kwargs), + DistributedTracingPolicy(**kwargs), + CloudEventDistributedTracingPolicy(), + HttpLoggingPolicy(**kwargs), + ] + return policies + + @distributed_trace + def send(self, events, **kwargs): + # type: (SendType, Any) -> None + """Sends events to a topic or a domain specified during the client initialization. + + A single instance or a list of dictionaries, CloudEvents or EventGridEvents are accepted. + + .. admonition:: Example: + + .. literalinclude:: ../samples/sync_samples/sample_publish_eg_events_to_a_topic.py + :start-after: [START publish_eg_event_to_topic] + :end-before: [END publish_eg_event_to_topic] + :language: python + :dedent: 0 + :caption: Publishing an EventGridEvent. + + .. literalinclude:: ../samples/sync_samples/sample_publish_events_using_cloud_events_1.0_schema.py + :start-after: [START publish_cloud_event_to_topic] + :end-before: [END publish_cloud_event_to_topic] + :language: python + :dedent: 0 + :caption: Publishing a CloudEvent. + + Dict representation of respective serialized models is accepted as CloudEvent(s) or + EventGridEvent(s) apart from the strongly typed objects. + + .. admonition:: Example: + + .. literalinclude:: ../samples/sync_samples/sample_publish_eg_event_using_dict.py + :start-after: [START publish_eg_event_dict] + :end-before: [END publish_eg_event_dict] + :language: python + :dedent: 4 + :caption: Publishing a list of EventGridEvents using a dict-like representation. + + .. literalinclude:: ../samples/sync_samples/sample_publish_cloud_event_using_dict.py + :start-after: [START publish_cloud_event_dict] + :end-before: [END publish_cloud_event_dict] + :language: python + :dedent: 0 + :caption: Publishing a CloudEvent using a dict-like representation. + + When publishing a Custom Schema Event(s), dict-like representation is accepted. + Either a single dictionary or a list of dictionaries can be passed. + + .. admonition:: Example: + + .. literalinclude:: ../samples/sync_samples/sample_publish_custom_schema_to_a_topic.py + :start-after: [START publish_custom_schema] + :end-before: [END publish_custom_schema] + :language: python + :dedent: 4 + :caption: Publishing a Custom Schema event. + + **WARNING**: When sending a list of multiple events at one time, iterating over and sending each event + will not result in optimal performance. For best performance, it is highly recommended to send + a list of events. + + :param events: A single instance or a list of dictionaries/CloudEvent/EventGridEvent to be sent. + :type events: ~azure.core.messaging.CloudEvent or ~azure.eventgrid.EventGridEvent or dict or + List[~azure.core.messaging.CloudEvent] or List[~azure.eventgrid.EventGridEvent] or List[dict] + :keyword str content_type: The type of content to be used to send the events. + Has default value "application/json; charset=utf-8" for EventGridEvents, + with "cloudevents-batch+json" for CloudEvents + :rtype: None + """ + if not isinstance(events, list): + events = cast(ListEventType, [events]) + content_type = kwargs.pop("content_type", "application/json; charset=utf-8") + + if isinstance(events[0], CloudEvent) or _is_cloud_event(events[0]): + try: + events = [ + _cloud_event_to_generated(e, **kwargs) + for e in events # pylint: disable=protected-access + ] + except AttributeError: + pass # means it's a dictionary + content_type = "application/cloudevents-batch+json; charset=utf-8" + elif isinstance(events[0], EventGridEvent) or _is_eventgrid_event(events[0]): + for event in events: + _eventgrid_data_typecheck(event) + self._client.send_request( # pylint: disable=protected-access + _build_request(self._endpoint, content_type, events), **kwargs + ) + + def close(self): + # type: () -> None + """Close the :class:`~azure.eventgrid.EventGridPublisherClient` session.""" + return self._client.close() + + def __enter__(self): + # type: () -> EventGridPublisherClient + self._client.__enter__() # pylint:disable=no-member + return self + + def __exit__(self, *args): + # type: (*Any) -> None + self._client.__exit__(*args) # pylint:disable=no-member diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_signature_credential_policy.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_signature_credential_policy.py new file mode 100644 index 00000000000..d0c6fc47d5e --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_signature_credential_policy.py @@ -0,0 +1,36 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See LICENSE.txt in the project root for +# license information. +# ------------------------------------------------------------------------- + +from typing import Any, TYPE_CHECKING +import six + +from azure.core.pipeline.policies import SansIOHTTPPolicy + +if TYPE_CHECKING: + from azure.core.credentials import AzureSasCredential + + +class EventGridSasCredentialPolicy(SansIOHTTPPolicy): + """Adds a token header for the provided credential. + :param credential: The credential used to authenticate requests. + :type credential: ~azure.core.credentials.AzureSasCredential + :param str name: The name of the token header used for the credential. + :raises: ValueError or TypeError + """ + + def __init__(self, credential, name, **kwargs): # pylint: disable=unused-argument + # type: (AzureSasCredential, str, Any) -> None + super(EventGridSasCredentialPolicy, self).__init__() + self._credential = credential + if not name: + raise ValueError("name can not be None or empty") + if not isinstance(name, six.string_types): + raise TypeError("name must be a string.") + self._name = name + + def on_request(self, request): + # Request must contain one of the following authorization signature: aeg-sas-token, aeg-sas-key + request.http_request.headers[self._name] = self._credential.signature diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_version.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_version.py new file mode 100644 index 00000000000..766cedfaf63 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_version.py @@ -0,0 +1,12 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- + +VERSION = "4.6.1" diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/aio/__init__.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/aio/__init__.py new file mode 100644 index 00000000000..0d2dce7aaea --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/aio/__init__.py @@ -0,0 +1,9 @@ +# coding=utf-8 +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ + +from ._publisher_client_async import EventGridPublisherClient + +__all__ = ["EventGridPublisherClient"] diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/aio/_publisher_client_async.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/aio/_publisher_client_async.py new file mode 100644 index 00000000000..b2cb0faa33c --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/aio/_publisher_client_async.py @@ -0,0 +1,213 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from typing import Any, Union, List, Dict, TYPE_CHECKING, cast +from azure.core.credentials import AzureKeyCredential, AzureSasCredential +from azure.core.tracing.decorator_async import distributed_trace_async +from azure.core.messaging import CloudEvent +from azure.core.pipeline.policies import ( + RequestIdPolicy, + HeadersPolicy, + AsyncRedirectPolicy, + AsyncRetryPolicy, + ContentDecodePolicy, + CustomHookPolicy, + NetworkTraceLoggingPolicy, + ProxyPolicy, + DistributedTracingPolicy, + HttpLoggingPolicy, + UserAgentPolicy, + AsyncBearerTokenCredentialPolicy, +) +from .._policies import CloudEventDistributedTracingPolicy +from .._models import EventGridEvent +from .._helpers import ( + _is_cloud_event, + _is_eventgrid_event, + _eventgrid_data_typecheck, + _build_request, + _cloud_event_to_generated, + _get_authentication_policy, +) +from .._generated.aio import EventGridPublisherClient as EventGridPublisherClientAsync +from .._version import VERSION + +if TYPE_CHECKING: + from azure.core.credentials_async import AsyncTokenCredential + +SendType = Union[ + CloudEvent, EventGridEvent, Dict, List[CloudEvent], List[EventGridEvent], List[Dict] +] + +ListEventType = Union[List[CloudEvent], List[EventGridEvent], List[Dict]] + + +class EventGridPublisherClient: + """Asynchronous EventGridPublisherClient publishes events to an EventGrid topic or domain. + It can be used to publish either an EventGridEvent, a CloudEvent or a Custom Schema. + + :param str endpoint: The topic endpoint to send the events to. + :param credential: The credential object used for authentication which implements + SAS key authentication or SAS token authentication or an AsyncTokenCredential. + :type credential: ~azure.core.credentials.AzureKeyCredential or ~azure.core.credentials.AzureSasCredential or + ~azure.core.credentials_async.AsyncTokenCredential + :rtype: None + + .. admonition:: Example: + + .. literalinclude:: ../samples/async_samples/sample_authentication_async.py + :start-after: [START client_auth_with_key_cred_async] + :end-before: [END client_auth_with_key_cred_async] + :language: python + :dedent: 0 + :caption: Creating the EventGridPublisherClient with an endpoint and AzureKeyCredential. + + .. literalinclude:: ../samples/async_samples/sample_authentication_async.py + :start-after: [START client_auth_with_sas_cred_async] + :end-before: [END client_auth_with_sas_cred_async] + :language: python + :dedent: 0 + :caption: Creating the EventGridPublisherClient with an endpoint and AzureSasCredential. + """ + + def __init__( + self, + endpoint: str, + credential: Union[ + "AsyncTokenCredential", AzureKeyCredential, AzureSasCredential + ], + **kwargs: Any + ) -> None: + self._client = EventGridPublisherClientAsync( + policies=EventGridPublisherClient._policies(credential, **kwargs), **kwargs + ) + self._endpoint = endpoint + + @staticmethod + def _policies( + credential: Union[ + AzureKeyCredential, AzureSasCredential, "AsyncTokenCredential" + ], + **kwargs: Any + ) -> List[Any]: + auth_policy = _get_authentication_policy( + credential, AsyncBearerTokenCredentialPolicy + ) + sdk_moniker = "eventgridpublisherclient/{}".format(VERSION) + policies = [ + RequestIdPolicy(**kwargs), + HeadersPolicy(**kwargs), + UserAgentPolicy(sdk_moniker=sdk_moniker, **kwargs), + ProxyPolicy(**kwargs), + ContentDecodePolicy(**kwargs), + AsyncRedirectPolicy(**kwargs), + AsyncRetryPolicy(**kwargs), + auth_policy, + CustomHookPolicy(**kwargs), + NetworkTraceLoggingPolicy(**kwargs), + DistributedTracingPolicy(**kwargs), + CloudEventDistributedTracingPolicy(), + HttpLoggingPolicy(**kwargs), + ] + return policies + + @distributed_trace_async + async def send(self, events: SendType, **kwargs: Any) -> None: + """Sends events to a topic or a domain specified during the client initialization. + + A single instance or a list of dictionaries, CloudEvents or EventGridEvents are accepted. + + .. admonition:: Example: + + .. literalinclude:: ../samples/async_samples/sample_publish_eg_events_to_a_topic_async.py + :start-after: [START publish_eg_event_to_topic_async] + :end-before: [END publish_eg_event_to_topic_async] + :language: python + :dedent: 0 + :caption: Publishing an EventGridEvent. + + .. literalinclude:: ../samples/async_samples/sample_publish_events_using_cloud_events_1.0_schema_async.py + :start-after: [START publish_cloud_event_to_topic_async] + :end-before: [END publish_cloud_event_to_topic_async] + :language: python + :dedent: 0 + :caption: Publishing a CloudEvent. + + Dict representation of respective serialized models is accepted as CloudEvent(s) or + EventGridEvent(s) apart from the strongly typed objects. + + .. admonition:: Example: + + .. literalinclude:: ../samples/async_samples/sample_publish_eg_event_using_dict_async.py + :start-after: [START publish_eg_event_dict_async] + :end-before: [END publish_eg_event_dict_async] + :language: python + :dedent: 4 + :caption: Publishing a list of EventGridEvents using a dict-like representation. + + .. literalinclude:: ../samples/async_samples/sample_publish_cloud_event_using_dict_async.py + :start-after: [START publish_cloud_event_dict_async] + :end-before: [END publish_cloud_event_dict_async] + :language: python + :dedent: 4 + :caption: Publishing a CloudEvent using a dict-like representation. + + When publishing a Custom Schema Event(s), dict-like representation is accepted. + Either a single dictionary or a list of dictionaries can be passed. + + .. admonition:: Example: + + .. literalinclude:: ../samples/async_samples/sample_publish_custom_schema_to_a_topic_async.py + :start-after: [START publish_custom_schema_async] + :end-before: [END publish_custom_schema_async] + :language: python + :dedent: 4 + :caption: Publishing a Custom Schema event. + + **WARNING**: When sending a list of multiple events at one time, iterating over and sending each event + will not result in optimal performance. For best performance, it is highly recommended to send + a list of events. + + :param events: A single instance or a list of dictionaries/CloudEvent/EventGridEvent to be sent. + :type events: ~azure.core.messaging.CloudEvent or ~azure.eventgrid.EventGridEvent or dict or + List[~azure.core.messaging.CloudEvent] or List[~azure.eventgrid.EventGridEvent] or List[dict] + :keyword str content_type: The type of content to be used to send the events. + Has default value "application/json; charset=utf-8" for EventGridEvents, + with "cloudevents-batch+json" for CloudEvents + :rtype: None + """ + if not isinstance(events, list): + events = cast(ListEventType, [events]) + content_type = kwargs.pop("content_type", "application/json; charset=utf-8") + + if isinstance(events[0], CloudEvent) or _is_cloud_event(events[0]): + try: + events = [ + _cloud_event_to_generated(e, **kwargs) + for e in events # pylint: disable=protected-access + ] + except AttributeError: + pass # means it's a dictionary + content_type = "application/cloudevents-batch+json; charset=utf-8" + elif isinstance(events[0], EventGridEvent) or _is_eventgrid_event(events[0]): + for event in events: + _eventgrid_data_typecheck(event) + await self._client.send_request( # pylint: disable=protected-access + _build_request(self._endpoint, content_type, events), **kwargs + ) + + async def __aenter__(self) -> "EventGridPublisherClient": + await self._client.__aenter__() + return self + + async def __aexit__(self, *args: "Any") -> None: + await self._client.__aexit__(*args) + + async def close(self) -> None: + """Close the :class:`~azure.eventgrid.aio.EventGridPublisherClient` session.""" + await self._client.__aexit__() diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/py.typed b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/py.typed new file mode 100644 index 00000000000..e69de29bb2d diff --git a/sdk/eventgrid/azure-eventgrid/dev_requirements.txt b/sdk/eventgrid/azure-eventgrid/dev_requirements.txt new file mode 100644 index 00000000000..3f90c92310b --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/dev_requirements.txt @@ -0,0 +1,7 @@ +-e ../../../tools/azure-devtools +-e ../../../tools/azure-sdk-tools +-e ../../core/azure-core +-e ../../identity/azure-identity +-e ../azure-mgmt-eventgrid +azure-storage-queue +aiohttp>=3.0; python_version >= '3.5' diff --git a/sdk/eventgrid/azure-eventgrid/migration_guide.md b/sdk/eventgrid/azure-eventgrid/migration_guide.md new file mode 100644 index 00000000000..5e6fd5190dc --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/migration_guide.md @@ -0,0 +1,102 @@ +# Guide for migrating to azure-eventgrid v4.0 from azure-eventgrid v1.3 + +This guide is intended to assist in the migration to azure-eventgrid v4.0 from azure-eventgrid v1.3. It will focus on side-by-side comparisons for similar operations between the two packages. + +Familiarity with the azure-eventgrid v1.3 package is assumed. For those new to the eventgrid client library for Python, please refer to the [README for azure-eventgrid v4.0](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/README.md) rather than this guide. + +## Table of contents + +* [Migration benefits](#migration-benefits) + - [Cross Service SDK improvements](#cross-service-sdk-improvements) +* [Important Changes](#important-changes) + - [Support for Cloud Events](#support-for-cloud-events) + - [Client Constructors](#client-constructors) + - [Publishing Events](#publishing-events) + - [Consuming Events](#consuming-events) +* [Additional Samples](#additional-samples) + +## Migration benefits + +A natural question to ask when considering whether or not to adopt a new version or library is what the benefits of doing so would be. As Azure has matured and been embraced by a more diverse group of developers, we have been focused on learning the patterns and practices to best support developer productivity and to understand the gaps that the Python client libraries have. + +There were several areas of consistent feedback expressed across the Azure client library ecosystem. One of the most important is that the client libraries for different Azure services have not had a consistent approach to organization, naming, and API structure. Additionally, many developers have felt that the learning curve was difficult, and the APIs did not offer a good, approachable, and consistent onboarding story for those learning Azure or exploring a specific Azure service. + +To try and improve the development experience across Azure services, a set of uniform [design guidelines](https://azure.github.io/azure-sdk/general_introduction.html) was created for all languages to drive a consistent experience with established API patterns for all services. A set of [Azure SDK Design Guidelines for Python](https://azure.github.io/azure-sdk/python_design.html) was also introduced to ensure that Python clients have a natural and idiomatic feel with respect to the Python ecosystem. Further details are available in the guidelines for those interested. + +### Cross Service SDK improvements + +The modern Event Grid client library also provides the ability to share in some of the cross-service improvements made to the Azure development experience, such as +- a unified logging and diagnostics pipeline offering a common view of the activities across each of the client libraries +- using the new [`azure-identity`](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/identity/azure-identity/README.md) library to share a single authentication approach between clients + +## Important changes + +### Support for Cloud Events + +The v4.x major version comes with support for [CloudEvents](https://github.com/cloudevents/spec). Now the cloud native Cloud Events can be directly published using the `CloudEvent` constructor or as a dictionary as follows: + +```Python +from azure.core.messaging import CloudEvent + +cloud_event = CloudEvent( + type="Contoso.Items.ItemReceived", + source="/contoso/items", + data={ + "itemSku": "Contoso Item SKU #1" + }, + subject="Door1" +) + +# as a dictionary + +cloud_event = { + "type":"a0517898-9fa4-4e70-b4a3-afda1dd68672", + "source":"/subscriptions/{subscription-id}/resourceGroups/{resource-group}/providers/Microsoft.Storage/storageAccounts/{storage-account}", + "data": {"hello": "world"}, + "subject": "Door1" + } +``` + +### Client constructors + +* The `EventGridClient` in the v1.3 has been replaced with `EventGridPublisherClient`. +* `EventGridPublisherClient` requires the full endpoint, which is typically in the format of `https://..eventgrid.azure.net/api/events` + +| In v1.3 | Equivalent in v4.0 | Sample | +|---|---|---| +|`EventGridClient(credentials)`|`EventGridPublisherClient(endpoint, credential)`|[Sample for client construction](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_events_using_cloud_events_1.0_schema.py)| + +### Publishing Events + +The `publish_events` API is replaced with `send` in v4.0. Additionally, `send` API accepts `CloudEvent`, `EventGridEvent` along with their dict representations. + +| In v1.3 | Equivalent in v4.0 | Sample | +|---|---|---| +|`EventGridClient(credentials).publish_events(topic_hostname, events)`|`EventGridPublisherClient(endpoint, credential).send(events)`|[Sample for client construction](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_events_using_cloud_events_1.0_schema.py)| + +### Consuming Events + +The v4.x major version supports deserializing dictionaries into strongly typed objects. The `from_dict` methods in the `CloudEvent` and `EventGridEvent` models can be used for the same. + +This example consumes a payload message received from ServiceBus and deserializes it to an EventGridEvent object. + +```Python +from azure.eventgrid import EventGridEvent +from azure.servicebus import ServiceBusClient +import os +import json + +# all types of EventGridEvents below produce same DeserializedEvent +connection_str = os.environ['SERVICE_BUS_CONN_STR'] +queue_name = os.environ['SERVICE_BUS_QUEUE_NAME'] + +with ServiceBusClient.from_connection_string(connection_str) as sb_client: + payload = sb_client.get_queue_receiver(queue_name).receive_messages() + + ## deserialize payload into a list of typed Events + events = [EventGridEvent.from_dict(json.loads(next(msg.body).decode('utf-8'))) for msg in payload] +``` + +## Additional samples + +More examples can be found at [here](https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/eventgrid/azure-eventgrid/samples) diff --git a/sdk/eventgrid/azure-eventgrid/mypy.ini b/sdk/eventgrid/azure-eventgrid/mypy.ini new file mode 100644 index 00000000000..b8d3b2b6283 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/mypy.ini @@ -0,0 +1,13 @@ +[mypy] +python_version = 3.7 +warn_return_any = True +warn_unused_configs = True +ignore_missing_imports = True + +# Per-module options: + +[mypy-azure.eventgrid._generated.*] +ignore_errors = True + +[mypy-azure.core.*] +ignore_errors = True diff --git a/sdk/eventgrid/azure-eventgrid/samples/README.md b/sdk/eventgrid/azure-eventgrid/samples/README.md new file mode 100644 index 00000000000..226c849d8d0 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/samples/README.md @@ -0,0 +1,76 @@ +--- +page_type: sample +languages: + - python +products: + - azure + - azure-event-grid +urlFragment: eventgrid-samples +--- + +# Azure Event Grid Client Library Python Samples + +## Sync samples +These code samples show common champion scenario operations with the Azure Event Grid client library. + +* Generate Shared Access Signature: [sample_generate_sas.py][python-eg-generate-sas] + +* Authenticate the client: [sample_authentication.py][python-eg-auth] + +* Publish events to a topic using SAS: [sample_publish_events_to_a_topic_using_sas_credential_async.py][python-eg-sample-send-using-sas] +* Publish Event Grid Events to a topic: [sample_publish_eg_events_to_a_topic.py][python-eg-sample-eg-event] +* Publish EventGrid Events to a domain topic: [sample_publish_eg_events_to_a_domain_topic.py][python-eg-sample-eg-event-to-domain] +* Publish a Cloud Event: [sample_publish_events_using_cloud_events_1.0_schema.py][python-eg-sample-send-cloudevent] +* Publish a Custom Schema: [sample_publish_custom_schema_to_a_topic.py][python-eg-publish-custom-schema] + +To publish events, dict representation of the models could also be used as follows: +* Publish EventGridEvent as dict like representation: [sample_publish_eg_event_using_dict.py][python-eg-sample-send-eg-as-dict] +* Publish CloudEvent as dict like representation: [sample_publish_cloud_event_using_dict.py][python-eg-sample-send-cloudevent-as-dict] + +* Consume a Custom Payload of raw cloudevent data: [sample_consume_custom_payload.py][python-eg-sample-consume-custom-payload] + +## Async samples +These code samples show common champion scenario operations with the Azure Event Grid client library using the async client. + +* Authenticate the client: [sample_authentication_async.py][python-eg-auth-async] + +* Publish events to a topic using SAS: [sample_publish_events_to_a_topic_using_sas_credential_async.py][python-eg-sample-send-using-sas-async] +* Publish EventGrid Events to a topic: [sample_publish_eg_events_to_a_topic_async.py][python-eg-sample-eg-event-async] +* Publish EventGrid Events to a domain topic: [sample_publish_eg_events_to_a_domain_topic_async.py][python-eg-sample-eg-event-to-domain-async] +* Publish a Cloud Event: [sample_publish_events_using_cloud_events_1.0_schema_async.py][python-eg-sample-send-cloudevent-async] +* Publish a Custom Schema: [sample_publish_custom_schema_to_a_topic_async.py][python-eg-publish-custom-schema-async] + +To publish events, dict representation of the models could also be used as follows: +* Publish EventGridEvent as dict like representation: [sample_publish_eg_event_using_dict_async.py][python-eg-sample-send-eg-as-dict-async] +* Publish CloudEvent as dict like representation: [sample_publish_cloud_event_using_dict_async.py][python-eg-sample-send-cloudevent-as-dict-async] + +## More Samples + +* More samples related to the send scenario can be seen [here][python-eg-publish-samples]. +* To see more samples related to consuming a payload from different messaging services as a typed object, please visit [Consume Samples][python-eg-consume-samples] + +[python-eg-auth]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_authentication.py +[python-eg-generate-sas]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_generate_sas.py +[python-eg-sample-send-using-sas]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_events_to_a_topic_using_sas_credential.py +[python-eg-sample-eg-event]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_eg_events_to_a_topic.py +[python-eg-sample-eg-event-to-domain]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_eg_events_to_a_domain.py +[python-eg-sample-send-cloudevent]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_events_using_cloud_events_1.0_schema.py +[python-eg-publish-custom-schema]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_custom_schema_to_a_topic.py +[python-eg-sample-send-eg-as-dict]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_eg_event_using_dict.py +[python-eg-sample-send-cloudevent-as-dict]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_cloud_event_using_dict.py + +[python-eg-auth-async]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_authentication_async.py +[python-eg-sample-send-using-sas-async]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_publish_events_to_a_topic_using_sas_credential_async.py +[python-eg-sample-eg-event-async]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_publish_eg_events_to_a_topic_async.py +[python-eg-sample-eg-event-to-domain-async]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_publish_eg_events_to_a_domain_async.py +[python-eg-sample-send-cloudevent-async]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_publish_events_using_cloud_events_1.0_schema_async.py +[python-eg-publish-custom-schema-async]:https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_publish_custom_schema_to_a_topic_async.py +[python-eg-sample-send-eg-as-dict-async]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_publish_eg_event_using_dict_async.py +[python-eg-sample-send-cloudevent-as-dict-async]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_publish_cloud_event_using_dict_async.py + +[python-eg-publish-samples]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/samples/publish_samples +[python-eg-consume-samples]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/samples/consume_samples + +[python-eg-sample-consume-custom-payload]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_consume_custom_payload.py + +[publisher-service-doc]: https://docs.microsoft.com/azure/event-grid/concepts diff --git a/sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_authentication_async.py b/sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_authentication_async.py new file mode 100644 index 00000000000..efe9df4efeb --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_authentication_async.py @@ -0,0 +1,57 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +""" +FILE: sample_authentication_async.py +DESCRIPTION: + These samples demonstrate authenticating an EventGridPublisherClient. +USAGE: + python sample_authentication_async.py + Set the environment variables with your own values before running the sample: + 1) EG_ACCESS_KEY - The access key of your eventgrid account. + 2) EG_TOPIC_HOSTNAME - The topic hostname. Typically it exists in the format + "https://..eventgrid.azure.net/api/events". + 3) EVENTGRID_SAS - The shared access signature that is to be used to authenticate the client. +""" +# [START client_auth_with_key_cred_async] +import os +from azure.eventgrid.aio import EventGridPublisherClient +from azure.core.credentials import AzureKeyCredential + +topic_key = os.environ["EG_ACCESS_KEY"] +endpoint = os.environ["EG_TOPIC_HOSTNAME"] + +credential = AzureKeyCredential(topic_key) +client = EventGridPublisherClient(endpoint, credential) +# [END client_auth_with_key_cred_async] + +# [START client_auth_with_sas_cred_async] +import os +from azure.eventgrid.aio import EventGridPublisherClient +from azure.core.credentials import AzureSasCredential + +signature = os.environ["EVENTGRID_SAS"] +endpoint = os.environ["EG_TOPIC_HOSTNAME"] + +credential = AzureSasCredential(signature) +client = EventGridPublisherClient(endpoint, credential) +# [END client_auth_with_sas_cred_async] + +# [START client_auth_with_token_cred_async] +from azure.identity.aio import DefaultAzureCredential +from azure.eventgrid.aio import EventGridPublisherClient +from azure.eventgrid import EventGridEvent + +event = EventGridEvent( + data={"team": "azure-sdk"}, + subject="Door1", + event_type="Azure.Sdk.Demo", + data_version="2.0" +) + +credential = DefaultAzureCredential() +endpoint = os.environ["EG_TOPIC_HOSTNAME"] +client = EventGridPublisherClient(endpoint, credential) +# [END client_auth_with_token_cred_async] \ No newline at end of file diff --git a/sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_publish_cloud_event_using_dict_async.py b/sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_publish_cloud_event_using_dict_async.py new file mode 100644 index 00000000000..ad74e9e17c5 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_publish_cloud_event_using_dict_async.py @@ -0,0 +1,49 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +""" +FILE: sample_publish_cloud_event_using_dict_async.py +DESCRIPTION: + These samples demonstrate creating a list of CloudEvents using dict representations + and sending then as a list. +USAGE: + python sample_publish_cloud_event_using_dict_async.py + Set the environment variables with your own values before running the sample: + 1) CLOUD_ACCESS_KEY - The access key of your eventgrid account. + 2) CLOUD_TOPIC_HOSTNAME - The topic hostname. Typically it exists in the format + "https://..eventgrid.azure.net/api/events". +""" +import os +import asyncio +from azure.core.messaging import CloudEvent +from azure.eventgrid.aio import EventGridPublisherClient +from azure.core.credentials import AzureKeyCredential + +topic_key = os.environ["CLOUD_ACCESS_KEY"] +endpoint = os.environ["CLOUD_TOPIC_HOSTNAME"] + +async def publish(): + credential = AzureKeyCredential(topic_key) + client = EventGridPublisherClient(endpoint, credential) + + # [START publish_cloud_event_dict_async] + async with client: + await client.send([ + { + "type": "Contoso.Items.ItemReceived", + "source": "/contoso/items", + "data": { + "itemSku": "Contoso Item SKU #1" + }, + "subject": "Door1", + "specversion": "1.0", + "id": "randomclouduuid11" + } + ]) + # [END publish_cloud_event_dict_async] + +if __name__ == '__main__': + loop = asyncio.get_event_loop() + loop.run_until_complete(publish()) diff --git a/sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_publish_custom_schema_to_a_topic_async.py b/sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_publish_custom_schema_to_a_topic_async.py new file mode 100644 index 00000000000..e3d2d40a4df --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_publish_custom_schema_to_a_topic_async.py @@ -0,0 +1,53 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +""" +FILE: sample_publish_custom_schema_to_a_topic_async.py +DESCRIPTION: + These samples demonstrate creating a list of Custom Events and sending them as a list. +USAGE: + python sample_publish_custom_schema_to_a_topic_async.py + Set the environment variables with your own values before running the sample: + 1) CUSTOM_SCHEMA_ACCESS_KEY - The access key of your eventgrid account. + 2) CUSTOM_SCHEMA_TOPIC_HOSTNAME - The topic hostname. Typically it exists in the format + "https://..eventgrid.azure.net/api/events". +""" +import os +import asyncio +from random import randint, sample +import time +import uuid +from msrest.serialization import UTC +import datetime as dt + +from azure.core.credentials import AzureKeyCredential +from azure.eventgrid.aio import EventGridPublisherClient + +key = os.environ["CUSTOM_SCHEMA_ACCESS_KEY"] +endpoint = os.environ["CUSTOM_SCHEMA_TOPIC_HOSTNAME"] + +async def publish_event(): + # authenticate client + # [START publish_custom_schema_async] + credential = AzureKeyCredential(key) + client = EventGridPublisherClient(endpoint, credential) + + custom_schema_event = { + "customSubject": "sample", + "customEventType": "sample.event", + "customDataVersion": "2.0", + "customId": uuid.uuid4(), + "customEventTime": dt.datetime.now(UTC()).isoformat(), + "customData": "sample data" + } + async with client: + # publish list of events + await client.send(custom_schema_event) + + # [END publish_custom_schema_async] + +if __name__ == '__main__': + loop = asyncio.get_event_loop() + loop.run_until_complete(publish_event()) diff --git a/sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_publish_eg_event_using_dict_async.py b/sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_publish_eg_event_using_dict_async.py new file mode 100644 index 00000000000..a4c49ba0c15 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_publish_eg_event_using_dict_async.py @@ -0,0 +1,61 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +""" +FILE: sample_publish_eg_event_using_dict_async.py +DESCRIPTION: + These samples demonstrate sending an EventGrid Event as a dict representation + directly to a topic. The dict representation should be that of the serialized + model of EventGridEvent. +USAGE: + python sample_publish_eg_event_using_dict_async.py + Set the environment variables with your own values before running the sample: + 1) EG_ACCESS_KEY - The access key of your eventgrid account. + 2) EG_TOPIC_HOSTNAME - The topic hostname. Typically it exists in the format + "https://..eventgrid.azure.net/api/events". +""" +import os +import asyncio +from datetime import datetime +from azure.eventgrid import EventGridEvent +from azure.eventgrid.aio import EventGridPublisherClient +from azure.core.credentials import AzureKeyCredential + +topic_key = os.environ["EG_ACCESS_KEY"] +endpoint = os.environ["EG_TOPIC_HOSTNAME"] + +async def publish(): + credential = AzureKeyCredential(topic_key) + client = EventGridPublisherClient(endpoint, credential) + + # [START publish_eg_event_dict_async] + event0 = { + "eventType": "Contoso.Items.ItemReceived", + "data": { + "itemSku": "Contoso Item SKU #1" + }, + "subject": "Door1", + "dataVersion": "2.0", + "id": "randomuuid11", + "eventTime": datetime.utcnow() + } + event1 = { + "eventType": "Contoso.Items.ItemReceived", + "data": { + "itemSku": "Contoso Item SKU #2" + }, + "subject": "Door1", + "dataVersion": "2.0", + "id": "randomuuid12", + "eventTime": datetime.utcnow() + } + + async with client: + await client.send([event0, event1]) + # [END publish_eg_event_dict_async] + +if __name__ == '__main__': + loop = asyncio.get_event_loop() + loop.run_until_complete(publish()) diff --git a/sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_publish_eg_events_to_a_domain_async.py b/sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_publish_eg_events_to_a_domain_async.py new file mode 100644 index 00000000000..677d95dc98d --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_publish_eg_events_to_a_domain_async.py @@ -0,0 +1,54 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +""" +FILE: sample_publish_eg_events_to_a_domain_async.py +DESCRIPTION: + These samples demonstrate creating a list of EventGrid Events and sending them as a list to a topic + in a domain. +USAGE: + python sample_publish_eg_events_to_a_domain_async.py + Set the environment variables with your own values before running the sample: + 1) EG_ACCESS_KEY - The access key of your eventgrid account. + 2) EG_TOPIC_HOSTNAME - The topic hostname. Typically it exists in the format + "https://..eventgrid.azure.net/api/events". +""" +import os +import asyncio +from azure.eventgrid import EventGridEvent +from azure.eventgrid.aio import EventGridPublisherClient +from azure.core.credentials import AzureKeyCredential + +domain_key = os.environ["EG_DOMAIN_ACCESS_KEY"] +domain_hostname = os.environ["EG_DOMAIN_TOPIC_HOSTNAME"] + +async def publish(): + credential = AzureKeyCredential(domain_key) + client = EventGridPublisherClient(domain_hostname, credential) + + await client.send([ + EventGridEvent( + topic="MyCustomDomainTopic1", + event_type="Contoso.Items.ItemReceived", + data={ + "itemSku": "Contoso Item SKU #1" + }, + subject="Door1", + data_version="2.0" + ), + EventGridEvent( + topic="MyCustomDomainTopic2", + event_type="Contoso.Items.ItemReceived", + data={ + "itemSku": "Contoso Item SKU #2" + }, + subject="Door1", + data_version="2.0" + ) + ]) + +if __name__ == '__main__': + loop = asyncio.get_event_loop() + loop.run_until_complete(publish()) diff --git a/sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_publish_eg_events_to_a_topic_async.py b/sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_publish_eg_events_to_a_topic_async.py new file mode 100644 index 00000000000..841ff932ca7 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_publish_eg_events_to_a_topic_async.py @@ -0,0 +1,45 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +""" +FILE: sample_publish_eg_events_to_a_topic_async.py +DESCRIPTION: + These samples demonstrate sending an EventGrid Event directly to a topic. +USAGE: + python sample_publish_eg_events_to_a_topic_async.py + Set the environment variables with your own values before running the sample: + 1) EG_ACCESS_KEY - The access key of your eventgrid account. + 2) EG_TOPIC_HOSTNAME - The topic hostname. Typically it exists in the format + "https://..eventgrid.azure.net/api/events". +""" +# [START publish_eg_event_to_topic_async] +import os +import asyncio +from azure.eventgrid import EventGridEvent +from azure.eventgrid.aio import EventGridPublisherClient +from azure.core.credentials import AzureKeyCredential + +topic_key = os.environ["EG_ACCESS_KEY"] +endpoint = os.environ["EG_TOPIC_HOSTNAME"] + +async def publish(): + credential = AzureKeyCredential(topic_key) + client = EventGridPublisherClient(endpoint, credential) + + await client.send([ + EventGridEvent( + event_type="Contoso.Items.ItemReceived", + data={ + "itemSku": "Contoso Item SKU #1" + }, + subject="Door1", + data_version="2.0" + ) + ]) +# [END publish_eg_event_to_topic_async] + +if __name__ == '__main__': + loop = asyncio.get_event_loop() + loop.run_until_complete(publish()) diff --git a/sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_publish_events_to_a_topic_using_sas_credential_async.py b/sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_publish_events_to_a_topic_using_sas_credential_async.py new file mode 100644 index 00000000000..35772befd5a --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_publish_events_to_a_topic_using_sas_credential_async.py @@ -0,0 +1,44 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +""" +FILE: sample_publish_events_to_a_topic_using_sas_credential_async.py +DESCRIPTION: + These samples demonstrate sending an EventGrid Event using a shared access signature for authentication. +USAGE: + python sample_publish_events_to_a_topic_using_sas_credential_async.py + Set the environment variables with your own values before running the sample: + 1) EVENTGRID_SAS - The access key of your eventgrid account. + 2) EG_TOPIC_HOSTNAME - The topic hostname. Typically it exists in the format + "https://..eventgrid.azure.net/api/events". +""" +import os +import asyncio +from azure.eventgrid import EventGridEvent +from azure.eventgrid.aio import EventGridPublisherClient +from azure.core.credentials import AzureSasCredential + +sas = os.environ["EVENTGRID_SAS"] +endpoint = os.environ["EG_TOPIC_HOSTNAME"] + +async def publish(): + credential = AzureSasCredential(sas) + client = EventGridPublisherClient(endpoint, credential) + + async with client: + await client.send([ + EventGridEvent( + event_type="Contoso.Items.ItemReceived", + data={ + "itemSku": "Contoso Item SKU #1" + }, + subject="Door1", + data_version="2.0" + ) + ]) + +if __name__ == '__main__': + loop = asyncio.get_event_loop() + loop.run_until_complete(publish()) diff --git a/sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_publish_events_using_cloud_events_1.0_schema_async.py b/sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_publish_events_using_cloud_events_1.0_schema_async.py new file mode 100644 index 00000000000..091feaa40d4 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/samples/async_samples/sample_publish_events_using_cloud_events_1.0_schema_async.py @@ -0,0 +1,45 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +""" +FILE: sample_publish_events_using_cloud_events_1.0_schema_async.py +DESCRIPTION: + These samples demonstrate creating a list of CloudEvents and sending then as a list. +USAGE: + python sample_publish_events_using_cloud_events_1.0_schema_async.py + Set the environment variables with your own values before running the sample: + 1) CLOUD_ACCESS_KEY - The access key of your eventgrid account. + 2) CLOUD_TOPIC_HOSTNAME - The topic hostname. Typically it exists in the format + "https://..eventgrid.azure.net/api/events". +""" +# [START publish_cloud_event_to_topic_async] +import os +import asyncio +from azure.core.messaging import CloudEvent +from azure.eventgrid.aio import EventGridPublisherClient +from azure.core.credentials import AzureKeyCredential + +topic_key = os.environ["CLOUD_ACCESS_KEY"] +endpoint = os.environ["CLOUD_TOPIC_HOSTNAME"] + +async def publish(): + credential = AzureKeyCredential(topic_key) + client = EventGridPublisherClient(endpoint, credential) + + await client.send([ + CloudEvent( + type="Contoso.Items.ItemReceived", + source="/contoso/items", + data={ + "itemSku": "Contoso Item SKU #1" + }, + subject="Door1" + ) + ]) +# [END publish_cloud_event_to_topic_async] + +if __name__ == '__main__': + loop = asyncio.get_event_loop() + loop.run_until_complete(publish()) diff --git a/sdk/eventgrid/azure-eventgrid/samples/consume_samples/consume_cloud_events_from_eventhub.py b/sdk/eventgrid/azure-eventgrid/samples/consume_samples/consume_cloud_events_from_eventhub.py new file mode 100644 index 00000000000..9aee835f0bf --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/samples/consume_samples/consume_cloud_events_from_eventhub.py @@ -0,0 +1,42 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +""" +FILE: consume_cloud_events_from_eventhub.py +DESCRIPTION: + These samples demonstrate receiving events from an Event Hub. +USAGE: + python consume_cloud_events_from_eventhub.py + Set the environment variables with your own values before running the sample: + 1) EVENT_HUB_CONN_STR: The connection string to the Event hub account + 3) EVENTHUB_NAME: The name of the eventhub account +""" + +# Note: This sample would not work on pypy since azure-eventhub +# depends on uamqp which is not pypy compatible. + +import os +import json +from azure.core.messaging import CloudEvent +from azure.eventhub import EventHubConsumerClient + +CONNECTION_STR = os.environ["EVENT_HUB_CONN_STR"] +EVENTHUB_NAME = os.environ["EVENT_HUB_NAME"] +def on_event(partition_context, event): + dict_event = CloudEvent.from_json(event) + print("data: {}\n".format(dict_event.data)) + +consumer_client = EventHubConsumerClient.from_connection_string( + conn_str=CONNECTION_STR, + consumer_group='$Default', + eventhub_name=EVENTHUB_NAME, +) + +with consumer_client: + event_list = consumer_client.receive( + on_event=on_event, + starting_position="-1", # "-1" is from the beginning of the partition. + prefetch=5 + ) diff --git a/sdk/eventgrid/azure-eventgrid/samples/consume_samples/consume_cloud_events_from_storage_queue.py b/sdk/eventgrid/azure-eventgrid/samples/consume_samples/consume_cloud_events_from_storage_queue.py new file mode 100644 index 00000000000..4db27504690 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/samples/consume_samples/consume_cloud_events_from_storage_queue.py @@ -0,0 +1,36 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +""" +FILE: consume_cloud_events_from_storage_queue.py +DESCRIPTION: + These samples demonstrate receiving events from a Storage Queue. +USAGE: + python consume_cloud_events_from_storage_queue.py + Set the environment variables with your own values before running the sample: + 1) STORAGE_QUEUE_CONN_STR: The connection string to the Storage account + 3) STORAGE_QUEUE_NAME: The name of the storage queue. +""" + +from azure.core.messaging import CloudEvent +from azure.storage.queue import QueueServiceClient, BinaryBase64DecodePolicy +import os +import json + +# all types of CloudEvents below produce same DeserializedEvent +connection_str = os.environ['AZURE_STORAGE_CONNECTION_STRING'] +queue_name = os.environ['STORAGE_QUEUE_NAME'] + +with QueueServiceClient.from_connection_string(connection_str) as qsc: + payload = qsc.get_queue_client( + queue=queue_name, + message_decode_policy=BinaryBase64DecodePolicy() + ).peek_messages(max_messages=32) + + ## deserialize payload into a list of typed Events + events = [CloudEvent.from_json(msg) for msg in payload] + + for event in events: + print(type(event)) ## CloudEvent diff --git a/sdk/eventgrid/azure-eventgrid/samples/consume_samples/consume_eventgrid_events_from_service_bus_queue.py b/sdk/eventgrid/azure-eventgrid/samples/consume_samples/consume_eventgrid_events_from_service_bus_queue.py new file mode 100644 index 00000000000..9889ea87c11 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/samples/consume_samples/consume_eventgrid_events_from_service_bus_queue.py @@ -0,0 +1,36 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +""" +FILE: consume_cloud_events_from_service_bus_queue.py +DESCRIPTION: + These samples demonstrate receiving events from Service Bus. +USAGE: + python consume_cloud_events_from_service_bus_queue.py + Set the environment variables with your own values before running the sample: + 1) SB_CONN_STR: The connection string to the Service Bus account + 3) SERVICE_BUS_QUEUE_NAME: The name of the servicebus account +""" + +# Note: This sample would not work on pypy since azure-servicebus +# depends on uamqp which is not pypy compatible. + +from azure.eventgrid import EventGridEvent +from azure.servicebus import ServiceBusClient +import os +import json + +# all types of EventGridEvents below produce same DeserializedEvent +connection_str = os.environ['SERVICE_BUS_CONNECTION_STR'] +queue_name = os.environ['SERVICE_BUS_QUEUE_NAME'] + +with ServiceBusClient.from_connection_string(connection_str) as sb_client: + payload = sb_client.get_queue_receiver(queue_name).receive_messages() + + ## deserialize payload into a list of typed Events + events = [EventGridEvent.from_json(msg) for msg in payload] + + for event in events: + print(type(event)) ## EventGridEvent diff --git a/sdk/eventgrid/azure-eventgrid/samples/consume_samples/functionsapp/.funcignore b/sdk/eventgrid/azure-eventgrid/samples/consume_samples/functionsapp/.funcignore new file mode 100644 index 00000000000..0678ea2b227 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/samples/consume_samples/functionsapp/.funcignore @@ -0,0 +1,5 @@ +.git* +.vscode +local.settings.json +test +.venv \ No newline at end of file diff --git a/sdk/eventgrid/azure-eventgrid/samples/consume_samples/functionsapp/.gitignore b/sdk/eventgrid/azure-eventgrid/samples/consume_samples/functionsapp/.gitignore new file mode 100644 index 00000000000..a10127be5c9 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/samples/consume_samples/functionsapp/.gitignore @@ -0,0 +1,130 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don’t work, or not +# install all needed dependencies. +#Pipfile.lock + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# Azure Functions artifacts +bin +obj +appsettings.json +local.settings.json +.python_packages \ No newline at end of file diff --git a/sdk/eventgrid/azure-eventgrid/samples/consume_samples/functionsapp/EventGridTrigger1/__init__.py b/sdk/eventgrid/azure-eventgrid/samples/consume_samples/functionsapp/EventGridTrigger1/__init__.py new file mode 100644 index 00000000000..b7a38ab6b5b --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/samples/consume_samples/functionsapp/EventGridTrigger1/__init__.py @@ -0,0 +1,21 @@ +import json +import logging +import sys + +import azure.functions as func +from azure.eventgrid import EventGridEvent + +def main(event: func.EventGridEvent): + logging.info(sys.version) + logging.info(event) + result = json.dumps({ + 'id': event.id, + 'data': event.get_json(), + 'topic': event.topic, + 'subject': event.subject, + 'event_type': event.event_type + }) + logging.info(result) + deserialized_event = EventGridEvent.from_dict(json.loads(result)) + ## can only be EventGridEvent + print("event: {}".format(event)) diff --git a/sdk/eventgrid/azure-eventgrid/samples/consume_samples/functionsapp/EventGridTrigger1/function.json b/sdk/eventgrid/azure-eventgrid/samples/consume_samples/functionsapp/EventGridTrigger1/function.json new file mode 100644 index 00000000000..e2764c7fdba --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/samples/consume_samples/functionsapp/EventGridTrigger1/function.json @@ -0,0 +1,10 @@ +{ + "scriptFile": "__init__.py", + "bindings": [ + { + "type": "eventGridTrigger", + "name": "event", + "direction": "in" + } + ] +} diff --git a/sdk/eventgrid/azure-eventgrid/samples/consume_samples/functionsapp/EventGridTrigger1/host.json b/sdk/eventgrid/azure-eventgrid/samples/consume_samples/functionsapp/EventGridTrigger1/host.json new file mode 100644 index 00000000000..8f3cf9db3fb --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/samples/consume_samples/functionsapp/EventGridTrigger1/host.json @@ -0,0 +1,7 @@ +{ + "version": "2.0", + "extensionBundle": { + "id": "Microsoft.Azure.Functions.ExtensionBundle", + "version": "[1.*, 2.0.0)" + } +} \ No newline at end of file diff --git a/sdk/eventgrid/azure-eventgrid/samples/consume_samples/functionsapp/EventGridTrigger1/sample.dat b/sdk/eventgrid/azure-eventgrid/samples/consume_samples/functionsapp/EventGridTrigger1/sample.dat new file mode 100644 index 00000000000..5e172b50e0d --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/samples/consume_samples/functionsapp/EventGridTrigger1/sample.dat @@ -0,0 +1,20 @@ +{ + 'topic': '/subscriptions/5b4b650e-28b9-4790-b3ab-ddbd88d727c4/resourcegroups/test/providers/Microsoft.EventHub/namespaces/test', + 'subject': 'eventhubs/test', + 'eventType': 'captureFileCreated', + 'eventTime': '2017-07-14T23:10:27.7689666Z', + 'id': '7b11c4ce-1c34-4416-848b-1730e766f126', + 'data': { + 'fileUrl': 'https://test.blob.core.windows.net/debugging/testblob.txt', + 'fileType': 'AzureBlockBlob', + 'partitionId': '1', + 'sizeInBytes': 0, + 'eventCount': 0, + 'firstSequenceNumber': -1, + 'lastSequenceNumber': -1, + 'firstEnqueueTime': '0001-01-01T00:00:00', + 'lastEnqueueTime': '0001-01-01T00:00:00' + }, + "dataVersion": "", + "metadataVersion": "1" +} diff --git a/sdk/eventgrid/azure-eventgrid/samples/consume_samples/functionsapp/host.json b/sdk/eventgrid/azure-eventgrid/samples/consume_samples/functionsapp/host.json new file mode 100644 index 00000000000..6ab664374ff --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/samples/consume_samples/functionsapp/host.json @@ -0,0 +1,15 @@ +{ + "version": "2.0", + "logging": { + "applicationInsights": { + "samplingSettings": { + "isEnabled": true, + "excludedTypes": "Request" + } + } + }, + "extensionBundle": { + "id": "Microsoft.Azure.Functions.ExtensionBundle", + "version": "[1.*, 2.0.0)" + } +} diff --git a/sdk/eventgrid/azure-eventgrid/samples/consume_samples/functionsapp/proxies.json b/sdk/eventgrid/azure-eventgrid/samples/consume_samples/functionsapp/proxies.json new file mode 100644 index 00000000000..b385252f5ed --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/samples/consume_samples/functionsapp/proxies.json @@ -0,0 +1,4 @@ +{ + "$schema": "http://json.schemastore.org/proxies", + "proxies": {} +} diff --git a/sdk/eventgrid/azure-eventgrid/samples/consume_samples/functionsapp/requirements.txt b/sdk/eventgrid/azure-eventgrid/samples/consume_samples/functionsapp/requirements.txt new file mode 100644 index 00000000000..75db2c4f60f --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/samples/consume_samples/functionsapp/requirements.txt @@ -0,0 +1 @@ +azure-functions diff --git a/sdk/eventgrid/azure-eventgrid/samples/publish_samples/publish_cloud_events_to_custom_topic_sample.py b/sdk/eventgrid/azure-eventgrid/samples/publish_samples/publish_cloud_events_to_custom_topic_sample.py new file mode 100644 index 00000000000..a54148f9202 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/samples/publish_samples/publish_cloud_events_to_custom_topic_sample.py @@ -0,0 +1,56 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +""" +FILE: publish_cloud_events_to_custom_topic_sample.py +DESCRIPTION: + These samples demonstrate creating a list of CloudEvents and sending them as a list + to a custom topic. +USAGE: + python publish_cloud_events_to_custom_topic_sample.py + Set the environment variables with your own values before running the sample: + 1) CLOUD_ACCESS_KEY - The access key of your eventgrid account. + 2) CLOUD_TOPIC_HOSTNAME - The topic hostname. Typically it exists in the format + "https://..eventgrid.azure.net/api/events". +""" +import os +from random import randint, sample +import time + +from azure.core.credentials import AzureKeyCredential +from azure.core.messaging import CloudEvent +from azure.eventgrid import EventGridPublisherClient + +key = os.environ.get("CLOUD_ACCESS_KEY") +endpoint = os.environ["CLOUD_TOPIC_HOSTNAME"] + +# authenticate client +credential = AzureKeyCredential(key) +client = EventGridPublisherClient(endpoint, credential) + +services = ["EventGrid", "ServiceBus", "EventHubs", "Storage"] # possible values for data field + +def publish_event(): + # publish events + for _ in range(3): + event_list = [] # list of events to publish + # create events and append to list + for j in range(randint(1, 1)): + sample_members = sample(services, k=randint(1, 4)) # select random subset of team members + data_dict = {"team": sample_members} + event = CloudEvent( + type="Azure.Sdk.Sample", + source="https://egsample.dev/sampleevent", + data={"team": sample_members} + ) + event_list.append(event) + + # publish list of events + client.send(event_list) + print("Batch of size {} published".format(len(event_list))) + time.sleep(randint(1, 5)) + +if __name__ == "__main__": + publish_event() diff --git a/sdk/eventgrid/azure-eventgrid/samples/publish_samples/publish_cloud_events_to_domain_topic_sample.py b/sdk/eventgrid/azure-eventgrid/samples/publish_samples/publish_cloud_events_to_domain_topic_sample.py new file mode 100644 index 00000000000..a1015971df9 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/samples/publish_samples/publish_cloud_events_to_domain_topic_sample.py @@ -0,0 +1,58 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +""" +FILE: publish_cloud_events_to_domain_topic_sample.py +DESCRIPTION: + These samples demonstrate creating a list of CloudEvents and sending them as a list + to a domain topic. +USAGE: + python publish_cloud_events_to_domain_topic_sample.py + Set the environment variables with your own values before running the sample: + 1) DOMAIN_ACCESS_KEY - The access key of your eventgrid account. + 2) DOMAIN_TOPIC_HOSTNAME - The topic hostname. Typically it exists in the format + "https://..eventgrid.azure.net/api/events". +""" +import sys +import os +from random import randint, sample +import time + +from azure.core.credentials import AzureKeyCredential +from azure.core.messaging import CloudEvent +from azure.eventgrid import EventGridPublisherClient + +domain_key = os.environ["DOMAIN_ACCESS_KEY"] +domain_endpoint = os.environ["DOMAIN_TOPIC_HOSTNAME"] + + +# authenticate client +credential = AzureKeyCredential(domain_key) +client = EventGridPublisherClient(domain_endpoint, credential) + +def publish_event(): + # publish events + for _ in range(3): + + event_list = [] # list of events to publish + services = ["EventGrid", "ServiceBus", "EventHubs", "Storage"] # possible values for data field + + # create events and append to list + for j in range(randint(1, 3)): + sample_members = sample(services, k=randint(1, 4)) # select random subset of team members + event = CloudEvent( + type="Azure.Sdk.Demo", + source='/demo/domain_name', + data={"team": sample_members} + ) + event_list.append(event) + + # publish list of events + client.send(event_list) + print("Batch of size {} published".format(len(event_list))) + time.sleep(randint(1, 5)) + +if __name__ == '__main__': + publish_event() diff --git a/sdk/eventgrid/azure-eventgrid/samples/publish_samples/publish_custom_schema_events_to_topic_sample.py b/sdk/eventgrid/azure-eventgrid/samples/publish_samples/publish_custom_schema_events_to_topic_sample.py new file mode 100644 index 00000000000..002cbaa86d4 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/samples/publish_samples/publish_custom_schema_events_to_topic_sample.py @@ -0,0 +1,59 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +""" +FILE: publish_custom_schema_events_to_topic_sample.py +DESCRIPTION: + These samples demonstrate creating a list of Custom Events and sending them as a list. +USAGE: + python publish_custom_schema_events_to_topic_sample.py + Set the environment variables with your own values before running the sample: + 1) CUSTOM_SCHEMA_ACCESS_KEY - The access key of your eventgrid account. + 2) CUSTOM_SCHEMA_TOPIC_HOSTNAME - The topic hostname. Typically it exists in the format + "https://..eventgrid.azure.net/api/events". +""" +import os +from random import randint, sample +import time +import uuid +from msrest.serialization import UTC +import datetime as dt + +from azure.core.credentials import AzureKeyCredential +from azure.eventgrid import EventGridPublisherClient + +key = os.environ["CUSTOM_SCHEMA_ACCESS_KEY"] +endpoint = os.environ["CUSTOM_SCHEMA_TOPIC_HOSTNAME"] + +def publish_event(): + # authenticate client + credential = AzureKeyCredential(key) + client = EventGridPublisherClient(endpoint, credential) + + custom_schema_event = { + "customSubject": "sample", + "customEventType": "sample.event", + "customDataVersion": "2.0", + "customId": uuid.uuid4(), + "customEventTime": dt.datetime.now(UTC()).isoformat(), + "customData": "sample data" + } + + # publish events + for _ in range(3): + + event_list = [] # list of events to publish + # create events and append to list + for j in range(randint(1, 3)): + event_list.append(custom_schema_event) + + # publish list of events + client.send(event_list) + print("Batch of size {} published".format(len(event_list))) + time.sleep(randint(1, 5)) + + +if __name__ == '__main__': + publish_event() diff --git a/sdk/eventgrid/azure-eventgrid/samples/publish_samples/publish_event_grid_events_to_custom_topic_sample.py b/sdk/eventgrid/azure-eventgrid/samples/publish_samples/publish_event_grid_events_to_custom_topic_sample.py new file mode 100644 index 00000000000..e8a92097a02 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/samples/publish_samples/publish_event_grid_events_to_custom_topic_sample.py @@ -0,0 +1,55 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +""" +FILE: publish_event_grid_events_to_custom_topic_sample.py +DESCRIPTION: + These samples demonstrate creating a list of Eventgrid Events and sending them as a list + to custom topic. +USAGE: + python publish_event_grid_events_to_custom_topic_sample.py + Set the environment variables with your own values before running the sample: + 1) EG_ACCESS_KEY - The access key of your eventgrid account. + 2) EG_TOPIC_HOSTNAME - The topic hostname. Typically it exists in the format + "https://..eventgrid.azure.net/api/events". +""" +import os +from random import randint, sample +import time + +from azure.core.credentials import AzureKeyCredential +from azure.eventgrid import EventGridPublisherClient, EventGridEvent + +key = os.environ["EG_ACCESS_KEY"] +endpoint = os.environ["EG_TOPIC_HOSTNAME"] + +# authenticate client +credential = AzureKeyCredential(key) +client = EventGridPublisherClient(endpoint, credential) +services = ["EventGrid", "ServiceBus", "EventHubs", "Storage"] # possible values for data field + +def publish_event(): + # publish events + for _ in range(3): + + event_list = [] # list of events to publish + # create events and append to list + for j in range(randint(1, 3)): + sample_members = sample(services, k=randint(1, 4)) # select random subset of team members + event = EventGridEvent( + subject="Door1", + data={"team": sample_members}, + event_type="Azure.Sdk.Demo", + data_version="2.0" + ) + event_list.append(event) + + # publish list of events + client.send(event_list) + print("Batch of size {} published".format(len(event_list))) + time.sleep(randint(1, 5)) + +if __name__ == '__main__': + publish_event() diff --git a/sdk/eventgrid/azure-eventgrid/samples/publish_samples/publish_with_shared_access_signature_sample.py b/sdk/eventgrid/azure-eventgrid/samples/publish_samples/publish_with_shared_access_signature_sample.py new file mode 100644 index 00000000000..969ed44236c --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/samples/publish_samples/publish_with_shared_access_signature_sample.py @@ -0,0 +1,60 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +""" +FILE: publish_with_shared_access_signature_sample.py +DESCRIPTION: + These samples demonstrate creating a list of CloudEvents and publish them + using the shared access signature for authentication. +USAGE: + python publish_with_shared_access_signature_sample.py + Set the environment variables with your own values before running the sample: + 1) CLOUD_ACCESS_KEY - The access key of your eventgrid account. + 2) CLOUD_TOPIC_HOSTNAME - The topic hostname. Typically it exists in the format + "https://..eventgrid.azure.net/api/events". +""" +import os +from random import randint, sample +import time + +from datetime import datetime, timedelta +from azure.core.credentials import AzureSasCredential +from azure.core.messaging import CloudEvent +from azure.eventgrid import EventGridPublisherClient, generate_sas + +key = os.environ["CLOUD_ACCESS_KEY"] +endpoint = os.environ["CLOUD_TOPIC_HOSTNAME"] +expiration_date_utc = datetime.utcnow() + timedelta(hours=1) + +signature = generate_sas(endpoint, key, expiration_date_utc) + +# authenticate client +credential = AzureSasCredential(signature) +client = EventGridPublisherClient(endpoint, credential) + +services = ["EventGrid", "ServiceBus", "EventHubs", "Storage"] # possible values for data field + +def publish_event(): + # publish events + for _ in range(3): + + event_list = [] # list of events to publish + # create events and append to list + for j in range(randint(1, 3)): + sample_members = sample(services, k=randint(1, 4)) # select random subset of team members + event = CloudEvent( + type="Azure.Sdk.Demo", + source="https://egdemo.dev/demowithsignature", + data={"team": sample_members} + ) + event_list.append(event) + + # publish list of events + client.send(event_list) + print("Batch of size {} published".format(len(event_list))) + time.sleep(randint(1, 5)) + +if __name__ == '__main__': + publish_event() diff --git a/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_authentication.py b/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_authentication.py new file mode 100644 index 00000000000..108f4f3010e --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_authentication.py @@ -0,0 +1,49 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +""" +FILE: sample_authentication.py +DESCRIPTION: + These samples demonstrate authenticating an EventGridPublisherClient. +USAGE: + python sample_authentication.py + Set the environment variables with your own values before running the sample: + 1) EG_ACCESS_KEY - The access key of your eventgrid account. + 2) EG_TOPIC_HOSTNAME - The topic hostname. Typically it exists in the format + "https://..eventgrid.azure.net/api/events". + 3) EVENTGRID_SAS - The shared access signature that is to be used to authenticate the client. +""" +# [START client_auth_with_key_cred] +import os +from azure.eventgrid import EventGridPublisherClient +from azure.core.credentials import AzureKeyCredential + +topic_key = os.environ["EG_ACCESS_KEY"] +endpoint = os.environ["EG_TOPIC_HOSTNAME"] + +credential = AzureKeyCredential(topic_key) +client = EventGridPublisherClient(endpoint, credential) +# [END client_auth_with_key_cred] + +# [START client_auth_with_sas_cred] +import os +from azure.eventgrid import EventGridPublisherClient +from azure.core.credentials import AzureSasCredential + +signature = os.environ["EVENTGRID_SAS"] +endpoint = os.environ["EG_TOPIC_HOSTNAME"] + +credential = AzureSasCredential(signature) +client = EventGridPublisherClient(endpoint, credential) +# [END client_auth_with_sas_cred] + +# [START client_auth_with_token_cred] +from azure.identity import DefaultAzureCredential +from azure.eventgrid import EventGridPublisherClient, EventGridEvent + +credential = DefaultAzureCredential() +endpoint = os.environ["EG_TOPIC_HOSTNAME"] +client = EventGridPublisherClient(endpoint, credential) +# [END client_auth_with_token_cred] \ No newline at end of file diff --git a/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_consume_custom_payload.py b/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_consume_custom_payload.py new file mode 100644 index 00000000000..b9559e94ffd --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_consume_custom_payload.py @@ -0,0 +1,34 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +""" +FILE: sample_consume_custom_payload.py +DESCRIPTION: + These samples demonstrate consuming a raw json with a list of jsons and + deserializing them into typed objects of CloudEvents. +USAGE: + python sample_consume_custom_payload.py +""" + +from azure.core.messaging import CloudEvent +import json + +# all types of CloudEvents below produce same DeserializedEvent +cloud_custom_dict = """[{ + "id":"de0fd76c-4ef4-4dfb-ab3a-8f24a307e033", + "source":"https://egtest.dev/cloudcustomevent", + "data":{ + "team": "event grid squad" + }, + "type":"Azure.Sdk.Sample", + "time":"2020-08-07T02:06:08.11969Z", + "specversion":"1.0" +}]""" + +deserialized_dict_events = [CloudEvent(**msg) for msg in json.loads(cloud_custom_dict)] + +for event in deserialized_dict_events: + print(event.data) + print(type(event)) diff --git a/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_generate_sas.py b/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_generate_sas.py new file mode 100644 index 00000000000..4cfb195b556 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_generate_sas.py @@ -0,0 +1,32 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +""" +FILE: sample_generate_sas.py +DESCRIPTION: + These samples demonstrate creating a shared access signature for eventgrid. +USAGE: + python sample_generate_sas.py + Set the environment variables with your own values before running the sample: + 1) EG_ACCESS_KEY - The access key of your eventgrid account. + 2) EG_TOPIC_HOSTNAME - The topic hostname. Typically it exists in the format + "https://..eventgrid.azure.net/api/events". +""" +# [START generate_sas] +import os +from azure.eventgrid import generate_sas +from datetime import datetime, timedelta + +topic_key = os.environ["EG_ACCESS_KEY"] +endpoint = os.environ["EG_TOPIC_HOSTNAME"] + +#represents the expiration date for sas +expiration_date_utc = datetime.utcnow() + timedelta(hours=10) + +signature = generate_sas(endpoint, topic_key, expiration_date_utc) + +# [END generate_sas] + +print(signature) \ No newline at end of file diff --git a/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_cloud_event_using_dict.py b/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_cloud_event_using_dict.py new file mode 100644 index 00000000000..7087c4f7b90 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_cloud_event_using_dict.py @@ -0,0 +1,41 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +""" +FILE: sample_publish_cloud_event_using_dict.py +DESCRIPTION: + These samples demonstrate creating a list of CloudEvents using dict representations + and sending them as a list. +USAGE: + python sample_publish_cloud_event_using_dict.py + Set the environment variables with your own values before running the sample: + 1) CLOUD_ACCESS_KEY - The access key of your eventgrid account. + 2) CLOUD_TOPIC_HOSTNAME - The topic hostname. Typically it exists in the format + "https://..eventgrid.azure.net/api/events". +""" +import os +from azure.eventgrid import EventGridPublisherClient +from azure.core.credentials import AzureKeyCredential + +topic_key = os.environ["CLOUD_ACCESS_KEY"] +endpoint = os.environ["CLOUD_TOPIC_HOSTNAME"] + +credential = AzureKeyCredential(topic_key) +client = EventGridPublisherClient(endpoint, credential) + +# [START publish_cloud_event_dict] +client.send([ + { + "type": "Contoso.Items.ItemReceived", + "source": "/contoso/items", + "data": { + "itemSku": "Contoso Item SKU #1" + }, + "subject": "Door1", + "specversion": "1.0", + "id": "randomclouduuid11" + } +]) +# [END publish_cloud_event_dict] diff --git a/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_custom_schema_to_a_topic.py b/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_custom_schema_to_a_topic.py new file mode 100644 index 00000000000..1fc5028edf4 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_custom_schema_to_a_topic.py @@ -0,0 +1,49 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +""" +FILE: sample_publish_custom_schema_to_a_topic.py +DESCRIPTION: + These samples demonstrate creating a list of Custom Events and sending them as a list. +USAGE: + python sample_publish_custom_schema_to_a_topic.py + Set the environment variables with your own values before running the sample: + 1) CUSTOM_SCHEMA_ACCESS_KEY - The access key of your eventgrid account. + 2) CUSTOM_SCHEMA_TOPIC_HOSTNAME - The topic hostname. Typically it exists in the format + "https://..eventgrid.azure.net/api/events". +""" +import os +from random import randint +import time +import uuid +from msrest.serialization import UTC +import datetime as dt + +from azure.core.credentials import AzureKeyCredential +from azure.eventgrid import EventGridPublisherClient + +key = os.environ["CUSTOM_SCHEMA_ACCESS_KEY"] +endpoint = os.environ["CUSTOM_SCHEMA_TOPIC_HOSTNAME"] + +def publish_event(): + # authenticate client + credential = AzureKeyCredential(key) + client = EventGridPublisherClient(endpoint, credential) + + # [START publish_custom_schema] + custom_schema_event = { + "customSubject": "sample", + "customEventType": "sample.event", + "customDataVersion": "2.0", + "customId": uuid.uuid4(), + "customEventTime": dt.datetime.now(UTC()).isoformat(), + "customData": "sample data" + } + + client.send(custom_schema_event) + # [END publish_custom_schema] + +if __name__ == '__main__': + publish_event() diff --git a/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_eg_event_using_dict.py b/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_eg_event_using_dict.py new file mode 100644 index 00000000000..31b6ca14441 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_eg_event_using_dict.py @@ -0,0 +1,57 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +""" +FILE: sample_publish_eg_event_using_dict.py +DESCRIPTION: + These samples demonstrate sending an EventGrid Event as a dict representation + directly to a topic. The dict representation should be that of the serialized + model of EventGridEvent. +USAGE: + python sample_publish_eg_event_using_dict.py + Set the environment variables with your own values before running the sample: + 1) EG_ACCESS_KEY - The access key of your eventgrid account. + 2) EG_TOPIC_HOSTNAME - The topic hostname. Typically it exists in the format + "https://..eventgrid.azure.net/api/events". +""" +import os +from datetime import datetime +from msrest.serialization import UTC +from azure.eventgrid import EventGridPublisherClient, EventGridEvent +from azure.core.credentials import AzureKeyCredential + +topic_key = os.environ["EG_ACCESS_KEY"] +endpoint = os.environ["EG_TOPIC_HOSTNAME"] + +def publish(): + # [START publish_eg_event_dict] + credential = AzureKeyCredential(topic_key) + client = EventGridPublisherClient(endpoint, credential) + + event0 = { + "eventType": "Contoso.Items.ItemReceived", + "data": { + "itemSku": "Contoso Item SKU #1" + }, + "subject": "Door1", + "dataVersion": "2.0", + "id": "randomuuid11", + "eventTime": datetime.now(UTC()) + } + event1 = { + "eventType": "Contoso.Items.ItemReceived", + "data": { + "itemSku": "Contoso Item SKU #2" + }, + "subject": "Door1", + "dataVersion": "2.0", + "id": "randomuuid12", + "eventTime": datetime.now(UTC()) + } + client.send([event0, event1]) + # [END publish_eg_event_dict] + +if __name__ == '__main__': + publish() diff --git a/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_eg_events_to_a_domain.py b/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_eg_events_to_a_domain.py new file mode 100644 index 00000000000..12c029dcae8 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_eg_events_to_a_domain.py @@ -0,0 +1,46 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +""" +FILE: sample_publish_eg_events_to_a_domain.py +DESCRIPTION: + These samples demonstrate creating a list of EventGrid Events and sending them as a list to a topic in a domain. +USAGE: + python sample_publish_eg_events_to_a_domain.py + Set the environment variables with your own values before running the sample: + 1) EG_ACCESS_KEY - The access key of your eventgrid account. + 2) EG_TOPIC_HOSTNAME - The topic hostname. Typically it exists in the format + "https://..eventgrid.azure.net/api/events". +""" +import os +from azure.eventgrid import EventGridPublisherClient, EventGridEvent +from azure.core.credentials import AzureKeyCredential + +domain_key = os.environ["EG_DOMAIN_ACCESS_KEY"] +domain_hostname = os.environ["EG_DOMAIN_TOPIC_HOSTNAME"] + +credential = AzureKeyCredential(domain_key) +client = EventGridPublisherClient(domain_hostname, credential) + +client.send([ + EventGridEvent( + topic="MyCustomDomainTopic1", + event_type="Contoso.Items.ItemReceived", + data={ + "itemSku": "Contoso Item SKU #1" + }, + subject="Door1", + data_version="2.0" + ), + EventGridEvent( + topic="MyCustomDomainTopic2", + event_type="Contoso.Items.ItemReceived", + data={ + "itemSku": "Contoso Item SKU #2" + }, + subject="Door1", + data_version="2.0" + ) +]) diff --git a/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_eg_events_to_a_topic.py b/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_eg_events_to_a_topic.py new file mode 100644 index 00000000000..a0c02df2b09 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_eg_events_to_a_topic.py @@ -0,0 +1,38 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +""" +FILE: sample_publish_eg_events_to_a_topic.py +DESCRIPTION: + These samples demonstrate sending an EventGrid Event directly to a topic. +USAGE: + python sample_publish_eg_events_to_a_topic.py + Set the environment variables with your own values before running the sample: + 1) EG_ACCESS_KEY - The access key of your eventgrid account. + 2) EG_TOPIC_HOSTNAME - The topic hostname. Typically it exists in the format + "https://..eventgrid.azure.net/api/events". +""" +# [START publish_eg_event_to_topic] +import os +from azure.eventgrid import EventGridPublisherClient, EventGridEvent +from azure.core.credentials import AzureKeyCredential + +topic_key = os.environ["EG_ACCESS_KEY"] +endpoint = os.environ["EG_TOPIC_HOSTNAME"] + +credential = AzureKeyCredential(topic_key) +client = EventGridPublisherClient(endpoint, credential) + +client.send([ + EventGridEvent( + event_type="Contoso.Items.ItemReceived", + data={ + "itemSku": "Contoso Item SKU #1" + }, + subject="Door1", + data_version="2.0" + ) +]) +# [END publish_eg_event_to_topic] diff --git a/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_events_to_a_topic_using_sas_credential.py b/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_events_to_a_topic_using_sas_credential.py new file mode 100644 index 00000000000..45a4b1a5da6 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_events_to_a_topic_using_sas_credential.py @@ -0,0 +1,37 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +""" +FILE: sample_publish_events_to_a_topic_using_sas_credential.py +DESCRIPTION: + These samples demonstrate sending an EventGrid Event using a shared access signature for authentication. +USAGE: + python sample_publish_events_to_a_topic_using_sas_credential.py + Set the environment variables with your own values before running the sample: + 1) EVENTGRID_SAS - The shared access signature to use Event Grid. This is typically given to you + after creating it using the `generate_sas` method. + 2) EG_TOPIC_HOSTNAME - The topic hostname. Typically it exists in the format + "https://..eventgrid.azure.net/api/events". +""" +import os +from azure.eventgrid import EventGridPublisherClient, EventGridEvent, generate_sas +from azure.core.credentials import AzureKeyCredential, AzureSasCredential + +sas = os.environ["EVENTGRID_SAS"] +endpoint = os.environ["EG_TOPIC_HOSTNAME"] + +credential = AzureSasCredential(sas) +client = EventGridPublisherClient(endpoint, credential) + +client.send([ + EventGridEvent( + event_type="Contoso.Items.ItemReceived", + data={ + "itemSku": "Contoso Item SKU #1" + }, + subject="Door1", + data_version="2.0" + ) +]) diff --git a/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_events_using_cloud_events_1.0_schema.py b/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_events_using_cloud_events_1.0_schema.py new file mode 100644 index 00000000000..a366655721e --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/samples/sync_samples/sample_publish_events_using_cloud_events_1.0_schema.py @@ -0,0 +1,39 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +""" +FILE: sample_publish_events_using_cloud_events_1.0_schema.py +DESCRIPTION: + These samples demonstrate creating a list of CloudEvents and sending then as a list. +USAGE: + python sample_publish_events_using_cloud_events_1.0_schema.py + Set the environment variables with your own values before running the sample: + 1) CLOUD_ACCESS_KEY - The access key of your eventgrid account. + 2) CLOUD_TOPIC_HOSTNAME - The topic hostname. Typically it exists in the format + "https://..eventgrid.azure.net/api/events". +""" +# [START publish_cloud_event_to_topic] +import os +from azure.eventgrid import EventGridPublisherClient +from azure.core.credentials import AzureKeyCredential +from azure.core.messaging import CloudEvent + +topic_key = os.environ["CLOUD_ACCESS_KEY"] +endpoint = os.environ["CLOUD_TOPIC_HOSTNAME"] + +credential = AzureKeyCredential(topic_key) +client = EventGridPublisherClient(endpoint, credential) + +client.send([ + CloudEvent( + type="Contoso.Items.ItemReceived", + source="/contoso/items", + data={ + "itemSku": "Contoso Item SKU #1" + }, + subject="Door1" + ) +]) +# [END publish_cloud_event_to_topic] diff --git a/sdk/eventgrid/azure-eventgrid/sdk_packaging.toml b/sdk/eventgrid/azure-eventgrid/sdk_packaging.toml new file mode 100644 index 00000000000..1e819554563 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/sdk_packaging.toml @@ -0,0 +1,7 @@ +[packaging] +auto_update = false +package_name = "azure-eventgrid" +package_pprint_name = "Event Grid" +package_doc_id = "event-grid" +is_stable = false +is_arm = false diff --git a/sdk/eventgrid/azure-eventgrid/setup.cfg b/sdk/eventgrid/azure-eventgrid/setup.cfg new file mode 100644 index 00000000000..3c6e79cf31d --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/setup.cfg @@ -0,0 +1,2 @@ +[bdist_wheel] +universal=1 diff --git a/sdk/eventgrid/azure-eventgrid/setup.py b/sdk/eventgrid/azure-eventgrid/setup.py new file mode 100644 index 00000000000..dede80b02c5 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/setup.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python + +#------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +#-------------------------------------------------------------------------- + +import re +import os.path +from io import open +from setuptools import find_packages, setup + +# Change the PACKAGE_NAME only to change folder and different name +PACKAGE_NAME = "azure-eventgrid" +PACKAGE_PPRINT_NAME = "Event Grid" + +# a-b-c => a/b/c +package_folder_path = PACKAGE_NAME.replace('-', '/') +# a-b-c => a.b.c +namespace_name = PACKAGE_NAME.replace('-', '.') + +# azure v0.x is not compatible with this package +# azure v0.x used to have a __version__ attribute (newer versions don't) +try: + import azure + try: + ver = azure.__version__ + raise Exception( + 'This package is incompatible with azure=={}. '.format(ver) + + 'Uninstall it with "pip uninstall azure".' + ) + except AttributeError: + pass +except ImportError: + pass + +# Version extraction inspired from 'requests' +with open(os.path.join(package_folder_path, 'version.py') + if os.path.exists(os.path.join(package_folder_path, 'version.py')) + else os.path.join(package_folder_path, '_version.py'), 'r') as fd: + version = re.search(r'^VERSION\s*=\s*[\'"]([^\'"]*)[\'"]', + fd.read(), re.MULTILINE).group(1) + +if not version: + raise RuntimeError('Cannot find version information') + +with open('README.md', encoding='utf-8') as f: + readme = f.read() +with open('CHANGELOG.md', encoding='utf-8') as f: + changelog = f.read() + +setup( + name=PACKAGE_NAME, + version=version, + include_package_data=True, + description='Microsoft Azure {} Client Library for Python'.format(PACKAGE_PPRINT_NAME), + long_description=readme + '\n\n' + changelog, + long_description_content_type='text/markdown', + license='MIT License', + author='Microsoft Corporation', + author_email='azpysdkhelp@microsoft.com', + url='https://github.com/Azure/azure-sdk-for-python', + classifiers=[ + "Development Status :: 5 - Production/Stable", + 'Programming Language :: Python', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', + 'License :: OSI Approved :: MIT License', + ], + zip_safe=False, + packages=find_packages(exclude=[ + 'tests', + 'samples', + # Exclude packages that will be covered by PEP420 or nspkg + 'azure', + ]), + install_requires=[ + 'msrest>=0.6.21', + 'azure-core<2.0.0,>=1.18.0', + ], + extras_require={ + ":python_version<'3.0'": ['azure-nspkg'], + } +) diff --git a/sdk/eventgrid/azure-eventgrid/swagger/README.PYTHON_T2.md b/sdk/eventgrid/azure-eventgrid/swagger/README.PYTHON_T2.md new file mode 100644 index 00000000000..b77bacef576 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/swagger/README.PYTHON_T2.md @@ -0,0 +1,24 @@ +# Azure EventGrid Client for Python + +> see https://aka.ms/autorest + +### Configuration + +```yaml +title: EventGridPublisherClient +description: EventGrid Python Publisher Client +generated-metadata: false +license-header: MICROSOFT_MIT_NO_VERSION +no-namespace-folders: true +low-level-client: true +show-operations: false +models: msrest +output-folder: ../azure/eventgrid/_generated +source-code-folder-path: ./azure/eventgrid/_generated +input-file: + - https://github.com/Azure/azure-rest-api-specs/blob/master/specification/eventgrid/data-plane/Microsoft.EventGrid/stable/2018-01-01/EventGrid.json + +python: true +v3: true +use: "@autorest/python@5.6.4" +``` \ No newline at end of file diff --git a/sdk/eventgrid/azure-eventgrid/swagger/postprocess_eventnames.py b/sdk/eventgrid/azure-eventgrid/swagger/postprocess_eventnames.py new file mode 100644 index 00000000000..15b0bc4b171 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/swagger/postprocess_eventnames.py @@ -0,0 +1,56 @@ +import inspect +import re +import warnings +import sys +from azure.eventgrid._generated import models + +backward_compat = { + 'AcsChatMemberAddedToThreadWithUserEventName': "Microsoft.Communication.ChatMemberAddedToThreadWithUser", + 'ResourceWriteFailureEventName': "Microsoft.Resources.ResourceWriteFailure", + 'IoTHubDeviceDeletedEventName': "Microsoft.Devices.DeviceDeleted", + 'IoTHubDeviceDisconnectedEventName': "Microsoft.Devices.DeviceDisconnected", + 'ResourceDeleteFailureEventName': "Microsoft.Resources.ResourceDeleteFailure", + 'ResourceDeleteCancelEventName': "Microsoft.Resources.ResourceDeleteCancel", + 'AcsChatThreadParticipantAddedEventName': "Microsoft.Communication.ChatThreadParticipantAdded", + 'ResourceDeleteSuccessEventName': "Microsoft.Resources.ResourceDeleteSuccess", + 'EventGridSubscriptionValidationEventName': "Microsoft.EventGrid.SubscriptionValidationEvent", + 'ResourceWriteSuccessEventName': "Microsoft.Resources.ResourceWriteSuccess", + 'ResourceActionSuccessEventName': "Microsoft.Resources.ResourceActionSuccess", + 'ResourceWriteCancelEventName': "Microsoft.Resources.ResourceWriteCancel", + 'ResourceActionFailureEventName': "Microsoft.Resources.ResourceActionFailure", + 'AcsChatMemberRemovedFromThreadWithUserEventName': "Microsoft.Communication.ChatMemberRemovedFromThreadWithUser", + 'IoTHubDeviceConnectedEventName': "Microsoft.Devices.DeviceConnected", + 'EventGridSubscriptionDeletedEventName': "Microsoft.EventGrid.SubscriptionDeletedEvent", + 'AcsChatThreadParticipantRemovedEventName': "Microsoft.Communication.ChatThreadParticipantRemoved", + 'ResourceActionCancelEventName': "Microsoft.Resources.ResourceActionCancel", + 'IoTHubDeviceCreatedEventName': "Microsoft.Devices.DeviceCreated" +} + +def event_tuples(system_events): + tup_list = [] + for event in system_events: + class_name = "Name".join(event[0].rsplit('Data', 1)) + try: + event_name = re.findall("Microsoft.[a-zA-Z]+.[a-zA-Z]+", event[1].__doc__)[0] + except: + # these two are just superclasses and are known exceptions. + if event[0] not in ('ContainerRegistryArtifactEventData', 'ContainerRegistryEventData'): + warnings.warn("Unable to generate the event mapping for {}".format(event[0])) + sys.exit(1) + tup_list.append((class_name, event_name)) + return tup_list + +def generate_enum_content(tuples): + print("# these names below are for backward compat only - refrain from using them.") + for k, v in backward_compat.items(): + print(k + " = '" + v + "'\n") + print("# backward compat names end here.") + for tup in tup_list: + print(tup[0] + " = '" + tup[1].replace('API', 'Api') + "'\n") + print("# servicebus alias") + print("ServiceBusDeadletterMessagesAvailableWithNoListenerEventName = 'Microsoft.ServiceBus.DeadletterMessagesAvailableWithNoListeners'") + +system_events = [m for m in inspect.getmembers(models) if m[0].endswith('Data')] +tup_list = event_tuples(system_events) + +generate_enum_content(tup_list) diff --git a/sdk/eventgrid/azure-eventgrid/tests/_mocks.py b/sdk/eventgrid/azure-eventgrid/tests/_mocks.py new file mode 100644 index 00000000000..107d6d6175e --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/tests/_mocks.py @@ -0,0 +1,77 @@ +import json + + +# storage cloud event +cloud_storage_dict = { + "id":"a0517898-9fa4-4e70-b4a3-afda1dd68672", + "source":"/subscriptions/{subscription-id}/resourceGroups/{resource-group}/providers/Microsoft.Storage/storageAccounts/{storage-account}", + "data":{ + "api":"PutBlockList", + "client_request_id":"6d79dbfb-0e37-4fc4-981f-442c9ca65760", + "request_id":"831e1650-001e-001b-66ab-eeb76e000000", + "e_tag":"0x8D4BCC2E4835CD0", + "content_type":"application/octet-stream", + "content_length":524288, + "blob_type":"BlockBlob", + "url":"https://oc2d2817345i60006.blob.core.windows.net/oc2d2817345i200097container/oc2d2817345i20002296blob", + "sequencer":"00000000000004420000000000028963", + "storage_diagnostics":{"batchId":"b68529f3-68cd-4744-baa4-3c0498ec19f0"} + }, + "type":"Microsoft.Storage.BlobCreated", + "time":"2020-08-07T01:11:49.765846Z", + "specversion":"1.0" +} +cloud_storage_string = json.dumps(cloud_storage_dict) +cloud_storage_bytes = cloud_storage_string.encode("utf-8") + +# custom cloud event +cloud_custom_dict = { + "id":"de0fd76c-4ef4-4dfb-ab3a-8f24a307e033", + "source":"https://egtest.dev/cloudcustomevent", + "data":{"team": "event grid squad"}, + "type":"Azure.Sdk.Sample", + "time":"2020-08-07T02:06:08.11969Z", + "specversion":"1.0" +} +cloud_custom_string = json.dumps(cloud_custom_dict) +cloud_custom_bytes = cloud_custom_string.encode("utf-8") + +# storage eg event +eg_storage_dict = { + "id":"bbab6625-dc56-4b22-abeb-afcc72e5290c", + "subject":"/blobServices/default/containers/oc2d2817345i200097container/blobs/oc2d2817345i20002296blob", + "data":{ + "api":"PutBlockList", + "clientRequestId":"6d79dbfb-0e37-4fc4-981f-442c9ca65760", + "requestId":"831e1650-001e-001b-66ab-eeb76e000000", + "eTag":"0x8D4BCC2E4835CD0", + "contentType":"application/octet-stream", + "contentLength":524288, + "blobType":"BlockBlob", + "url":"https://oc2d2817345i60006.blob.core.windows.net/oc2d2817345i200097container/oc2d2817345i20002296blob", + "sequencer":"00000000000004420000000000028963", + "storageDiagnostics":{"batchId":"b68529f3-68cd-4744-baa4-3c0498ec19f0"} + }, + "eventType":"Microsoft.Storage.BlobCreated", + "dataVersion":"2.0", + "metadataVersion":"1", + "eventTime":"2020-08-07T02:28:23.867525Z", + "topic":"/subscriptions/faa080af-c1d8-40ad-9cce-e1a450ca5b57/resourceGroups/t-swpill-test/providers/Microsoft.EventGrid/topics/eventgridegsub" +} + +eg_storage_string = json.dumps(eg_storage_dict) +eg_storage_bytes = eg_storage_string.encode("utf-8") + +# custom eg event +eg_custom_dict = { + "id":"3a30afef-b604-4b67-973e-7dfff7e178a7", + "subject":"Test EG Custom Event", + "data":{"team":"event grid squad"}, + "eventType":"Azure.Sdk.Sample", + "dataVersion":"2.0", + "metadataVersion":"1", + "eventTime":"2020-08-07T02:19:05.16916Z", + "topic":"/subscriptions/f8aa80ae-d1c8-60ad-9bce-e1a850ba5b67/resourceGroups/sample-resource-group-test/providers/Microsoft.EventGrid/topics/egtopicsamplesub" +} +eg_custom_string = json.dumps(eg_custom_dict) +eg_custom_bytes = eg_custom_string.encode("utf-8") diff --git a/sdk/eventgrid/azure-eventgrid/tests/conftest.py b/sdk/eventgrid/azure-eventgrid/tests/conftest.py new file mode 100644 index 00000000000..2e685fe040d --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/tests/conftest.py @@ -0,0 +1,33 @@ +# -------------------------------------------------------------------------- +# +# Copyright (c) Microsoft Corporation. All rights reserved. +# +# The MIT License (MIT) +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the ""Software""), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. +# +# -------------------------------------------------------------------------- +import platform +import sys + + +# Ignore async tests for Python < 3.5 +collect_ignore_glob = [] +if sys.version_info < (3, 5): + collect_ignore_glob.append("*_async.py") diff --git a/sdk/eventgrid/azure-eventgrid/tests/eventgrid_preparer.py b/sdk/eventgrid/azure-eventgrid/tests/eventgrid_preparer.py new file mode 100644 index 00000000000..320f778ce38 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/tests/eventgrid_preparer.py @@ -0,0 +1,109 @@ +import functools +import hashlib +import os +from collections import namedtuple + +from azure_devtools.scenario_tests import ReplayableTest +from azure.core.credentials import AccessToken +from azure.mgmt.eventgrid import EventGridManagementClient +from azure.mgmt.eventgrid.models import Topic, InputSchema, JsonInputSchemaMapping, JsonField, JsonFieldWithDefault +from azure_devtools.scenario_tests.exceptions import AzureTestError + +from devtools_testutils import ( + ResourceGroupPreparer, AzureMgmtPreparer, FakeResource, AzureMgmtTestCase +) + +from devtools_testutils.resource_testcase import RESOURCE_GROUP_PARAM + +EVENTGRID_TOPIC_PARAM = 'eventgrid_topic' +EVENTGRID_TOPIC_LOCATION = 'westus' +CLOUD_EVENT_SCHEMA = InputSchema.cloud_event_schema_v1_0 +CUSTOM_EVENT_SCHEMA = InputSchema.custom_event_schema +ID_JSON_FIELD = JsonField(source_field='customId') +TOPIC_JSON_FIELD = JsonField(source_field='customTopic') +EVENT_TIME_JSON_FIELD = JsonField(source_field='customEventTime') +EVENT_TYPE_JSON_FIELD_WITH_DEFAULT = JsonFieldWithDefault(source_field='customEventType', default_value='') +SUBJECT_JSON_FIELD_WITH_DEFAULT = JsonFieldWithDefault(source_field='customSubject', default_value='') +DATA_VERSION_JSON_FIELD_WITH_DEFAULT = JsonFieldWithDefault(source_field='customDataVersion', default_value='') +CUSTOM_JSON_INPUT_SCHEMA_MAPPING = JsonInputSchemaMapping(id=ID_JSON_FIELD, topic=TOPIC_JSON_FIELD, event_time=EVENT_TIME_JSON_FIELD, event_type=EVENT_TYPE_JSON_FIELD_WITH_DEFAULT, subject=SUBJECT_JSON_FIELD_WITH_DEFAULT, data_version=DATA_VERSION_JSON_FIELD_WITH_DEFAULT) + +class FakeTokenCredential(object): + """Protocol for classes able to provide OAuth tokens. + :param str scopes: Lets you specify the type of access needed. + """ + def __init__(self): + self.token = AccessToken("YOU SHALL NOT PASS", 0) + + def get_token(self, *args): + return self.token + +class EventGridTopicPreparer(AzureMgmtPreparer): + def __init__(self, + name_prefix='', + use_cache=False, + parameter_location=EVENTGRID_TOPIC_LOCATION, + parameter_name=EVENTGRID_TOPIC_PARAM, + resource_group_parameter_name=RESOURCE_GROUP_PARAM, + disable_recording=True, playback_fake_resource=None, + client_kwargs=None, random_name_enabled=True): + super(EventGridTopicPreparer, self).__init__(name_prefix, random_name_length=24, + random_name_enabled=random_name_enabled, + disable_recording=disable_recording, + playback_fake_resource=playback_fake_resource, + client_kwargs=client_kwargs) + self.resource_group_parameter_name = resource_group_parameter_name + self.parameter_name = parameter_name + self.parameter_location = parameter_location + self.name_prefix = name_prefix + if random_name_enabled: + self.resource_moniker = self.name_prefix + "egtopic" + + self.set_cache(use_cache, name_prefix) + + def create_resource(self, name, **kwargs): + if self.is_live: + self.client = self.create_mgmt_client(EventGridManagementClient) + group = self._get_resource_group(**kwargs) + + if self.name_prefix.startswith("cloud"): + # Create a new topic and verify that it is created successfully + topic = Topic(location=self.parameter_location, tags=None, input_schema=CLOUD_EVENT_SCHEMA, input_schema_mapping=None) + elif self.name_prefix.startswith("custom"): + # Create a new topic and verify that it is created successfully + topic = Topic(location=self.parameter_location, tags=None, input_schema=CUSTOM_EVENT_SCHEMA, input_schema_mapping=CUSTOM_JSON_INPUT_SCHEMA_MAPPING) + else: + topic = Topic(location=self.parameter_location) + topic_operation = self.client.topics.begin_create_or_update( + group.name, + name, + topic, + ) + self.resource = topic_operation.result() + key = self.client.topics.list_shared_access_keys(group.name, name) + self.primary_key = key.key1 + self.endpoint = self.resource.endpoint + else: + self.resource = FakeResource(name=name, id=name) + self.primary_key = "ZmFrZV9hY29jdW50X2tleQ==" # test key copied from sb_preparer + self.endpoint = "https://{}.westus-1.eventgrid.azure.net/api/events".format(name) + return { + self.parameter_name: self.resource, + '{}_primary_key'.format(self.parameter_name): self.primary_key, + '{}_endpoint'.format(self.parameter_name): self.endpoint, + } + + def remove_resource(self, name, **kwargs): + if self.is_live: + group = self._get_resource_group(**kwargs) + self.client.topics.begin_delete(group.name, name, polling=False) + + def _get_resource_group(self, **kwargs): + try: + return kwargs.get(self.resource_group_parameter_name) + except KeyError: + template = 'To create this event grid topic resource, a resource group is required. Please add ' \ + 'decorator @{} in front of this event grid topic preparer.' + raise AzureTestError(template.format(ResourceGroupPreparer.__name__)) + + +CachedEventGridTopicPreparer = functools.partial(EventGridTopicPreparer, use_cache=True) diff --git a/sdk/eventgrid/azure-eventgrid/tests/perfstress_tests/README.md b/sdk/eventgrid/azure-eventgrid/tests/perfstress_tests/README.md new file mode 100644 index 00000000000..7e51435d647 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/tests/perfstress_tests/README.md @@ -0,0 +1,48 @@ +# EventGrid Performance Tests + +In order to run the performance tests, the `azure-devtools` package must be installed. This is done as part of the `dev_requirements`. +Start by creating a new virtual environment for your perf tests. This will need to be a Python 3 environment, preferably >=3.7. + +### Setup for test resources + +These tests will run against a pre-configured Eventgrid topic. The following environment variable will need to be set for the tests to access the live resources: +``` +EG_ACCESS_KEY= +EG_TOPIC_HOSTNAME= +``` + +### Setup for perf test runs + +```cmd +(env) ~/azure-eventgrid> pip install -r dev_requirements.txt +(env) ~/azure-eventgrid> pip install -e . +``` + +## Test commands + +```cmd +(env) ~/azure-eventgrid> cd tests +(env) ~/azure-eventgrid/tests> perfstress +``` + +### Common perf command line options +These options are available for all perf tests: +- `--duration=10` Number of seconds to run as many operations (the "run" function) as possible. Default is 10. +- `--iterations=1` Number of test iterations to run. Default is 1. +- `--parallel=1` Number of tests to run in parallel. Default is 1. +- `--warm-up=5` Number of seconds to spend warming up the connection before measuring begins. Default is 5. +- `--sync` Whether to run the tests in sync or async. Default is False (async). +- `--no-cleanup` Whether to keep newly created resources after test run. Default is False (resources will be deleted). + +### EventGrid Test options +These options are available for all eventgrid perf tests: +- `--num-events` Number of events to be published using the send method. + +### T2 Tests +The tests currently written for the T2 SDK: +- `EventGridPerfTest` Publishes a list of eventgrid events. + +## Example command +```cmd +(env) ~/azure-eventgrid/tests> perfstress EventGridPerfTest --num-events=100 +``` diff --git a/sdk/eventgrid/azure-eventgrid/tests/perfstress_tests/__init__.py b/sdk/eventgrid/azure-eventgrid/tests/perfstress_tests/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/sdk/eventgrid/azure-eventgrid/tests/perfstress_tests/send.py b/sdk/eventgrid/azure-eventgrid/tests/perfstress_tests/send.py new file mode 100644 index 00000000000..4f13b3c39cf --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/tests/perfstress_tests/send.py @@ -0,0 +1,73 @@ +#------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +#-------------------------------------------------------------------------- + +import asyncio +from azure_devtools.perfstress_tests import PerfStressTest + +from azure.eventgrid import EventGridPublisherClient as SyncPublisherClient, EventGridEvent +from azure.eventgrid.aio import EventGridPublisherClient as AsyncPublisherClient + +from azure.core.credentials import AzureKeyCredential + +class EventGridPerfTest(PerfStressTest): + def __init__(self, arguments): + super().__init__(arguments) + + # auth configuration + topic_key = self.get_from_env("EG_ACCESS_KEY") + endpoint = self.get_from_env("EG_TOPIC_HOSTNAME") + + # Create clients + self.publisher_client = SyncPublisherClient( + endpoint=endpoint, + credential=AzureKeyCredential(topic_key) + ) + self.async_publisher_client = AsyncPublisherClient( + endpoint=endpoint, + credential=AzureKeyCredential(topic_key) + ) + + self.event_list = [] + for _ in range(self.args.num_events): + self.event_list.append(EventGridEvent( + event_type="Contoso.Items.ItemReceived", + data={ + "services": ["EventGrid", "ServiceBus", "EventHubs", "Storage"] + }, + subject="Door1", + data_version="2.0" + )) + + async def close(self): + """This is run after cleanup. + + Use this to close any open handles or clients. + """ + await self.async_publisher_client.close() + await super().close() + + def run_sync(self): + """The synchronous perf test. + + Try to keep this minimal and focused. Using only a single client API. + Avoid putting any ancilliary logic (e.g. generating UUIDs), and put this in the setup/init instead + so that we're only measuring the client API call. + """ + self.publisher_client.send(self.event_list) + + async def run_async(self): + """The asynchronous perf test. + + Try to keep this minimal and focused. Using only a single client API. + Avoid putting any ancilliary logic (e.g. generating UUIDs), and put this in the setup/init instead + so that we're only measuring the client API call. + """ + await self.async_publisher_client.send(self.event_list) + + @staticmethod + def add_arguments(parser): + super(EventGridPerfTest, EventGridPerfTest).add_arguments(parser) + parser.add_argument('-n', '--num-events', nargs='?', type=int, help='Number of events to be sent. Defaults to 100', default=100) diff --git a/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_cloud_event_data_as_list.yaml b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_cloud_event_data_as_list.yaml new file mode 100644 index 00000000000..51865651d79 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_cloud_event_data_as_list.yaml @@ -0,0 +1,38 @@ +interactions: +- request: + body: '[{"id": "faf85db8-1f8e-45df-afee-a58858789404", "source": "http://samplesource.dev", + "data": "cloudevent", "type": "Sample.Cloud.Event", "time": "2021-03-09T23:36:13.142724Z", + "specversion": "1.0"}]' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '198' + Content-Type: + - application/cloudevents-batch+json; charset=utf-8 + User-Agent: + - azsdk-python-eventgrid/4.0.0 Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://cloudeventgridtestegtopic.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 + response: + body: + string: '' + headers: + api-supported-versions: + - '2018-01-01' + content-length: + - '0' + date: + - Tue, 09 Mar 2021 23:36:13 GMT + server: + - Microsoft-HTTPAPI/2.0 + strict-transport-security: + - max-age=31536000; includeSubDomains + status: + code: 200 + message: OK +version: 1 diff --git a/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_cloud_event_data_base64_using_data.yaml b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_cloud_event_data_base64_using_data.yaml new file mode 100644 index 00000000000..dff2f78a2f8 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_cloud_event_data_base64_using_data.yaml @@ -0,0 +1,38 @@ +interactions: +- request: + body: '[{"id": "87d70d3b-c581-4301-b95a-25afe75fb263", "source": "http://samplesource.dev", + "data_base64": "Y2xvdWRldmVudA==", "type": "Sample.Cloud.Event", "time": "2021-03-09T23:36:13.799001Z", + "specversion": "1.0"}]' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '211' + Content-Type: + - application/cloudevents-batch+json; charset=utf-8 + User-Agent: + - azsdk-python-eventgrid/4.0.0 Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://cloudeventgridtestegtopic.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 + response: + body: + string: '' + headers: + api-supported-versions: + - '2018-01-01' + content-length: + - '0' + date: + - Tue, 09 Mar 2021 23:36:13 GMT + server: + - Microsoft-HTTPAPI/2.0 + strict-transport-security: + - max-age=31536000; includeSubDomains + status: + code: 200 + message: OK +version: 1 diff --git a/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_cloud_event_data_bytes.yaml b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_cloud_event_data_bytes.yaml new file mode 100644 index 00000000000..be5c3d88064 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_cloud_event_data_bytes.yaml @@ -0,0 +1,38 @@ +interactions: +- request: + body: '[{"id": "e18be644-6df9-428d-b32b-ad3db396b1e4", "source": "http://samplesource.dev", + "data_base64": "Y2xvdWRldmVudA==", "type": "Sample.Cloud.Event", "time": "2021-03-09T23:36:14.337313Z", + "specversion": "1.0"}]' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '211' + Content-Type: + - application/cloudevents-batch+json; charset=utf-8 + User-Agent: + - azsdk-python-eventgrid/4.0.0 Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://cloudeventgridtestegtopic.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 + response: + body: + string: '' + headers: + api-supported-versions: + - '2018-01-01' + content-length: + - '0' + date: + - Tue, 09 Mar 2021 23:36:14 GMT + server: + - Microsoft-HTTPAPI/2.0 + strict-transport-security: + - max-age=31536000; includeSubDomains + status: + code: 200 + message: OK +version: 1 diff --git a/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_cloud_event_data_dict.yaml b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_cloud_event_data_dict.yaml new file mode 100644 index 00000000000..ec666a82935 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_cloud_event_data_dict.yaml @@ -0,0 +1,38 @@ +interactions: +- request: + body: '[{"id": "a7e381a2-b5de-4e41-87ac-a87c53c53a37", "source": "http://samplesource.dev", + "data": {"sample": "cloudevent"}, "type": "Sample.Cloud.Event", "time": "2021-03-09T23:36:14.619707Z", + "specversion": "1.0"}]' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '210' + Content-Type: + - application/cloudevents-batch+json; charset=utf-8 + User-Agent: + - azsdk-python-eventgrid/4.0.0 Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://cloudeventgridtestegtopic.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 + response: + body: + string: '' + headers: + api-supported-versions: + - '2018-01-01' + content-length: + - '0' + date: + - Tue, 09 Mar 2021 23:36:14 GMT + server: + - Microsoft-HTTPAPI/2.0 + strict-transport-security: + - max-age=31536000; includeSubDomains + status: + code: 200 + message: OK +version: 1 diff --git a/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_cloud_event_data_none.yaml b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_cloud_event_data_none.yaml new file mode 100644 index 00000000000..1f41ea59940 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_cloud_event_data_none.yaml @@ -0,0 +1,38 @@ +interactions: +- request: + body: '[{"id": "b0cf1bb0-c01f-4bc8-9356-52ad52e49a73", "source": "http://samplesource.dev", + "type": "Sample.Cloud.Event", "time": "2021-03-09T23:36:15.038105Z", "specversion": + "1.0"}]' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '176' + Content-Type: + - application/cloudevents-batch+json; charset=utf-8 + User-Agent: + - azsdk-python-eventgrid/4.0.0 Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://cloudeventgridtestegtopic.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 + response: + body: + string: '' + headers: + api-supported-versions: + - '2018-01-01' + content-length: + - '0' + date: + - Tue, 09 Mar 2021 23:36:15 GMT + server: + - Microsoft-HTTPAPI/2.0 + strict-transport-security: + - max-age=31536000; includeSubDomains + status: + code: 200 + message: OK +version: 1 diff --git a/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_cloud_event_data_str.yaml b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_cloud_event_data_str.yaml new file mode 100644 index 00000000000..bf6fff94069 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_cloud_event_data_str.yaml @@ -0,0 +1,38 @@ +interactions: +- request: + body: '[{"id": "c8950e2d-c3af-40e0-b1c1-ce75211c3238", "source": "http://samplesource.dev", + "data": "cloudevent", "type": "Sample.Cloud.Event", "time": "2021-03-09T23:36:15.623974Z", + "specversion": "1.0"}]' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '198' + Content-Type: + - application/cloudevents-batch+json; charset=utf-8 + User-Agent: + - azsdk-python-eventgrid/4.0.0 Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://cloudeventgridtestegtopic.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 + response: + body: + string: '' + headers: + api-supported-versions: + - '2018-01-01' + content-length: + - '0' + date: + - Tue, 09 Mar 2021 23:36:15 GMT + server: + - Microsoft-HTTPAPI/2.0 + strict-transport-security: + - max-age=31536000; includeSubDomains + status: + code: 200 + message: OK +version: 1 diff --git a/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_cloud_event_data_with_extensions.yaml b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_cloud_event_data_with_extensions.yaml new file mode 100644 index 00000000000..e73909b49a3 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_cloud_event_data_with_extensions.yaml @@ -0,0 +1,38 @@ +interactions: +- request: + body: '[{"reasoncode": 204, "extension": "hello", "id": "264e57c5-feb9-4a1a-b681-fefcec1a8fc2", + "source": "http://samplesource.dev", "data": "cloudevent", "type": "Sample.Cloud.Event", + "time": "2021-03-09T23:36:15.973973Z", "specversion": "1.0"}]' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '239' + Content-Type: + - application/cloudevents-batch+json; charset=utf-8 + User-Agent: + - azsdk-python-eventgrid/4.0.0 Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://cloudeventgridtestegtopic.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 + response: + body: + string: '' + headers: + api-supported-versions: + - '2018-01-01' + content-length: + - '0' + date: + - Tue, 09 Mar 2021 23:36:15 GMT + server: + - Microsoft-HTTPAPI/2.0 + strict-transport-security: + - max-age=31536000; includeSubDomains + status: + code: 200 + message: OK +version: 1 diff --git a/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_cloud_event_dict.yaml b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_cloud_event_dict.yaml new file mode 100644 index 00000000000..634ac4d4ee7 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_cloud_event_dict.yaml @@ -0,0 +1,37 @@ +interactions: +- request: + body: '[{"id": "1234", "source": "http://samplesource.dev", "specversion": "1.0", + "data": "cloudevent", "type": "Sample.Cloud.Event"}]' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '127' + Content-Type: + - application/cloudevents-batch+json; charset=utf-8 + User-Agent: + - azsdk-python-eventgrid/4.0.0 Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://cloudeventgridtestegtopic.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 + response: + body: + string: '' + headers: + api-supported-versions: + - '2018-01-01' + content-length: + - '0' + date: + - Tue, 09 Mar 2021 23:36:15 GMT + server: + - Microsoft-HTTPAPI/2.0 + strict-transport-security: + - max-age=31536000; includeSubDomains + status: + code: 200 + message: OK +version: 1 diff --git a/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_custom_schema_event.yaml b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_custom_schema_event.yaml new file mode 100644 index 00000000000..d39fff8101f --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_custom_schema_event.yaml @@ -0,0 +1,38 @@ +interactions: +- request: + body: '[{"customSubject": "sample", "customEventType": "sample.event", "customDataVersion": + "2.0", "customId": "1234", "customEventTime": "2021-03-09T23:36:30.264615+00:00", + "customData": "sample data"}]' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '196' + Content-Type: + - application/json + User-Agent: + - azsdk-python-eventgrid/4.0.0 Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://customeventgridtestegtopic.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 + response: + body: + string: '' + headers: + api-supported-versions: + - '2018-01-01' + content-length: + - '0' + date: + - Tue, 09 Mar 2021 23:36:30 GMT + server: + - Microsoft-HTTPAPI/2.0 + strict-transport-security: + - max-age=31536000; includeSubDomains + status: + code: 200 + message: OK +version: 1 diff --git a/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_custom_schema_event_as_list.yaml b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_custom_schema_event_as_list.yaml new file mode 100644 index 00000000000..14ef78662cd --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_custom_schema_event_as_list.yaml @@ -0,0 +1,40 @@ +interactions: +- request: + body: '[{"customSubject": "sample", "customEventType": "sample.event", "customDataVersion": + "2.0", "customId": "1234", "customEventTime": "2021-03-09T23:36:30.800753+00:00", + "customData": "sample data"}, {"customSubject": "sample2", "customEventType": + "sample.event", "customDataVersion": "2.0", "customId": "12345", "customEventTime": + "2021-03-09T23:36:30.800753+00:00", "customData": "sample data 2"}]' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '396' + Content-Type: + - application/json + User-Agent: + - azsdk-python-eventgrid/4.0.0 Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://customeventgridtestegtopic.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 + response: + body: + string: '' + headers: + api-supported-versions: + - '2018-01-01' + content-length: + - '0' + date: + - Tue, 09 Mar 2021 23:36:30 GMT + server: + - Microsoft-HTTPAPI/2.0 + strict-transport-security: + - max-age=31536000; includeSubDomains + status: + code: 200 + message: OK +version: 1 diff --git a/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_event_grid_event_data_as_list.yaml b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_event_grid_event_data_as_list.yaml new file mode 100644 index 00000000000..f6224cd4edf --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_event_grid_event_data_as_list.yaml @@ -0,0 +1,40 @@ +interactions: +- request: + body: '[{"id": "6afb5986-c134-4bd6-92a6-c2e6728d7526", "subject": "sample", "data": + "eventgridevent", "eventType": "Sample.EventGrid.Event", "eventTime": "2021-03-09T23:36:31.238209Z", + "dataVersion": "2.0"}, {"id": "8b752ec6-9f19-40ea-ac55-3452ce1ae592", "subject": + "sample2", "data": "eventgridevent2", "eventType": "Sample.EventGrid.Event", + "eventTime": "2021-03-09T23:36:31.238209Z", "dataVersion": "2.0"}]' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '402' + Content-Type: + - application/json; charset=utf-8 + User-Agent: + - azsdk-python-eventgrid/4.0.0 Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://eventgridtestegtopic.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 + response: + body: + string: '' + headers: + api-supported-versions: + - '2018-01-01' + content-length: + - '0' + date: + - Tue, 09 Mar 2021 23:36:31 GMT + server: + - Microsoft-HTTPAPI/2.0 + strict-transport-security: + - max-age=31536000; includeSubDomains + status: + code: 200 + message: OK +version: 1 diff --git a/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_event_grid_event_data_dict.yaml b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_event_grid_event_data_dict.yaml new file mode 100644 index 00000000000..aef53977c94 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_event_grid_event_data_dict.yaml @@ -0,0 +1,38 @@ +interactions: +- request: + body: '[{"id": "c6c6ca30-f093-4620-bbb9-aad357fbae48", "subject": "sample", "data": + {"sample": "eventgridevent"}, "eventType": "Sample.EventGrid.Event", "eventTime": + "2021-03-09T23:36:31.662708Z", "dataVersion": "2.0"}]' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '212' + Content-Type: + - application/json; charset=utf-8 + User-Agent: + - azsdk-python-eventgrid/4.0.0 Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://eventgridtestegtopic.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 + response: + body: + string: '' + headers: + api-supported-versions: + - '2018-01-01' + content-length: + - '0' + date: + - Tue, 09 Mar 2021 23:36:31 GMT + server: + - Microsoft-HTTPAPI/2.0 + strict-transport-security: + - max-age=31536000; includeSubDomains + status: + code: 200 + message: OK +version: 1 diff --git a/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_event_grid_event_data_str.yaml b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_event_grid_event_data_str.yaml new file mode 100644 index 00000000000..251875991b0 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_event_grid_event_data_str.yaml @@ -0,0 +1,38 @@ +interactions: +- request: + body: '[{"id": "a4019f70-62cf-4b9c-84c6-542a1f88b37f", "subject": "sample", "data": + "eventgridevent", "eventType": "Sample.EventGrid.Event", "eventTime": "2021-03-09T23:36:32.059713Z", + "dataVersion": "2.0"}]' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '200' + Content-Type: + - application/json; charset=utf-8 + User-Agent: + - azsdk-python-eventgrid/4.0.0 Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://eventgridtestegtopic.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 + response: + body: + string: '' + headers: + api-supported-versions: + - '2018-01-01' + content-length: + - '0' + date: + - Tue, 09 Mar 2021 23:36:31 GMT + server: + - Microsoft-HTTPAPI/2.0 + strict-transport-security: + - max-age=31536000; includeSubDomains + status: + code: 200 + message: OK +version: 1 diff --git a/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_event_grid_event_dict_data_dict.yaml b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_event_grid_event_dict_data_dict.yaml new file mode 100644 index 00000000000..d4e255c797c --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_event_grid_event_dict_data_dict.yaml @@ -0,0 +1,38 @@ +interactions: +- request: + body: '[{"subject": "sample", "data": {"key1": "Sample.EventGrid.Event"}, "eventType": + "Sample.EventGrid.Event", "dataVersion": "2.0", "id": "f53822f8-12a4-4c27-9077-fe66058c07af", + "eventTime": "2021-03-09 15:36:32.481019"}]' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '217' + Content-Type: + - application/json; charset=utf-8 + User-Agent: + - azsdk-python-eventgrid/4.0.0 Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://eventgridtestegtopic.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 + response: + body: + string: '' + headers: + api-supported-versions: + - '2018-01-01' + content-length: + - '0' + date: + - Tue, 09 Mar 2021 23:36:32 GMT + server: + - Microsoft-HTTPAPI/2.0 + strict-transport-security: + - max-age=31536000; includeSubDomains + status: + code: 200 + message: OK +version: 1 diff --git a/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_signature_credential.yaml b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_signature_credential.yaml new file mode 100644 index 00000000000..b4c5db7e0cd --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_signature_credential.yaml @@ -0,0 +1,38 @@ +interactions: +- request: + body: '[{"id": "cc5be5f0-2829-40e0-87a9-d61647c3a3a5", "subject": "sample", "data": + {"sample": "eventgridevent"}, "eventType": "Sample.EventGrid.Event", "eventTime": + "2021-03-10T17:45:27.319301Z", "dataVersion": "2.0"}]' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '212' + Content-Type: + - application/json; charset=utf-8 + User-Agent: + - azsdk-python-eventgrid/4.0.0 Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://eventgridtestegtopic.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 + response: + body: + string: '' + headers: + api-supported-versions: + - '2018-01-01' + content-length: + - '0' + date: + - Wed, 10 Mar 2021 17:45:26 GMT + server: + - Microsoft-HTTPAPI/2.0 + strict-transport-security: + - max-age=31536000; includeSubDomains + status: + code: 200 + message: OK +version: 1 diff --git a/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_and_close_async_session.yaml b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_and_close_async_session.yaml new file mode 100644 index 00000000000..4ea66ba31ab --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_and_close_async_session.yaml @@ -0,0 +1,28 @@ +interactions: +- request: + body: '[{"id": "662ab79d-a155-4c36-b73a-2128a30e359c", "source": "http://samplesource.dev", + "data": "cloudevent", "type": "Sample.Cloud.Event", "time": "2021-03-09T23:37:08.531001Z", + "specversion": "1.0"}]' + headers: + Content-Length: + - '198' + Content-Type: + - application/cloudevents-batch+json; charset=utf-8 + User-Agent: + - azsdk-python-eventgridpublisherclient/4.0.0 Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://cloudeventgridtestegtopic.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 + response: + body: + string: '' + headers: + api-supported-versions: '2018-01-01' + content-length: '0' + date: Tue, 09 Mar 2021 23:37:08 GMT + server: Microsoft-HTTPAPI/2.0 + strict-transport-security: max-age=31536000; includeSubDomains + status: + code: 200 + message: OK + url: https://cloudeventgridtestcxhotk.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 +version: 1 diff --git a/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_cloud_event_data_as_list.yaml b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_cloud_event_data_as_list.yaml new file mode 100644 index 00000000000..b977cec6ca9 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_cloud_event_data_as_list.yaml @@ -0,0 +1,28 @@ +interactions: +- request: + body: '[{"id": "a09030c8-7c28-4118-bf44-4c0d05ecd9d6", "source": "http://samplesource.dev", + "data": "cloudevent", "type": "Sample.Cloud.Event", "time": "2021-03-09T23:37:08.925482Z", + "specversion": "1.0"}]' + headers: + Content-Length: + - '198' + Content-Type: + - application/cloudevents-batch+json; charset=utf-8 + User-Agent: + - azsdk-python-eventgridpublisherclient/4.0.0 Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://cloudeventgridtestegtopic.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 + response: + body: + string: '' + headers: + api-supported-versions: '2018-01-01' + content-length: '0' + date: Tue, 09 Mar 2021 23:37:08 GMT + server: Microsoft-HTTPAPI/2.0 + strict-transport-security: max-age=31536000; includeSubDomains + status: + code: 200 + message: OK + url: https://cloudeventgridtestcxhotk.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 +version: 1 diff --git a/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_cloud_event_data_bytes.yaml b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_cloud_event_data_bytes.yaml new file mode 100644 index 00000000000..41240c98edf --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_cloud_event_data_bytes.yaml @@ -0,0 +1,28 @@ +interactions: +- request: + body: '[{"id": "574e66bf-58f3-402c-883b-cff60825153d", "source": "http://samplesource.dev", + "data_base64": "Y2xvdWRldmVudA==", "type": "Sample.Cloud.Event", "time": "2021-03-09T23:37:09.279372Z", + "specversion": "1.0"}]' + headers: + Content-Length: + - '211' + Content-Type: + - application/cloudevents-batch+json; charset=utf-8 + User-Agent: + - azsdk-python-eventgridpublisherclient/4.0.0 Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://cloudeventgridtestegtopic.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 + response: + body: + string: '' + headers: + api-supported-versions: '2018-01-01' + content-length: '0' + date: Tue, 09 Mar 2021 23:37:09 GMT + server: Microsoft-HTTPAPI/2.0 + strict-transport-security: max-age=31536000; includeSubDomains + status: + code: 200 + message: OK + url: https://cloudeventgridtestcxhotk.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 +version: 1 diff --git a/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_cloud_event_data_dict.yaml b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_cloud_event_data_dict.yaml new file mode 100644 index 00000000000..eda7d1210dd --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_cloud_event_data_dict.yaml @@ -0,0 +1,28 @@ +interactions: +- request: + body: '[{"id": "5d2286cd-d7a5-472f-a6b4-c8c061acce32", "source": "http://samplesource.dev", + "data": {"sample": "cloudevent"}, "type": "Sample.Cloud.Event", "time": "2021-03-09T23:37:09.581385Z", + "specversion": "1.0"}]' + headers: + Content-Length: + - '210' + Content-Type: + - application/cloudevents-batch+json; charset=utf-8 + User-Agent: + - azsdk-python-eventgridpublisherclient/4.0.0 Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://cloudeventgridtestegtopic.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 + response: + body: + string: '' + headers: + api-supported-versions: '2018-01-01' + content-length: '0' + date: Tue, 09 Mar 2021 23:37:09 GMT + server: Microsoft-HTTPAPI/2.0 + strict-transport-security: max-age=31536000; includeSubDomains + status: + code: 200 + message: OK + url: https://cloudeventgridtestcxhotk.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 +version: 1 diff --git a/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_cloud_event_data_none.yaml b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_cloud_event_data_none.yaml new file mode 100644 index 00000000000..4b3d6949337 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_cloud_event_data_none.yaml @@ -0,0 +1,28 @@ +interactions: +- request: + body: '[{"id": "68e29039-ef5c-46a5-a77b-063b6736a445", "source": "http://samplesource.dev", + "type": "Sample.Cloud.Event", "time": "2021-03-09T23:37:09.987352Z", "specversion": + "1.0"}]' + headers: + Content-Length: + - '176' + Content-Type: + - application/cloudevents-batch+json; charset=utf-8 + User-Agent: + - azsdk-python-eventgridpublisherclient/4.0.0 Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://cloudeventgridtestegtopic.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 + response: + body: + string: '' + headers: + api-supported-versions: '2018-01-01' + content-length: '0' + date: Tue, 09 Mar 2021 23:37:09 GMT + server: Microsoft-HTTPAPI/2.0 + strict-transport-security: max-age=31536000; includeSubDomains + status: + code: 200 + message: OK + url: https://cloudeventgridtestcxhotk.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 +version: 1 diff --git a/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_cloud_event_data_str.yaml b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_cloud_event_data_str.yaml new file mode 100644 index 00000000000..1dac0a3edac --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_cloud_event_data_str.yaml @@ -0,0 +1,28 @@ +interactions: +- request: + body: '[{"id": "bf72d636-e0ce-4241-a94f-2d6047d9fe86", "source": "http://samplesource.dev", + "data": "cloudevent", "type": "Sample.Cloud.Event", "time": "2021-03-09T23:37:10.278325Z", + "specversion": "1.0"}]' + headers: + Content-Length: + - '198' + Content-Type: + - application/cloudevents-batch+json; charset=utf-8 + User-Agent: + - azsdk-python-eventgridpublisherclient/4.0.0 Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://cloudeventgridtestegtopic.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 + response: + body: + string: '' + headers: + api-supported-versions: '2018-01-01' + content-length: '0' + date: Tue, 09 Mar 2021 23:37:09 GMT + server: Microsoft-HTTPAPI/2.0 + strict-transport-security: max-age=31536000; includeSubDomains + status: + code: 200 + message: OK + url: https://cloudeventgridtestcxhotk.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 +version: 1 diff --git a/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_cloud_event_data_with_extensions.yaml b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_cloud_event_data_with_extensions.yaml new file mode 100644 index 00000000000..439a2ea90be --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_cloud_event_data_with_extensions.yaml @@ -0,0 +1,28 @@ +interactions: +- request: + body: '[{"reasoncode": 204, "extension": "hello", "id": "7b760fe0-a828-4df8-b1bd-cc6cdcfc1f49", + "source": "http://samplesource.dev", "data": "cloudevent", "type": "Sample.Cloud.Event", + "time": "2021-03-09T23:37:10.543913Z", "specversion": "1.0"}]' + headers: + Content-Length: + - '239' + Content-Type: + - application/cloudevents-batch+json; charset=utf-8 + User-Agent: + - azsdk-python-eventgridpublisherclient/4.0.0 Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://cloudeventgridtestegtopic.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 + response: + body: + string: '' + headers: + api-supported-versions: '2018-01-01' + content-length: '0' + date: Tue, 09 Mar 2021 23:37:10 GMT + server: Microsoft-HTTPAPI/2.0 + strict-transport-security: max-age=31536000; includeSubDomains + status: + code: 200 + message: OK + url: https://cloudeventgridtestcxhotk.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 +version: 1 diff --git a/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_cloud_event_dict.yaml b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_cloud_event_dict.yaml new file mode 100644 index 00000000000..007589d04eb --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_cloud_event_dict.yaml @@ -0,0 +1,27 @@ +interactions: +- request: + body: '[{"id": "1234", "source": "http://samplesource.dev", "specversion": "1.0", + "data": "cloudevent", "type": "Sample.Cloud.Event"}]' + headers: + Content-Length: + - '127' + Content-Type: + - application/cloudevents-batch+json; charset=utf-8 + User-Agent: + - azsdk-python-eventgridpublisherclient/4.0.0 Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://cloudeventgridtestegtopic.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 + response: + body: + string: '' + headers: + api-supported-versions: '2018-01-01' + content-length: '0' + date: Tue, 09 Mar 2021 23:37:10 GMT + server: Microsoft-HTTPAPI/2.0 + strict-transport-security: max-age=31536000; includeSubDomains + status: + code: 200 + message: OK + url: https://cloudeventgridtestcxhotk.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 +version: 1 diff --git a/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_custom_schema_event.yaml b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_custom_schema_event.yaml new file mode 100644 index 00000000000..d0f1ccb87f7 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_custom_schema_event.yaml @@ -0,0 +1,28 @@ +interactions: +- request: + body: '[{"customSubject": "sample", "customEventType": "sample.event", "customDataVersion": + "2.0", "customId": "1234", "customEventTime": "2021-03-09T23:37:24.167980+00:00", + "customData": "sample data"}]' + headers: + Content-Length: + - '196' + Content-Type: + - application/json + User-Agent: + - azsdk-python-eventgridpublisherclient/4.0.0 Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://customeventgridtestegtopic.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 + response: + body: + string: '' + headers: + api-supported-versions: '2018-01-01' + content-length: '0' + date: Tue, 09 Mar 2021 23:37:24 GMT + server: Microsoft-HTTPAPI/2.0 + strict-transport-security: max-age=31536000; includeSubDomains + status: + code: 200 + message: OK + url: https://customeventgridtestbz4pr.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 +version: 1 diff --git a/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_custom_schema_event_as_list.yaml b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_custom_schema_event_as_list.yaml new file mode 100644 index 00000000000..18582c0d63b --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_custom_schema_event_as_list.yaml @@ -0,0 +1,30 @@ +interactions: +- request: + body: '[{"customSubject": "sample", "customEventType": "sample.event", "customDataVersion": + "2.0", "customId": "1234", "customEventTime": "2021-03-09T23:37:24.600983+00:00", + "customData": "sample data"}, {"customSubject": "sample2", "customEventType": + "sample.event", "customDataVersion": "2.0", "customId": "12345", "customEventTime": + "2021-03-09T23:37:24.600983+00:00", "customData": "sample data 2"}]' + headers: + Content-Length: + - '396' + Content-Type: + - application/json + User-Agent: + - azsdk-python-eventgridpublisherclient/4.0.0 Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://customeventgridtestegtopic.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 + response: + body: + string: '' + headers: + api-supported-versions: '2018-01-01' + content-length: '0' + date: Tue, 09 Mar 2021 23:37:23 GMT + server: Microsoft-HTTPAPI/2.0 + strict-transport-security: max-age=31536000; includeSubDomains + status: + code: 200 + message: OK + url: https://customeventgridtestbz4pr.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 +version: 1 diff --git a/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_event_grid_event_data_as_list.yaml b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_event_grid_event_data_as_list.yaml new file mode 100644 index 00000000000..bff67118749 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_event_grid_event_data_as_list.yaml @@ -0,0 +1,30 @@ +interactions: +- request: + body: '[{"id": "382fff4a-c3cb-4646-992c-3f0d5b369de6", "subject": "sample", "data": + "eventgridevent", "eventType": "Sample.EventGrid.Event", "eventTime": "2021-03-09T23:37:37.658738Z", + "dataVersion": "2.0"}, {"id": "fd0af8df-871a-4138-aef7-2e13d27564f2", "subject": + "sample2", "data": "eventgridevent2", "eventType": "Sample.EventGrid.Event", + "eventTime": "2021-03-09T23:37:37.658738Z", "dataVersion": "2.0"}]' + headers: + Content-Length: + - '402' + Content-Type: + - application/json; charset=utf-8 + User-Agent: + - azsdk-python-eventgridpublisherclient/4.0.0 Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://eventgridtestegtopic.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 + response: + body: + string: '' + headers: + api-supported-versions: '2018-01-01' + content-length: '0' + date: Tue, 09 Mar 2021 23:37:37 GMT + server: Microsoft-HTTPAPI/2.0 + strict-transport-security: max-age=31536000; includeSubDomains + status: + code: 200 + message: OK + url: https://eventgridtestzs77j53quzy.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 +version: 1 diff --git a/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_event_grid_event_data_dict.yaml b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_event_grid_event_data_dict.yaml new file mode 100644 index 00000000000..16a819e6eb9 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_event_grid_event_data_dict.yaml @@ -0,0 +1,28 @@ +interactions: +- request: + body: '[{"id": "19b5b900-2f95-41c9-8b26-7f4997b0407b", "subject": "sample", "data": + {"sample": "eventgridevent"}, "eventType": "Sample.EventGrid.Event", "eventTime": + "2021-03-09T23:37:38.133744Z", "dataVersion": "2.0"}]' + headers: + Content-Length: + - '212' + Content-Type: + - application/json; charset=utf-8 + User-Agent: + - azsdk-python-eventgridpublisherclient/4.0.0 Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://eventgridtestegtopic.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 + response: + body: + string: '' + headers: + api-supported-versions: '2018-01-01' + content-length: '0' + date: Tue, 09 Mar 2021 23:37:37 GMT + server: Microsoft-HTTPAPI/2.0 + strict-transport-security: max-age=31536000; includeSubDomains + status: + code: 200 + message: OK + url: https://eventgridtestzs77j53quzy.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 +version: 1 diff --git a/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_event_grid_event_data_str.yaml b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_event_grid_event_data_str.yaml new file mode 100644 index 00000000000..062ea7e5374 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_event_grid_event_data_str.yaml @@ -0,0 +1,28 @@ +interactions: +- request: + body: '[{"id": "c9f98dbc-9b68-40e2-9446-58c7b7a2d745", "subject": "sample", "data": + "eventgridevent", "eventType": "Sample.EventGrid.Event", "eventTime": "2021-03-09T23:37:38.476044Z", + "dataVersion": "2.0"}]' + headers: + Content-Length: + - '200' + Content-Type: + - application/json; charset=utf-8 + User-Agent: + - azsdk-python-eventgridpublisherclient/4.0.0 Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://eventgridtestegtopic.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 + response: + body: + string: '' + headers: + api-supported-versions: '2018-01-01' + content-length: '0' + date: Tue, 09 Mar 2021 23:37:38 GMT + server: Microsoft-HTTPAPI/2.0 + strict-transport-security: max-age=31536000; includeSubDomains + status: + code: 200 + message: OK + url: https://eventgridtestzs77j53quzy.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 +version: 1 diff --git a/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_signature_credential.yaml b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_signature_credential.yaml new file mode 100644 index 00000000000..0f632393573 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client_async.test_send_signature_credential.yaml @@ -0,0 +1,28 @@ +interactions: +- request: + body: '[{"id": "ff9a22f0-95f4-4aab-85a5-6719e5396d5c", "subject": "sample", "data": + {"sample": "eventgridevent"}, "eventType": "Sample.EventGrid.Event", "eventTime": + "2021-03-10T17:46:05.537294Z", "dataVersion": "2.0"}]' + headers: + Content-Length: + - '212' + Content-Type: + - application/json; charset=utf-8 + User-Agent: + - azsdk-python-eventgridpublisherclient/4.0.0 Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://eventgridtestegtopic.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 + response: + body: + string: '' + headers: + api-supported-versions: '2018-01-01' + content-length: '0' + date: Wed, 10 Mar 2021 17:46:04 GMT + server: Microsoft-HTTPAPI/2.0 + strict-transport-security: max-age=31536000; includeSubDomains + status: + code: 200 + message: OK + url: https://eventgridtesti6xu5cqpiro.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 +version: 1 diff --git a/sdk/eventgrid/azure-eventgrid/tests/test_cloud_event_tracing.py b/sdk/eventgrid/azure-eventgrid/tests/test_cloud_event_tracing.py new file mode 100644 index 00000000000..feed7d9865d --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/tests/test_cloud_event_tracing.py @@ -0,0 +1,67 @@ +#------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +#-------------------------------------------------------------------------- + +import pytest +import json + +from azure.core.pipeline import ( + PipelineRequest, + PipelineContext +) +from azure.core.pipeline.transport import HttpRequest +from azure.core.messaging import CloudEvent +from azure.eventgrid._policies import CloudEventDistributedTracingPolicy +from _mocks import ( + cloud_storage_dict +) + +_content_type = "application/cloudevents-batch+json; charset=utf-8" +_traceparent_value = "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01" +_tracestate_value = "rojo=00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01,congo=lZWRzIHRoNhcm5hbCBwbGVhc3VyZS4" + + +class EventGridSerializationTests(object): + + def test_cloud_event_policy_copies(self): + policy = CloudEventDistributedTracingPolicy() + + body = json.dumps([cloud_storage_dict]) + universal_request = HttpRequest('POST', 'http://127.0.0.1/', data=body) + universal_request.headers['content-type'] = _content_type + universal_request.headers['traceparent'] = _traceparent_value + universal_request.headers['tracestate'] = _tracestate_value + + request = PipelineRequest(universal_request, PipelineContext(None)) + + resp = policy.on_request(request) + + body = json.loads(request.http_request.body) + + for item in body: + assert 'traceparent' in item + assert 'tracestate' in item + + def test_cloud_event_policy_no_copy_if_trace_exists(self): + policy = CloudEventDistributedTracingPolicy() + + cloud_storage_dict.update({'traceparent': 'exists', 'tracestate': 'state_exists'}) + body = json.dumps([cloud_storage_dict]) + universal_request = HttpRequest('POST', 'http://127.0.0.1/', data=body) + universal_request.headers['content-type'] = _content_type + universal_request.headers['traceparent'] = _traceparent_value + universal_request.headers['tracestate'] = _tracestate_value + + request = PipelineRequest(universal_request, PipelineContext(None)) + + resp = policy.on_request(request) + + body = json.loads(request.http_request.body) + + for item in body: + assert 'traceparent' in item + assert 'tracestate' in item + assert item['traceparent'] == 'exists' + assert item['tracestate'] == 'state_exists' diff --git a/sdk/eventgrid/azure-eventgrid/tests/test_eg_event_get_bytes.py b/sdk/eventgrid/azure-eventgrid/tests/test_eg_event_get_bytes.py new file mode 100644 index 00000000000..1ae80ecde2c --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/tests/test_eg_event_get_bytes.py @@ -0,0 +1,266 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +import datetime +import pytest +import uuid +from msrest.serialization import UTC +from azure.eventgrid._messaging_shared import _get_json_content +from azure.eventgrid import EventGridEvent + +class MockQueueMessage(object): + def __init__(self, content=None): + self.id = uuid.uuid4() + self.inserted_on = datetime.datetime.now() + self.expires_on = datetime.datetime.now() + datetime.timedelta(days=100) + self.dequeue_count = 1 + self.content = content + self.pop_receipt = None + self.next_visible_on = None + +class MockServiceBusReceivedMessage(object): + def __init__(self, body=None, **kwargs): + self.body=body + self.application_properties=None + self.session_id=None + self.message_id='3f6c5441-5be5-4f33-80c3-3ffeb6a090ce' + self.content_type='application/cloudevents+json; charset=utf-8' + self.correlation_id=None + self.to=None + self.reply_to=None + self.reply_to_session_id=None + self.subject=None + self.time_to_live=datetime.timedelta(days=14) + self.partition_key=None + self.scheduled_enqueue_time_utc=None + self.auto_renew_error=None, + self.dead_letter_error_description=None + self.dead_letter_reason=None + self.dead_letter_source=None + self.delivery_count=13 + self.enqueued_sequence_number=0 + self.enqueued_time_utc=datetime.datetime(2021, 7, 22, 22, 27, 41, 236000) + self.expires_at_utc=datetime.datetime(2021, 8, 5, 22, 27, 41, 236000) + self.sequence_number=11219 + self.lock_token='233146e3-d5a6-45eb-826f-691d82fb8b13' + +class MockEventhubData(object): + def __init__(self, body=None): + self._last_enqueued_event_properties = {} + self._sys_properties = None + if body is None: + raise ValueError("EventData cannot be None.") + + # Internal usage only for transforming AmqpAnnotatedMessage to outgoing EventData + self.body=body + self._raw_amqp_message = "some amqp data" + self.message_id = None + self.content_type = None + self.correlation_id = None + + +class MockBody(object): + def __init__(self, data=None): + self.data = data + + def __iter__(self): + return self + + def __next__(self): + if not self.data: + return """{"id":"f208feff-099b-4bda-a341-4afd0fa02fef","subject":"https://egsample.dev/sampleevent","data":"ServiceBus","event_type":"Azure.Sdk.Sample","event_time":"2021-07-22T22:27:38.960209Z","data_version":"1.0"}""" + return self.data + + next = __next__ + + +class MockEhBody(object): + def __init__(self, data=None): + self.data = data + + def __iter__(self): + return self + + def __next__(self): + if not self.data: + return b'[{"id":"f208feff-099b-4bda-a341-4afd0fa02fef","subject":"https://egsample.dev/sampleevent","data":"Eventhub","event_type":"Azure.Sdk.Sample","event_time":"2021-07-22T22:27:38.960209Z","data_version":"1.0"}]' + return self.data + + next = __next__ + +def test_get_bytes_storage_queue(): + cloud_storage_dict = """{ + "id":"a0517898-9fa4-4e70-b4a3-afda1dd68672", + "subject":"/subscriptions/{subscription-id}/resourceGroups/{resource-group}/providers/Microsoft.Storage/storageAccounts/{storage-account}", + "data":{ + "api":"PutBlockList", + "client_request_id":"6d79dbfb-0e37-4fc4-981f-442c9ca65760", + "request_id":"831e1650-001e-001b-66ab-eeb76e000000", + "e_tag":"0x8D4BCC2E4835CD0", + "content_type":"application/octet-stream", + "content_length":524288, + "blob_type":"BlockBlob", + "url":"https://oc2d2817345i60006.blob.core.windows.net/oc2d2817345i200097container/oc2d2817345i20002296blob", + "sequencer":"00000000000004420000000000028963", + "storage_diagnostics":{"batchId":"b68529f3-68cd-4744-baa4-3c0498ec19f0"} + }, + "event_type":"Microsoft.Storage.BlobCreated", + "event_time":"2021-02-18T20:18:10.581147898Z", + "data_version":"1.0" + }""" + obj = MockQueueMessage(content=cloud_storage_dict) + + dict = _get_json_content(obj) + assert dict.get('data') == { + "api":"PutBlockList", + "client_request_id":"6d79dbfb-0e37-4fc4-981f-442c9ca65760", + "request_id":"831e1650-001e-001b-66ab-eeb76e000000", + "e_tag":"0x8D4BCC2E4835CD0", + "content_type":"application/octet-stream", + "content_length":524288, + "blob_type":"BlockBlob", + "url":"https://oc2d2817345i60006.blob.core.windows.net/oc2d2817345i200097container/oc2d2817345i20002296blob", + "sequencer":"00000000000004420000000000028963", + "storage_diagnostics":{"batchId":"b68529f3-68cd-4744-baa4-3c0498ec19f0"} + } + assert dict.get('data_version') == "1.0" + +def test_get_bytes_storage_queue_wrong_content(): + string = u'This is a random string which must fail' + obj = MockQueueMessage(content=string) + + with pytest.raises(ValueError, match="Failed to load JSON content from the object."): + _get_json_content(obj) + +def test_get_bytes_servicebus(): + obj = MockServiceBusReceivedMessage( + body=MockBody(), + message_id='3f6c5441-5be5-4f33-80c3-3ffeb6a090ce', + content_type='application/cloudevents+json; charset=utf-8', + time_to_live=datetime.timedelta(days=14), + delivery_count=13, + enqueued_sequence_number=0, + enqueued_time_utc=datetime.datetime(2021, 7, 22, 22, 27, 41, 236000), + expires_at_utc=datetime.datetime(2021, 8, 5, 22, 27, 41, 236000), + sequence_number=11219, + lock_token='233146e3-d5a6-45eb-826f-691d82fb8b13' + ) + dict = _get_json_content(obj) + assert dict.get('data') == "ServiceBus" + assert dict.get('data_version') == '1.0' + +def test_get_bytes_servicebus_wrong_content(): + obj = MockServiceBusReceivedMessage( + body=MockBody(data='random'), + message_id='3f6c5441-5be5-4f33-80c3-3ffeb6a090ce', + content_type='application/json; charset=utf-8', + time_to_live=datetime.timedelta(days=14), + delivery_count=13, + enqueued_sequence_number=0, + enqueued_time_utc=datetime.datetime(2021, 7, 22, 22, 27, 41, 236000), + expires_at_utc=datetime.datetime(2021, 8, 5, 22, 27, 41, 236000), + sequence_number=11219, + lock_token='233146e3-d5a6-45eb-826f-691d82fb8b13' + ) + with pytest.raises(ValueError, match="Failed to load JSON content from the object."): + dict = _get_json_content(obj) + + +def test_get_bytes_eventhubs(): + obj = MockEventhubData( + body=MockEhBody() + ) + dict = _get_json_content(obj) + assert dict.get('data') == 'Eventhub' + assert dict.get('data_version') == '1.0' + +def test_get_bytes_eventhubs_wrong_content(): + obj = MockEventhubData( + body=MockEhBody(data='random string') + ) + + with pytest.raises(ValueError, match="Failed to load JSON content from the object."): + dict = _get_json_content(obj) + + +def test_get_bytes_random_obj(): + json_str = '{"id": "de0fd76c-4ef4-4dfb-ab3a-8f24a307e033", "subject": "https://egtest.dev/cloudcustomevent", "data": {"team": "event grid squad"}, "event_type": "Azure.Sdk.Sample", "event_time": "2020-08-07T02:06:08.11969Z", "data_version": "1.0"}' + random_obj = { + "id":"de0fd76c-4ef4-4dfb-ab3a-8f24a307e033", + "subject":"https://egtest.dev/cloudcustomevent", + "data":{"team": "event grid squad"}, + "event_type":"Azure.Sdk.Sample", + "event_time":"2020-08-07T02:06:08.11969Z", + "data_version":"1.0", + } + + assert _get_json_content(json_str) == random_obj + +def test_from_json_sb(): + obj = MockServiceBusReceivedMessage( + body=MockBody(), + message_id='3f6c5441-5be5-4f33-80c3-3ffeb6a090ce', + content_type='application/cloudevents+json; charset=utf-8', + time_to_live=datetime.timedelta(days=14), + delivery_count=13, + enqueued_sequence_number=0, + enqueued_time_utc=datetime.datetime(2021, 7, 22, 22, 27, 41, 236000), + expires_at_utc=datetime.datetime(2021, 8, 5, 22, 27, 41, 236000), + sequence_number=11219, + lock_token='233146e3-d5a6-45eb-826f-691d82fb8b13' + ) + event = EventGridEvent.from_json(obj) + + assert event.id == "f208feff-099b-4bda-a341-4afd0fa02fef" + assert event.data == "ServiceBus" + +def test_from_json_eh(): + obj = MockEventhubData( + body=MockEhBody() + ) + event = EventGridEvent.from_json(obj) + assert event.id == "f208feff-099b-4bda-a341-4afd0fa02fef" + assert event.data == "Eventhub" + +def test_from_json_storage(): + eg_storage_dict = """{ + "id":"a0517898-9fa4-4e70-b4a3-afda1dd68672", + "subject":"/subscriptions/{subscription-id}/resourceGroups/{resource-group}/providers/Microsoft.Storage/storageAccounts/{storage-account}", + "data":{ + "api":"PutBlockList", + "client_request_id":"6d79dbfb-0e37-4fc4-981f-442c9ca65760", + "request_id":"831e1650-001e-001b-66ab-eeb76e000000", + "e_tag":"0x8D4BCC2E4835CD0", + "content_type":"application/octet-stream", + "content_length":524288, + "blob_type":"BlockBlob", + "url":"https://oc2d2817345i60006.blob.core.windows.net/oc2d2817345i200097container/oc2d2817345i20002296blob", + "sequencer":"00000000000004420000000000028963", + "storage_diagnostics":{"batchId":"b68529f3-68cd-4744-baa4-3c0498ec19f0"} + }, + "event_type":"Microsoft.Storage.BlobCreated", + "event_time":"2021-02-18T20:18:10.581147898Z", + "data_version":"1.0" + }""" + obj = MockQueueMessage(content=eg_storage_dict) + event = EventGridEvent.from_json(obj) + assert event.data == { + "api":"PutBlockList", + "client_request_id":"6d79dbfb-0e37-4fc4-981f-442c9ca65760", + "request_id":"831e1650-001e-001b-66ab-eeb76e000000", + "e_tag":"0x8D4BCC2E4835CD0", + "content_type":"application/octet-stream", + "content_length":524288, + "blob_type":"BlockBlob", + "url":"https://oc2d2817345i60006.blob.core.windows.net/oc2d2817345i200097container/oc2d2817345i20002296blob", + "sequencer":"00000000000004420000000000028963", + "storage_diagnostics":{"batchId":"b68529f3-68cd-4744-baa4-3c0498ec19f0"} + } + + +def test_from_json(): + json_str = '{"id": "de0fd76c-4ef4-4dfb-ab3a-8f24a307e033", "subject": "https://egtest.dev/cloudcustomevent", "data": {"team": "event grid squad"}, "event_type": "Azure.Sdk.Sample", "event_time": "2020-08-07T02:06:08.11969Z", "data_version": "1.0"}' + event = EventGridEvent.from_json(json_str) + assert event.data == {"team": "event grid squad"} + assert event.event_time == datetime.datetime(2020, 8, 7, 2, 6, 8, 119690, UTC()) diff --git a/sdk/eventgrid/azure-eventgrid/tests/test_eg_publisher_client.py b/sdk/eventgrid/azure-eventgrid/tests/test_eg_publisher_client.py new file mode 100644 index 00000000000..3651363c243 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/tests/test_eg_publisher_client.py @@ -0,0 +1,361 @@ +#------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +#-------------------------------------------------------------------------- + +import logging +import sys +import os +import json +import pytest +import uuid +from datetime import datetime, timedelta +from msrest.serialization import UTC +import datetime as dt + +try: + from urllib.parse import urlparse +except ImportError: + from urlparse import urlparse + +from devtools_testutils import AzureMgmtTestCase, CachedResourceGroupPreparer + +from azure_devtools.scenario_tests import ReplayableTest +from azure.core.credentials import AzureKeyCredential, AzureSasCredential +from azure.core.messaging import CloudEvent +from azure.core.serialization import NULL +from azure.eventgrid import EventGridPublisherClient, EventGridEvent, generate_sas +from azure.eventgrid._helpers import _cloud_event_to_generated + +from eventgrid_preparer import ( + CachedEventGridTopicPreparer, +) + +class EventGridPublisherClientTests(AzureMgmtTestCase): + FILTER_HEADERS = ReplayableTest.FILTER_HEADERS + ['aeg-sas-key', 'aeg-sas-token'] + + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='eventgridtest') + def test_send_event_grid_event_data_dict(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + akc_credential = AzureKeyCredential(eventgrid_topic_primary_key) + client = EventGridPublisherClient(eventgrid_topic_endpoint, akc_credential) + eg_event = EventGridEvent( + subject="sample", + data={"sample": "eventgridevent"}, + event_type="Sample.EventGrid.Event", + data_version="2.0" + ) + client.send(eg_event) + + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='eventgridtest') + def test_send_event_grid_event_fails_without_full_url(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + akc_credential = AzureKeyCredential(eventgrid_topic_primary_key) + parsed_url = urlparse(eventgrid_topic_endpoint) + client = EventGridPublisherClient(parsed_url.netloc, akc_credential) + eg_event = EventGridEvent( + subject="sample", + data={"sample": "eventgridevent"}, + event_type="Sample.EventGrid.Event", + data_version="2.0" + ) + with pytest.raises(ValueError): + client.send(eg_event) + + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='eventgridtest') + def test_send_event_grid_event_data_as_list(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + akc_credential = AzureKeyCredential(eventgrid_topic_primary_key) + client = EventGridPublisherClient(eventgrid_topic_endpoint, akc_credential) + eg_event1 = EventGridEvent( + subject="sample", + data=u"eventgridevent", + event_type="Sample.EventGrid.Event", + data_version="2.0" + ) + eg_event2 = EventGridEvent( + subject="sample2", + data=u"eventgridevent2", + event_type="Sample.EventGrid.Event", + data_version="2.0" + ) + client.send([eg_event1, eg_event2]) + + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='eventgridtest') + def test_send_event_grid_event_data_str(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + akc_credential = AzureKeyCredential(eventgrid_topic_primary_key) + client = EventGridPublisherClient(eventgrid_topic_endpoint, akc_credential) + eg_event = EventGridEvent( + subject="sample", + data=u"eventgridevent", + event_type="Sample.EventGrid.Event", + data_version="2.0" + ) + client.send(eg_event) + + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='eventgridtest') + def test_send_event_grid_event_data_bytes(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + akc_credential = AzureKeyCredential(eventgrid_topic_primary_key) + client = EventGridPublisherClient(eventgrid_topic_endpoint, akc_credential) + eg_event = EventGridEvent( + subject="sample", + data=b"eventgridevent", + event_type="Sample.EventGrid.Event", + data_version="2.0" + ) + with pytest.raises(TypeError, match="Data in EventGridEvent cannot be bytes*"): + client.send(eg_event) + + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='eventgridtest') + def test_send_event_grid_event_dict_data_bytes(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + akc_credential = AzureKeyCredential(eventgrid_topic_primary_key) + client = EventGridPublisherClient(eventgrid_topic_endpoint, akc_credential) + eg_event = { + "subject":"sample", + "data":b"eventgridevent", + "eventType":"Sample.EventGrid.Event", + "dataVersion":"2.0", + "id": uuid.uuid4(), + "eventTime": datetime.now() + } + with pytest.raises(TypeError, match="Data in EventGridEvent cannot be bytes*"): + client.send(eg_event) + + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='eventgridtest') + def test_send_event_grid_event_dict_data_dict(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + akc_credential = AzureKeyCredential(eventgrid_topic_primary_key) + client = EventGridPublisherClient(eventgrid_topic_endpoint, akc_credential) + eg_event = { + "subject":"sample", + "data":{"key1": "Sample.EventGrid.Event"}, + "eventType":"Sample.EventGrid.Event", + "dataVersion":"2.0", + "id": uuid.uuid4(), + "eventTime": datetime.now() + } + client.send(eg_event) + + + ### CLOUD EVENT TESTS + + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='cloudeventgridtest') + def test_send_cloud_event_data_dict(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + akc_credential = AzureKeyCredential(eventgrid_topic_primary_key) + client = EventGridPublisherClient(eventgrid_topic_endpoint, akc_credential) + cloud_event = CloudEvent( + source = "http://samplesource.dev", + data = {"sample": "cloudevent"}, + type="Sample.Cloud.Event" + ) + client.send(cloud_event) + + @pytest.mark.skip("https://github.com/Azure/azure-sdk-for-python/issues/16993") + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='cloudeventgridtest') + def test_send_cloud_event_data_NULL(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + akc_credential = AzureKeyCredential(eventgrid_topic_primary_key) + client = EventGridPublisherClient(eventgrid_topic_endpoint, akc_credential) + cloud_event = CloudEvent( + source = "http://samplesource.dev", + data = NULL, + type="Sample.Cloud.Event" + ) + + def callback(request): + req = json.loads(request.http_request.body) + assert req[0].get("data") is None + + client.send(cloud_event, raw_request_hook=callback) + + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='cloudeventgridtest') + def test_send_cloud_event_data_base64_using_data(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + akc_credential = AzureKeyCredential(eventgrid_topic_primary_key) + client = EventGridPublisherClient(eventgrid_topic_endpoint, akc_credential) + cloud_event = CloudEvent( + source = "http://samplesource.dev", + data = b'cloudevent', + type="Sample.Cloud.Event" + ) + + def callback(request): + req = json.loads(request.http_request.body) + assert req[0].get("data_base64") is not None + assert req[0].get("data") is None + + client.send(cloud_event, raw_response_hook=callback) + + def test_send_cloud_event_fails_on_providing_data_and_b64(self): + with pytest.raises(ValueError, match="Unexpected keyword arguments data_base64.*"): + cloud_event = CloudEvent( + source = "http://samplesource.dev", + data_base64 = b'cloudevent', + data = "random data", + type="Sample.Cloud.Event" + ) + + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='cloudeventgridtest') + def test_send_cloud_event_data_none(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + akc_credential = AzureKeyCredential(eventgrid_topic_primary_key) + client = EventGridPublisherClient(eventgrid_topic_endpoint, akc_credential) + cloud_event = CloudEvent( + source = "http://samplesource.dev", + data = None, + type="Sample.Cloud.Event" + ) + client.send(cloud_event) + + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='cloudeventgridtest') + def test_send_cloud_event_data_str(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + akc_credential = AzureKeyCredential(eventgrid_topic_primary_key) + client = EventGridPublisherClient(eventgrid_topic_endpoint, akc_credential) + cloud_event = CloudEvent( + source = "http://samplesource.dev", + data = "cloudevent", + type="Sample.Cloud.Event" + ) + client.send(cloud_event) + + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='cloudeventgridtest') + def test_send_cloud_event_data_bytes(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + akc_credential = AzureKeyCredential(eventgrid_topic_primary_key) + client = EventGridPublisherClient(eventgrid_topic_endpoint, akc_credential) + cloud_event = CloudEvent( + source = "http://samplesource.dev", + data = b"cloudevent", + type="Sample.Cloud.Event" + ) + client.send(cloud_event) + + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='cloudeventgridtest') + def test_send_cloud_event_data_as_list(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + akc_credential = AzureKeyCredential(eventgrid_topic_primary_key) + client = EventGridPublisherClient(eventgrid_topic_endpoint, akc_credential) + cloud_event = CloudEvent( + source = "http://samplesource.dev", + data = "cloudevent", + type="Sample.Cloud.Event" + ) + client.send([cloud_event]) + + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='cloudeventgridtest') + def test_send_cloud_event_data_with_extensions(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + akc_credential = AzureKeyCredential(eventgrid_topic_primary_key) + client = EventGridPublisherClient(eventgrid_topic_endpoint, akc_credential) + cloud_event = CloudEvent( + source = "http://samplesource.dev", + data = "cloudevent", + type="Sample.Cloud.Event", + extensions={ + 'reasoncode':204, + 'extension':'hello' + } + ) + client.send([cloud_event]) + internal = _cloud_event_to_generated(cloud_event).serialize() + assert 'reasoncode' in internal + assert 'extension' in internal + assert internal['reasoncode'] == 204 + + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='cloudeventgridtest') + def test_send_cloud_event_dict(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + akc_credential = AzureKeyCredential(eventgrid_topic_primary_key) + client = EventGridPublisherClient(eventgrid_topic_endpoint, akc_credential) + cloud_event1 = { + "id": "1234", + "source": "http://samplesource.dev", + "specversion": "1.0", + "data": "cloudevent", + "type": "Sample.Cloud.Event" + } + client.send(cloud_event1) + + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='eventgridtest') + def test_send_signature_credential(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + expiration_date_utc = dt.datetime.now(UTC()) + timedelta(hours=1) + signature = generate_sas(eventgrid_topic_endpoint, eventgrid_topic_primary_key, expiration_date_utc) + credential = AzureSasCredential(signature) + client = EventGridPublisherClient(eventgrid_topic_endpoint, credential) + eg_event = EventGridEvent( + subject="sample", + data={"sample": "eventgridevent"}, + event_type="Sample.EventGrid.Event", + data_version="2.0" + ) + client.send(eg_event) + + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='eventgridtest') + def test_send_NONE_credential(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + with pytest.raises(ValueError, match="Parameter 'self._credential' must not be None."): + client = EventGridPublisherClient(eventgrid_topic_endpoint, None) + + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='customeventgridtest') + def test_send_custom_schema_event(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + akc_credential = AzureKeyCredential(eventgrid_topic_primary_key) + client = EventGridPublisherClient(eventgrid_topic_endpoint, akc_credential) + custom_event = { + "customSubject": "sample", + "customEventType": "sample.event", + "customDataVersion": "2.0", + "customId": "1234", + "customEventTime": dt.datetime.now(UTC()).isoformat(), + "customData": "sample data" + } + client.send(custom_event) + + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='customeventgridtest') + def test_send_custom_schema_event_as_list(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + akc_credential = AzureKeyCredential(eventgrid_topic_primary_key) + client = EventGridPublisherClient(eventgrid_topic_endpoint, akc_credential) + custom_event1 = { + "customSubject": "sample", + "customEventType": "sample.event", + "customDataVersion": "2.0", + "customId": "1234", + "customEventTime": dt.datetime.now(UTC()).isoformat(), + "customData": "sample data" + } + custom_event2 = { + "customSubject": "sample2", + "customEventType": "sample.event", + "customDataVersion": "2.0", + "customId": "12345", + "customEventTime": dt.datetime.now(UTC()).isoformat(), + "customData": "sample data 2" + } + client.send([custom_event1, custom_event2]) + + def test_send_throws_with_bad_credential(self): + bad_credential = "I am a bad credential" + with pytest.raises(ValueError, match="The provided credential should be an instance of a TokenCredential, AzureSasCredential or AzureKeyCredential"): + client = EventGridPublisherClient("eventgrid_endpoint", bad_credential) + + @pytest.mark.live_test_only + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='eventgridtest') + def test_send_token_credential(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + credential = self.get_credential(EventGridPublisherClient) + client = EventGridPublisherClient(eventgrid_topic_endpoint, credential) + eg_event = EventGridEvent( + subject="sample", + data={"sample": "eventgridevent"}, + event_type="Sample.EventGrid.Event", + data_version="2.0" + ) + client.send(eg_event) diff --git a/sdk/eventgrid/azure-eventgrid/tests/test_eg_publisher_client_async.py b/sdk/eventgrid/azure-eventgrid/tests/test_eg_publisher_client_async.py new file mode 100644 index 00000000000..b2ec715a6a6 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/tests/test_eg_publisher_client_async.py @@ -0,0 +1,347 @@ +#------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +#-------------------------------------------------------------------------- + +import logging +import asyncio +import sys +import os +import json +import pytest +from datetime import timedelta +from msrest.serialization import UTC +from urllib.parse import urlparse +import datetime as dt + +from devtools_testutils import AzureMgmtTestCase, CachedResourceGroupPreparer + +from azure_devtools.scenario_tests import ReplayableTest +from azure.core.credentials import AzureKeyCredential, AzureSasCredential +from azure.core.messaging import CloudEvent +from azure.core.serialization import NULL +from azure.eventgrid import EventGridEvent, generate_sas +from azure.eventgrid.aio import EventGridPublisherClient +from azure.eventgrid._helpers import _cloud_event_to_generated + +from eventgrid_preparer import ( + CachedEventGridTopicPreparer +) + + +class EventGridPublisherClientTests(AzureMgmtTestCase): + FILTER_HEADERS = ReplayableTest.FILTER_HEADERS + ['aeg-sas-key', 'aeg-sas-token'] + + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='eventgridtest') + @pytest.mark.asyncio + async def test_send_event_grid_event_data_dict(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + akc_credential = AzureKeyCredential(eventgrid_topic_primary_key) + client = EventGridPublisherClient(eventgrid_topic_endpoint, akc_credential) + eg_event = EventGridEvent( + subject="sample", + data={"sample": "eventgridevent"}, + event_type="Sample.EventGrid.Event", + data_version="2.0" + ) + await client.send(eg_event) + + + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='eventgridtest') + @pytest.mark.asyncio + async def test_send_event_grid_event_data_as_list(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + akc_credential = AzureKeyCredential(eventgrid_topic_primary_key) + client = EventGridPublisherClient(eventgrid_topic_endpoint, akc_credential) + eg_event1 = EventGridEvent( + subject="sample", + data="eventgridevent", + event_type="Sample.EventGrid.Event", + data_version="2.0" + ) + eg_event2 = EventGridEvent( + subject="sample2", + data="eventgridevent2", + event_type="Sample.EventGrid.Event", + data_version="2.0" + ) + await client.send([eg_event1, eg_event2]) + + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='eventgridtest') + @pytest.mark.asyncio + async def test_send_event_grid_event_fails_without_full_url(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + akc_credential = AzureKeyCredential(eventgrid_topic_primary_key) + parsed_url = urlparse(eventgrid_topic_endpoint) + client = EventGridPublisherClient(parsed_url.netloc, akc_credential) + eg_event = EventGridEvent( + subject="sample", + data={"sample": "eventgridevent"}, + event_type="Sample.EventGrid.Event", + data_version="2.0" + ) + with pytest.raises(ValueError): + await client.send(eg_event) + + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='eventgridtest') + @pytest.mark.asyncio + async def test_send_event_grid_event_data_str(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + akc_credential = AzureKeyCredential(eventgrid_topic_primary_key) + client = EventGridPublisherClient(eventgrid_topic_endpoint, akc_credential) + eg_event = EventGridEvent( + subject="sample", + data="eventgridevent", + event_type="Sample.EventGrid.Event", + data_version="2.0" + ) + await client.send(eg_event) + + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='eventgridtest') + @pytest.mark.asyncio + async def test_send_event_grid_event_data_bytes(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + akc_credential = AzureKeyCredential(eventgrid_topic_primary_key) + client = EventGridPublisherClient(eventgrid_topic_endpoint, akc_credential) + eg_event = EventGridEvent( + subject="sample", + data=b"eventgridevent", + event_type="Sample.EventGrid.Event", + data_version="2.0" + ) + with pytest.raises(TypeError, match="Data in EventGridEvent cannot be bytes*"): + await client.send(eg_event) + + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='eventgridtest') + @pytest.mark.asyncio + async def test_send_event_grid_event_dict_data_bytes(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + akc_credential = AzureKeyCredential(eventgrid_topic_primary_key) + client = EventGridPublisherClient(eventgrid_topic_endpoint, akc_credential) + eg_event = { + "subject":"sample", + "data":b"eventgridevent", + "eventType":"Sample.EventGrid.Event", + "dataVersion":"2.0", + "id": "123-ddf-133-324255ffd", + "eventTime": dt.datetime.utcnow() + } + with pytest.raises(TypeError, match="Data in EventGridEvent cannot be bytes*"): + await client.send(eg_event) + + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='cloudeventgridtest') + @pytest.mark.asyncio + async def test_send_cloud_event_data_dict(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + akc_credential = AzureKeyCredential(eventgrid_topic_primary_key) + client = EventGridPublisherClient(eventgrid_topic_endpoint, akc_credential) + cloud_event = CloudEvent( + source = "http://samplesource.dev", + data = {"sample": "cloudevent"}, + type="Sample.Cloud.Event" + ) + await client.send(cloud_event) + + + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='cloudeventgridtest') + @pytest.mark.asyncio + async def test_send_cloud_event_data_str(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + akc_credential = AzureKeyCredential(eventgrid_topic_primary_key) + client = EventGridPublisherClient(eventgrid_topic_endpoint, akc_credential) + cloud_event = CloudEvent( + source = "http://samplesource.dev", + data = "cloudevent", + type="Sample.Cloud.Event" + ) + await client.send(cloud_event) + + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='cloudeventgridtest') + @pytest.mark.asyncio + async def test_send_cloud_event_data_bytes(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + akc_credential = AzureKeyCredential(eventgrid_topic_primary_key) + client = EventGridPublisherClient(eventgrid_topic_endpoint, akc_credential) + cloud_event = CloudEvent( + source = "http://samplesource.dev", + data = b"cloudevent", + type="Sample.Cloud.Event" + ) + await client.send(cloud_event) + + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='cloudeventgridtest') + @pytest.mark.asyncio + async def test_send_cloud_event_data_as_list(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + akc_credential = AzureKeyCredential(eventgrid_topic_primary_key) + client = EventGridPublisherClient(eventgrid_topic_endpoint, akc_credential) + cloud_event = CloudEvent( + source = "http://samplesource.dev", + data = "cloudevent", + type="Sample.Cloud.Event" + ) + await client.send([cloud_event]) + + + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='cloudeventgridtest') + @pytest.mark.asyncio + async def test_send_cloud_event_data_with_extensions(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + akc_credential = AzureKeyCredential(eventgrid_topic_primary_key) + client = EventGridPublisherClient(eventgrid_topic_endpoint, akc_credential) + cloud_event = CloudEvent( + source = "http://samplesource.dev", + data = "cloudevent", + type="Sample.Cloud.Event", + extensions={ + 'reasoncode':204, + 'extension':'hello' + } + ) + await client.send([cloud_event]) + internal = _cloud_event_to_generated(cloud_event).serialize() + assert 'reasoncode' in internal + assert 'extension' in internal + assert internal['reasoncode'] == 204 + + + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='cloudeventgridtest') + @pytest.mark.asyncio + async def test_send_cloud_event_dict(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + akc_credential = AzureKeyCredential(eventgrid_topic_primary_key) + client = EventGridPublisherClient(eventgrid_topic_endpoint, akc_credential) + cloud_event1 = { + "id": "1234", + "source": "http://samplesource.dev", + "specversion": "1.0", + "data": "cloudevent", + "type": "Sample.Cloud.Event" + } + await client.send(cloud_event1) + + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='cloudeventgridtest') + @pytest.mark.asyncio + async def test_send_cloud_event_data_none(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + akc_credential = AzureKeyCredential(eventgrid_topic_primary_key) + client = EventGridPublisherClient(eventgrid_topic_endpoint, akc_credential) + cloud_event = CloudEvent( + source = "http://samplesource.dev", + data = None, + type="Sample.Cloud.Event" + ) + await client.send(cloud_event) + + @pytest.mark.skip("https://github.com/Azure/azure-sdk-for-python/issues/16993") + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='cloudeventgridtest') + @pytest.mark.asyncio + async def test_send_cloud_event_data_NULL(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + akc_credential = AzureKeyCredential(eventgrid_topic_primary_key) + client = EventGridPublisherClient(eventgrid_topic_endpoint, akc_credential) + cloud_event = CloudEvent( + source = "http://samplesource.dev", + data = NULL, + type="Sample.Cloud.Event" + ) + def callback(request): + req = json.loads(request.http_request.body) + assert req[0].get("data") is None + + await client.send(cloud_event, raw_request_hook=callback) + + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='eventgridtest') + @pytest.mark.asyncio + async def test_send_signature_credential(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + expiration_date_utc = dt.datetime.now(UTC()) + timedelta(hours=1) + signature = generate_sas(eventgrid_topic_endpoint, eventgrid_topic_primary_key, expiration_date_utc) + credential = AzureSasCredential(signature) + client = EventGridPublisherClient(eventgrid_topic_endpoint, credential) + eg_event = EventGridEvent( + subject="sample", + data={"sample": "eventgridevent"}, + event_type="Sample.EventGrid.Event", + data_version="2.0" + ) + await client.send(eg_event) + + + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='customeventgridtest') + @pytest.mark.asyncio + async def test_send_custom_schema_event(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + akc_credential = AzureKeyCredential(eventgrid_topic_primary_key) + client = EventGridPublisherClient(eventgrid_topic_endpoint, akc_credential) + custom_event = { + "customSubject": "sample", + "customEventType": "sample.event", + "customDataVersion": "2.0", + "customId": "1234", + "customEventTime": dt.datetime.now(UTC()).isoformat(), + "customData": "sample data" + } + await client.send(custom_event) + + + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='customeventgridtest') + @pytest.mark.asyncio + async def test_send_custom_schema_event_as_list(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + akc_credential = AzureKeyCredential(eventgrid_topic_primary_key) + client = EventGridPublisherClient(eventgrid_topic_endpoint, akc_credential) + custom_event1 = { + "customSubject": "sample", + "customEventType": "sample.event", + "customDataVersion": "2.0", + "customId": "1234", + "customEventTime": dt.datetime.now(UTC()).isoformat(), + "customData": "sample data" + } + custom_event2 = { + "customSubject": "sample2", + "customEventType": "sample.event", + "customDataVersion": "2.0", + "customId": "12345", + "customEventTime": dt.datetime.now(UTC()).isoformat(), + "customData": "sample data 2" + } + await client.send([custom_event1, custom_event2]) + + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='cloudeventgridtest') + @pytest.mark.asyncio + async def test_send_and_close_async_session(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + akc_credential = AzureKeyCredential(eventgrid_topic_primary_key) + client = EventGridPublisherClient(eventgrid_topic_endpoint, akc_credential) + async with client: # this throws if client can't close + cloud_event = CloudEvent( + source = "http://samplesource.dev", + data = "cloudevent", + type="Sample.Cloud.Event" + ) + await client.send(cloud_event) + + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='cloudeventgridtest') + @pytest.mark.asyncio + def test_send_NONE_credential_async(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + with pytest.raises(ValueError, match="Parameter 'self._credential' must not be None."): + client = EventGridPublisherClient(eventgrid_topic_endpoint, None) + + @pytest.mark.live_test_only + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='eventgridtest') + @pytest.mark.asyncio + async def test_send_token_credential(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + credential = self.get_credential(EventGridPublisherClient) + client = EventGridPublisherClient(eventgrid_topic_endpoint, credential) + eg_event = EventGridEvent( + subject="sample", + data={"sample": "eventgridevent"}, + event_type="Sample.EventGrid.Event", + data_version="2.0" + ) + await client.send(eg_event) \ No newline at end of file diff --git a/sdk/eventgrid/azure-eventgrid/tests/test_serialization.py b/sdk/eventgrid/azure-eventgrid/tests/test_serialization.py new file mode 100644 index 00000000000..4336ae81ac5 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/tests/test_serialization.py @@ -0,0 +1,140 @@ +#------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +#-------------------------------------------------------------------------- + +import logging +import sys +import os +import pytest +import json +import base64 +import datetime as dt + +from devtools_testutils import AzureMgmtTestCase +from msrest.serialization import UTC +from azure.core.messaging import CloudEvent +from azure.eventgrid._generated import models as internal_models +from azure.eventgrid._helpers import _cloud_event_to_generated +from azure.eventgrid import SystemEventNames, EventGridEvent +from _mocks import ( + cloud_storage_dict, + cloud_storage_string, + cloud_storage_bytes, + ) + +class EventGridSerializationTests(AzureMgmtTestCase): + + def _assert_cloud_event_serialized(self, expected, actual): + assert expected['source'] == actual['source'] + assert expected['type'] == actual['type'] + assert actual['specversion'] == '1.0' + assert 'id' in actual + assert 'time' in actual + + # Cloud Event tests + def test_cloud_event_serialization_extension_bytes(self, **kwargs): + data = b"cloudevent" + cloud_event = CloudEvent( + source="http://samplesource.dev", + data=data, + type="Sample.Cloud.Event", + extensions={'e1':1, 'e2':2} + ) + + cloud_event.subject = "subject" # to test explicit setting of prop + encoded = base64.b64encode(data).decode('utf-8') + internal = _cloud_event_to_generated(cloud_event) + + assert internal.additional_properties is not None + assert 'e1' in internal.additional_properties + + json = internal.serialize() + + expected = { + 'source':'http://samplesource.dev', + 'data_base64': encoded, + 'type':'Sample.Cloud.Event', + 'reason_code':204, + 'e1':1, + 'e2':2 + } + + self._assert_cloud_event_serialized(expected, json) + assert expected['data_base64'] == json['data_base64'] + + + def test_cloud_event_serialization_extension_string(self, **kwargs): + data = "cloudevent" + cloud_event = CloudEvent( + source="http://samplesource.dev", + data=data, + type="Sample.Cloud.Event", + extensions={'e1':1, 'e2':2} + ) + + cloud_event.subject = "subject" # to test explicit setting of prop + internal = _cloud_event_to_generated(cloud_event) + + assert internal.additional_properties is not None + assert 'e1' in internal.additional_properties + + json = internal.serialize() + + expected = { + 'source':'http://samplesource.dev', + 'data': data, + 'type':'Sample.Cloud.Event', + 'reason_code':204, + 'e1':1, + 'e2':2 + } + + self._assert_cloud_event_serialized(expected, json) + if sys.version_info > (3, 5): + assert expected['data'] == json['data'] + else: + encoded = base64.b64encode(data).decode('utf-8') + expected['data_base64'] = encoded + assert expected['data_base64'] == json['data_base64'] + assert 'data' not in json + + def test_event_grid_event_raises_on_no_data(self): + with pytest.raises(TypeError): + eg_event = EventGridEvent( + subject="sample", + event_type="Sample.EventGrid.Event", + data_version="2.0" + ) + + def test_import_from_sytem_events(self): + var = SystemEventNames.AcsChatMemberAddedToThreadWithUserEventName + assert var == "Microsoft.Communication.ChatMemberAddedToThreadWithUser" + assert SystemEventNames.KeyVaultKeyNearExpiryEventName == "Microsoft.KeyVault.KeyNearExpiry" + var = SystemEventNames.ServiceBusActiveMessagesAvailableWithNoListenersEventName + assert var == "Microsoft.ServiceBus.ActiveMessagesAvailableWithNoListeners" + var = SystemEventNames.AcsChatThreadParticipantAddedEventName + assert var == "Microsoft.Communication.ChatThreadParticipantAdded" + var = SystemEventNames.AcsChatThreadParticipantRemovedEventName + assert var == "Microsoft.Communication.ChatThreadParticipantRemoved" + + def test_eg_event_repr(self): + event = EventGridEvent( + subject="sample2", + data="eventgridevent2", + event_type="Sample.EventGrid.Event", + data_version="2.0" + ) + + assert "EventGridEvent(subject=sample2" in event.__repr__() + + def test_servicebus_system_events_alias(self): + val = "Microsoft.ServiceBus.DeadletterMessagesAvailableWithNoListeners" + assert SystemEventNames.ServiceBusDeadletterMessagesAvailableWithNoListenerEventName == SystemEventNames.ServiceBusDeadletterMessagesAvailableWithNoListenersEventName + assert SystemEventNames.ServiceBusDeadletterMessagesAvailableWithNoListenerEventName == val + assert SystemEventNames.ServiceBusDeadletterMessagesAvailableWithNoListenersEventName == val + assert SystemEventNames(val) == SystemEventNames.ServiceBusDeadletterMessagesAvailableWithNoListenerEventName + assert SystemEventNames(val) == SystemEventNames.ServiceBusDeadletterMessagesAvailableWithNoListenersEventName + with pytest.raises(ValueError): + SystemEventNames("Microsoft.ServiceBus.DeadletterMessagesAvailableWithNoListener") diff --git a/sdk/eventgrid/ci.yml b/sdk/eventgrid/ci.yml index 1417f9ae133..454a46748bb 100644 --- a/sdk/eventgrid/ci.yml +++ b/sdk/eventgrid/ci.yml @@ -30,3 +30,5 @@ extends: Artifacts: - name: azure-mgmt-eventgrid safeName: azuremgmteventgrid + - name: azure-eventgrid + safeName: azureeventgrid diff --git a/sdk/eventgrid/test-resources.json b/sdk/eventgrid/test-resources.json new file mode 100644 index 00000000000..e3153ba1245 --- /dev/null +++ b/sdk/eventgrid/test-resources.json @@ -0,0 +1,127 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "baseName": { + "type": "String" + } + }, + "variables": { + "apiVersion": "2020-04-01-preview", + "eventGridTopicName": "[concat(parameters('baseName'), 'topic')]", + "eventGridDomainName": "[concat(parameters('baseName'), 'domain')]", + "cloudeventTopicName": "[concat(parameters('baseName'), 'cloudevent-topic')]", + "customeventTopicName": "[concat(parameters('baseName'), 'customevent-topic')]", + "cloudeventDomainName": "[concat(parameters('baseName'), 'cloudevent-domain')]" + }, + "resources": [ + { + "type": "Microsoft.EventGrid/topics", + "apiVersion": "[variables('apiVersion')]", + "name": "[variables('eventGridTopicName')]", + "location": "[resourceGroup().location]" + }, + { + "name": "[variables('eventGridDomainName')]", + "type": "Microsoft.EventGrid/domains", + "apiVersion": "[variables('apiVersion')]", + "location": "[resourceGroup().location]", + "properties": {} + }, + { + "type": "Microsoft.EventGrid/topics", + "apiVersion": "[variables('apiVersion')]", + "name": "[variables('cloudeventTopicName')]", + "location": "[resourceGroup().location]", + "properties": { + "inputSchema": "CloudEventSchemaV1_0" + } + }, + { + "name": "[variables('cloudeventDomainName')]", + "type": "Microsoft.EventGrid/domains", + "apiVersion": "[variables('apiVersion')]", + "location": "[resourceGroup().location]", + "properties": { + "inputSchema": "CloudEventSchemaV1_0" + } + }, + { + "type": "Microsoft.EventGrid/topics", + "apiVersion": "[variables('apiVersion')]", + "name": "[variables('customeventTopicName')]", + "location": "[resourceGroup().location]", + "properties": { + "inputSchema": "CustomEventSchema", + "inputSchemaMapping": { + "inputSchemaMappingType": "Json", + "properties": { + "dataVersion": { + "defaultValue": "default", + "sourceField": "TestVersion" + }, + "eventTime": { + "sourceField": "TestEventTime" + }, + "eventType": { + "defaultValue": "default", + "sourceField": "TestEventType" + }, + "id": { + "sourceField": "TestID" + }, + "subject": { + "defaultValue": "default", + "sourceField": "TestSubject" + }, + "topic": { + "sourceField": "TestTopic" + } + } + } + } + } + ], + "outputs": { + "EG_TOPIC_HOSTNAME": { + "type": "string", + "value": "[reference(variables('eventGridTopicName')).endpoint]" + }, + "EG_ACCESS_KEY": { + "type": "string", + "value": "[listKeys(resourceId('Microsoft.EventGrid/topics', variables('eventGridTopicName')), variables('apiVersion')).key1]" + }, + "EG_DOMAIN_TOPIC_HOSTNAME": { + "type": "string", + "value": "[reference(variables('eventGridDomainName')).endpoint]" + }, + "EG_DOMAIN_ACCESS_KEY": { + "type": "string", + "value": "[listKeys(resourceId('Microsoft.EventGrid/domains', variables('eventGridDomainName')), variables('apiVersion')).key1]" + }, + "CLOUD_TOPIC_HOSTNAME": { + "type": "string", + "value": "[reference(variables('cloudeventTopicName')).endpoint]" + }, + "CLOUD_ACCESS_KEY": { + "type": "string", + "value": "[listKeys(resourceId('Microsoft.EventGrid/topics', variables('cloudeventTopicName')), variables('apiVersion')).key1]" + }, + "DOMAIN_TOPIC_HOSTNAME": { + "type": "string", + "value": "[reference(variables('cloudeventDomainName')).endpoint]" + }, + "DOMAIN_ACCESS_KEY": { + "type": "string", + "value": "[listKeys(resourceId('Microsoft.EventGrid/domains', variables('cloudeventDomainName')), variables('apiVersion')).key1]" + }, + "CUSTOM_SCHEMA_TOPIC_HOSTNAME": { + "type": "string", + "value": "[reference(variables('customeventTopicName')).endpoint]" + }, + "CUSTOM_SCHEMA_ACCESS_KEY": { + "type": "string", + "value": "[listKeys(resourceId('Microsoft.EventGrid/topics', variables('customeventTopicName')), variables('apiVersion')).key1]" + } + } +} \ No newline at end of file diff --git a/sdk/eventgrid/tests.yml b/sdk/eventgrid/tests.yml new file mode 100644 index 00000000000..99b94c808f2 --- /dev/null +++ b/sdk/eventgrid/tests.yml @@ -0,0 +1,17 @@ +trigger: none + +stages: + - template: ../../eng/pipelines/templates/stages/archetype-sdk-tests.yml + parameters: + ServiceDirectory: eventgrid + BuildTargetingString: azure-eventgrid* + MatrixReplace: + - TestSamples=.*/true + EnvVars: + AZURE_STORAGE_CONNECTION_STRING: $(python-storage-blob-connection-string) + AZURE_SUBSCRIPTION_ID: $(azure-subscription-id) + AZURE_TENANT_ID: $(aad-azure-sdk-test-tenant-id) + AZURE_CLIENT_ID: $(aad-azure-sdk-test-client-id) + AZURE_CLIENT_SECRET: $(aad-azure-sdk-test-client-secret) + EVENTGRID_SAS: $(python-sdk-test-eg-sas) + STORAGE_QUEUE_NAME: $(python-storage-queue-name)