├── .github
├── ISSUE_TEMPLATE.md
└── PULL_REQUEST_TEMPLATE.md
├── .gitignore
├── .vscode
└── settings.json
├── CHANGELOG.md
├── CONTRIBUTING.md
├── ConsumerFunction
├── ConsumerFunction
│ ├── function.json
│ └── run.py
├── README.md
└── deploy_vscode.png
├── LICENSE.md
├── Pipfile
├── Pipfile.lock
├── README.md
├── create_arm_event_subscriptions.py
├── create_eg_topics_and_event_subscriptions.py
├── create_storage_event_subscriptions.py
├── env_template
└── event_grid_publisher.py
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
4 | > Please provide us with the following information:
5 | > ---------------------------------------------------------------
6 |
7 | ### This issue is for a: (mark with an `x`)
8 | ```
9 | - [ ] bug report -> please search issues before submitting
10 | - [ ] feature request
11 | - [ ] documentation issue or request
12 | - [ ] regression (a behavior that used to work and stopped in a new release)
13 | ```
14 |
15 | ### Minimal steps to reproduce
16 | >
17 |
18 | ### Any log messages given by the failure
19 | >
20 |
21 | ### Expected/desired behavior
22 | >
23 |
24 | ### OS and Version?
25 | > Windows 7, 8 or 10. Linux (which distribution). macOS (Yosemite? El Capitan? Sierra?)
26 |
27 | ### Versions
28 | >
29 |
30 | ### Mention any other details that might be useful
31 |
32 | > ---------------------------------------------------------------
33 | > Thanks! We'll be in touch soon.
34 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ## Purpose
2 |
3 | * ...
4 |
5 | ## Does this introduce a breaking change?
6 |
7 | ```
8 | [ ] Yes
9 | [ ] No
10 | ```
11 |
12 | ## Pull Request Type
13 | What kind of change does this Pull Request introduce?
14 |
15 |
16 | ```
17 | [ ] Bugfix
18 | [ ] Feature
19 | [ ] Code style update (formatting, local variables)
20 | [ ] Refactoring (no functional changes, no api changes)
21 | [ ] Documentation content changes
22 | [ ] Other... Please describe:
23 | ```
24 |
25 | ## How to Test
26 | * Get the code
27 |
28 | ```
29 | git clone [repo-address]
30 | cd [repo-name]
31 | git checkout [branch-name]
32 | npm install
33 | ```
34 |
35 | * Test the code
36 |
37 | ```
38 | ```
39 |
40 | ## What to Check
41 | Verify that the following are valid
42 | * ...
43 |
44 | ## Other Information
45 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | *.egg-info/
24 | .installed.cfg
25 | *.egg
26 | MANIFEST
27 |
28 | # PyInstaller
29 | # Usually these files are written by a python script from a template
30 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
31 | *.manifest
32 | *.spec
33 |
34 | # Installer logs
35 | pip-log.txt
36 | pip-delete-this-directory.txt
37 |
38 | # Unit test / coverage reports
39 | htmlcov/
40 | .tox/
41 | .coverage
42 | .coverage.*
43 | .cache
44 | nosetests.xml
45 | coverage.xml
46 | *.cover
47 | .hypothesis/
48 | .pytest_cache/
49 |
50 | # Translations
51 | *.mo
52 | *.pot
53 |
54 | # Django stuff:
55 | *.log
56 | local_settings.py
57 | db.sqlite3
58 |
59 | # Flask stuff:
60 | instance/
61 | .webassets-cache
62 |
63 | # Scrapy stuff:
64 | .scrapy
65 |
66 | # Sphinx documentation
67 | docs/_build/
68 |
69 | # PyBuilder
70 | target/
71 |
72 | # Jupyter Notebook
73 | .ipynb_checkpoints
74 |
75 | # pyenv
76 | .python-version
77 |
78 | # celery beat schedule file
79 | celerybeat-schedule
80 |
81 | # SageMath parsed files
82 | *.sage.py
83 |
84 | # Environments
85 | .env
86 | .venv
87 | env/
88 | venv/
89 | ENV/
90 | env.bak/
91 | venv.bak/
92 |
93 | # Spyder project settings
94 | .spyderproject
95 | .spyproject
96 |
97 | # Rope project settings
98 | .ropeproject
99 |
100 | # mkdocs documentation
101 | /site
102 |
103 | # mypy
104 | .mypy_cache/
105 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "azureFunctions.projectLanguage": "Python",
3 | "azureFunctions.projectRuntime": "~1"
4 | }
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## [project-title] Changelog
2 |
3 |
4 | # x.y.z (yyyy-mm-dd)
5 |
6 | *Features*
7 | * ...
8 |
9 | *Bug Fixes*
10 | * ...
11 |
12 | *Breaking Changes*
13 | * ...
14 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to [project-title]
2 |
3 | This project welcomes contributions and suggestions. Most contributions require you to agree to a
4 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
5 | the rights to use your contribution. For details, visit https://cla.microsoft.com.
6 |
7 | When you submit a pull request, a CLA-bot will automatically determine whether you need to provide
8 | a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions
9 | provided by the bot. You will only need to do this once across all repos using our CLA.
10 |
11 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
12 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
13 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
14 |
15 | - [Code of Conduct](#coc)
16 | - [Issues and Bugs](#issue)
17 | - [Feature Requests](#feature)
18 | - [Submission Guidelines](#submit)
19 |
20 | ## Code of Conduct
21 | Help us keep this project open and inclusive. Please read and follow our [Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
22 |
23 | ## Found an Issue?
24 | If you find a bug in the source code or a mistake in the documentation, you can help us by
25 | [submitting an issue](#submit-issue) to the GitHub Repository. Even better, you can
26 | [submit a Pull Request](#submit-pr) with a fix.
27 |
28 | ## Want a Feature?
29 | You can *request* a new feature by [submitting an issue](#submit-issue) to the GitHub
30 | Repository. If you would like to *implement* a new feature, please submit an issue with
31 | a proposal for your work first, to be sure that we can use it.
32 |
33 | * **Small Features** can be crafted and directly [submitted as a Pull Request](#submit-pr).
34 |
35 | ## Submission Guidelines
36 |
37 | ### Submitting an Issue
38 | Before you submit an issue, search the archive, maybe your question was already answered.
39 |
40 | If your issue appears to be a bug, and hasn't been reported, open a new issue.
41 | Help us to maximize the effort we can spend fixing issues and adding new
42 | features, by not reporting duplicate issues. Providing the following information will increase the
43 | chances of your issue being dealt with quickly:
44 |
45 | * **Overview of the Issue** - if an error is being thrown a non-minified stack trace helps
46 | * **Version** - what version is affected (e.g. 0.1.2)
47 | * **Motivation for or Use Case** - explain what are you trying to do and why the current behavior is a bug for you
48 | * **Browsers and Operating System** - is this a problem with all browsers?
49 | * **Reproduce the Error** - provide a live example or a unambiguous set of steps
50 | * **Related Issues** - has a similar issue been reported before?
51 | * **Suggest a Fix** - if you can't fix the bug yourself, perhaps you can point to what might be
52 | causing the problem (line of code or commit)
53 |
54 | You can file new issues by providing the above information at the corresponding repository's issues link: https://github.com/[organization-name]/[repository-name]/issues/new].
55 |
56 | ### Submitting a Pull Request (PR)
57 | Before you submit your Pull Request (PR) consider the following guidelines:
58 |
59 | * Search the repository (https://github.com/[organization-name]/[repository-name]/pulls) for an open or closed PR
60 | that relates to your submission. You don't want to duplicate effort.
61 |
62 | * Make your changes in a new git fork:
63 |
64 | * Commit your changes using a descriptive commit message
65 | * Push your fork to GitHub:
66 | * In GitHub, create a pull request
67 | * If we suggest changes then:
68 | * Make the required updates.
69 | * Rebase your fork and force push to your GitHub repository (this will update your Pull Request):
70 |
71 | ```shell
72 | git rebase master -i
73 | git push -f
74 | ```
75 |
76 | That's it! Thank you for your contribution!
77 |
--------------------------------------------------------------------------------
/ConsumerFunction/ConsumerFunction/function.json:
--------------------------------------------------------------------------------
1 | {
2 | "bindings": [
3 | {
4 | "authLevel": "anonymous",
5 | "type": "httpTrigger",
6 | "direction": "in",
7 | "name": "req",
8 | "methods": [
9 | "post"
10 | ]
11 | },
12 | {
13 | "type": "http",
14 | "direction": "out",
15 | "name": "res"
16 | }
17 | ],
18 | "disabled": false
19 | }
--------------------------------------------------------------------------------
/ConsumerFunction/ConsumerFunction/run.py:
--------------------------------------------------------------------------------
1 | import os
2 | import json
3 |
4 | #
5 | # This code is designed for Azure Function for Python v1.
6 | #
7 | # This could be copied/pasted directly into a Python function,
8 | # or to be deployed using VSCode
9 | # https://code.visualstudio.com/tutorials/functions-extension/getting-started
10 | #
11 | # Note that Azure Function and Python is considered experimental
12 | #
13 |
14 | # The validation event, see https://aka.ms/esvalidation for details
15 | SUBSCRIPTION_VALIDATION_EVENT = "Microsoft.EventGrid.SubscriptionValidationEvent"
16 | # Blob created in a storage account
17 | STORAGE_BLOB_CREATED_EVENT = "Microsoft.Storage.BlobCreated"
18 | # The one used in the "Publisher" sample
19 | CUSTOM_EVENT = "PersonalEventType"
20 |
21 | postreqdata = json.loads(open(os.environ['req']).read())
22 | print("Received events: {}".format(postreqdata))
23 |
24 | response = open(os.environ['res'], 'w')
25 | for event in postreqdata:
26 | event_data = event['data']
27 |
28 | # Deserialize the event data into the appropriate type based on event type using if/elif/else
29 |
30 | if event['eventType'] == SUBSCRIPTION_VALIDATION_EVENT:
31 | validation_code = event_data['validationCode']
32 | # If you don't use the preview version of EventGrid, this might no exist
33 | validation_url = event_data.get('validationUrl', None)
34 | print("Got a SubscriptionValidation event data, validation code is: {}, validation url is {}".format(
35 | validation_code,
36 | validation_url
37 | ))
38 | answer_payload = {
39 | "validationResponse": validation_code
40 | }
41 | response.write(json.dumps(answer_payload))
42 | elif event['eventType'] == STORAGE_BLOB_CREATED_EVENT:
43 | print("Got BlobCreated event data, blob URI {}".format(
44 | event_data['url']))
45 | elif event['eventType'] == CUSTOM_EVENT:
46 | print("Got a custom event {} and received {}".format(
47 | CUSTOM_EVENT, event_data))
48 |
49 | response.close()
50 |
--------------------------------------------------------------------------------
/ConsumerFunction/README.md:
--------------------------------------------------------------------------------
1 | # Python Azure Function for Event Grid
2 |
3 | You can directly deploy this folder using VSCode, by installing the [Azure Function extension for VSCode](https://aka.ms/vscode-azure-functions).
4 |
5 | Then you can deploy your app by just doing a right click and "Deploy to Function App":
6 |
7 | 
8 |
9 | This will create a Function called "ConsumerFunction" available at the url:
10 |
11 | `https://.azurewebsites.net/api/ConsumerFunction`
--------------------------------------------------------------------------------
/ConsumerFunction/deploy_vscode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azure-Samples/event-grid-python-public-consume-events/53c15453864cb5cbb93e74d7c22cf1c340a47e41/ConsumerFunction/deploy_vscode.png
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) Microsoft Corporation. All rights reserved.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE
--------------------------------------------------------------------------------
/Pipfile:
--------------------------------------------------------------------------------
1 | [[source]]
2 | url = "https://pypi.org/simple"
3 | verify_ssl = true
4 | name = "pypi"
5 |
6 | [packages]
7 | azure-eventgrid = "*"
8 | azure-mgmt-eventgrid = ">=2.0.0rc1"
9 | azure-mgmt-resource = "*"
10 | haikunator = "*"
11 |
12 | [dev-packages]
13 | pylint = "*"
14 |
15 | [pipenv]
16 | allow_prereleases = true
17 |
--------------------------------------------------------------------------------
/Pipfile.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_meta": {
3 | "hash": {
4 | "sha256": "4c0a6cb7fd75c4b8eda702adca225c697bc7dc5bd9c2d7744373538f090a2bb4"
5 | },
6 | "pipfile-spec": 6,
7 | "requires": {},
8 | "sources": [
9 | {
10 | "name": "pypi",
11 | "url": "https://pypi.org/simple",
12 | "verify_ssl": true
13 | }
14 | ]
15 | },
16 | "default": {
17 | "adal": {
18 | "hashes": [
19 | "sha256:7a15d22b1ee7ce1be92441199958748982feba6b7dec35fbf60f9b607bad1bc0",
20 | "sha256:b332316f54d947f39acd9628e7d61d90f6e54d413d6f97025a51482c96bac6bc"
21 | ],
22 | "version": "==1.2.4"
23 | },
24 | "asn1crypto": {
25 | "hashes": [
26 | "sha256:4bcdf33c861c7d40bdcd74d8e4dd7661aac320fcdf40b9a3f95b4ee12fde2fa8",
27 | "sha256:f4f6e119474e58e04a2b1af817eb585b4fd72bdd89b998624712b5c99be7641c"
28 | ],
29 | "version": "==1.4.0"
30 | },
31 | "azure-common": {
32 | "hashes": [
33 | "sha256:ce0f1013e6d0e9faebaf3188cc069f4892fc60a6ec552e3f817c1a2f92835054",
34 | "sha256:fd02e4256dc9cdd2d4422bc795bdca2ef302f7a86148b154fbf4ea1f09da400a"
35 | ],
36 | "version": "==1.1.25"
37 | },
38 | "azure-eventgrid": {
39 | "hashes": [
40 | "sha256:c55062f7f7f69791688d60efda84162b0bdccdcded2a90ed052a01a6d67fd51c",
41 | "sha256:fca3d830bf887fcc61fa71cb541531c9e155a4437d861149cbfb842d36fb272f"
42 | ],
43 | "index": "pypi",
44 | "version": "==1.1.0"
45 | },
46 | "azure-mgmt-eventgrid": {
47 | "hashes": [
48 | "sha256:5d125980af374d029a639d918c541a4042ceb195db17016ef247cec0d11bf3af",
49 | "sha256:7cf7d1fe33dd178a9514aaf3e5153fe75501621815ce323ba3594b00b2cb3180"
50 | ],
51 | "index": "pypi",
52 | "version": "==2.0.0rc1"
53 | },
54 | "azure-mgmt-nspkg": {
55 | "hashes": [
56 | "sha256:1c6f5134de78c8907e8b73a8ceaaf1f336a24193a543039994fe002bb5f7f39f",
57 | "sha256:8b2287f671529505b296005e6de9150b074344c2c7d1c805b3f053d081d58c52",
58 | "sha256:d638ea5fda3ed323db943feb29acaa200f5d8ff092078bf8d29d4a2f8ed16999"
59 | ],
60 | "version": "==3.0.2"
61 | },
62 | "azure-mgmt-resource": {
63 | "hashes": [
64 | "sha256:8b116e31be2e5895502f2088a592870b057441b3efe3e75d62efb624e13e8e32",
65 | "sha256:fce4e085c5517826c81ff9ff6dbee06da98f08750c68789cc279b3e3d040429a"
66 | ],
67 | "index": "pypi",
68 | "version": "==2.0.0rc1"
69 | },
70 | "azure-nspkg": {
71 | "hashes": [
72 | "sha256:1d0bbb2157cf57b1bef6c8c8e5b41133957364456c43b0a43599890023cca0a8",
73 | "sha256:31a060caca00ed1ebd369fc7fe01a56768c927e404ebc92268f4d9d636435e28",
74 | "sha256:e7d3cea6af63e667d87ba1ca4f8cd7cb4dfca678e4c55fc1cedb320760e39dd0"
75 | ],
76 | "version": "==3.0.2"
77 | },
78 | "certifi": {
79 | "hashes": [
80 | "sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3",
81 | "sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41"
82 | ],
83 | "version": "==2020.6.20"
84 | },
85 | "cffi": {
86 | "hashes": [
87 | "sha256:005f2bfe11b6745d726dbb07ace4d53f057de66e336ff92d61b8c7e9c8f4777d",
88 | "sha256:09e96138280241bd355cd585148dec04dbbedb4f46128f340d696eaafc82dd7b",
89 | "sha256:0b1ad452cc824665ddc682400b62c9e4f5b64736a2ba99110712fdee5f2505c4",
90 | "sha256:0ef488305fdce2580c8b2708f22d7785ae222d9825d3094ab073e22e93dfe51f",
91 | "sha256:15f351bed09897fbda218e4db5a3d5c06328862f6198d4fb385f3e14e19decb3",
92 | "sha256:22399ff4870fb4c7ef19fff6eeb20a8bbf15571913c181c78cb361024d574579",
93 | "sha256:23e5d2040367322824605bc29ae8ee9175200b92cb5483ac7d466927a9b3d537",
94 | "sha256:2791f68edc5749024b4722500e86303a10d342527e1e3bcac47f35fbd25b764e",
95 | "sha256:2f9674623ca39c9ebe38afa3da402e9326c245f0f5ceff0623dccdac15023e05",
96 | "sha256:3363e77a6176afb8823b6e06db78c46dbc4c7813b00a41300a4873b6ba63b171",
97 | "sha256:33c6cdc071ba5cd6d96769c8969a0531be2d08c2628a0143a10a7dcffa9719ca",
98 | "sha256:3b8eaf915ddc0709779889c472e553f0d3e8b7bdf62dab764c8921b09bf94522",
99 | "sha256:3cb3e1b9ec43256c4e0f8d2837267a70b0e1ca8c4f456685508ae6106b1f504c",
100 | "sha256:3eeeb0405fd145e714f7633a5173318bd88d8bbfc3dd0a5751f8c4f70ae629bc",
101 | "sha256:44f60519595eaca110f248e5017363d751b12782a6f2bd6a7041cba275215f5d",
102 | "sha256:4d7c26bfc1ea9f92084a1d75e11999e97b62d63128bcc90c3624d07813c52808",
103 | "sha256:529c4ed2e10437c205f38f3691a68be66c39197d01062618c55f74294a4a4828",
104 | "sha256:6642f15ad963b5092d65aed022d033c77763515fdc07095208f15d3563003869",
105 | "sha256:85ba797e1de5b48aa5a8427b6ba62cf69607c18c5d4eb747604b7302f1ec382d",
106 | "sha256:8f0f1e499e4000c4c347a124fa6a27d37608ced4fe9f7d45070563b7c4c370c9",
107 | "sha256:a624fae282e81ad2e4871bdb767e2c914d0539708c0f078b5b355258293c98b0",
108 | "sha256:b0358e6fefc74a16f745afa366acc89f979040e0cbc4eec55ab26ad1f6a9bfbc",
109 | "sha256:bbd2f4dfee1079f76943767fce837ade3087b578aeb9f69aec7857d5bf25db15",
110 | "sha256:bf39a9e19ce7298f1bd6a9758fa99707e9e5b1ebe5e90f2c3913a47bc548747c",
111 | "sha256:c11579638288e53fc94ad60022ff1b67865363e730ee41ad5e6f0a17188b327a",
112 | "sha256:c150eaa3dadbb2b5339675b88d4573c1be3cb6f2c33a6c83387e10cc0bf05bd3",
113 | "sha256:c53af463f4a40de78c58b8b2710ade243c81cbca641e34debf3396a9640d6ec1",
114 | "sha256:cb763ceceae04803adcc4e2d80d611ef201c73da32d8f2722e9d0ab0c7f10768",
115 | "sha256:cc75f58cdaf043fe6a7a6c04b3b5a0e694c6a9e24050967747251fb80d7bce0d",
116 | "sha256:d80998ed59176e8cba74028762fbd9b9153b9afc71ea118e63bbf5d4d0f9552b",
117 | "sha256:de31b5164d44ef4943db155b3e8e17929707cac1e5bd2f363e67a56e3af4af6e",
118 | "sha256:e66399cf0fc07de4dce4f588fc25bfe84a6d1285cc544e67987d22663393926d",
119 | "sha256:f0620511387790860b249b9241c2f13c3a80e21a73e0b861a2df24e9d6f56730",
120 | "sha256:f4eae045e6ab2bb54ca279733fe4eb85f1effda392666308250714e01907f394",
121 | "sha256:f92cdecb618e5fa4658aeb97d5eb3d2f47aa94ac6477c6daf0f306c5a3b9e6b1",
122 | "sha256:f92f789e4f9241cd262ad7a555ca2c648a98178a953af117ef7fad46aa1d5591"
123 | ],
124 | "version": "==1.14.3"
125 | },
126 | "chardet": {
127 | "hashes": [
128 | "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
129 | "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
130 | ],
131 | "version": "==3.0.4"
132 | },
133 | "cryptography": {
134 | "hashes": [
135 | "sha256:21af753934f2f6d1a10fe8f4c0a64315af209ef6adeaee63ca349797d747d687",
136 | "sha256:27bb401a20a838d6d0ea380f08c6ead3ccd8c9d8a0232dc9adcc0e4994576a66",
137 | "sha256:29720c4253263cff9aea64585adbbe85013ba647f6e98367efff9db2d7193ded",
138 | "sha256:2a35b7570d8f247889784010aac8b384fd2e4a47b33e15c4a60b45a7c1944120",
139 | "sha256:42c531a6a354407f42ee07fda5c2c0dc822cf6d52744949c182f2b295fbd4183",
140 | "sha256:5eb86f03f9c4f0ac2336ac5431271072ddf7ecc76b338e26366732cfac58aa19",
141 | "sha256:67f7f57eae8dede577f3f7775957f5bec93edd6bdb6ce597bb5b28e1bdf3d4fb",
142 | "sha256:6ec84edcbc966ae460560a51a90046503ff0b5b66157a9efc61515c68059f6c8",
143 | "sha256:7ba834564daef87557e7fcd35c3c3183a4147b0b3a57314e53317360b9b201b3",
144 | "sha256:7d7f084cbe1fdb82be5a0545062b59b1ad3637bc5a48612ac2eb428ff31b31ea",
145 | "sha256:82409f5150e529d699e5c33fa8fd85e965104db03bc564f5f4b6a9199e591f7c",
146 | "sha256:87d092a7c2a44e5f7414ab02fb4145723ebba411425e1a99773531dd4c0e9b8d",
147 | "sha256:8c56ef989342e42b9fcaba7c74b446f0cc9bed546dd00034fa7ad66fc00307ef",
148 | "sha256:9449f5d4d7c516a6118fa9210c4a00f34384cb1d2028672100ee0c6cce49d7f6",
149 | "sha256:bc2301170986ad82d9349a91eb8884e0e191209c45f5541b16aa7c0cfb135978",
150 | "sha256:c132bab45d4bd0fff1d3fe294d92b0a6eb8404e93337b3127bdec9f21de117e6",
151 | "sha256:c3d945b7b577f07a477700f618f46cbc287af3a9222cd73035c6ef527ef2c363",
152 | "sha256:cee18beb4c807b5c0b178f4fa2fae03cef9d51821a358c6890f8b23465b7e5d2",
153 | "sha256:d01dfc5c2b3495184f683574e03c70022674ca9a7be88589c5aba130d835ea90"
154 | ],
155 | "index": "pypi",
156 | "version": "==2.3"
157 | },
158 | "haikunator": {
159 | "hashes": [
160 | "sha256:66f68b15345b279f78a5fffd4ab56cfb19a9dbb1f41b7f442472efd4cb83458e",
161 | "sha256:91ee3949a3a613cac037ddde0b16b17062e248376b11491436e49d5ddc75ff9b"
162 | ],
163 | "index": "pypi",
164 | "version": "==2.1.0"
165 | },
166 | "idna": {
167 | "hashes": [
168 | "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6",
169 | "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"
170 | ],
171 | "version": "==2.10"
172 | },
173 | "isodate": {
174 | "hashes": [
175 | "sha256:2e364a3d5759479cdb2d37cce6b9376ea504db2ff90252a2e5b7cc89cc9ff2d8",
176 | "sha256:aa4d33c06640f5352aca96e4b81afd8ab3b47337cc12089822d6f322ac772c81"
177 | ],
178 | "version": "==0.6.0"
179 | },
180 | "msrest": {
181 | "hashes": [
182 | "sha256:55f8c3940bc5dc609f8cf9fcd639444716cc212a943606756272e0d0017bbb5b",
183 | "sha256:87aa64948c3ef3dbf6f6956d2240493e68d714e4621b92b65b3c4d5808297929"
184 | ],
185 | "version": "==0.6.19"
186 | },
187 | "msrestazure": {
188 | "hashes": [
189 | "sha256:3de50f56147ef529b31e099a982496690468ecef33f0544cb0fa0cfe1e1de5b9",
190 | "sha256:a06f0dabc9a6f5efe3b6add4bd8fb623aeadacf816b7a35b0f89107e0544d189"
191 | ],
192 | "version": "==0.6.4"
193 | },
194 | "oauthlib": {
195 | "hashes": [
196 | "sha256:bee41cc35fcca6e988463cacc3bcb8a96224f470ca547e697b604cc697b2f889",
197 | "sha256:df884cd6cbe20e32633f1db1072e9356f53638e4361bef4e8b03c9127c9328ea"
198 | ],
199 | "version": "==3.1.0"
200 | },
201 | "pycparser": {
202 | "hashes": [
203 | "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0",
204 | "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"
205 | ],
206 | "version": "==2.20"
207 | },
208 | "pyjwt": {
209 | "hashes": [
210 | "sha256:5c6eca3c2940464d106b99ba83b00c6add741c9becaec087fb7ccdefea71350e",
211 | "sha256:8d59a976fb773f3e6a39c85636357c4f0e242707394cadadd9814f5cbaa20e96"
212 | ],
213 | "version": "==1.7.1"
214 | },
215 | "python-dateutil": {
216 | "hashes": [
217 | "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c",
218 | "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"
219 | ],
220 | "version": "==2.8.1"
221 | },
222 | "requests": {
223 | "hashes": [
224 | "sha256:b3559a131db72c33ee969480840fff4bb6dd111de7dd27c8ee1f820f4f00231b",
225 | "sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898"
226 | ],
227 | "version": "==2.24.0"
228 | },
229 | "requests-oauthlib": {
230 | "hashes": [
231 | "sha256:7f71572defaecd16372f9006f33c2ec8c077c3cfa6f5911a9a90202beb513f3d",
232 | "sha256:b4261601a71fd721a8bd6d7aa1cc1d6a8a93b4a9f5e96626f8e4d91e8beeaa6a"
233 | ],
234 | "version": "==1.3.0"
235 | },
236 | "six": {
237 | "hashes": [
238 | "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259",
239 | "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"
240 | ],
241 | "version": "==1.15.0"
242 | },
243 | "urllib3": {
244 | "hashes": [
245 | "sha256:91056c15fa70756691db97756772bb1eb9678fa585d9184f24534b100dc60f4a",
246 | "sha256:e7983572181f5e1522d9c98453462384ee92a0be7fac5f1413a1e35c56cc0461"
247 | ],
248 | "version": "==1.25.10"
249 | }
250 | },
251 | "develop": {
252 | "astroid": {
253 | "hashes": [
254 | "sha256:2f4078c2a41bf377eea06d71c9d2ba4eb8f6b1af2135bec27bbbb7d8f12bb703",
255 | "sha256:bc58d83eb610252fd8de6363e39d4f1d0619c894b0ed24603b881c02e64c7386"
256 | ],
257 | "version": "==2.4.2"
258 | },
259 | "isort": {
260 | "hashes": [
261 | "sha256:2f510f34ae18a8d0958c53eec51ef84fd099f07c4c639676525acbcd7b5bd3ff",
262 | "sha256:dd3211f513f4a92ec1ec1876fc1dc3c686649c349d49523f5b5adbb0814e5960"
263 | ],
264 | "version": "==5.6.1"
265 | },
266 | "lazy-object-proxy": {
267 | "hashes": [
268 | "sha256:0c4b206227a8097f05c4dbdd323c50edf81f15db3b8dc064d08c62d37e1a504d",
269 | "sha256:194d092e6f246b906e8f70884e620e459fc54db3259e60cf69a4d66c3fda3449",
270 | "sha256:1be7e4c9f96948003609aa6c974ae59830a6baecc5376c25c92d7d697e684c08",
271 | "sha256:4677f594e474c91da97f489fea5b7daa17b5517190899cf213697e48d3902f5a",
272 | "sha256:48dab84ebd4831077b150572aec802f303117c8cc5c871e182447281ebf3ac50",
273 | "sha256:5541cada25cd173702dbd99f8e22434105456314462326f06dba3e180f203dfd",
274 | "sha256:59f79fef100b09564bc2df42ea2d8d21a64fdcda64979c0fa3db7bdaabaf6239",
275 | "sha256:8d859b89baf8ef7f8bc6b00aa20316483d67f0b1cbf422f5b4dc56701c8f2ffb",
276 | "sha256:9254f4358b9b541e3441b007a0ea0764b9d056afdeafc1a5569eee1cc6c1b9ea",
277 | "sha256:9651375199045a358eb6741df3e02a651e0330be090b3bc79f6d0de31a80ec3e",
278 | "sha256:97bb5884f6f1cdce0099f86b907aa41c970c3c672ac8b9c8352789e103cf3156",
279 | "sha256:9b15f3f4c0f35727d3a0fba4b770b3c4ebbb1fa907dbcc046a1d2799f3edd142",
280 | "sha256:a2238e9d1bb71a56cd710611a1614d1194dc10a175c1e08d75e1a7bcc250d442",
281 | "sha256:a6ae12d08c0bf9909ce12385803a543bfe99b95fe01e752536a60af2b7797c62",
282 | "sha256:ca0a928a3ddbc5725be2dd1cf895ec0a254798915fb3a36af0964a0a4149e3db",
283 | "sha256:cb2c7c57005a6804ab66f106ceb8482da55f5314b7fcb06551db1edae4ad1531",
284 | "sha256:d74bb8693bf9cf75ac3b47a54d716bbb1a92648d5f781fc799347cfc95952383",
285 | "sha256:d945239a5639b3ff35b70a88c5f2f491913eb94871780ebfabb2568bd58afc5a",
286 | "sha256:eba7011090323c1dadf18b3b689845fd96a61ba0a1dfbd7f24b921398affc357",
287 | "sha256:efa1909120ce98bbb3777e8b6f92237f5d5c8ea6758efea36a473e1d38f7d3e4",
288 | "sha256:f3900e8a5de27447acbf900b4750b0ddfd7ec1ea7fbaf11dfa911141bc522af0"
289 | ],
290 | "version": "==1.4.3"
291 | },
292 | "mccabe": {
293 | "hashes": [
294 | "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42",
295 | "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"
296 | ],
297 | "version": "==0.6.1"
298 | },
299 | "pylint": {
300 | "hashes": [
301 | "sha256:0990347c0f605927fadb2a9366a0b3d40bd19eb44e4312f0a1ef729a389b2f40",
302 | "sha256:19b902f93f2dc3fa45565e54b88702b28379be40107f509a8516dde152460d1f"
303 | ],
304 | "index": "pypi",
305 | "version": "==2.0.0.dev1"
306 | },
307 | "six": {
308 | "hashes": [
309 | "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259",
310 | "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"
311 | ],
312 | "version": "==1.15.0"
313 | },
314 | "wrapt": {
315 | "hashes": [
316 | "sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7"
317 | ],
318 | "version": "==1.12.1"
319 | }
320 | }
321 | }
322 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_type: sample
3 | languages:
4 | - python
5 | products:
6 | - azure
7 | description: "This contains Python samples for publishing events to Azure Event Grid and consuming events from Azure Event Grid."
8 | urlFragment: event-grid-python-public-consume-events
9 | ---
10 |
11 | ***DISCLAIMER: The data plane samples in this repo are for azure-eventgrid v1 (1.x). For the samples for v4 (4.x and above) please visit [here](https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/eventgrid/azure-eventgrid/samples). This repo is archived since v4 has become stable. For management plane samples, please visit [here](https://github.com/Azure-Samples/azure-samples-python-management/tree/master/samples/eventgrid).***
12 |
13 | ***DISCLAIMER: If you are looking to migrate from azure-eventgrid v1(1.x) to v4(4.x), we suggest getting started at the [migration guide](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/eventgrid/azure-eventgrid/migration_guide.md).***
14 |
15 |
16 | # Microsoft Azure Event Grid Publish/Consume Samples for Python
17 |
18 | This contains Python samples for publishing events to Azure Event Grid and consuming events from Azure Event Grid. It also contains a set of management samples that demonstrates how to manage topics and event subscriptions.
19 |
20 | ## Features
21 |
22 | These samples demonstrates the following features:
23 |
24 | Data Plane:
25 |
26 | * How to publish events to Azure Event Grid.
27 | * How to consume events delivered by Azure Event Grid.
28 |
29 | The above two samples use the Event Grid data plane SDK [azure-eventgrid](https://pypi.org/project/azure-eventgrid/).
30 |
31 | Management Plane:
32 |
33 | * How to create a topic and an event subscription to a topic.
34 | * How to create an event subscription to a Storage account.
35 | * How to create an event subscription to an Azure subscription / Resource Group.
36 |
37 | The above three samples use the Event Grid management plane SDK [azure-mgmt-eventgrid](https://pypi.org/project/azure-mgmt-eventgrid/)
38 |
39 | ## Getting Started
40 |
41 | ### Prerequisites
42 |
43 | - Python 2.7, 3.4 or higher.
44 | - [Pipenv](https://docs.pipenv.org/). If you don't have it, follow the [pipenv installation tutorial](https://docs.pipenv.org/#install-pipenv-today).
45 |
46 |
47 | ### Quickstart
48 |
49 | 1. git clone https://github.com/Azure-Samples/event-grid-python-public-consume-events.git
50 | 2. cd event-grid-python-public-consume-events
51 | 3. pipenv install
52 | 4. For Management only, rename the file `env_template` to `.env` and update the correct values inside with your
53 | subscription ID and [Azure Service Principal credentials](https://docs.microsoft.com/azure/azure-resource-manager/resource-group-create-service-principal-portal).
54 |
55 | ## Running the samples
56 |
57 | ### Management Plane
58 |
59 | 1. `create_eg_topics_and_event_subscriptions.py` creates a new event subscription for an Event Grid Topic, and send it to a webhook
60 |
61 | In order for this sample to work, you need to have a valid `.env` file (see previous section).
62 |
63 | **This sample requires a endpoint that supports EventGrid security validation. See https://aka.ms/esvalidation for details**
64 |
65 | Run the sample : `pipenv run python create_eg_topics_and_event_subscriptions.py`
66 |
67 | 2. `create_storage_event_subscriptions.py` creates a new event subscription for a storage account, filtering jpg creation, and send it to an Relay Hybrid Connection
68 |
69 | In order for this sample to work, you need to have a valid `.env` file (see previous section).
70 |
71 | Run the sample : `pipenv run python create_storage_event_subscriptions.py`
72 |
73 | 3. `create_arm_event_subscriptions.py` creates a new event subscription for an Azure Subscription and send it to a Storage Queue
74 |
75 | In order for this sample to work, you need to have a valid `.env` file (see previous section).
76 |
77 | Run the sample : `pipenv run python create_arm_event_subscriptions.py`
78 |
79 | ### Data plane
80 |
81 | 1. `event_grid_publisher.py` publishes a custom event to a Topic. Topic might be created by the initial sample `create_eg_topics_and_event_subscriptions.py`
82 | or [CLI](https://docs.microsoft.com/azure/event-grid/custom-event-quickstart#create-a-custom-topic).
83 |
84 | In order for this sample to work, you need an Event Grid Topic and a Key (replace global variables in the script)
85 |
86 | Run the sample : `pipenv run python event_grid_publisher.py`
87 |
88 | 2. `ConsumerFunction` is an Azure Function app that receive an event from EventGrid. You can deploy the `ConsumerFunction` folder to an Azure Function using [VSCode](https://aka.ms/vscode-azure-functions),
89 | this folder is ready to deploy. See the Readme in that directory for details.
90 |
91 | If you just want the code, look at `ConsumerFunction/ConsumerFunction/run.py`.
92 |
93 | Creating an Azure Function is out of the scope of this sample, you can follow [CLI tutorial](https://docs.microsoft.com/azure/azure-functions/functions-create-first-azure-function-azure-cli)
94 | or [Portal tutorial](https://docs.microsoft.com/azure/azure-functions/functions-create-first-azure-function) or using [VSCode](https://aka.ms/vscode-azure-functions).
95 |
96 | ## Resources
97 |
98 | - https://docs.microsoft.com/azure/event-grid/overview
99 | - https://docs.microsoft.com/python/api/overview/azure/event-grid
100 |
--------------------------------------------------------------------------------
/create_arm_event_subscriptions.py:
--------------------------------------------------------------------------------
1 | import os
2 | from haikunator import Haikunator
3 |
4 | from azure.common.credentials import ServicePrincipalCredentials
5 |
6 | from azure.mgmt.resource import ResourceManagementClient
7 | from azure.mgmt.eventgrid import EventGridManagementClient
8 | from azure.mgmt.eventgrid.models import Topic, EventSubscriptionFilter, EventSubscription, StorageQueueEventSubscriptionDestination
9 |
10 | # If you wish to debug
11 | # import logging
12 | # logging.basicConfig(level=logging.DEBUG)
13 |
14 | _haikunator = Haikunator()
15 |
16 | # Resource
17 |
18 | LOCATION = 'westus'
19 | GROUP_NAME = 'event-grid-python-sample-rg'
20 |
21 | # Event grid
22 |
23 | # Using a random topic name. Optionally, replace this with a topic name of your choice.
24 | TOPIC_NAME = "topicsample-" + _haikunator.haikunate(delimiter='')
25 |
26 | # In this sample, we will be demonstrating using a storage queue as the destination for the event subscription.
27 | # This should be in the format /subscriptions/id/resourceGroups/rg/providers/Microsoft.Storage/storageAccounts/account1
28 | # More info on Storage queue as an event handler is at https://docs.microsoft.com/en-us/azure/event-grid/event-handlers#queue-storage
29 | STORAGE_ACOUNT_RESOURCE_ID = 'replace-with-your-storage-account-resource-id'
30 | QUEUE_NAME = 'replace-with-your-queue-name-under-the-above-storage-account'
31 |
32 | # To run the sample, you must first create an Azure service principal. To create the service principal, follow one of these guides:
33 | # Azure Portal: https://azure.microsoft.com/documentation/articles/resource-group-create-service-principal-portal/)
34 | # PowerShell: https://azure.microsoft.com/documentation/articles/resource-group-authenticate-service-principal/
35 | # Azure CLI: https://azure.microsoft.com/documentation/articles/resource-group-authenticate-service-principal-cli/
36 | #
37 | # This script expects that the following environment vars are set:
38 | #
39 | # AZURE_TENANT_ID: with your Azure Active Directory tenant id or domain
40 | # AZURE_CLIENT_ID: with your Azure Active Directory Application Client ID
41 | # AZURE_CLIENT_SECRET: with your Azure Active Directory Application Secret
42 | # AZURE_SUBSCRIPTION_ID: with your Azure Subscription Id
43 | #
44 |
45 |
46 | def run_example():
47 | """Resource Group management example."""
48 | #
49 | # Create the Resource Manager Client with an Application (service principal) token provider
50 | #
51 | subscription_id = os.environ.get(
52 | 'AZURE_SUBSCRIPTION_ID',
53 | '11111111-1111-1111-1111-111111111111') # your Azure Subscription Id
54 | credentials = ServicePrincipalCredentials(
55 | client_id=os.environ['AZURE_CLIENT_ID'],
56 | secret=os.environ['AZURE_CLIENT_SECRET'],
57 | tenant=os.environ['AZURE_TENANT_ID']
58 | )
59 | resource_client = ResourceManagementClient(credentials, subscription_id)
60 | event_grid_client = EventGridManagementClient(credentials, subscription_id)
61 |
62 | # Create Resource group
63 | print('\nCreating a Resource Group...')
64 | resource_group = resource_client.resource_groups.create_or_update(
65 | GROUP_NAME,
66 | {'location': LOCATION}
67 | )
68 | print_item(resource_group)
69 |
70 | # Creating an event subscription to storage account {StorageAccountResourceId} with destination as {HybridConnectionResourceId}
71 | print('\nCreating an event subscription to storage account {} with destination as {}'.format(
72 | STORAGE_ACOUNT_RESOURCE_ID, QUEUE_NAME))
73 |
74 | # Scope could be any ARM resource ID that supports EventGrid
75 | # https://docs.microsoft.com/azure/event-grid/event-sources
76 | scope = "/subscriptions/{}".format(subscription_id)
77 | event_subscription_name = 'EventSubscription1'
78 | destination = StorageQueueEventSubscriptionDestination(
79 | resource_id=STORAGE_ACOUNT_RESOURCE_ID,
80 | queue_name=QUEUE_NAME
81 | )
82 | filter = EventSubscriptionFilter(
83 | # By default, "All" event types are included
84 | is_subject_case_sensitive=False,
85 | subject_begins_with='',
86 | subject_ends_with=''
87 | )
88 |
89 | event_subscription_info = EventSubscription(
90 | destination=destination, filter=filter)
91 |
92 | event_subscription_async_poller = event_grid_client.event_subscriptions.create_or_update(
93 | scope,
94 | event_subscription_name,
95 | event_subscription_info,
96 | )
97 | # Blocking call for the EventSubscription to be created
98 | event_subscription = event_subscription_async_poller.result() # type: EventSubscription
99 | print_item(event_subscription)
100 |
101 | input("Press enter to delete all created resources.")
102 |
103 | # Delete the EventSubscription
104 | print('\nDeleting the event subscription')
105 | delete_async_operation = event_grid_client.event_subscriptions.delete(
106 | scope,
107 | event_subscription_name
108 | )
109 | delete_async_operation.wait()
110 | print("\nDeleted: {}".format(event_subscription_name))
111 |
112 | # Delete Resource group and everything in it
113 | print('\nDelete Resource Group')
114 | delete_async_operation = resource_client.resource_groups.delete(GROUP_NAME)
115 | delete_async_operation.wait()
116 | print("\nDeleted: {}".format(GROUP_NAME))
117 |
118 |
119 | def print_item(group):
120 | """Print a ResourceGroup instance."""
121 | print("\tName: {}".format(group.name))
122 | print("\tId: {}".format(group.id))
123 | if hasattr(group, 'location'):
124 | print("\tLocation: {}".format(group.location))
125 | print_properties(getattr(group, 'properties', None))
126 |
127 |
128 | def print_properties(props):
129 | """Print a ResourceGroup propertyies instance."""
130 | if props and hasattr(props, 'provisioning_state'):
131 | print("\tProperties:")
132 | print("\t\tProvisioning State: {}".format(props.provisioning_state))
133 | print("\n\n")
134 |
135 |
136 | if __name__ == "__main__":
137 | run_example()
138 |
--------------------------------------------------------------------------------
/create_eg_topics_and_event_subscriptions.py:
--------------------------------------------------------------------------------
1 | import os
2 | from haikunator import Haikunator
3 |
4 | from azure.common.credentials import ServicePrincipalCredentials
5 |
6 | from azure.mgmt.resource import ResourceManagementClient
7 | from azure.mgmt.eventgrid import EventGridManagementClient
8 | from azure.mgmt.eventgrid.models import Topic, EventSubscriptionFilter, EventSubscription, WebHookEventSubscriptionDestination
9 |
10 | # If you wish to debug
11 | # import logging
12 | # logging.basicConfig(level=logging.DEBUG)
13 |
14 | _haikunator = Haikunator()
15 |
16 | # Resource
17 |
18 | LOCATION = 'westus'
19 | GROUP_NAME = 'event-grid-python-sample-rg'
20 |
21 | # Event grid
22 |
23 | # Using a random topic name. Optionally, replace this with a topic name of your choice.
24 | TOPIC_NAME = "topicsample-" + _haikunator.haikunate(delimiter='')
25 |
26 | # Replace the endpoint URL with the URL of your Azure function, or whatever endpoint you want to sent the event.
27 | # See the EventGridConsumer sample for a sample of an Azure function that can handle EventGridEvents
28 | # Publish the ConsumerFunction sample as an Azure function and use the URL of that function for the below.
29 | #
30 | # Your endpoint will be validated, see https://aka.ms/esvalidation for details
31 | ENDPOINT_URL = "replace with your Azure function-URL that support validation"
32 |
33 |
34 | # To run the sample, you must first create an Azure service principal. To create the service principal, follow one of these guides:
35 | # Azure Portal: https://azure.microsoft.com/documentation/articles/resource-group-create-service-principal-portal/)
36 | # PowerShell: https://azure.microsoft.com/documentation/articles/resource-group-authenticate-service-principal/
37 | # Azure CLI: https://azure.microsoft.com/documentation/articles/resource-group-authenticate-service-principal-cli/
38 | #
39 | # This script expects that the following environment vars are set:
40 | #
41 | # AZURE_TENANT_ID: with your Azure Active Directory tenant id or domain
42 | # AZURE_CLIENT_ID: with your Azure Active Directory Application Client ID
43 | # AZURE_CLIENT_SECRET: with your Azure Active Directory Application Secret
44 | # AZURE_SUBSCRIPTION_ID: with your Azure Subscription Id
45 | #
46 | def run_example():
47 | """Resource Group management example."""
48 | #
49 | # Create the Resource Manager Client with an Application (service principal) token provider
50 | #
51 | subscription_id = os.environ.get(
52 | 'AZURE_SUBSCRIPTION_ID',
53 | '11111111-1111-1111-1111-111111111111') # your Azure Subscription Id
54 | credentials = ServicePrincipalCredentials(
55 | client_id=os.environ['AZURE_CLIENT_ID'],
56 | secret=os.environ['AZURE_CLIENT_SECRET'],
57 | tenant=os.environ['AZURE_TENANT_ID']
58 | )
59 | resource_client = ResourceManagementClient(credentials, subscription_id)
60 | event_grid_client = EventGridManagementClient(credentials, subscription_id)
61 |
62 | # Create Resource group
63 | print('\nCreating a Resource Group...')
64 | resource_group = resource_client.resource_groups.create_or_update(
65 | GROUP_NAME,
66 | {'location': LOCATION}
67 | )
68 | print_item(resource_group)
69 |
70 | # Create EventGrid topic
71 | print('\nCreating an EventGrid topic...')
72 | topic_result_async_poller = event_grid_client.topics.create_or_update(
73 | resource_group.name,
74 | TOPIC_NAME,
75 | Topic(
76 | location=resource_group.location,
77 | tags={'key1': 'value1', 'key2': 'value2'}
78 | )
79 | )
80 | # Blocking call for the Topic to be created
81 | topic = topic_result_async_poller.result() # type: Topic
82 | print_item(topic)
83 |
84 | # Get the keys for the topic
85 | print('\nGetting the topic keys...')
86 | keys = event_grid_client.topics.list_shared_access_keys(
87 | resource_group.name,
88 | topic.name
89 | ) # type: TopicSharedAccessKeys
90 | print('The key1 value of topic {} is: {}'.format(topic.name, keys.key1))
91 |
92 | # Create an event subscription
93 | print('\nCreating an event subscription')
94 | event_subscription_name = 'EventSubscription1'
95 | destination = WebHookEventSubscriptionDestination(
96 | endpoint_url=ENDPOINT_URL
97 | )
98 | filter = EventSubscriptionFilter(
99 | # By default, "All" event types are included
100 | is_subject_case_sensitive=False,
101 | subject_begins_with='',
102 | subject_ends_with=''
103 | )
104 |
105 | event_subscription_info = EventSubscription(
106 | destination=destination, filter=filter)
107 |
108 | event_subscription_async_poller = event_grid_client.event_subscriptions.create_or_update(
109 | topic.id,
110 | event_subscription_name,
111 | event_subscription_info,
112 | )
113 | # Blocking call for the EventSubscription to be created
114 | event_subscription = event_subscription_async_poller.result() # type: EventSubscription
115 | print_item(event_subscription)
116 |
117 | input("Press enter to delete all created resources.")
118 |
119 | # Delete the EventSubscription
120 | print('\nDeleting the event subscription')
121 | delete_async_operation = event_grid_client.event_subscriptions.delete(
122 | topic.id,
123 | event_subscription_name
124 | )
125 | delete_async_operation.wait()
126 | print("\nDeleted: {}".format(event_subscription_name))
127 |
128 | # Delete the topic
129 | print('\nDeleting the topic')
130 | delete_async_operation = event_grid_client.topics.delete(
131 | resource_group.name,
132 | topic.name
133 | )
134 | delete_async_operation.wait()
135 | print("\nDeleted: {}".format(topic.name))
136 |
137 | # Delete Resource group and everything in it
138 | print('\nDelete Resource Group')
139 | delete_async_operation = resource_client.resource_groups.delete(GROUP_NAME)
140 | delete_async_operation.wait()
141 | print("\nDeleted: {}".format(GROUP_NAME))
142 |
143 |
144 | def print_item(group):
145 | """Print a ResourceGroup instance."""
146 | print("\tName: {}".format(group.name))
147 | print("\tId: {}".format(group.id))
148 | if hasattr(group, 'location'):
149 | print("\tLocation: {}".format(group.location))
150 | print_properties(getattr(group, 'properties', None))
151 |
152 |
153 | def print_properties(props):
154 | """Print a ResourceGroup propertyies instance."""
155 | if props and hasattr(props, 'provisioning_state'):
156 | print("\tProperties:")
157 | print("\t\tProvisioning State: {}".format(props.provisioning_state))
158 | print("\n\n")
159 |
160 |
161 | if __name__ == "__main__":
162 | run_example()
163 |
--------------------------------------------------------------------------------
/create_storage_event_subscriptions.py:
--------------------------------------------------------------------------------
1 | import os
2 | from haikunator import Haikunator
3 |
4 | from azure.common.credentials import ServicePrincipalCredentials
5 |
6 | from azure.mgmt.resource import ResourceManagementClient
7 | from azure.mgmt.eventgrid import EventGridManagementClient
8 | from azure.mgmt.eventgrid.models import Topic, EventSubscriptionFilter, EventSubscription, HybridConnectionEventSubscriptionDestination
9 |
10 | # If you wish to debug
11 | # import logging
12 | # logging.basicConfig(level=logging.DEBUG)
13 |
14 | _haikunator = Haikunator()
15 |
16 | # Resource
17 |
18 | LOCATION = 'westus'
19 | GROUP_NAME = 'event-grid-python-sample-rg'
20 |
21 | # Event grid
22 |
23 | # Using a random topic name. Optionally, replace this with a topic name of your choice.
24 | TOPIC_NAME = "topicsample-" + _haikunator.haikunate(delimiter='')
25 |
26 | # In this sample, we will be creating an event subscription to this storage account.
27 | # Specify the Azure resource ID of an already existing storage account. The account must be
28 | # a General Purpose V2 Storage account or a Blob Storage account.
29 | # This should be in the format /subscriptions/id/resourceGroups/rg/providers/Microsoft.Storage/storageAccounts/account1
30 | # More info on Storage as an event source is at https://docs.microsoft.com/en-us/azure/event-grid/event-sources#storage
31 | STORAGE_ACOUNT_RESOURCE_ID = 'replace-with-your-storage-account-resource-id'
32 |
33 | # In this sample, we will be demonstrating using a hybridconnection as the destination for the event subscription.
34 | # This should be in the format /subscriptions/id/resourceGroups/rg/providers/Microsoft.Relay/namespaces/namespace1/hybridConnections/test
35 | # More info on HybridConnection as an event handler is at https://docs.microsoft.com/en-us/azure/event-grid/event-handlers#hybrid-connections
36 | HYBRID_CONNECTION_RESOURCE_ID = 'replace-with-your-hybrid-connection-resource-id'
37 |
38 | # To run the sample, you must first create an Azure service principal. To create the service principal, follow one of these guides:
39 | # Azure Portal: https://azure.microsoft.com/documentation/articles/resource-group-create-service-principal-portal/)
40 | # PowerShell: https://azure.microsoft.com/documentation/articles/resource-group-authenticate-service-principal/
41 | # Azure CLI: https://azure.microsoft.com/documentation/articles/resource-group-authenticate-service-principal-cli/
42 | #
43 | # This script expects that the following environment vars are set:
44 | #
45 | # AZURE_TENANT_ID: with your Azure Active Directory tenant id or domain
46 | # AZURE_CLIENT_ID: with your Azure Active Directory Application Client ID
47 | # AZURE_CLIENT_SECRET: with your Azure Active Directory Application Secret
48 | # AZURE_SUBSCRIPTION_ID: with your Azure Subscription Id
49 | #
50 |
51 |
52 | def run_example():
53 | """Resource Group management example."""
54 | #
55 | # Create the Resource Manager Client with an Application (service principal) token provider
56 | #
57 | subscription_id = os.environ.get(
58 | 'AZURE_SUBSCRIPTION_ID',
59 | '11111111-1111-1111-1111-111111111111') # your Azure Subscription Id
60 | credentials = ServicePrincipalCredentials(
61 | client_id=os.environ['AZURE_CLIENT_ID'],
62 | secret=os.environ['AZURE_CLIENT_SECRET'],
63 | tenant=os.environ['AZURE_TENANT_ID']
64 | )
65 | resource_client = ResourceManagementClient(credentials, subscription_id)
66 | event_grid_client = EventGridManagementClient(credentials, subscription_id)
67 |
68 | # Create Resource group
69 | print('\nCreating a Resource Group...')
70 | resource_group = resource_client.resource_groups.create_or_update(
71 | GROUP_NAME,
72 | {'location': LOCATION}
73 | )
74 | print_item(resource_group)
75 |
76 | # Creating an event subscription to storage account {StorageAccountResourceId} with destination as {HybridConnectionResourceId}
77 | print('\nCreating an event subscription to storage account {} with destination as {}'.format(
78 | STORAGE_ACOUNT_RESOURCE_ID, HYBRID_CONNECTION_RESOURCE_ID))
79 | event_subscription_name = 'EventSubscription1'
80 | destination = HybridConnectionEventSubscriptionDestination(
81 | resource_id=HYBRID_CONNECTION_RESOURCE_ID
82 | )
83 | filter = EventSubscriptionFilter(
84 | included_event_types=['Microsoft.Storage.BlobCreatedEvent'],
85 | is_subject_case_sensitive=False,
86 | subject_begins_with='/blobServices/default/containers/container1',
87 | subject_ends_with='.jpg'
88 | )
89 |
90 | event_subscription_info = EventSubscription(
91 | destination=destination, filter=filter)
92 |
93 | event_subscription_async_poller = event_grid_client.event_subscriptions.create_or_update(
94 | STORAGE_ACOUNT_RESOURCE_ID,
95 | event_subscription_name,
96 | event_subscription_info,
97 | )
98 | # Blocking call for the EventSubscription to be created
99 | event_subscription = event_subscription_async_poller.result() # type: EventSubscription
100 | print_item(event_subscription)
101 |
102 | input("Press enter to delete all created resources.")
103 |
104 | # Delete the EventSubscription
105 | print('\nDeleting the event subscription')
106 | delete_async_operation = event_grid_client.event_subscriptions.delete(
107 | STORAGE_ACOUNT_RESOURCE_ID,
108 | event_subscription_name
109 | )
110 | delete_async_operation.wait()
111 | print("\nDeleted: {}".format(event_subscription_name))
112 |
113 | # Delete Resource group and everything in it
114 | print('\nDelete Resource Group')
115 | delete_async_operation = resource_client.resource_groups.delete(GROUP_NAME)
116 | delete_async_operation.wait()
117 | print("\nDeleted: {}".format(GROUP_NAME))
118 |
119 |
120 | def print_item(group):
121 | """Print a ResourceGroup instance."""
122 | print("\tName: {}".format(group.name))
123 | print("\tId: {}".format(group.id))
124 | if hasattr(group, 'location'):
125 | print("\tLocation: {}".format(group.location))
126 | print_properties(getattr(group, 'properties', None))
127 |
128 |
129 | def print_properties(props):
130 | """Print a ResourceGroup propertyies instance."""
131 | if props and hasattr(props, 'provisioning_state'):
132 | print("\tProperties:")
133 | print("\t\tProvisioning State: {}".format(props.provisioning_state))
134 | print("\n\n")
135 |
136 |
137 | if __name__ == "__main__":
138 | run_example()
139 |
--------------------------------------------------------------------------------
/env_template:
--------------------------------------------------------------------------------
1 | # Rename this file to ".env" to be auto-loaded by Pipenv and update the values
2 | #
3 | # To run the sample, you must first create an Azure service principal. To create the service principal, follow one of these guides:
4 | # Azure Portal: https://azure.microsoft.com/documentation/articles/resource-group-create-service-principal-portal/)
5 | # PowerShell: https://azure.microsoft.com/documentation/articles/resource-group-authenticate-service-principal/
6 | # Azure CLI: https://azure.microsoft.com/documentation/articles/resource-group-authenticate-service-principal-cli/
7 | AZURE_SUBSCRIPTION_ID=11111111-1111-1111-1111-111111111111
8 | AZURE_CLIENT_ID=11111111-1111-1111-1111-111111111111
9 | AZURE_CLIENT_SECRET=AZURE_CLIENT_SECRET
10 | AZURE_TENANT_ID=common
--------------------------------------------------------------------------------
/event_grid_publisher.py:
--------------------------------------------------------------------------------
1 | import datetime
2 | import uuid
3 |
4 | from msrest.authentication import TopicCredentials
5 | from azure.eventgrid import EventGridClient
6 | from azure.eventgrid.models import EventGridEvent
7 |
8 | # If you wish to debug
9 | # import logging
10 | # logging.basicConfig(level=logging.DEBUG)
11 |
12 | # Enter values for and
13 | TOPIC_ENDPOINT = ".-1.eventgrid.azure.net"
14 |
15 | # Enter value for
16 | EVENT_GRID_KEY = ''
17 |
18 |
19 | def build_events_list():
20 | # type: () -> List[EventGridEvent]
21 | result = []
22 | for i in range(1):
23 | result.append(EventGridEvent(
24 | id=uuid.uuid4(),
25 | subject="My subject {}".format(i),
26 | data={
27 | 'key': 'I accept any kind of data here, this is a free dictionary'
28 | },
29 | event_type='PersonalEventType',
30 | event_time=datetime.datetime.now(),
31 | data_version=2.0
32 | ))
33 | return result
34 |
35 |
36 | def run_example():
37 |
38 | credentials = TopicCredentials(
39 | EVENT_GRID_KEY
40 | )
41 | event_grid_client = EventGridClient(credentials)
42 | event_grid_client.publish_events(
43 | TOPIC_ENDPOINT,
44 | events=build_events_list()
45 | )
46 | print("Published events to Event Grid.")
47 |
48 |
49 | if __name__ == "__main__":
50 | run_example()
51 | ()
52 |
--------------------------------------------------------------------------------