├── .github
├── CODE_OF_CONDUCT.md
├── ISSUE_TEMPLATE.md
├── PULL_REQUEST_TEMPLATE.md
├── fabricbot.json
└── workflows
│ └── codeql-analysis.yml
├── .gitignore
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE.md
├── README.md
├── SAMPLES.md
├── SECURITY.md
├── app-config
├── .env-sample
├── .vscode
│ └── launch.json
├── get-configuration-setting.js
├── list-configuration-settings.js
├── package-lock.json
└── package.json
├── apps
├── apps
│ ├── interactive-download-certificate-orders.js
│ ├── interactive-download-settings.js
│ └── interactive-download-settings.json
├── azure-functions-http-trigger-typescript
│ ├── .devcontainer
│ │ ├── Dockerfile
│ │ └── devcontainer.json
│ ├── .funcignore
│ ├── .gitignore
│ ├── .vscode
│ │ ├── extensions.json
│ │ ├── launch.json
│ │ ├── settings.json
│ │ └── tasks.json
│ ├── babel.config.js
│ ├── host.json
│ ├── package-lock.json
│ ├── package.json
│ ├── proxies.json
│ ├── readme.md
│ ├── tsconfig.json
│ ├── validateTweet
│ │ ├── function.json
│ │ ├── index.test.ts
│ │ └── index.ts
│ └── yarn.lock
└── nodejs-redirect
│ ├── index.js
│ └── package.json
├── cognitive-services
├── face-detection-result.json
├── face.js
└── package.json
├── database
├── cassandra
│ ├── index.js
│ └── package.json
├── cosmos-db-sql-core-api
│ ├── find_product_by_query_with_param_like_keyword.js
│ ├── package.json
│ ├── update-products.js
│ └── upsert_products.js
├── mariadb
│ ├── index.js
│ └── package.json
├── mongodb
│ ├── .env
│ ├── azure-cosmosdb-mongodb.ts
│ ├── books.csv
│ ├── bulk_insert_mongodb.js
│ ├── index_mongodb.js
│ ├── index_mongoose.js
│ ├── package-lock.json
│ ├── package.json
│ └── readme.md
├── mssql
│ └── index.js
├── mysql
│ ├── index.js
│ └── package.json
├── postgresql
│ ├── index.js
│ └── package.json
├── redis
│ ├── .devcontainer
│ │ └── devcontainer.json
│ ├── .env.sample
│ ├── MOCK_DATA.csv
│ ├── bulk_insert.js
│ ├── config.js
│ ├── get-set.js
│ ├── package-lock.json
│ ├── package.json
│ ├── quickstart.js
│ └── readme.md
└── sql
│ ├── .env.sample
│ ├── .vscode
│ └── launch.json
│ ├── package.json
│ └── quickstart.js
├── docs
└── templates
│ └── end-to-end-scenario.md
├── events
└── event-hubs
│ ├── package.json
│ ├── receive-passwordless.js
│ ├── receive.js
│ ├── send-passwordless.js
│ └── send.js
├── graph
├── my-profile-from-rest-api.js
└── my-profile-from-sdk.js
├── keyvault
├── azure-keyvault-secrets.js
├── package-lock.json
└── package.json
├── package-lock.json
├── resources
├── .env
├── authorization
│ ├── list.js
│ ├── package-lock.json
│ └── package.json
├── billing
│ ├── billing.js
│ ├── package-lock.json
│ └── package.json
├── create-resource-default-credential.js
├── create-resource.js
├── monitor
│ ├── .vscode
│ │ └── launch.json
│ ├── package-lock.json
│ ├── package.json
│ └── resource-creation-history.js
├── package.json
├── resource-group-create
│ ├── README.md
│ ├── package-lock.json
│ ├── package.json
│ └── resource-group-create.js
├── resource-group-default-credential.js
├── resource-group.js
├── resource-groups-list
│ ├── README.md
│ ├── package.json
│ └── resource-groups-list.js
├── resources-list-in-subscription
│ └── list-resources-in-subscription.js
├── subscriptions
│ ├── list-locations.js
│ ├── list.js
│ ├── package-lock.json
│ └── package.json
└── virtual-machines
│ ├── README.md
│ ├── create-vm.js
│ ├── delete-resources.js
│ ├── list-vms.js
│ ├── package-lock.json
│ ├── package.json
│ ├── start-vm.js
│ ├── status-vms-all.js
│ ├── status.js
│ ├── stop-vm.js
│ └── vm-info.js
├── search
├── bulk-insert-books-from-csv
│ ├── books.csv
│ ├── books.schema.json
│ └── bulk_insert_books.js
├── package.json
└── readme.md
├── storage
├── blob-paging
│ ├── blob-paging.js
│ ├── package-lock.json
│ └── package.json
├── file-paging
│ ├── README.md
│ ├── package.json
│ └── page-through-files.js
├── queue
│ └── convert-into-and-out-of-string.js
├── upload-files-from-url
│ ├── .vscode
│ │ └── launch.json
│ ├── README.md
│ ├── copy-from-files-to-blobs.js
│ ├── package-lock.json
│ └── package.json
├── upload-string-to-file
│ ├── package-lock.json
│ ├── package.json
│ └── upload-string-to-file.js
└── upload-url-to-blob-poll-until-done
│ ├── .vscode
│ └── launch.json
│ ├── README.md
│ ├── package-lock.json
│ ├── package.json
│ ├── upload-url-to-blob-poll-until-done-by-page.js
│ └── upload-url-to-blob-poll-until-done.js
├── vscode-docs-linter
└── config.json
└── windows-terminal
└── readme.md
/.github/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Microsoft Open Source Code of Conduct
2 |
3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
4 |
5 | Resources:
6 |
7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns
10 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/.github/workflows/codeql-analysis.yml:
--------------------------------------------------------------------------------
1 | # For most projects, this workflow file will not need changing; you simply need
2 | # to commit it to your repository.
3 | #
4 | # You may wish to alter this file to override the set of languages analyzed,
5 | # or to provide custom queries or build logic.
6 | #
7 | # ******** NOTE ********
8 | # We have attempted to detect the languages in your repository. Please check
9 | # the `language` matrix defined below to confirm you have the correct set of
10 | # supported CodeQL languages.
11 | #
12 | name: "CodeQL"
13 |
14 | on:
15 | push:
16 | branches: [ main ]
17 | pull_request:
18 | # The branches below must be a subset of the branches above
19 | branches: [ main ]
20 | schedule:
21 | - cron: '43 14 * * 5'
22 |
23 | jobs:
24 | analyze:
25 | name: Analyze
26 | runs-on: ubuntu-latest
27 |
28 | strategy:
29 | fail-fast: false
30 | matrix:
31 | language: [ 'javascript' ]
32 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
33 | # Learn more:
34 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
35 |
36 | steps:
37 | - name: Checkout repository
38 | uses: actions/checkout@v2
39 |
40 | # Initializes the CodeQL tools for scanning.
41 | - name: Initialize CodeQL
42 | uses: github/codeql-action/init@v1
43 | with:
44 | languages: ${{ matrix.language }}
45 | # If you wish to specify custom queries, you can do so here or in a config file.
46 | # By default, queries listed here will override any specified in a config file.
47 | # Prefix the list here with "+" to use these queries and those in the config file.
48 | # queries: ./path/to/local/query, your-org/your-repo/queries@main
49 |
50 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
51 | # If this step fails, then you should remove it and run the build manually (see below)
52 | - name: Autobuild
53 | uses: github/codeql-action/autobuild@v1
54 |
55 | # ℹ️ Command-line programs to run using the OS shell.
56 | # 📚 https://git.io/JvXDl
57 |
58 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
59 | # and modify them (or add more) to build your code if your project
60 | # uses a compiled language
61 |
62 | #- run: |
63 | # make bootstrap
64 | # make release
65 |
66 | - name: Perform CodeQL Analysis
67 | uses: github/codeql-action/analyze@v1
68 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | lerna-debug.log*
8 |
9 | # Diagnostic reports (https://nodejs.org/api/report.html)
10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
11 |
12 | # Runtime data
13 | pids
14 | *.pid
15 | *.seed
16 | *.pid.lock
17 |
18 | # Directory for instrumented libs generated by jscoverage/JSCover
19 | lib-cov
20 |
21 | # Coverage directory used by tools like istanbul
22 | coverage
23 | *.lcov
24 |
25 | # nyc test coverage
26 | .nyc_output
27 |
28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
29 | .grunt
30 |
31 | # Bower dependency directory (https://bower.io/)
32 | bower_components
33 |
34 | # node-waf configuration
35 | .lock-wscript
36 |
37 | # Compiled binary addons (https://nodejs.org/api/addons.html)
38 | build/Release
39 |
40 | # Dependency directories
41 | node_modules/
42 | jspm_packages/
43 |
44 | # TypeScript v1 declaration files
45 | typings/
46 |
47 | # TypeScript cache
48 | *.tsbuildinfo
49 |
50 | # Optional npm cache directory
51 | .npm
52 |
53 | # Optional eslint cache
54 | .eslintcache
55 |
56 | # Microbundle cache
57 | .rpt2_cache/
58 | .rts2_cache_cjs/
59 | .rts2_cache_es/
60 | .rts2_cache_umd/
61 |
62 | # Optional REPL history
63 | .node_repl_history
64 |
65 | # Output of 'npm pack'
66 | *.tgz
67 |
68 | # Yarn Integrity file
69 | .yarn-integrity
70 |
71 | # dotenv environment variables file
72 | .env
73 | .env.test
74 |
75 | # parcel-bundler cache (https://parceljs.org/)
76 | .cache
77 |
78 | # Next.js build output
79 | .next
80 |
81 | # Nuxt.js build / generate output
82 | .nuxt
83 | dist
84 |
85 | # Gatsby files
86 | .cache/
87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js
88 | # https://nextjs.org/blog/next-9-1#public-directory-support
89 | # public
90 |
91 | # vuepress build output
92 | .vuepress/dist
93 |
94 | # Serverless directories
95 | .serverless/
96 |
97 | # FuseBox cache
98 | .fusebox/
99 |
100 | # DynamoDB Local files
101 | .dynamodb/
102 |
103 | # TernJS port file
104 | .tern-port
105 |
--------------------------------------------------------------------------------
/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.opensource.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., status check, 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 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) Microsoft Corporation.
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
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_type: sample
3 | languages:
4 | - javascript
5 | - typescript
6 | - nodejs
7 | name: "JavaScript end-to-end samples"
8 | description: "These samples are part of the documentation for the Azure JavaScript Developer Center - https://docs.microsoft.com/azure/developer/javascript/."
9 | products:
10 | - azure
11 | - azure-functions
12 | - azure-cognitive-services
13 | - azure-cosmos-db
14 | - azure-database-mariadb
15 | - azure-database-mysql
16 | - azure-database-postgresql
17 | - azure-cache-redis
18 | - azure-key-vault
19 | - azure-resource-manager
20 | - azure-cognitive-search
21 | - azure-portal
22 | - vs-code
23 | ---
24 |
25 | # JavaScript end to end samples
26 |
27 | These samples are part of the documentation for the [Azure JavaScript Developer Center](https://docs.microsoft.com/azure/developer/javascript/).
28 |
29 | ## Resources
30 |
31 | * Azure
32 | * Learn TV
33 | * [The Launch Space](https://github.com/microsoft/TheLaunchSpace)
34 | * [Web wednesday](https://channel9.msdn.com/Shows/Web-Wednesday/)
35 | * [Developer Advocate resources](https://docs.microsoft.com/azure/developer/javascript/whats-new-developer-advocacy) - produced by advocates
36 | * [Community resources](https://docs.microsoft.com/javascript/) - produced by members of the community
37 | * [Code Samples of Azure JavaScript/TypeScript SDK Management Libraries](https://github.com/Azure-Samples/azure-samples-js-management)
38 | * [JS e2e Samples list](https://docs.microsoft.com/azure/developer/javascript/how-to/common-javascript-tasks#samples-supporting-these-tasks)
39 |
40 | ### Azure functions
41 |
42 | * Documentation
43 | * Tools
44 | * [OpenAPI for Azure Functions](https://github.com/aaronpowell/azure-functions-nodejs-openapi) - This is an extension for Azure Functions to generate OpenAPI spec files from annotated Azure Functions.
45 |
46 | ### Microsoft JavaScript packages
47 |
48 | * [Azure SDKs](https://github.com/Azure/azure-sdk-for-js)
49 | * [PlayWright](https://github.com/microsoft/playwright)
50 | * [Application Insights](https://github.com/microsoft/ApplicationInsights-node.js)
51 | * [Rooster](https://www.npmjs.com/package/roosterjs-react)
52 |
53 | ## Let us know
54 |
55 | If the code, documentation, or other information has errors or is incomplete, let us know.
56 |
--------------------------------------------------------------------------------
/SAMPLES.md:
--------------------------------------------------------------------------------
1 | ### E2E applications
2 |
3 | These are client, server, or full-stack applications using Azure services - found in other repositories.
4 |
5 | |Sample|corresponding docs|
6 | |--|--|
7 | |[Client Azure login button](https://github.com/Azure-Samples/js-e2e-client-azure-login-button)|[docs](https://docs.microsoft.com/en-us/azure/developer/javascript/tutorial/single-page-application-azure-login-button-sdk-msal)|
8 | |Add easy authentication to app|[docs](https://docs.microsoft.com/en-us/azure/developer/javascript/how-to/with-web-app/add-authentication-to-web-app)|
9 | |[Add MSAL authentication to Express.js app](https://github.com/Azure-Samples/js-e2e-web-app-server-auth.git)||
10 | |[Client file upload to Azure Storage Blobs](https://github.com/Azure-Samples/js-e2e-browser-file-upload-storage-blob)|[docs](https://docs.microsoft.com/en-us/azure/developer/javascript/tutorial/browser-file-upload-azure-storage-blob)|
11 | |[Static Web App Client using Cognitive Services Computer Vision](https://github.com/Azure-Samples/js-e2e-client-cognitive-services/blob/main/.github/workflows/sample-github-workflow.yml)|[docs](https://docs.microsoft.com/azure/developer/javascript/tutorial/static-web-app/introduction)|
12 | |[Server](https://github.com/Azure-Samples/js-e2e-express-server)|[docs](https://docs.microsoft.com/azure/developer/javascript/tutorial/tutorial-vscode-azure-cli-node/tutorial-vscode-azure-cli-node-01)|
13 | |[Server as VM deployed to Azure](https://github.com/Azure-Samples/js-e2e-vm)|[docs](https://docs.microsoft.com/en-us/azure/developer/javascript/tutorial/nodejs-virtual-machine-vm/introduction)|
14 | |[Server - Text to Speech conversion to MP3 files using Cognitive Services Speech](https://github.com/Azure-Samples/js-e2e-express-server-cognitive-services)|[docs](https://docs.microsoft.com/azure/developer/javascript/tutorial/convert-text-to-speech-cognitive-services)|
15 | |[Server with MongoDB](https://github.com/Azure-Samples/js-e2e-express-mongodb)|[docs](https://docs.microsoft.com/azure/developer/javascript/tutorial/deploy-nodejs-mongodb-app-service-from-visual-studio-code)|
16 | |[Full stack with MongoDB](https://github.com/Azure-Samples/js-e2e-express-react-mongodb)||
17 | |[GraphQL serverless function](https://github.com/azure-samples/js-e2e-azure-function-graphql-hello) - Hello world with TypeScript, ready to deploy to Azure Function.|[docs](https://docs.microsoft.com/en-us/azure/developer/javascript/how-to/with-web-app/graphql/get-started)|
18 | |[GraphQL serverless CRUD function](https://github.com/azure-samples/js-e2e-azure-function-graphql-crud-operations)|[docs](https://docs.microsoft.com/en-us/azure/developer/javascript/how-to/with-web-app/graphql/get-started#reading-and-writing-apollo-graphql-with-queries-and-mutations)|
19 | |[GraphQL static web app with Function API](https://github.com/azure-samples/js-e2e-graphql-cosmosdb-static-web-app)|[docs](https://docs.microsoft.com/en-us/azure/developer/javascript/how-to/with-web-app/graphql/static-web-app-graphql/introduction?branch=master)|
20 |
21 | ## Other Samples
22 |
23 | * [Azure SDK for JS - samples, snippets, and how-to guides](https://github.com/Azure/azure-sdk-for-js/tree/main/samples)
24 | * [Microsoft Authentication Library for JavaScript (MSAL.js)](https://github.com/AzureAD/microsoft-authentication-library-for-js)
25 | * [Microsoft Graph](https://developer.microsoft.com/en-us/graph/gallery/)
26 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Security Policy
2 |
3 | ## Supported Versions
4 |
5 | This repo isn't currently versioned.
6 |
7 | ## Reporting a Vulnerability
8 |
9 | Please open an issue if you find a vulnerability.
10 |
--------------------------------------------------------------------------------
/app-config/.env-sample:
--------------------------------------------------------------------------------
1 | AZURE_TENANT_ID=
2 | AZURE_CLIENT_ID=
3 | AZURE_CLIENT_SECRET=
4 | KEYVAULT_URI=https://YOUR-RESOURCE-NAME.vault.azure.net/
5 | APPCONFIG_CONNECTION_STRING="Endpoint=https://YOUR-RESOURCE-NAME.azconfig.io;Id=YOUR-ID;Secret=YOUR-SECRET"
--------------------------------------------------------------------------------
/app-config/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "type": "pwa-node",
9 | "request": "launch",
10 | "name": "Launch Program",
11 | "skipFiles": [
12 | "/**"
13 | ],
14 | "program": "${workspaceFolder}\\${file}"
15 | }
16 | ]
17 | }
--------------------------------------------------------------------------------
/app-config/get-configuration-setting.js:
--------------------------------------------------------------------------------
1 | const { AppConfigurationClient } = require("@azure/app-configuration");
2 |
3 | const connectionString =
4 | process.env["APPCONFIG_CONNECTION_STRING"] ||
5 | "Endpoint=https://YOUR-RESOURCE-NAME...";
6 | const appConfigClient = new AppConfigurationClient(connectionString);
7 |
8 | const getConfigurationSetting = async (key) => {
9 | return await appConfigClient.getConfigurationSetting({
10 | key,
11 | });
12 | };
13 |
14 | const settingName = "AppTitle";
15 | getConfigurationSetting(settingName)
16 | .then((result) => {
17 | console.log(result);
18 |
19 | /*
20 | {
21 | value: 'Text title of app - used in build pipeline',
22 | syncToken: '98765',
23 | lastModified: 2021-11-10T18:52:24.000Z,
24 | 'access-control-allow-credentials': 'true',
25 | 'access-control-allow-origin': '*',
26 | 'access-control-expose-headers': 'DNT, X-CustomHeader, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Authorization, x-ms-client-request-id, x-ms-useragent, x-ms-content-sha256, x-ms-date, host, Accept, Accept-Datetime, Date, If-Match, If-None-Match, Sync-Token, x-ms-return-client-request-id, ETag, Last-Modified, Link, Memento-Datetime, retry-after-ms, x-ms-request-id, x-ms-client-session-id, x-ms-effective-locale, WWW-Authenticate',
27 | connection: 'close',
28 | 'content-type': 'application/vnd.microsoft.appconfig.kv+json; charset=utf-8',
29 | date: 'Wed, 10 Nov 2021 19:36:17 GMT',
30 | server: 'openresty/1.17.8.2',
31 | 'strict-transport-security': 'max-age=15724800; includeSubDomains',
32 | 'transfer-encoding': 'chunked',
33 | 'x-ms-correlation-request-id': '123456',
34 | 'x-ms-request-id': '123456',
35 | key: 'AppTitle',
36 | label: null,
37 | contentType: '',
38 | tags: {},
39 | etag: 'YDxy2NHJexhh1X4LZZc9TK8mrnt',
40 | isReadOnly: false,
41 | statusCode: 200
42 | }
43 | */
44 | })
45 | .catch((ex) => {
46 | console.log(ex);
47 | });
48 |
--------------------------------------------------------------------------------
/app-config/list-configuration-settings.js:
--------------------------------------------------------------------------------
1 | const {
2 | AppConfigurationClient,
3 | parseSecretReference,
4 | parseFeatureFlag,
5 | isSecretReference,
6 | isFeatureFlag,
7 | } = require("@azure/app-configuration");
8 | const { SecretClient, parseKeyVaultSecretIdentifier } = require("@azure/keyvault-secrets");
9 | const { DefaultAzureCredential } = require("@azure/identity");
10 | const { parse } = require("dotenv");
11 |
12 | // Load the .env file if it exists
13 | require("dotenv").config();
14 |
15 | const credential = new DefaultAzureCredential();
16 | const url = process.env["KEYVAULT_URI"] || "";
17 | const connectionString =
18 | process.env["APPCONFIG_CONNECTION_STRING"] || "";
19 |
20 | const listSettings = async () => {
21 | const secretClient = new SecretClient(url, credential);
22 | const appConfigClient = new AppConfigurationClient(connectionString);
23 | const settingsIterator = appConfigClient.listConfigurationSettings();
24 |
25 | const settingList = [];
26 |
27 | for await (const setting of settingsIterator) {
28 | let parsed = null;
29 |
30 | // Feature Flat
31 | if (isFeatureFlag(setting)) {
32 | parsed = parseFeatureFlag(setting);
33 | } else if (isSecretReference(setting)) {
34 | // Secret retrieved from Key Vault
35 | parsed = parseSecretReference(setting);
36 | const secretInKeyVault = parseKeyVaultSecretIdentifier(parsed.value.secretId);
37 |
38 | try{
39 | parsed.secretValue = await secretClient.getSecret(secretInKeyVault.name);
40 | }catch(ex){
41 | // handle case where secret has been removed from key vault but not from app config
42 | parsed.secretValue = null;
43 | //throw(ex);
44 | }
45 |
46 | } else {
47 | // Configuration Setting
48 | parsed = setting;
49 | }
50 |
51 | settingList.push(parsed);
52 | }
53 | return settingList;
54 | };
55 |
56 | listSettings()
57 | .then((list) => {
58 | console.log(list);
59 | })
60 | .catch((ex) => {
61 | console.log(ex);
62 | });
63 |
--------------------------------------------------------------------------------
/app-config/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "app-config",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "get-configuration-setting.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "@azure/app-configuration": "^1.3.0",
14 | "@azure/identity": "^2.0.1",
15 | "@azure/keyvault-secrets": "^4.3.0",
16 | "dotenv": "^10.0.0"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/apps/apps/interactive-download-certificate-orders.js:
--------------------------------------------------------------------------------
1 | const { InteractiveBrowserCredential } = require("@azure/identity");
2 | const { WebSiteManagementClient } = require("@azure/arm-appservice");
3 |
4 | // CHANGE THESE VALUES TO YOUR OWN
5 | // Either set environment variables
6 | // or set your value to the string at the end
7 | const subscriptionId = process.env["MY-SUBSCRIPTION"] || "";
8 | const resourceGroupName = process.env["MY-RESOURCE-GROUP"] || "";
9 | const resourceName = process.env["MY-RESOURCE-NAME"] || "";
10 |
11 | const creds = new InteractiveBrowserCredential();
12 |
13 | async function getCertificates(creds) {
14 | const client = new WebSiteManagementClient(creds, subscriptionId);
15 | const certificateOrdersList = new Array();
16 | for await (const item of client.appServiceCertificateOrders.list()) {
17 | certificateOrdersList.push(item);
18 | }
19 | return certificateOrdersList;
20 | }
21 |
22 | getCertificates(creds)
23 | .then((res) => {
24 | console.log(JSON.stringify(res));
25 | })
26 | .catch((err) => {
27 | console.log(err);
28 | });
29 |
--------------------------------------------------------------------------------
/apps/apps/interactive-download-settings.js:
--------------------------------------------------------------------------------
1 | const { InteractiveBrowserCredential } = require("@azure/identity");
2 | const { WebSiteManagementClient } = require("@azure/arm-appservice");
3 |
4 | // CHANGE THESE VALUES TO YOUR OWN
5 | // Either set environment variables
6 | // or set your value to the string at the end
7 | const subscriptionId = process.env["MY-SUBSCRIPTION"] || "";
8 | const resourceGroupName = process.env["MY-RESOURCE-GROUP"] || "";
9 | const resourceName = process.env["MY-RESOURCE-NAME"] || "";
10 |
11 | const creds = new InteractiveBrowserCredential();
12 |
13 | async function getSettings(creds) {
14 | const client = new WebSiteManagementClient(creds, subscriptionId);
15 | const ApplicationSettingsList = new Array();
16 | for await (const item of client.webApps.listApplicationSettings(
17 | resourceGroupName,
18 | resourceName
19 | )) {
20 | ApplicationSettingsList.push(item);
21 | }
22 | return ApplicationSettingsList;
23 | }
24 |
25 | getSettings(creds)
26 | .then((result) => {
27 | console.log(JSON.stringify(result));
28 | })
29 | .catch((err) => {
30 | console.log(err);
31 | });
32 |
--------------------------------------------------------------------------------
/apps/apps/interactive-download-settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "/subscriptions/MY-SUBSCRIPTION/resourceGroups/MY-RESOURCE-GROUP/providers/Microsoft.Web/sites/MY-RESOURCE-NAME/config/appsettings",
3 | "name": "appsettings",
4 | "type": "Microsoft.Web/sites/config",
5 | "properties": {
6 | "APPINSIGHTS_INSTRUMENTATIONKEY": "MY-APP-INSIGHTS-KEY",
7 | "APPLICATIONINSIGHTS_CONNECTION_STRING": "InstrumentationKey=MY-APP-INSIGHTS-KEY;IngestionEndpoint=https://centralus-0.in.applicationinsights.azure.com/",
8 | "ApplicationInsightsAgent_EXTENSION_VERSION": "~2",
9 | "CUSTOM_KEY": "ABC_123",
10 | "MICROSOFT_PROVIDER_AUTHENTICATION_SECRET": "MY-SECRET",
11 | "XDT_MicrosoftApplicationInsights_Mode": "default"
12 | },
13 | "location": "Central US",
14 | "tags": {}
15 | }
--------------------------------------------------------------------------------
/apps/azure-functions-http-trigger-typescript/.devcontainer/Dockerfile:
--------------------------------------------------------------------------------
1 | # Find the Dockerfile for mcr.microsoft.com/azure-functions/node at the following URLs:
2 | # Node 10: https://github.com/Azure/azure-functions-docker/blob/master/host/3.0/buster/amd64/node/node10/node10-core-tools.Dockerfile
3 | # Node 12: https://github.com/Azure/azure-functions-docker/blob/master/host/3.0/buster/amd64/node/node12/node12-core-tools.Dockerfile
4 | ARG VARIANT=12
5 | FROM mcr.microsoft.com/azure-functions/node:3.0-node${VARIANT}-core-tools
6 |
7 | # [Optional] Uncomment this section to install additional OS packages.
8 | RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
9 | && apt-get -y install --no-install-recommends azure-functions-core-tools-3
10 |
11 |
--------------------------------------------------------------------------------
/apps/azure-functions-http-trigger-typescript/.devcontainer/devcontainer.json:
--------------------------------------------------------------------------------
1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
2 | // https://github.com/microsoft/vscode-dev-containers/tree/v0.158.0/containers/azure-functions-node
3 | {
4 | "name": "Azure Functions & Node.js",
5 | "build": {
6 | "dockerfile": "Dockerfile",
7 | // Update 'VARIANT' to pick a Node.js version: 10, 12
8 | "args": { "VARIANT": "12" }
9 | },
10 | "forwardPorts": [ 7071 ],
11 |
12 | // Set *default* container specific settings.json values on container create.
13 | "settings": {
14 | "terminal.integrated.shell.linux": "/bin/bash"
15 | },
16 |
17 | // Add the IDs of extensions you want installed when the container is created.
18 | "extensions": [
19 | "ms-azuretools.vscode-azurefunctions",
20 | "dbaeumer.vscode-eslint"
21 | ],
22 |
23 | // Use 'postCreateCommand' to run commands after the container is created.
24 | "postCreateCommand": "npm install",
25 |
26 | // Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
27 | "remoteUser": "node"
28 | }
--------------------------------------------------------------------------------
/apps/azure-functions-http-trigger-typescript/.funcignore:
--------------------------------------------------------------------------------
1 | *.js.map
2 | *.ts
3 | .git*
4 | .vscode
5 | local.settings.json
6 | test
7 | tsconfig.json
--------------------------------------------------------------------------------
/apps/azure-functions-http-trigger-typescript/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | lerna-debug.log*
8 |
9 | # Diagnostic reports (https://nodejs.org/api/report.html)
10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
11 |
12 | # Runtime data
13 | pids
14 | *.pid
15 | *.seed
16 | *.pid.lock
17 |
18 | # Directory for instrumented libs generated by jscoverage/JSCover
19 | lib-cov
20 |
21 | # Coverage directory used by tools like istanbul
22 | coverage
23 |
24 | # nyc test coverage
25 | .nyc_output
26 |
27 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
28 | .grunt
29 |
30 | # Bower dependency directory (https://bower.io/)
31 | bower_components
32 |
33 | # node-waf configuration
34 | .lock-wscript
35 |
36 | # Compiled binary addons (https://nodejs.org/api/addons.html)
37 | build/Release
38 |
39 | # Dependency directories
40 | node_modules/
41 | jspm_packages/
42 |
43 | # TypeScript v1 declaration files
44 | typings/
45 |
46 | # Optional npm cache directory
47 | .npm
48 |
49 | # Optional eslint cache
50 | .eslintcache
51 |
52 | # Optional REPL history
53 | .node_repl_history
54 |
55 | # Output of 'npm pack'
56 | *.tgz
57 |
58 | # Yarn Integrity file
59 | .yarn-integrity
60 |
61 | # dotenv environment variables file
62 | .env
63 | .env.test
64 |
65 | # parcel-bundler cache (https://parceljs.org/)
66 | .cache
67 |
68 | # next.js build output
69 | .next
70 |
71 | # nuxt.js build output
72 | .nuxt
73 |
74 | # vuepress build output
75 | .vuepress/dist
76 |
77 | # Serverless directories
78 | .serverless/
79 |
80 | # FuseBox cache
81 | .fusebox/
82 |
83 | # DynamoDB Local files
84 | .dynamodb/
85 |
86 | # TypeScript output
87 | dist
88 | out
89 |
90 | # Azure Functions artifacts
91 | bin
92 | obj
93 | appsettings.json
94 | local.settings.json
--------------------------------------------------------------------------------
/apps/azure-functions-http-trigger-typescript/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "ms-azuretools.vscode-azurefunctions",
4 | "ms-vscode-remote.remote-containers"
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/apps/azure-functions-http-trigger-typescript/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.0",
3 | "configurations": [
4 | {
5 | "name": "Run Functions",
6 | "type": "node",
7 | "request": "attach",
8 | "port": 9229,
9 | "preLaunchTask": "func: host start"
10 | },{
11 | "type": "node",
12 | "request": "launch",
13 | "name": "Run Tests",
14 | "disableOptimisticBPs": true,
15 | "program": "${workspaceRoot}/node_modules/jest/bin/jest.js",
16 | "args": [
17 | "-i"
18 | ],
19 | "internalConsoleOptions": "openOnSessionStart"
20 | }
21 | ]
22 | }
--------------------------------------------------------------------------------
/apps/azure-functions-http-trigger-typescript/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "azureFunctions.deploySubpath": ".",
3 | "azureFunctions.postDeployTask": "npm install",
4 | "azureFunctions.projectLanguage": "TypeScript",
5 | "azureFunctions.projectRuntime": "~3",
6 | "debug.internalConsoleOptions": "neverOpen",
7 | "azureFunctions.preDeployTask": "npm prune"
8 | }
--------------------------------------------------------------------------------
/apps/azure-functions-http-trigger-typescript/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0.0",
3 | "tasks": [
4 | {
5 | "type": "func",
6 | "command": "host start",
7 | "problemMatcher": "$func-node-watch",
8 | "isBackground": true,
9 | "dependsOn": "npm build"
10 | },
11 | {
12 | "type": "shell",
13 | "label": "npm build",
14 | "command": "npm run build",
15 | "dependsOn": "npm install",
16 | "problemMatcher": "$tsc"
17 | },
18 | {
19 | "type": "shell",
20 | "label": "npm install",
21 | "command": "npm install"
22 | },
23 | {
24 | "type": "shell",
25 | "label": "npm prune",
26 | "command": "npm prune --production",
27 | "dependsOn": "npm build",
28 | "problemMatcher": []
29 | }
30 | ]
31 | }
--------------------------------------------------------------------------------
/apps/azure-functions-http-trigger-typescript/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = api => {
2 | const isTest = api.env('test');
3 | // You can use isTest to determine what presets and plugins to use.
4 |
5 | return {
6 | presets: [
7 | ['@babel/preset-env',
8 | {
9 | targets:
10 | { node: 'current' }
11 | }
12 | ],
13 | '@babel/preset-typescript',
14 | ]
15 | };
16 | };
--------------------------------------------------------------------------------
/apps/azure-functions-http-trigger-typescript/host.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0",
3 | "logging": {
4 | "applicationInsights": {
5 | "samplingSettings": {
6 | "isEnabled": true,
7 | "excludedTypes": "Request"
8 | }
9 | }
10 | },
11 | "extensionBundle": {
12 | "id": "Microsoft.Azure.Functions.ExtensionBundle",
13 | "version": "[1.*, 2.0.0)"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/apps/azure-functions-http-trigger-typescript/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "twitterfunction",
3 | "version": "1.0.0",
4 | "description": "",
5 | "scripts": {
6 | "build": "tsc",
7 | "watch": "tsc -w",
8 | "prestart": "npm run clean && npm run build",
9 | "start": "func start --watch",
10 | "test": "npm run prestart && jest /dist --verbose --coverage",
11 | "clean": "rm -rf dist"
12 | },
13 | "dependencies": {
14 | "jest": "^26.6.3",
15 | "twitter-text": "^3.1.0"
16 | },
17 | "devDependencies": {
18 | "@azure/functions": "^1.2.3",
19 | "@babel/core": "^7.13.8",
20 | "@babel/preset-env": "^7.13.8",
21 | "@babel/preset-typescript": "^7.13.0",
22 | "@types/jest": "^26.0.20",
23 | "babel-jest": "^26.6.3",
24 | "typescript": "^3.3.3"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/apps/azure-functions-http-trigger-typescript/proxies.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json.schemastore.org/proxies",
3 | "proxies": {}
4 | }
5 |
--------------------------------------------------------------------------------
/apps/azure-functions-http-trigger-typescript/readme.md:
--------------------------------------------------------------------------------
1 | # Azure Functions with TypeScript
2 |
3 | ## Visual Studio Code extensions
4 |
5 | * Azure Functions - ms-azuretools.vscode-azurefunctions
6 | * Remote - Containers - ms-vscode-remote.remote-containers
7 |
8 | ## Azure resources
9 |
10 | * Run this app locally in the container provided:
11 | * all environment and JS dependencies are installed
12 | * there isn't a problem with the version of Node.js you have locally installed. This allows you to use the same version of Node.js as the Azure Function runtime environment.
13 |
14 | ## Azure Functions
15 |
16 | * 200 - Post with valid body value
17 | * 404 - Post without body or without body.tweetText
18 |
19 | ## HTTP Request
20 |
21 | Function is configured to use HTTP Post and expects the POST Body to look like:
22 |
23 | ```JSON
24 | { tweetText: "This is my tweet" }
25 | ```
26 |
27 | You can see this used in the test.
28 |
29 | ## HTTP Response
30 |
31 | ```JSON
32 | {
33 | "textReturn": "16 / 280",
34 | "isValid": true
35 | }
36 | ```
37 | ## Local Function runtime
38 |
39 | Use [Azure Function core tools](https://www.npmjs.com/package/azure-functions-core-tools) to run local function environment. If you run the project in the Docker container, core tools is already installed with the `./devcontainer.json/DockerFile`.
40 |
41 | ## CORS
42 |
43 | ## Function authentication
44 |
45 | Create the function (not the function app) with function-level authentication. This requires the requestor to pass an `x-functions-key` header with the key value (found in the Azure portal) to validate the requestor has proper auth to call the function.
46 |
47 | ## Test local functions
48 |
49 | The boilerplate for the project was created with the Azure Functions VSCode extension. It didn't include the Jest integration, which was added afterward.
50 |
51 | ```bash
52 | curl -i \
53 | --header "Accept: application/json" \
54 | --request POST \
55 | --data '{"tweetText":"This is my tweet"}' \
56 | http://localhost:7071/api/validateTweet
57 | ```
58 |
59 | ## Test remote functions
60 |
61 | ```bash
62 | curl -i \
63 | --header "Accept: application/json" \
64 | --header "x-functions-key: SEE-VALUE-IN-AZURE-PORTAL-FOR-FUNCTION" \
65 | --request POST \
66 | --data '{"tweetText":"This is my tweet"}' \
67 | https://YOUR-RESOURCE-NAME.azurewebsites.net/api/validateTweet
68 | ```
69 |
70 |
--------------------------------------------------------------------------------
/apps/azure-functions-http-trigger-typescript/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "target": "es6",
5 | "outDir": "dist",
6 | "rootDir": ".",
7 | "sourceMap": true,
8 | "strict": false
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/apps/azure-functions-http-trigger-typescript/validateTweet/function.json:
--------------------------------------------------------------------------------
1 | {
2 | "bindings": [
3 | {
4 | "authLevel": "function",
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 | "scriptFile": "../dist/validateTweet/index.js"
19 | }
20 |
--------------------------------------------------------------------------------
/apps/azure-functions-http-trigger-typescript/validateTweet/index.test.ts:
--------------------------------------------------------------------------------
1 | import httpTrigger from "./index";
2 | import { Context } from "@azure/functions";
3 |
4 | describe("Test for validateTweet Function", () => {
5 | let context: Context;
6 |
7 | beforeEach(() => {
8 | context = ({ log: jest.fn() } as unknown) as Context;
9 | });
10 |
11 | test('404 - Http trigger request missing required params', async () => {
12 |
13 | const request = {
14 | body: null
15 | };
16 |
17 | await httpTrigger(context, request);
18 |
19 | expect(JSON.stringify(context.res.status)).toEqual("404");
20 | });
21 |
22 | test('200 - Http trigger returns success object', async () => {
23 |
24 | const request = {
25 | body: { tweetText: "This is my tweet" },
26 | headers: {
27 | Accept: 'application/json'
28 | }
29 | };
30 |
31 | await httpTrigger(context, request);
32 |
33 | expect(JSON.stringify(context.res.headers["Content-Type"]).includes('application/json')).toEqual(true)
34 | expect(JSON.stringify(context.res.body)).toEqual(JSON.stringify({
35 | "textReturn": "16 / 280",
36 | "isValid": true
37 | }));
38 | });
39 | });
--------------------------------------------------------------------------------
/apps/azure-functions-http-trigger-typescript/validateTweet/index.ts:
--------------------------------------------------------------------------------
1 | import { AzureFunction, Context, HttpRequest } from "@azure/functions"
2 |
3 | const twttr = require('twitter-text');
4 |
5 | // Call twitter's SDK to validate tweet
6 | const validateTweetBody = (text): any => {
7 | const result = twttr.parseTweet(text);
8 | const maxChars = 280;
9 | if (result) {
10 | let textReturn = `${result.weightedLength} / ${maxChars}`;
11 | let isValid = result.weightedLength <= maxChars ? true : false;
12 | return {
13 | textReturn: textReturn,
14 | isValid: isValid
15 | }
16 | }
17 | }
18 |
19 | /*
20 | To test locally:
21 |
22 | curl -i \
23 | --header "Accept: application/json" \
24 | --request POST \
25 | --data '{"tweetText":"This is my tweet"}' \
26 | http://localhost:7071/api/validateTweet
27 |
28 | To test after deployed to Azure functions:
29 |
30 | curl -i \
31 | --header "Accept: application/json" \
32 | --header "x-functions-key: YOUR-FUNCTION-KEY" \
33 | --request POST \
34 | --data '{"tweetText":"This is my tweet"}' \
35 | https://YOUR-RESOURCE-NAME.azurewebsites.net/api/validateTweet
36 |
37 | */
38 |
39 | const httpTrigger: AzureFunction = async (context: Context, req: HttpRequest): Promise => {
40 |
41 | const tweet = req.body;
42 |
43 | if (!tweet || !tweet.tweetText) {
44 | context.res = {
45 | status: 404,
46 | body: "Invalid function params - expected Post to include tweet object {tweetText}"
47 | };
48 | return;
49 | }
50 |
51 | const validation:any = validateTweetBody(tweet.tweetText);
52 |
53 | /*
54 | {
55 | "textReturn": "16 / 280",
56 | "isValid": true
57 | }
58 | */
59 | context.res = {
60 | body: validation,
61 | headers: {
62 | "Content-Type":"application/json"
63 | }
64 | };
65 |
66 | };
67 |
68 | export default httpTrigger;
--------------------------------------------------------------------------------
/apps/nodejs-redirect/index.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const app = express();
3 | var debug = require("debug")("node_blog:server");
4 |
5 | const port = process.env.PORT || "8080";
6 | const redirLocation = "https://abc.com";
7 |
8 | app.get("*", (req, res) => {
9 | res.redirect(redirLocation);
10 | });
11 |
12 | app.listen(port, () => {
13 | console.log(`App listening on port ${port}`);
14 | });
15 |
--------------------------------------------------------------------------------
/apps/nodejs-redirect/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nodejs-redirect",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "express": "^4.18.2"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/cognitive-services/face.js:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Use Cognitive Services Face resource to detect faces in a list of images.
4 |
5 | Requires:
6 |
7 | Azure subscription, Azure resource group, Azure Face resource already exists.
8 |
9 | Add your Face resource key and name:
10 | * "REPLACE-WITH-YOUR-FACE-RESOURCE-KEY"
11 | * "REPLACE-WITH-YOUR-FACE-RESOURCE-NAME"
12 |
13 | References:
14 | * [Azure SDK Ref Docs for Face detectWithUrl](https://docs.microsoft.com/en-us/javascript/api/@azure/cognitiveservices-face/face?view=azure-node-latest#detectWithUrl_string__Models_FaceDetectWithUrlOptionalParams_)
15 | * [Azure Service documentation for Face](https://docs.microsoft.com/en-us/azure/cognitive-services/face/)
16 |
17 | */
18 |
19 | const msRest = require("@azure/ms-rest-js");
20 | const Face = require("@azure/cognitiveservices-face");
21 |
22 | const azureResourceKey = process.env["FACE-RESOURCE-KEY"] || "REPLACE-WITH-YOUR-FACE-RESOURCE-KEY";
23 | const azureResourceName = process.env["FACE-RESOURCE-NAME"] || "REPLACE-WITH-YOUR-FACE-RESOURCE-NAME";
24 |
25 | endpoint = `https://${azureResourceName}.cognitiveservices.azure.com/`
26 |
27 |
28 | const credentials = new msRest.ApiKeyCredentials({ inHeader: { 'Ocp-Apim-Subscription-Key': azureResourceKey } });
29 | const client = new Face.FaceClient(credentials, endpoint);
30 |
31 |
32 | const image_base_url = "https://csdx.blob.core.windows.net/resources/Face/Images/";
33 |
34 | const detectImage = async (imageUrl) => {
35 |
36 | const options = {
37 | returnFaceAttributes: ["Accessories", "Age", "Blur", "Emotion", "Exposure", "FacialHair", "Gender", "Glasses", "Hair", "HeadPose", "Makeup", "Noise", "Occlusion", "Smile"],
38 |
39 | // detection model 1 = retrieving attributes.
40 | detectionModel: "detection_01"
41 | }
42 |
43 | return await client.face.detectWithUrl(imageUrl, options);
44 | };
45 |
46 | const processImageList = async () => {
47 |
48 | // Create a list of images
49 | const image_file_names = [
50 | "detection1.jpg", // single female with glasses
51 | "detection5.jpg", // family, woman child man
52 | "detection6.jpg" // elderly couple, male female
53 | ];
54 |
55 | let results = [];
56 |
57 | for (let i = 0; i < image_file_names.length; i++) {
58 |
59 | const imageUrl = `${image_base_url}${image_file_names[i]}`;
60 | console.log(imageUrl);
61 |
62 | const detectImageResult = await detectImage(imageUrl);
63 | console.log("pushing " + i);
64 | results.push(detectImageResult);
65 | }
66 |
67 | return results;
68 | }
69 |
70 | processImageList().then(results => {
71 | console.log(JSON.stringify(results));
72 | }).catch(err => {
73 | console.log(err);
74 | })
--------------------------------------------------------------------------------
/cognitive-services/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cognitive-services",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "face.js",
6 | "scripts": {
7 | "start": "node face.js",
8 | "test": "echo \"Error: no test specified\" && exit 1"
9 | },
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "@azure/cognitiveservices-face": "^4.2.0",
14 | "@azure/ms-rest-js": "^2.3.0"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/database/cassandra/index.js:
--------------------------------------------------------------------------------
1 | // install cassandra-driver SDK
2 | // run at command line
3 | // npm install cassandra-driver
4 |
5 | const cassandra = require('cassandra-driver');
6 |
7 | const config = {
8 | username: 'YOUR-USERNAME', // Your Cassandra user name is the resource name
9 | password:
10 | 'YOUR-PASSWORD',
11 | contactPoint: 'YOUR-RESOURCE-NAME.cassandra.cosmos.azure.com',
12 | };
13 |
14 | let client = null;
15 |
16 | const callCassandra = async () => {
17 |
18 | // authentication
19 | const authProvider = new cassandra.auth.PlainTextAuthProvider(
20 | config.username,
21 | config.password
22 | );
23 |
24 | // create client
25 | client = new cassandra.Client({
26 | contactPoints: [`${config.contactPoint}:10350`],
27 | authProvider: authProvider,
28 | localDataCenter: 'Central US',
29 | sslOptions: {
30 | secureProtocol: 'TLSv1_2_method',
31 | rejectUnauthorized: false,
32 | },
33 | });
34 |
35 | await client.connect();
36 | console.log("connected");
37 |
38 | // create keyspace
39 | let query =
40 | "CREATE KEYSPACE IF NOT EXISTS uprofile WITH replication = {\'class\': \'NetworkTopologyStrategy\', \'datacenter\' : \'1\' }";
41 | await client.execute(query);
42 | console.log('created keyspace');
43 |
44 | // create table
45 | query =
46 | 'CREATE TABLE IF NOT EXISTS uprofile.user (name text, alias text, region text Primary Key)';
47 | await client.execute(query);
48 | console.log('created table');
49 |
50 | // insert 3 rows
51 | console.log('insert');
52 | const arr = [
53 | "INSERT INTO uprofile.user (name, alias , region) VALUES ('Tim Jones', 'TJones', 'centralus')",
54 | "INSERT INTO uprofile.user (name, alias , region) VALUES ('Joan Smith', 'JSmith', 'northus')",
55 | "INSERT INTO uprofile.user (name, alias , region) VALUES ('Bob Wright', 'BWright', 'westus')"
56 | ];
57 | for (const element of arr) {
58 | await client.execute(element);
59 | }
60 |
61 | // get all rows
62 | query = 'SELECT * FROM uprofile.user';
63 | const resultSelect = await client.execute(query);
64 |
65 | for (const row of resultSelect.rows) {
66 | console.log(
67 | 'Obtained row: %s | %s | %s ',
68 | row.name,
69 | row.alias,
70 | row.region
71 | );
72 | }
73 |
74 | // get filtered row
75 | console.log('Getting by region');
76 | query = 'SELECT * FROM uprofile.user where region=\'westus\'';
77 | const resultSelectWhere = await client.execute(query);
78 |
79 | for (const row of resultSelectWhere.rows) {
80 | console.log(
81 | 'Obtained row: %s | %s | %s ',
82 | row.name,
83 | row.alias,
84 | row.region
85 | );
86 | }
87 |
88 | client.shutdown();
89 | };
90 |
91 | callCassandra()
92 | .then(() => {
93 | console.log('done');
94 | })
95 | .catch((err) => {
96 | if (client) {
97 | client.shutdown();
98 | }
99 | console.log(err);
100 | });
--------------------------------------------------------------------------------
/database/cassandra/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cassandra",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "cassandra-driver": "^4.6.3"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/database/cosmos-db-sql-core-api/find_product_by_query_with_param_like_keyword.js:
--------------------------------------------------------------------------------
1 | // Prereq: data already exists in container
2 |
3 | // Get environment variables from .env
4 | import * as path from 'path';
5 | import { promises as fs } from 'fs';
6 | import { fileURLToPath } from 'url';
7 | const __dirname = path.dirname(fileURLToPath(import.meta.url));
8 |
9 |
10 | /*
11 |
12 | Data like
13 |
14 | {
15 | "id": "794ACC61-01E9-49BF-B150-1D02EE01DABC",
16 | "categoryId": "3E4CEACD-D007-46EB-82D7-31F6141752B2",
17 | "categoryName": "Components, Road Frames",
18 | "sku": "FR-R38B-38",
19 | "name": "LL Road Frame - Blue, 38",
20 | "description": "The product called \"LL Road Frame - Blue, 38\"",
21 | "price": 337.22000000000003,
22 | "tags": [
23 | {
24 | "_id": "A2443B36-76AE-4963-9E21-368868F9C514",
25 | "name": "Tag-6"
26 | },
27 | {
28 | "_id": "F07885AF-BD6C-4B71-88B1-F04295992176",
29 | "name": "Tag-149"
30 | }
31 | ]
32 | }
33 |
34 | */
35 |
36 |
37 | import * as dotenv from "dotenv";
38 | dotenv.config();
39 |
40 | // Get Cosmos Client
41 | import { CosmosClient } from "@azure/cosmos";
42 |
43 | // Provide required connection from environment variables
44 | const key = process.env.COSMOS_KEY;
45 | // Endpoint format: https://YOUR-RESOURCE-NAME.documents.azure.com:443/
46 | const endpoint = process.env.COSMOS_ENDPOINT;
47 | // Authenticate to Azure Cosmos DB
48 | const cosmosClient = new CosmosClient({ endpoint, key });
49 |
50 | // Set Database name and container name
51 | const databaseName = `contoso_1663344094228`;
52 | const containerName = `products_1663344094228`;
53 | const partitionKeyPath = ["/categoryName"];
54 |
55 | const { database } = await cosmosClient.databases.createIfNotExists({
56 | id: databaseName,
57 | });
58 | const { container } = await database.containers.createIfNotExists({
59 | id: containerName,
60 | partitionKey: {
61 | paths: partitionKeyPath,
62 | },
63 | });
64 |
65 | async function executeSql(property, value) {
66 |
67 | // value example string: "%value%"
68 | const querySpec = {
69 | query: `select * from products p where p.${property} LIKE @propertyValue`,
70 | parameters: [
71 | {
72 | name: "@propertyValue",
73 | value: `${value}`,
74 | },
75 | ],
76 | };
77 |
78 | console.log(querySpec);
79 |
80 | const { resources } = await container.items.query(querySpec).fetchAll();
81 |
82 | let i=0;
83 |
84 | for (const item of resources) {
85 | console.log(`${++i}: ${item.id}: ${item.name}, ${item.sku}`);
86 | }
87 | }
88 |
89 | executeSql('name', '%Blue%');
90 |
--------------------------------------------------------------------------------
/database/cosmos-db-sql-core-api/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "contosoretail",
3 | "version": "1.0.0",
4 | "description": "",
5 | "type": "module",
6 | "main": "index.js",
7 | "scripts": {
8 | "start:products": "node products.js categoryName 'Bikes, Road Bikes'",
9 | "test": "echo \"Error: no test specified\" && exit 1"
10 | },
11 | "keywords": [],
12 | "author": "",
13 | "license": "ISC",
14 | "dependencies": {
15 | "@azure/cosmos": "^3.17.1",
16 | "dotenv": "^16.0.2"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/database/cosmos-db-sql-core-api/update-products.js:
--------------------------------------------------------------------------------
1 | // Get environment variables from .env
2 | import * as path from "path";
3 | import { promises as fs } from "fs";
4 | import { fileURLToPath } from "url";
5 | const __dirname = path.dirname(fileURLToPath(import.meta.url));
6 |
7 | import * as dotenv from "dotenv";
8 | dotenv.config();
9 |
10 | // Get Cosmos Client
11 | import { CosmosClient } from "@azure/cosmos";
12 |
13 | // Provide required connection from environment variables
14 | const key = process.env.COSMOS_KEY;
15 | // Endpoint format: https://YOUR-RESOURCE-NAME.documents.azure.com:443/
16 | const endpoint = process.env.COSMOS_ENDPOINT;
17 | // Authenticate to Azure Cosmos DB
18 | const cosmosClient = new CosmosClient({ endpoint, key });
19 |
20 | // Set Database name and container name
21 | const databaseName = `contoso_1663344094228`;
22 | const containerName = `products_storedproc-16`;
23 | const partitionKeyPath = ["/categoryName"];
24 |
25 | const { database } = await cosmosClient.databases.createIfNotExists({
26 | id: databaseName,
27 | });
28 | const { container } = await database.containers.createIfNotExists({
29 | id: containerName,
30 | partitionKey: {
31 | paths: partitionKeyPath,
32 | },
33 | });
34 |
35 | const updatePrices = async(priceChanges)=>{
36 | const returnStatus = {
37 | success: true,
38 | status: {
39 | updated: [],
40 | failed: [],
41 | }};
42 |
43 | // Nothing to do
44 | if (!priceChanges || priceChanges.length == 0) {
45 | return returnStatus;
46 | }
47 |
48 | for (let priceChangeRequest of priceChanges) {
49 | try {
50 | // Get product
51 | const { resource } = await container.item(priceChangeRequest.id, priceChangeRequest.categoryName).read();
52 |
53 | if(!resource) {
54 | returnStatus.status.failed.push({...priceChangeRequest, status: "not found"});
55 | continue;
56 | }
57 |
58 | // update price
59 | resource.price += priceChangeRequest.priceChange;
60 |
61 | // update product in container
62 | const updateResult = await container.items.upsert(resource);
63 |
64 | // update status based on HTTP result code
65 | if ( (updateResult.statusCode > 199) && updateResult.statusCode < 300){
66 | returnStatus.status.updated.push(priceChangeRequest);
67 | } else {
68 | returnStatus.status.failed.push(priceChangeRequest);
69 | }
70 | } catch (err) {
71 | // update status
72 | returnStatus.status.failed.push(priceChangeRequest);
73 | }
74 | }
75 |
76 | return {
77 | success: returnStatus.status.updated.length === priceChanges.length ? true : false,
78 | status: returnStatus.status
79 | };
80 | };
81 |
82 |
83 |
84 | const initialData = [
85 | {
86 | "id": "027D0B9A-F9D9-4C96-8213-C8546C4AAE71",
87 | "categoryId": "26C74104-40BC-4541-8EF5-9892F7F03D72",
88 | "categoryName": "Components, Saddles",
89 | "sku": "SE-R581",
90 | "name": "LL Road Seat/Saddle",
91 | "description": "The product called \"LL Road Seat/Saddle\"",
92 | "price": 27.120000000000001,
93 | "tags": [
94 | {
95 | "id": "0573D684-9140-4DEE-89AF-4E4A90E65666",
96 | "name": "Tag-113"
97 | },
98 | {
99 | "id": "6C2F05C8-1E61-4912-BE1A-C67A378429BB",
100 | "name": "Tag-5"
101 | },
102 | {
103 | "id": "B48D6572-67EB-4630-A1DB-AFD4AD7041C9",
104 | "name": "Tag-100"
105 | },
106 | {
107 | "id": "D70F215D-A8AC-483A-9ABD-4A008D2B72B2",
108 | "name": "Tag-85"
109 | },
110 | {
111 | "id": "DCF66D9A-E2BF-4C70-8AC1-AD55E5988E9D",
112 | "name": "Tag-37"
113 | }
114 | ]
115 | },
116 | {
117 | "id": "08225A9E-F2B3-4FA3-AB08-8C70ADD6C3C2",
118 | "categoryId": "75BF1ACB-168D-469C-9AA3-1FD26BB4EA4C",
119 | "categoryName": "Bikes, Touring Bikes",
120 | "sku": "BK-T79U-50",
121 | "name": "Touring-1000 Blue, 50",
122 | "description": "The product called \"Touring-1000 Blue, 50\"",
123 | "price": 2384.0700000000002,
124 | "tags": [
125 | {
126 | "id": "27B7F8D5-1009-45B8-88F5-41008A0F0393",
127 | "name": "Tag-61"
128 | }
129 | ]
130 | },
131 | {
132 | "id": "0A7E57DA-C73F-467F-954F-17B7AFD6227E",
133 | "categoryId": "4F34E180-384D-42FC-AC10-FEC30227577F",
134 | "categoryName": "Components, Pedals",
135 | "sku": "PD-R563",
136 | "name": "ML Road Pedal",
137 | "description": "The product called \"ML Road Pedal\"",
138 | "price": 62.090000000000003,
139 | "tags": [
140 | {
141 | "id": "14CFF1D6-7749-4A57-85B3-783F47731F32",
142 | "name": "Tag-7"
143 | },
144 | {
145 | "id": "319E277F-6B7A-483D-81BA-1EC34CC700EB",
146 | "name": "Tag-163"
147 | }
148 | ]
149 | }
150 | ];
151 |
152 | const priceUpdates = [
153 | {
154 | "id": "027D0B9A-F9D9-4C96-8213-C8546C4AAE71",
155 | "categoryName": "Components, Saddles",
156 | "priceChange": 3
157 | },
158 | {
159 | "id": "08225A9E-F2B3-4FA3-AB08-8C70ADD6C3C2",
160 | "categoryName": "Bikes, Touring Bikes",
161 | "priceChange": 616
162 | },
163 | {
164 | "id": "0A7E57DA-C73F-467F-954F-17B7AFD6227E",
165 | "categoryName": "Components, Pedals",
166 | "price": -32
167 | },
168 | {
169 | "id": "not-in-data-set",
170 | "categoryName": "Components, Pedals",
171 | "price": -32
172 | }
173 | ];
174 |
175 | for (const item of initialData) {
176 |
177 | const { resource } = await container.items.create(item);
178 | console.log(`'${resource.name}' inserted`);
179 | }
180 | const updateResult = await updatePrices(priceUpdates);
181 | console.log(JSON.stringify(updateResult));
182 |
183 | /*
184 |
185 | 'LL Road Seat/Saddle' inserted
186 | 'Touring-1000 Blue, 50' inserted
187 | 'ML Road Pedal' inserted
188 | {"success":false,"status":{"updated":[{"id":"027D0B9A-F9D9-4C96-8213-C8546C4AAE71","categoryName":"Components, Saddles","priceChange":3},{"id":"08225A9E-F2B3-4FA3-AB08-8C70ADD6C3C2","categoryName":"Bikes, Touring Bikes","priceChange":616},{"id":"0A7E57DA-C73F-467F-954F-17B7AFD6227E","categoryName":"Components, Pedals","price":-32}],"failed":[{"id":"not-in-data-set","categoryName":"Components, Pedals","price":-32,"status":"not found"}]}}
189 |
190 | */
191 |
--------------------------------------------------------------------------------
/database/cosmos-db-sql-core-api/upsert_products.js:
--------------------------------------------------------------------------------
1 | // Get environment variables from .env
2 | import * as path from 'path';
3 | import { promises as fs } from 'fs';
4 | import { fileURLToPath } from 'url';
5 | const __dirname = path.dirname(fileURLToPath(import.meta.url));
6 |
7 | import * as dotenv from "dotenv";
8 | dotenv.config();
9 |
10 | // Get Cosmos Client
11 | import { CosmosClient } from "@azure/cosmos";
12 |
13 |
14 | // Provide required connection from environment variables
15 | const key = process.env.COSMOS_KEY;
16 | // Endpoint format: https://YOUR-RESOURCE-NAME.documents.azure.com:443/
17 | const endpoint = process.env.COSMOS_ENDPOINT;
18 | // Authenticate to Azure Cosmos DB
19 | const cosmosClient = new CosmosClient({ endpoint, key });
20 |
21 | // Set Database name and container name
22 | const databaseName = `contoso_1663344094228`;
23 | const containerName = `products_upsert-3`;
24 | const partitionKeyPath = ["/categoryName"];
25 |
26 | const { database } = await cosmosClient.databases.createIfNotExists({
27 | id: databaseName,
28 | });
29 | const { container } = await database.containers.createIfNotExists({
30 | id: containerName,
31 | partitionKey: {
32 | paths: partitionKeyPath,
33 | },
34 | });
35 |
36 | /*
37 |
38 | Rules:
39 | If item with same "id" is present, update
40 | If item with same "id" is not present, insert
41 |
42 |
43 | */
44 | async function upsert(fileAndPathToJson, encoding='utf-8') {
45 |
46 | console.log(fileAndPathToJson);
47 |
48 | const data = JSON.parse(await fs.readFile(path.join(__dirname, fileAndPathToJson), encoding));
49 | console.log(data);
50 |
51 | const { resource } = await container.items.upsert(data);
52 | console.log(`'${resource.name}' inserted`);
53 | }
54 |
55 | await upsert('./new_item.json');
56 | await upsert('./update_item.json');
57 | await upsert('./update_partition_key.json');
58 |
59 | const { resources } = await container.items.readAll().fetchAll();
60 |
61 | for (const item of resources) {
62 | console.log(`${item.id}: ${item.name}, ${item.sku}`);
63 | }
64 |
--------------------------------------------------------------------------------
/database/mariadb/index.js:
--------------------------------------------------------------------------------
1 | // To install npm package,
2 | // run following command at terminal
3 | // npm install mariadb
4 |
5 | // get mariadb SDK
6 | const mariadb = require('mariadb');
7 |
8 | // query server and close connection
9 | const query = async (config) => {
10 | // creation connection
11 | const connection = await mariadb.createConnection(config);
12 |
13 | // show databases on server
14 | const databases = await connection.query('SHOW DATABASES;');
15 | console.log(databases);
16 |
17 | // show tables in the mysql database
18 | const tables = await connection.query('SHOW TABLES FROM mysql;');
19 | console.log(tables);
20 |
21 | // show users configured for the server
22 | const rows = await connection.query('select User from mysql.user;');
23 | console.log(rows);
24 |
25 | // close connection
26 | connection.end();
27 | };
28 |
29 | const config = {
30 | host: 'YOUR-RESOURCE_NAME.mariadb.database.azure.com',
31 | user: 'YOUR-ADMIN-NAME@YOUR-RESOURCE_NAME',
32 | password: 'YOUR-ADMIN-PASSWORD',
33 | port: 3306,
34 | };
35 |
36 | query(config)
37 | .then(() => console.log('done'))
38 | .catch((err) => console.log(err));
--------------------------------------------------------------------------------
/database/mariadb/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mariadb",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "mariadb": "^2.5.3"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/database/mongodb/.env:
--------------------------------------------------------------------------------
1 | YOUR_RESOURCE_PRIMARY_CONNECTION_STRING=
2 | DATABASE_NAME=BooksDB
3 | DATABASE_COLLECTION_NAME=GoodBooks
4 |
--------------------------------------------------------------------------------
/database/mongodb/azure-cosmosdb-mongodb.ts:
--------------------------------------------------------------------------------
1 | import { Schema, model, connect } from "mongoose";
2 |
3 | const CategorySchema = new Schema(
4 | { categoryName: String },
5 | { timestamps: true }
6 | );
7 | const CategoryModel = model("Category", CategorySchema, "Bookstore");
8 |
9 | export const init = async () => {
10 | await connect(process.env["CosmosDbConnectionString"]);
11 | };
12 | export const addItem = async (doc) => {
13 | const modelToInsert = new CategoryModel();
14 | modelToInsert["categoryName"] = doc.name;
15 |
16 | return await modelToInsert.save();
17 | };
18 | export const findItemById = async (id) => {
19 | return await CategoryModel.findById(id);
20 | };
21 | export const findItems = async (query = {}) => {
22 | return await CategoryModel.find({});
23 | };
24 | export const deleteItemById = async (id) => {
25 | return await CategoryModel.findByIdAndDelete(id);
26 | };
27 |
--------------------------------------------------------------------------------
/database/mongodb/bulk_insert_mongodb.js:
--------------------------------------------------------------------------------
1 | const { MongoClient } = require('mongodb');
2 | const ObjectId = require('mongodb').ObjectID;
3 | require('dotenv').config();
4 |
5 | const fs = require('fs');
6 | const parse = require('csv-parser')
7 | const { finished } = require('stream/promises');
8 |
9 | const DATABASE_URL = process.env.YOUR_RESOURCE_PRIMARY_CONNECTION_STRING
10 | ? process.env.YOUR_RESOURCE_PRIMARY_CONNECTION_STRING
11 | : 'mongodb://localhost:27017';
12 | const DATABASE_NAME = process.env.DATABASE_NAME || 'my-tutorial-db';
13 | const DATABASE_COLLECTION_NAME =
14 | process.env.DATABASE_COLLECTION_NAME || 'my-collection';
15 |
16 | const csvFile = './books.csv'
17 |
18 | let mongoConnection = null;
19 | let db = null;
20 | let collection = null;
21 |
22 |
23 | // insert each row into MongoDB
24 | const insertData = async (readable) =>{
25 |
26 | let i = 0;
27 |
28 | for await (const row of readable) {
29 | console.log(`${i++} = ${JSON.stringify(row.goodreads_book_id)}`);
30 | await collection.insertOne(row);
31 | }
32 | }
33 | const bulkInsert = async () => {
34 |
35 | mongoConnection = await MongoClient.connect(DATABASE_URL, { useUnifiedTopology: true });
36 | db = mongoConnection.db(DATABASE_NAME);
37 | collection = await db.collection(DATABASE_COLLECTION_NAME);
38 |
39 | // read file, parse CSV, each row is a chunk
40 | const readable = fs
41 | .createReadStream(csvFile)
42 | .pipe(parse());
43 |
44 | // Pipe rows to insert function
45 | await insertData(readable)
46 | await mongoConnection.close();
47 | }
48 |
49 | bulkInsert().then(() => {
50 | console.log('done');
51 |
52 | }).catch(err => {
53 | console.log(`done + failed ${err}`)
54 | })
55 |
--------------------------------------------------------------------------------
/database/mongodb/index_mongodb.js:
--------------------------------------------------------------------------------
1 | const { MongoClient } = require('mongodb');
2 | const ObjectId = require('mongodb').ObjectID;
3 |
4 | // read .env file
5 | require('dotenv').config();
6 |
7 | /* eslint no-return-await: 0 */
8 |
9 | const DATABASE_URL = process.env."YOUR_RESOURCE_PRIMARY_CONNECTION_STRING"
10 | ? process.env."YOUR_RESOURCE_PRIMARY_CONNECTION_STRING"
11 | : 'mongodb://localhost:27017';
12 | const DATABASE_NAME = process.env.DATABASE_NAME || 'my-tutorial-db';
13 | const DATABASE_COLLECTION_NAME =
14 | process.env.DATABASE_COLLECTION_NAME || 'my-collection';
15 |
16 | let mongoConnection = null;
17 | let db = null;
18 |
19 | const insertDocuments = async (
20 | documents = [{ a: 1 }, { a: 2 }, { a: 3 }]
21 | ) => {
22 | // check params
23 | if (!db || !documents)
24 | throw Error('insertDocuments::missing required params');
25 |
26 | // Get the collection
27 | const collection = await db.collection(DATABASE_COLLECTION_NAME);
28 |
29 | // Insert some documents
30 | return await collection.insertMany(documents);
31 | };
32 | const findDocuments = async (
33 | query = { a: 3 }
34 | ) => {
35 |
36 | // check params
37 | if (!db)
38 | throw Error('findDocuments::missing required params');
39 |
40 | // Get the collection
41 | const collection = await db.collection(DATABASE_COLLECTION_NAME );
42 |
43 | // find documents
44 | return await collection.find(query).toArray();
45 | };
46 |
47 | const removeDocuments = async (
48 | docFilter = {}
49 | ) => {
50 |
51 | // check params
52 | if (!db )
53 | throw Error('removeDocuments::missing required params');
54 |
55 | // Get the documents collection
56 | const collection = await db.collection(DATABASE_COLLECTION_NAME);
57 |
58 | // Delete document
59 | return await collection.deleteMany(docFilter);
60 | };
61 |
62 | const connect = async (url) => {
63 |
64 | // check params
65 | if (!url) throw Error('connect::missing required params');
66 |
67 | return MongoClient.connect(url, { useUnifiedTopology: true });
68 | };
69 | /*
70 | eslint consistent-return: [0, { "treatUndefinedAsUnspecified": false }]
71 | */
72 | const connectToDatabase = async () => {
73 | try {
74 | if (!DATABASE_URL || !DATABASE_NAME) {
75 | console.log('DB required params are missing');
76 | console.log(`DB required params DATABASE_URL = ${DATABASE_URL}`);
77 | console.log(`DB required params DATABASE_NAME = ${DATABASE_NAME}`);
78 | }
79 |
80 | mongoConnection = await connect(DATABASE_URL);
81 | db = mongoConnection.db(DATABASE_NAME);
82 |
83 | console.log(`DB connected = ${!!db}`);
84 |
85 | return !!db;
86 |
87 | } catch (err) {
88 | console.log('DB not connected - err');
89 | console.log(err);
90 | }
91 | };
92 | module.exports = {
93 | insertDocuments,
94 | findDocuments,
95 | removeDocuments,
96 | ObjectId,
97 | connectToDatabase
98 | };
--------------------------------------------------------------------------------
/database/mongodb/index_mongoose.js:
--------------------------------------------------------------------------------
1 | // get mongoose SDK
2 | const mongoose = require("mongoose");
3 |
4 | const run = async () => {
5 | // connect to mongoose
6 | await mongoose.connect(
7 | "YOUR_RESOURCE_PRIMARY_CONNECTION_STRING",
8 | {
9 | useNewUrlParser: true,
10 | useUnifiedTopology: true,
11 | useFindAndModify: false,
12 | useCreateIndex: true,
13 | }
14 | );
15 |
16 | // define a schema
17 | const Schema = mongoose.Schema;
18 | const ObjectId = Schema.ObjectId;
19 |
20 | const JobSchema = new Schema({
21 | id: ObjectId,
22 | name: String,
23 | job: String,
24 | });
25 |
26 | // Create model for database collection `Job`
27 | const JobModel = mongoose.model("Job", JobSchema);
28 |
29 | // Add data to doc and save
30 | const doc1 = new JobModel();
31 | doc1.name = "Joan Smith";
32 | doc1.job = "Developer";
33 | await doc1.save();
34 |
35 | const doc2 = new JobModel();
36 | doc2.name = "Bob Jones";
37 | doc2.job = "Quality Assurance";
38 | await doc2.save();
39 |
40 | const doc3 = new JobModel();
41 | doc3.name = "Michelle Roberts";
42 | doc3.job = "Program Manager";
43 | await doc3.save();
44 |
45 | // find all docs in collection
46 | console.log("find all");
47 | const jobs = await JobModel.find({});
48 |
49 | //iterate over docs
50 | for (var job of jobs) {
51 | console.log(`loop ` + JSON.stringify(job));
52 | }
53 |
54 | // close connection
55 | mongoose.connection.close();
56 |
57 | return "succeeded";
58 | };
59 |
60 | run()
61 | .then((result) => {
62 | console.log(result);
63 | })
64 | .catch((err) => {
65 | console.log(err);
66 | });
67 |
--------------------------------------------------------------------------------
/database/mongodb/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mongodb",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "bulk_insert.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "csv-parser": "^3.0.0",
13 | "dotenv": "^8.2.0",
14 | "mongodb": "^3.6.4"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/database/mongodb/readme.md:
--------------------------------------------------------------------------------
1 | # MongoDB on Cosmos DB
2 |
3 | Code found here is used as part of the Azure JavaScript developer center.
4 |
5 | ## Bulk insert
6 |
7 | The bulk insert is derived from this Cognitive Search [blog post](https://devblogs.microsoft.com/azure-sdk/search-app-with-cognitive-search/) and [source code](https://github.com/dereklegenzoff/azure-search-react-template). This script replaces the blog's python bulk insert script. The bulk inserts use a `.csv` file found in the [zygmuntz
8 | /
9 | goodbooks-10k](https://github.com/zygmuntz/goodbooks-10k) dataset.
--------------------------------------------------------------------------------
/database/mssql/index.js:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Create Azure SQL with sample database to use this query
4 |
5 | */
6 |
7 | const sql = require('mssql')
8 |
9 | const connectionString = "Driver={ODBC Driver 18 for SQL Server};Server=tcp:YOUR-SERVER.database.windows.net,1433;Database=YOUR-DATABASE;Uid=YOUR-USER;Pwd=YOUR-PASSWORD;Encrypt=yes;TrustServerCertificate=no;Connection Timeout=30;Authentication=ActiveDirectoryPassword";
10 |
11 | const main = async() =>{
12 | await sql.connect(connectionString)
13 | const results = await sql.query`SELECT TOP (10) * FROM [SalesLT].[Product]`
14 | console.dir(results.recordsets[0])
15 |
16 | }
17 | main().then(()=>console.log('done')).catch((err)=> console.log(err))
18 |
--------------------------------------------------------------------------------
/database/mysql/index.js:
--------------------------------------------------------------------------------
1 | // To install npm package,
2 | // run following command at terminal
3 | // npm install promise-mysql
4 |
5 | // get MySQL SDK
6 | const MySQL = require('promise-mysql');
7 |
8 | // query server and close connection
9 | const query = async (config) => {
10 | // creation connection
11 | const connection = await MySQL.createConnection(config);
12 |
13 | // show databases on server
14 | const databases = await connection.query('SHOW DATABASES;');
15 | console.log(databases);
16 |
17 | // show tables in the mysql database
18 | const tables = await connection.query('SHOW TABLES FROM mysql;');
19 | console.log(tables);
20 |
21 | // show users configured for the server
22 | const rows = await connection.query('select User from mysql.user;');
23 | console.log(rows);
24 |
25 | // close connection
26 | connection.end();
27 | };
28 |
29 | const config = {
30 | host: 'YOUR-RESOURCE_NAME.mysql.database.azure.com',
31 | user: 'YOUR-ADMIN-NAME@YOUR-RESOURCE_NAME',
32 | password: 'YOUR-ADMIN-PASSWORD',
33 | port: 3306,
34 | };
35 |
36 | query(config)
37 | .then(() => console.log('done'))
38 | .catch((err) => console.log(err));
--------------------------------------------------------------------------------
/database/mysql/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mysql",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "promise-mysql": "^5.0.3"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/database/postgresql/index.js:
--------------------------------------------------------------------------------
1 | const { Client } = require('pg')
2 |
3 | const query = async (connectionString) => {
4 |
5 | // create connection
6 | const connection = new Client(connectionString);
7 | connection.connect();
8 |
9 | // show tables in the postgres database
10 | const tables = await connection.query('SELECT table_name FROM information_schema.tables where table_type=\'BASE TABLE\';');
11 | console.log(tables.rows);
12 |
13 | // show users configured for the server
14 | const users = await connection.query('select pg_user.usename FROM pg_catalog.pg_user;');
15 | console.log(users.rows);
16 |
17 | // close connection
18 | connection.end();
19 | }
20 |
21 | const server='YOURRESOURCENAME';
22 | const user='YOUR-ADMIN-USER';
23 | const password='YOUR-PASSWORD';
24 | const database='postgres';
25 |
26 | const connectionString = `postgres://${user}@${server}:${password}@${server}.postgres.database.azure.com:5432/${database}`;
27 |
28 | query(connectionString)
29 | .then(() => console.log('done'))
30 | .catch((err) => console.log(err));
--------------------------------------------------------------------------------
/database/postgresql/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "postgresql",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "pg": "^8.6.0"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/database/redis/.devcontainer/devcontainer.json:
--------------------------------------------------------------------------------
1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the
2 | // README at: https://github.com/devcontainers/templates/tree/main/src/javascript-node
3 | {
4 | "name": "Node.js",
5 | // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
6 | "image": "mcr.microsoft.com/devcontainers/javascript-node:0-18"
7 |
8 | // Features to add to the dev container. More info: https://containers.dev/features.
9 | // "features": {},
10 |
11 | // Use 'forwardPorts' to make a list of ports inside the container available locally.
12 | // "forwardPorts": [],
13 |
14 | // Use 'postCreateCommand' to run commands after the container is created.
15 | // "postCreateCommand": "yarn install",
16 |
17 | // Configure tool-specific properties.
18 | // "customizations": {},
19 |
20 | // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
21 | // "remoteUser": "root"
22 | }
23 |
--------------------------------------------------------------------------------
/database/redis/.env.sample:
--------------------------------------------------------------------------------
1 | AZURE_CACHE_FOR_REDIS_RESOURCE_NAME=
2 | AZURE_CACHE_FOR_REDIS_RESOURCE_KEY=
--------------------------------------------------------------------------------
/database/redis/MOCK_DATA.csv:
--------------------------------------------------------------------------------
1 | id,first_name,last_name,email,gender,ip_address
2 | 1,Rodrigo,Lock,rlock0@eventbrite.com,Agender,73.93.61.37
3 | 2,Nikos,Gutierrez,ngutierrez1@yahoo.com,Genderfluid,213.54.40.210
4 | 3,Eada,Sotham,esotham2@yellowpages.com,Bigender,28.236.183.89
5 | 4,Ana,Brazil,abrazil3@who.int,Polygender,142.30.140.225
6 | 5,Roman,Rohmer,rrohmer4@admin.ch,Genderqueer,235.197.52.85
7 | 6,Elyn,Sute,esute5@ftc.gov,Genderqueer,171.151.109.188
8 | 7,Omero,Childers,ochilders6@stanford.edu,Bigender,133.21.192.66
9 | 8,Stephana,Pipet,spipet7@parallels.com,Genderfluid,177.48.129.213
10 | 9,Anthiathia,Ulster,aulster8@weebly.com,Genderfluid,175.1.59.106
11 | 10,Yard,Pyson,ypyson9@jalbum.net,Non-binary,0.8.135.151
12 |
--------------------------------------------------------------------------------
/database/redis/bulk_insert.js:
--------------------------------------------------------------------------------
1 | const Redis = require('ioredis');
2 | const fs = require('fs');
3 | const parse = require('csv-parser')
4 | const { finished } = require('stream/promises');
5 | const { config } = require('./config')
6 |
7 | // Create Redis config object
8 | const configuration = {
9 | host: config.HOST,
10 | port: 6380,
11 | password: config.KEY,
12 | tls: {
13 | servername: config.HOST
14 | },
15 | database: 0,
16 | keyPrefix: config.KEY_PREFIX
17 | }
18 | var redis = new Redis(configuration);
19 |
20 | // insert each row into Redis
21 | async function insertData(readable) {
22 | for await (const row of readable) {
23 | await redis.set(`bar2:${row.id}`, JSON.stringify(row))
24 | }
25 | }
26 |
27 | /*
28 | id,first_name,last_name,email,gender,ip_address
29 | 1,Rodrigo,Lock,rlock0@eventbrite.com,Agender,73.93.61.37
30 | 2,Nikos,Gutierrez,ngutierrez1@yahoo.com,Genderfluid,213.54.40.210
31 | 3,Eada,Sotham,esotham2@yellowpages.com,Bigender,28.236.183.89
32 | 4,Ana,Brazil,abrazil3@who.int,Polygender,142.30.140.225
33 | 5,Roman,Rohmer,rrohmer4@admin.ch,Genderqueer,235.197.52.85
34 | 6,Elyn,Sute,esute5@ftc.gov,Genderqueer,171.151.109.188
35 | 7,Omero,Childers,ochilders6@stanford.edu,Bigender,133.21.192.66
36 | 8,Stephana,Pipet,spipet7@parallels.com,Genderfluid,177.48.129.213
37 | 9,Anthiathia,Ulster,aulster8@weebly.com,Genderfluid,175.1.59.106
38 | 10,Yard,Pyson,ypyson9@jalbum.net,Non-binary,0.8.135.151
39 | */
40 |
41 | // read file, parse CSV, each row is a chunck
42 | const readable = fs
43 | .createReadStream('./MOCK_DATA.csv')
44 | .pipe(parse());
45 |
46 | // Pipe rows to insert function
47 | insertData(readable)
48 | .then(() => {
49 | console.log('succeeded');
50 | redis.disconnect();
51 | })
52 | .catch(console.error);
53 |
--------------------------------------------------------------------------------
/database/redis/config.js:
--------------------------------------------------------------------------------
1 | require('dotenv').config()
2 |
3 | const resourceName = process.env.AZURE_CACHE_FOR_REDIS_RESOURCE_NAME
4 | const resourceKey = process.env.AZURE_CACHE_FOR_REDIS_RESOURCE_KEY
5 |
6 | const config = {
7 | "HOST": `${resourceName}.redis.cache.windows.net`,
8 | "KEY": `${resourceKey}`,
9 | "TIMEOUT": 300,
10 | "KEY_PREFIX": "demoExample:"
11 | }
12 |
13 | module.exports = {config}
--------------------------------------------------------------------------------
/database/redis/get-set.js:
--------------------------------------------------------------------------------
1 | const redis = require('ioredis');
2 | const { config } = require('./config')
3 |
4 | // Create Redis config object
5 | const configuration = {
6 | host: config.HOST,
7 | port: 6380,
8 | password: config.KEY,
9 | timeout: config.TIMEOUT,
10 | tls: {
11 | servername: config.HOST
12 | },
13 | database: 0,
14 | keyPrefix: config.KEY_PREFIX
15 | }
16 |
17 | const connect = () => {
18 | return redis.createClient(configuration);
19 | }
20 |
21 | const set = async (client, key, expiresInSeconds=configuration.timeout, stringify=true, data) => {
22 | return await client.setex(key, expiresInSeconds, stringify? JSON.stringify(data): data);
23 | }
24 |
25 | const get = async (client, key, stringParse=true) => {
26 | const value = await client.get(key);
27 | return stringParse ? JSON.parse(value) : value;
28 | }
29 |
30 | const remove = async (client, key) => {
31 | return await client.del(key);
32 | }
33 |
34 | const disconnect = (client) => {
35 | client.disconnect();
36 | }
37 |
38 | const test = async () => {
39 |
40 | // connect
41 | const dbConnection = await connect();
42 |
43 | // set
44 | const setResult1 = await set(dbConnection, "r1", "1000000", false, "record 1");
45 | const setResult2 = await set(dbConnection, "r2", "1000000", false, "record 2");
46 | const setResult3 = await set(dbConnection, "r3", "1000000", false, "record 3");
47 |
48 | // get
49 | const val2 = await get(dbConnection, "r2", false);
50 | console.log(val2);
51 |
52 | // delete
53 | const remove2 = await remove(dbConnection, "r2");
54 |
55 | // get again = won't be there
56 | const val2Again = await get(dbConnection, "r2", false);
57 | console.log(val2Again);
58 |
59 | // done
60 | disconnect(dbConnection)
61 | }
62 |
63 | test()
64 | .then(() => console.log("done"))
65 | .catch(err => console.log(err))
66 |
--------------------------------------------------------------------------------
/database/redis/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "azure-cache-for-redis",
3 | "version": "1.0.0",
4 | "description": "JavaScript to Azure Cache for Redis",
5 | "main": "index.js",
6 | "scripts": {
7 | "start:ui": "redis-commander --redis-password --redis-port 6379 --redis-host gh-redis-cache.redis.cache.windows.net --redis-tls"
8 | },
9 | "author": "",
10 | "license": "MIT",
11 | "dependencies": {
12 | "csv-parser": "^3.0.0",
13 | "dotenv": "^16.0.3",
14 | "ioredis": "^4.22.0",
15 | "redis": "^4.6.4"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/database/redis/quickstart.js:
--------------------------------------------------------------------------------
1 | var redis = require("redis");
2 | const { config } = require('./config')
3 |
4 | async function testCache() {
5 |
6 | // Connect to the Azure Cache for Redis over the TLS port using the key.
7 | var cacheHostName = config.HOST;
8 | var cachePassword = config.KEY;
9 | var cacheConnection = redis.createClient({
10 | // rediss for TLS
11 | url: "rediss://" + cacheHostName + ":6380",
12 | password: cachePassword,
13 | });
14 | await cacheConnection.connect();
15 |
16 | // Perform cache operations using the cache connection object...
17 |
18 | // Simple PING command
19 | console.log("\nCache command: PING");
20 | console.log("Cache response : " + await cacheConnection.ping());
21 |
22 | // Simple get and put of integral data types into the cache
23 | console.log("\nCache command: GET Message");
24 | console.log("Cache response : " + await cacheConnection.get("Message"));
25 |
26 | console.log("\nCache command: SET Message");
27 | console.log("Cache response : " + await cacheConnection.set("Message",
28 | "Hello! The cache is working from Node.js!"));
29 |
30 | // Demonstrate "SET Message" executed as expected...
31 | console.log("\nCache command: GET Message");
32 | console.log("Cache response : " + await cacheConnection.get("Message"));
33 |
34 | // Get the client list, useful to see if connection list is growing...
35 | console.log("\nCache command: CLIENT LIST");
36 | console.log("Cache response : " + await cacheConnection.sendCommand(["CLIENT", "LIST"]));
37 |
38 | console.log("\nDone");
39 | process.exit();
40 | }
41 |
42 | testCache();
--------------------------------------------------------------------------------
/database/redis/readme.md:
--------------------------------------------------------------------------------
1 | # Azure Cache for Redis sample code for JavaScript
2 |
3 | ## Create Azure Cache for Redis resource
4 |
5 | * [Azure portal](https://ms.portal.azure.com/#create/Microsoft.Cache)
6 |
7 | ## First party resources
8 |
9 | * [Azure Cache for Redis docs](https://docs.microsoft.com/en-us/azure/azure-cache-for-redis/)
10 | * JavaScript sample code
11 | * [Bulk insert](bulk_insert.js)
12 | * [Set key, get key, delete key](get-set.js)
13 |
14 | ## 3rd party resources
15 |
16 | The following 3rd party samples and resources may be helpful:
17 |
18 | * Express/Redis [example](https://github.com/aenesgur/Nodejs-RedisCache_MovieApp)
19 | * Express CLI [cheatsheet](https://gist.github.com/LeCoupa/1596b8f359ad8812c7271b5322c30946)
20 | * [Node/Redis series](https://medium.com/@stockholmux/the-node-redis-series-e812085c917f)
21 |
--------------------------------------------------------------------------------
/database/sql/.env.sample:
--------------------------------------------------------------------------------
1 | COSMOS_DB_ENDPOINT=
2 | COSMOS_DB_KEY=
--------------------------------------------------------------------------------
/database/sql/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "type": "node",
9 | "request": "launch",
10 | "name": "Launch Program",
11 | "skipFiles": [
12 | "/**"
13 | ],
14 | "program": "${workspaceFolder}\\${file}"
15 | }
16 | ]
17 | }
--------------------------------------------------------------------------------
/database/sql/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "sql",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "type": "module",
7 | "scripts": {
8 | "start": "node index.js",
9 | "test": "echo \"Error: no test specified\" && exit 1"
10 | },
11 | "keywords": [],
12 | "author": "",
13 | "license": "ISC",
14 | "dependencies": {
15 | "@azure/cosmos": "^3.17.0",
16 | "dotenv": "^16.0.2"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/database/sql/quickstart.js:
--------------------------------------------------------------------------------
1 | // Get environment variables from .env
2 | import * as dotenv from 'dotenv';
3 | dotenv.config();
4 |
5 | // Get Cosmos Client
6 | import { CosmosClient } from "@azure/cosmos";
7 |
8 | // Provide required connection from environment variables
9 | const key = process.env.COSMOS_KEY;
10 | // Endpoint format: https://YOUR-RESOURCE-NAME.documents.azure.com:443/
11 | const endpoint = process.env.COSMOS_ENDPOINT;
12 |
13 | // Uniqueness for database and container
14 | const timeStamp = + new Date();
15 |
16 | // Set Database name and container name with unique timestamp
17 | const databaseName = `contoso_${timeStamp}`;
18 | const containerName = `products_${timeStamp}`;
19 | const partitionKeyPath = ["/categoryName"];
20 |
21 | // Authenticate to Azure Cosmos DB
22 | const cosmosClient = new CosmosClient({ endpoint, key });
23 |
24 | // Create database if it doesn't exist
25 | const { database } = await cosmosClient.databases.createIfNotExists({ id: databaseName });
26 | console.log(`${database.id} database ready`);
27 |
28 | // Create container if it doesn't exist
29 | const { container } = await database.containers.createIfNotExists({
30 | id: containerName,
31 | partitionKey: {
32 | paths: partitionKeyPath
33 | }
34 | });
35 | console.log(`${container.id} container ready`);
36 |
37 | // Data items
38 | const items = [
39 | {
40 | "id": "08225A9E-F2B3-4FA3-AB08-8C70ADD6C3C2",
41 | "categoryId": "75BF1ACB-168D-469C-9AA3-1FD26BB4EA4C",
42 | "categoryName": "Bikes, Touring Bikes",
43 | "sku": "BK-T79U-50",
44 | "name": "Touring-1000 Blue, 50",
45 | "description": "The product called \"Touring-1000 Blue, 50\"",
46 | "price": 2384.0700000000002,
47 | "tags": [
48 | {
49 | "_id": "27B7F8D5-1009-45B8-88F5-41008A0F0393",
50 | "name": "Tag-61"
51 | }
52 | ]
53 | },
54 | {
55 | "id": "2C981511-AC73-4A65-9DA3-A0577E386394",
56 | "categoryId": "75BF1ACB-168D-469C-9AA3-1FD26BB4EA4C",
57 | "categoryName": "Bikes, Touring Bikes",
58 | "sku": "BK-T79U-46",
59 | "name": "Touring-1000 Blue, 46",
60 | "description": "The product called \"Touring-1000 Blue, 46\"",
61 | "price": 2384.0700000000002,
62 | "tags": [
63 | {
64 | "_id": "4E102F3F-7D57-4CD7-88F4-AC5076A42C59",
65 | "name": "Tag-91"
66 | }
67 | ]
68 | },
69 | {
70 | "id": "0F124781-C991-48A9-ACF2-249771D44029",
71 | "categoryId": "56400CF3-446D-4C3F-B9B2-68286DA3BB99",
72 | "categoryName": "Bikes, Mountain Bikes",
73 | "sku": "BK-M68B-42",
74 | "name": "Mountain-200 Black, 42",
75 | "description": "The product called \"Mountain-200 Black, 42\"",
76 | "price": 2294.9899999999998,
77 | "tags": [
78 | {
79 | "_id": "4F67013C-3B5E-4A3D-B4B0-8C597A491EB6",
80 | "name": "Tag-82"
81 | }
82 | ]
83 | }
84 | ];
85 |
86 | // Create all items
87 | for (const item of items) {
88 |
89 | const { resource } = await container.items.create(item);
90 | console.log(`'${resource.name}' inserted`);
91 | }
92 |
93 | // Read item by id and partitionKey - least expensive `find`
94 | const { resource } = await container.item(items[0].id, items[0].categoryName).read();
95 | console.log(`${resource.name} read`);
96 |
97 | // Query by SQL - more expensive `find`
98 | // find all items with same categoryName (partitionKey)
99 | const querySpec = {
100 | query: "select * from products p where p.categoryName=@categoryName",
101 | parameters: [
102 | {
103 | name: "@categoryName",
104 | value: items[2].categoryName
105 | }
106 | ]
107 | };
108 |
109 | // Get iterator for query
110 | const queryIterator = container.items.query(querySpec);
111 |
112 | let count = 0;
113 |
114 | // Artificially low value for quickstart
115 | const pageSize = 10;
116 |
117 | // Get pages
118 | while (queryIterator.hasMoreResults() && count <= pageSize) {
119 |
120 | // Get items in page
121 | const { resources: items } = await queryIterator.fetchNext();
122 |
123 | // loop through items in page
124 | for(let item of items){
125 | console.log(`${item.id}: ${item.name}, ${item.sku}`);
126 | }
127 | }
128 |
129 | // Delete item
130 | const { statusCode } = await container.item(items[2].id, items[2].categoryName).delete();
131 | console.log(`${items[2].id} ${statusCode==204 ? `Item deleted` : `Item not deleted`}`);
132 |
133 |
--------------------------------------------------------------------------------
/docs/templates/end-to-end-scenario.md:
--------------------------------------------------------------------------------
1 |
14 |
15 | # E2E scenario template
16 |
17 | This **enter a name for scenario** implements ... in order to solve ...
18 |
19 | ## Use Case
20 |
21 | This scenario was designed to solve the problem of ...
22 |
23 | This scenario is intended to be implemented by (finish with roles such as Dev Manager, FE/BE/FS engineer, QA engineer, etc).
24 |
25 | ## Architecture
26 |
27 | This architecture shows how to implement ...
28 |
29 | Include an architecture diagram
30 |
31 | The list of Azure resources includes:
32 |
33 | The list of tools to implement this scenario includes:
34 |
35 | What cloud planes are involved and how:
36 | * Management plane
37 | * Control plane
38 | * Data plane
39 |
40 | Some SDKs combine control and data plane together. If you know the scenario uses an SDK that does this, please state that.
41 |
42 | ## Implementation summary
43 |
44 | This implementation can be broken down into the following groups of tasks:
45 |
46 | * Group 1
47 | * Task 1
48 | * List of files, tools, websites that need to be shown/explained to understand the steps
49 | * Task 2
50 | * Task 3
51 | * Group 2
52 | * Group 3
53 |
54 | Link to any videos that would show procedures/steps to complete
55 |
56 | ## Implementation steps
57 |
58 | Each group or task needs to be broken down into steps you expect a customer to complete. Don't focus on grammar, spelling. Focus on the tool used and steps. If the tool isn't common, you may want to add a few more steps.
59 |
60 | Please be aware that the resources and configuration of this scenario needs to be automated in order for future-proofing of the scenario. For example, if a bug comes in against the scenario in a year, and someone new to the team has to verify and fix the content, this script helps them spend time on the issue and not the steps to spin up the scenario.
61 |
62 | ## What was your development environment when you engineered this scenario?
63 |
64 | I ran through this procedure on a (remove whatever doesn't apply - no expectation that you did this on all options):
65 |
66 | * Win
67 | * Mac
68 | * Linux
69 | * container
70 | * VM
71 |
72 | You generally interact with the environment with:
73 |
74 | * keyboard short cuts - please use those when describing a task - just once - not exhaustively
75 | * Command palatte in VSCode
76 | * Bash commands that you developed to short-circuit longer commands
77 | * etc
78 |
79 | If the person writing up the steps doesn't understand how to get from A to C because your B was not obvious - that is what I'm looking for here.
80 |
81 | ## Security/Identity considerations
82 |
83 | Any information about what is provided for security/identity and what is not.
84 |
85 | * RBAC
86 | * Easy auth
87 | * MSAL
88 | * VNet
89 | * Firewalls
90 | * CORS
91 | * AAD apps
92 | * 3rd party auth (GitHub, Stripe, etc)
93 |
94 | ## Pipeline/automation considerations
95 |
96 | What automation is used to complete this scenario?
97 |
98 | * Resource management scripts (Az CLI, AZD cli, SWA CLI, Func CLI, PowerShell)
99 | * GitHub Actions, Azure DevOps Pipelines
100 | * AAD automation
101 | * Custom or 3rd party automation
102 | * GH CLI
103 | * Stripe CLI
104 | * Mongo CLI
105 | * Any `hidden` or poorly known areas such as https://resources.azure.com - explain why you needed it so that can translate into content.
106 |
107 | All automation must include cleanup/teardown scripts
108 |
109 | ## Verify scenario
110 |
111 | This scenario must have steps so that a customer can know they have completed it successfully, so an end state that can be validated.
112 |
113 | Examples could include:
114 |
115 | * an API response
116 | * a web site image
117 | * a set of test files generated as part of playwright
118 |
119 | ## Troubleshooting
120 |
121 | What issues did you come across that the customer may also hit?
122 |
123 | Examples include:
124 |
125 | * You forgot a config step and that resulted in an error in a certain task
126 | * The SDK or CLI returned an confusing error.
127 | * The SDK reference docs example would have been more helpful it it included ... please include exact link to ref doc.
128 | * The pricing tier (free or basic) didn't support your scenario
129 | * The portal or UI was confusing and would have been more helpful if the button/textbox/etc was boxed and had an error.
130 |
131 | ## What surprised you about the scenario?
132 |
133 | It was hard, easy, you loved the code but hated the ....
134 |
135 | Have an opinion that I could invoke with a tone or point where a customer needs to be more careful at certain steps.
136 |
137 | ## What terminology restrictions should be used?
138 |
139 | If there are specific constraints on terminology dos/don'ts, please call them out.
140 |
141 | ## References
142 |
143 | What websites did you use to complete this work? What were you looking for when you went to these websites? I usually keep this as a running list in my dev diary.
144 |
145 | They don't have to be microsoft properties, but it would be helpful to know if/when MS content was incomplete and how it was incomplete.
146 |
--------------------------------------------------------------------------------
/events/event-hubs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "event-hubs",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "send.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "@azure/event-hubs": "^5.8.0",
13 | "@azure/eventhubs-checkpointstore-blob": "^1.0.1",
14 | "@azure/identity": "^3.1.2",
15 | "@azure/storage-blob": "^12.12.0"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/events/event-hubs/receive-passwordless.js:
--------------------------------------------------------------------------------
1 | const { DefaultAzureCredential } = require("@azure/identity");
2 | const { EventHubConsumerClient, earliestEventPosition } = require("@azure/event-hubs");
3 | const { ContainerClient } = require("@azure/storage-blob");
4 | const { BlobCheckpointStore } = require("@azure/eventhubs-checkpointstore-blob");
5 |
6 | // Event hubs
7 | const eventHubsResourceName = "YOUR EVENT HUBS RESOURCE NAME";
8 | const fullyQualifiedNamespace = `${eventHubsResourceName}.servicebus.windows.net`;
9 | const eventHubName = "YOUR EVENT HUB NAME";
10 | const consumerGroup = "$Default"; // name of the default consumer group
11 |
12 | // Azure Storage
13 | const storageAccountName = "YOUR STORAGE ACCOUNT NAME";
14 | const storageContainerName = "YOUR BLOB CONTAINER NAME";
15 | const baseUrl = `https://${storageAccountName}.blob.core.windows.net`;
16 |
17 | // Azure Identity - passwordless authentication
18 | const credential = new DefaultAzureCredential();
19 |
20 | async function main() {
21 |
22 | // Create a blob container client and a blob checkpoint store using the client.
23 | const containerClient = new ContainerClient(
24 | `${baseUrl}/${storageContainerName}`,
25 | credential
26 | );
27 | const checkpointStore = new BlobCheckpointStore(containerClient);
28 |
29 | // Create a consumer client for the event hub by specifying the checkpoint store.
30 | const consumerClient = new EventHubConsumerClient(consumerGroup, fullyQualifiedNamespace, eventHubName, credential, checkpointStore);
31 |
32 | // Subscribe to the events, and specify handlers for processing the events and errors.
33 | const subscription = consumerClient.subscribe({
34 | processEvents: async (events, context) => {
35 | if (events.length === 0) {
36 | console.log(`No events received within wait time. Waiting for next interval`);
37 | return;
38 | }
39 |
40 | for (const event of events) {
41 | console.log(`Received event: '${event.body}' from partition: '${context.partitionId}' and consumer group: '${context.consumerGroup}'`);
42 | }
43 | // Update the checkpoint.
44 | await context.updateCheckpoint(events[events.length - 1]);
45 | },
46 |
47 | processError: async (err, context) => {
48 | console.log(`Error : ${err}`);
49 | }
50 | },
51 | { startPosition: earliestEventPosition }
52 | );
53 |
54 | // After 30 seconds, stop processing.
55 | await new Promise((resolve) => {
56 | setTimeout(async () => {
57 | await subscription.close();
58 | await consumerClient.close();
59 | resolve();
60 | }, 30000);
61 | });
62 | }
63 |
64 | main().catch((err) => {
65 | console.log("Error occurred: ", err);
66 | });
--------------------------------------------------------------------------------
/events/event-hubs/receive.js:
--------------------------------------------------------------------------------
1 | const { EventHubConsumerClient, earliestEventPosition } = require("@azure/event-hubs");
2 | const { ContainerClient } = require("@azure/storage-blob");
3 | const { BlobCheckpointStore } = require("@azure/eventhubs-checkpointstore-blob");
4 |
5 | const connectionString = "EVENT HUBS NAMESPACE CONNECTION STRING";
6 | const eventHubName = "YOUR EVENT HUB NAME";
7 | const consumerGroup = "$Default"; // name of the default consumer group
8 | const storageConnectionString = "AZURE STORAGE CONNECTION STRING";
9 | const containerName = "BLOB CONTAINER NAME";
10 |
11 | async function main() {
12 | // Create a blob container client and a blob checkpoint store using the client.
13 | const containerClient = new ContainerClient(storageConnectionString, containerName);
14 | const checkpointStore = new BlobCheckpointStore(containerClient);
15 |
16 | // Create a consumer client for the event hub by specifying the checkpoint store.
17 | const consumerClient = new EventHubConsumerClient(consumerGroup, connectionString, eventHubName, checkpointStore);
18 |
19 | // Subscribe to the events, and specify handlers for processing the events and errors.
20 | const subscription = consumerClient.subscribe({
21 | processEvents: async (events, context) => {
22 | if (events.length === 0) {
23 | console.log(`No events received within wait time. Waiting for next interval`);
24 | return;
25 | }
26 |
27 | for (const event of events) {
28 | console.log(`Received event: '${event.body}' from partition: '${context.partitionId}' and consumer group: '${context.consumerGroup}'`);
29 | }
30 | // Update the checkpoint.
31 | await context.updateCheckpoint(events[events.length - 1]);
32 | },
33 |
34 | processError: async (err, context) => {
35 | console.log(`Error : ${err}`);
36 | }
37 | },
38 | { startPosition: earliestEventPosition }
39 | );
40 |
41 | // After 30 seconds, stop processing.
42 | await new Promise((resolve) => {
43 | setTimeout(async () => {
44 | await subscription.close();
45 | await consumerClient.close();
46 | resolve();
47 | }, 30000);
48 | });
49 | }
50 |
51 | main().catch((err) => {
52 | console.log("Error occurred: ", err);
53 | });
--------------------------------------------------------------------------------
/events/event-hubs/send-passwordless.js:
--------------------------------------------------------------------------------
1 | const { EventHubProducerClient } = require("@azure/event-hubs");
2 | const { DefaultAzureCredential } = require("@azure/identity");
3 |
4 | // Event hubs
5 | const eventHubsResourceName = "YOUR EVENT HUBS RESOURCE NAME";
6 | const fullyQualifiedNamespace = `${eventHubsResourceName}.servicebus.windows.net`;
7 | const eventHubName = "YOUR EVENT HUB NAME";
8 |
9 | // Azure Identity - passwordless authentication
10 | const credential = new DefaultAzureCredential();
11 |
12 | async function main() {
13 |
14 | // Create a producer client to send messages to the event hub.
15 | const producer = new EventHubProducerClient(fullyQualifiedNamespace, eventHubName, credential);
16 |
17 | // Prepare a batch of three events.
18 | const batch = await producer.createBatch();
19 | batch.tryAdd({ body: "passwordless First event" });
20 | batch.tryAdd({ body: "passwordless Second event" });
21 | batch.tryAdd({ body: "passwordless Third event" });
22 |
23 | // Send the batch to the event hub.
24 | await producer.sendBatch(batch);
25 |
26 | // Close the producer client.
27 | await producer.close();
28 |
29 | console.log("A batch of three events have been sent to the event hub");
30 | }
31 |
32 | main().catch((err) => {
33 | console.log("Error occurred: ", err);
34 | });
--------------------------------------------------------------------------------
/events/event-hubs/send.js:
--------------------------------------------------------------------------------
1 | const { EventHubProducerClient } = require("@azure/event-hubs");
2 |
3 | const connectionString = "EVENT HUBS NAMESPACE CONNECTION STRING";
4 | const eventHubName = "EVENT HUB NAME";
5 |
6 | async function main() {
7 |
8 | // Create a producer client to send messages to the event hub.
9 | const producer = new EventHubProducerClient(connectionString, eventHubName);
10 |
11 | // Prepare a batch of three events.
12 | const batch = await producer.createBatch();
13 | batch.tryAdd({ body: "First event" });
14 | batch.tryAdd({ body: "Second event" });
15 | batch.tryAdd({ body: "Third event" });
16 |
17 | // Send the batch to the event hub.
18 | await producer.sendBatch(batch);
19 |
20 | // Close the producer client.
21 | await producer.close();
22 |
23 | console.log("A batch of three events have been sent to the event hub");
24 | }
25 |
26 | main().catch((err) => {
27 | console.log("Error occurred: ", err);
28 | });
--------------------------------------------------------------------------------
/graph/my-profile-from-rest-api.js:
--------------------------------------------------------------------------------
1 | // package.json - type: "module"
2 |
3 | import axios from 'axios';
4 |
5 |
6 | // https://developer.microsoft.com/en-us/graph/graph-explorer
7 | // https://jwt.ms/
8 |
9 |
10 |
11 | const main = async (accessToken) => {
12 |
13 |
14 | try {
15 |
16 | const url = 'https://graph.microsoft.com/v1.0/me';
17 |
18 | const options = {
19 | method: 'GET',
20 | headers: {
21 | Authorization: 'Bearer ' + accessToken,
22 | 'Content-type': 'application/json',
23 | },
24 | };
25 |
26 | const graphResponse = await axios.get(url, options);
27 |
28 | const { data } = await graphResponse;
29 | return data;
30 |
31 | } catch (err) {
32 | throw err;
33 | }
34 | }
35 |
36 | const accessToken = "... replace with your access token ...";
37 |
38 | main(accessToken).then((userData)=>{
39 | console.log(userData);
40 | }).catch((err)=>{
41 | console.log(err);
42 | })
43 |
--------------------------------------------------------------------------------
/graph/my-profile-from-sdk.js:
--------------------------------------------------------------------------------
1 | // package.json - type: "module"
2 |
3 | import graph from '@microsoft/microsoft-graph-client';
4 | import 'isomorphic-fetch';
5 |
6 | const getAuthenticatedClient = (accessToken) => {
7 | // Initialize Graph client
8 | const client = graph.Client.init({
9 | // Use the provided access token to authenticate requests
10 | authProvider: (done) => {
11 | done(null, accessToken);
12 | }
13 | });
14 |
15 | return client;
16 | }
17 |
18 | // https://developer.microsoft.com/en-us/graph/graph-explorer
19 | // https://jwt.ms/
20 | // https://github.com/Azure-Samples/ms-identity-easyauth-nodejs-storage-graphapi/blob/main/2-WebApp-graphapi-on-behalf/controllers/graphController.js
21 |
22 | const main = async (accessToken) => {
23 |
24 |
25 | try {
26 | const graphClient = getAuthenticatedClient(accessToken);
27 |
28 | const profile = await graphClient
29 | .api('/me')
30 | .get();
31 |
32 | return profile;
33 |
34 | } catch (err) {
35 | throw err;
36 | }
37 | }
38 |
39 | const accessToken = "... replace with your access token ...";
40 |
41 | main(accessToken).then((userData)=>{
42 | console.log(userData);
43 | }).catch((err)=>{
44 | console.log(err);
45 | })
46 |
--------------------------------------------------------------------------------
/keyvault/azure-keyvault-secrets.js:
--------------------------------------------------------------------------------
1 | const { DefaultAzureCredential } = require("@azure/identity");
2 | const { SecretClient } = require("@azure/keyvault-secrets");
3 |
4 | const getSecret = async (secretName, keyVaultName) => {
5 |
6 | if (!secretName || !keyVaultName) {
7 | throw Error("getSecret: Required params missing")
8 | }
9 |
10 | /*
11 | *
12 | * 1. Create a resource group for all Azure resources in app
13 | * or project - skip if you have already completed for
14 | * this sample app
15 | *
16 | * 2. Create an Azure Key Vault resource in Azure CLI
17 | *
18 | * az keyvault create \
19 | * --subscription REPLACE-WITH-YOUR-SUBSCRIPTION-NAME-OR-ID \
20 | * --resource-group REPLACE-WITH-YOUR-RESOURCE-GROUP-NAME \
21 | * --name REPLACE-WITH-YOUR-KEY-VAULT-NAME
22 | *
23 | * 3. Create Service Principal (LOGICAL-APP-NAME) for new App
24 | * registration with the following Azure CLI command
25 | * in a bash terminal:
26 | *
27 | * az ad sp create-for-rbac \
28 | * --name REPLACE-WITH-YOUR-NEW-APP-LOGICAL-NAME
29 | * --skip-assignment
30 | *
31 | * ServicePrincipalOutput =
32 | *
33 | * {
34 | * "appId": "123456",
35 | * "displayName": "REPLACE-WITH-YOUR-NEW-APP-LOGICAL-NAME",
36 | * "name": "http://REPLACE-WITH-YOUR-NEW-APP-LOGICAL-NAME",
37 | * "password": "!@#$%",
38 | * "tenant": "987654"
39 | * }
40 | *
41 | * 4. Set these environment variables to create the REQUIRED
42 | * context to use DefaultAzureCredential.
43 | *
44 | * AZURE_TENANT_ID: The `tenant` in the JSON response above.
45 | * AZURE_CLIENT_ID: The `appId` in the JSON response above.
46 | * AZURE_CLIENT_SECRET: The `password` in the JSON response above.
47 | *
48 | * 5. Give Service Principal (LOGICAL-APP-NAME) access to
49 | * Key Vault with Azure CLI command. The value for --spn is
50 | * your `appId`.
51 | *
52 | * az keyvault set-policy \
53 | * --subscription REPLACE-WITH-YOUR-SUBSCRIPTION-NAME-OR-ID \
54 | * --name "REPLACE-WITH-YOUR-KEY-VAULT-NAME" \
55 | * --spn REPLACE-WITH-YOUR-SERVICE-PRINCIPAL-APP-ID \
56 | * --secret-permissions get list
57 | *
58 | * 6. Add database connection string as secret named `DATABASEURL`.
59 | *
60 | * az keyvault secret set \
61 | * --subscription REPLACE-WITH-YOUR-SUBSCRIPTION-NAME-OR-ID \
62 | * --vault-name "REPLACE-WITH-YOUR-KEY-VAULT-NAME" \
63 | * --name "DATABASEURL" \
64 | * --value "mongodb://my-cosmos-mongodb"
65 | *
66 | * 7. Call the getSecret function as
67 | *
68 | * const { getSecret } = require("./azure/azure-keyvault");
69 | * const KEY_VAULT_CONNECTION_STRING_SECRET_NAME = "DATABASEURL";
70 | * const KEY_VAULT_NAME = "my-keyvault";
71 | * let DATABASE_URL = await getSecret(KEY_VAULT_CONNECTION_STRING_SECRET_NAME, KEY_VAULT_NAME);
72 | */
73 |
74 | if (!process.env.AZURE_TENANT_ID ||
75 | !process.env.AZURE_CLIENT_ID ||
76 | !process.env.AZURE_CLIENT_SECRET) {
77 | throw Error("KeyVault can't use DefaultAzureCredential");
78 | }
79 |
80 | const credential = new DefaultAzureCredential();
81 |
82 | // Build the URL to reach your key vault
83 | const url = `https://${keyVaultName}.vault.azure.net`;
84 |
85 | try {
86 | // Create client to connect to service
87 | const client = new SecretClient(url, credential);
88 |
89 | // Get secret Obj
90 | const latestSecret = await client.getSecret(secretName);
91 |
92 | // Return value
93 | return latestSecret.value;
94 | } catch (ex) {
95 | console.log(ex)
96 | throw ex;
97 | }
98 | }
99 |
100 | module.exports = {
101 | getSecret
102 | };
103 |
104 |
--------------------------------------------------------------------------------
/keyvault/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "keyvault",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "@azure/identity": "^1.2.5",
14 | "@azure/keyvault-secrets": "^4.1.0"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/resources/.env:
--------------------------------------------------------------------------------
1 | AZURE_TENANT_ID=
2 | AZURE_CLIENT_ID=
3 | AZURE_CLIENT_SECRET=
4 | AZURE_SUBSCRIPTION_ID=
5 | AZURE-RESOURCE-GROUP-NAME=
6 | EMAIL-ALIAS=
7 | APP-NAME=
--------------------------------------------------------------------------------
/resources/authorization/list.js:
--------------------------------------------------------------------------------
1 | const { DefaultAzureCredential } = require("@azure/identity");
2 | const { AuthorizationManagementClient } = require("@azure/arm-authorization");
3 | const subscriptionId = process.env["AZURE_SUBSCRIPTION_ID"];
4 |
5 | // Use `DefaultAzureCredential` or any other credential of your choice based on https://aka.ms/azsdk/js/identity/examples
6 | // Please note that you can also use credentials from the `@azure/ms-rest-nodeauth` package instead.
7 | const creds = new DefaultAzureCredential();
8 | const client = new AuthorizationManagementClient(creds, subscriptionId);
9 |
10 | async function listOfSubscriptions() {
11 | const ListResult = new Array();
12 | for await (const item of client.classicAdministrators.list()) {
13 | ListResult.push(item);
14 | }
15 | return ListResult;
16 | }
17 |
18 | listOfSubscriptions()
19 | .then((result) => {
20 | console.log("The result is:");
21 | console.log(result);
22 | })
23 | .catch((err) => {
24 | console.log("An error occurred:");
25 | console.error(err);
26 | });
27 |
--------------------------------------------------------------------------------
/resources/authorization/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "authorization",
3 | "version": "1.0.0",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "@azure/abort-controller": {
8 | "version": "1.0.4",
9 | "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-1.0.4.tgz",
10 | "integrity": "sha512-lNUmDRVGpanCsiUN3NWxFTdwmdFI53xwhkTFfHDGTYk46ca7Ind3nanJc+U6Zj9Tv+9nTCWRBscWEW1DyKOpTw==",
11 | "requires": {
12 | "tslib": "^2.0.0"
13 | },
14 | "dependencies": {
15 | "tslib": {
16 | "version": "2.3.1",
17 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
18 | "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
19 | }
20 | }
21 | },
22 | "@azure/arm-authorization": {
23 | "version": "9.0.0-beta.1",
24 | "resolved": "https://registry.npmjs.org/@azure/arm-authorization/-/arm-authorization-9.0.0-beta.1.tgz",
25 | "integrity": "sha512-S3qzT28SFRnOoYFwydcbXHrN0Fc+aiETHe7pNIxA+sZOISmnYQWPIG4zEvsTOhpw1w4Quk3IcNHNSXxMRt91hA==",
26 | "requires": {
27 | "@azure/core-auth": "^1.1.4",
28 | "@azure/ms-rest-azure-js": "^2.1.0",
29 | "@azure/ms-rest-js": "^2.2.0",
30 | "tslib": "^1.9.3"
31 | }
32 | },
33 | "@azure/core-auth": {
34 | "version": "1.3.2",
35 | "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.3.2.tgz",
36 | "integrity": "sha512-7CU6DmCHIZp5ZPiZ9r3J17lTKMmYsm/zGvNkjArQwPkrLlZ1TZ+EUYfGgh2X31OLMVAQCTJZW4cXHJi02EbJnA==",
37 | "requires": {
38 | "@azure/abort-controller": "^1.0.0",
39 | "tslib": "^2.2.0"
40 | },
41 | "dependencies": {
42 | "tslib": {
43 | "version": "2.3.1",
44 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
45 | "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
46 | }
47 | }
48 | },
49 | "@azure/ms-rest-azure-js": {
50 | "version": "2.1.0",
51 | "resolved": "https://registry.npmjs.org/@azure/ms-rest-azure-js/-/ms-rest-azure-js-2.1.0.tgz",
52 | "integrity": "sha512-CjZjB8apvXl5h97Ck6SbeeCmU0sk56YPozPtTyGudPp1RGoHXNjFNtoOvwOG76EdpmMpxbK10DqcygI16Lu60Q==",
53 | "requires": {
54 | "@azure/core-auth": "^1.1.4",
55 | "@azure/ms-rest-js": "^2.2.0",
56 | "tslib": "^1.10.0"
57 | }
58 | },
59 | "@azure/ms-rest-js": {
60 | "version": "2.6.0",
61 | "resolved": "https://registry.npmjs.org/@azure/ms-rest-js/-/ms-rest-js-2.6.0.tgz",
62 | "integrity": "sha512-4C5FCtvEzWudblB+h92/TYYPiq7tuElX8icVYToxOdggnYqeec4Se14mjse5miInKtZahiFHdl8lZA/jziEc5g==",
63 | "requires": {
64 | "@azure/core-auth": "^1.1.4",
65 | "abort-controller": "^3.0.0",
66 | "form-data": "^2.5.0",
67 | "node-fetch": "^2.6.0",
68 | "tough-cookie": "^3.0.1",
69 | "tslib": "^1.10.0",
70 | "tunnel": "0.0.6",
71 | "uuid": "^8.3.2",
72 | "xml2js": "^0.4.19"
73 | }
74 | },
75 | "abort-controller": {
76 | "version": "3.0.0",
77 | "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
78 | "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
79 | "requires": {
80 | "event-target-shim": "^5.0.0"
81 | }
82 | },
83 | "asynckit": {
84 | "version": "0.4.0",
85 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
86 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
87 | },
88 | "combined-stream": {
89 | "version": "1.0.8",
90 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
91 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
92 | "requires": {
93 | "delayed-stream": "~1.0.0"
94 | }
95 | },
96 | "delayed-stream": {
97 | "version": "1.0.0",
98 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
99 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
100 | },
101 | "event-target-shim": {
102 | "version": "5.0.1",
103 | "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
104 | "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="
105 | },
106 | "form-data": {
107 | "version": "2.5.1",
108 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz",
109 | "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==",
110 | "requires": {
111 | "asynckit": "^0.4.0",
112 | "combined-stream": "^1.0.6",
113 | "mime-types": "^2.1.12"
114 | }
115 | },
116 | "ip-regex": {
117 | "version": "2.1.0",
118 | "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz",
119 | "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk="
120 | },
121 | "mime-db": {
122 | "version": "1.49.0",
123 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.49.0.tgz",
124 | "integrity": "sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA=="
125 | },
126 | "mime-types": {
127 | "version": "2.1.32",
128 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.32.tgz",
129 | "integrity": "sha512-hJGaVS4G4c9TSMYh2n6SQAGrC4RnfU+daP8G7cSCmaqNjiOoUY0VHCMS42pxnQmVF1GWwFhbHWn3RIxCqTmZ9A==",
130 | "requires": {
131 | "mime-db": "1.49.0"
132 | }
133 | },
134 | "node-fetch": {
135 | "version": "2.6.2",
136 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.2.tgz",
137 | "integrity": "sha512-aLoxToI6RfZ+0NOjmWAgn9+LEd30YCkJKFSyWacNZdEKTit/ZMcKjGkTRo8uWEsnIb/hfKecNPEbln02PdWbcA=="
138 | },
139 | "psl": {
140 | "version": "1.8.0",
141 | "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
142 | "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ=="
143 | },
144 | "punycode": {
145 | "version": "2.1.1",
146 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
147 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
148 | },
149 | "sax": {
150 | "version": "1.2.4",
151 | "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
152 | "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
153 | },
154 | "tough-cookie": {
155 | "version": "3.0.1",
156 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz",
157 | "integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==",
158 | "requires": {
159 | "ip-regex": "^2.1.0",
160 | "psl": "^1.1.28",
161 | "punycode": "^2.1.1"
162 | }
163 | },
164 | "tslib": {
165 | "version": "1.14.1",
166 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
167 | "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
168 | },
169 | "tunnel": {
170 | "version": "0.0.6",
171 | "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
172 | "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="
173 | },
174 | "uuid": {
175 | "version": "8.3.2",
176 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
177 | "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
178 | },
179 | "xml2js": {
180 | "version": "0.4.23",
181 | "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
182 | "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==",
183 | "requires": {
184 | "sax": ">=0.6.0",
185 | "xmlbuilder": "~11.0.0"
186 | }
187 | },
188 | "xmlbuilder": {
189 | "version": "11.0.1",
190 | "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
191 | "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA=="
192 | }
193 | }
194 | }
195 |
--------------------------------------------------------------------------------
/resources/authorization/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "authorization",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "@azure/arm-authorization": "^9.0.0-beta.1"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/resources/billing/billing.js:
--------------------------------------------------------------------------------
1 | const { DefaultAzureCredential } = require("@azure/identity");
2 | const { BillingManagementClient } = require("@azure/arm-billing");
3 |
4 | const subscriptionId = process.env["AZURE_SUBSCRIPTION_ID"];
5 | const creds = new DefaultAzureCredential();
6 |
7 | // Use `DefaultAzureCredential` or any other credential of your choice based on https://aka.ms/azsdk/js/identity/examples
8 | // Please note that you can also use credentials from the `@azure/ms-rest-nodeauth` package instead.
9 | try {
10 | const client = new BillingManagementClient(creds, subscriptionId);
11 | const result = new Array();
12 | const expand = "testexpand";
13 | for await (const item of client.billingAccounts.list(expand)) {
14 | result.push(item);
15 | }
16 | console.log("The result is:");
17 | console.log(JSON.stringify(result));
18 | } catch (error) {
19 | console.log("An error occurred:");
20 | console.error(JSON.stringify(err));
21 | }
22 |
--------------------------------------------------------------------------------
/resources/billing/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "billing",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "@azure/arm-billing": "^4.0.0",
13 | "@azure/identity": "^1.5.2"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/resources/create-resource-default-credential.js:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Create an Azure Cognitive Services Face resource.
4 |
5 | Requires:
6 |
7 | 1. Create .env file with key/value:
8 | * AZURE_SUBSCRIPTION_ID
9 | * AZURE-RESOURCE-GROUP-NAME
10 | * EMAIL-ALIAS
11 | * APP-NAME
12 |
13 | 2. Install npm packages.
14 |
15 | ```
16 | npm install dotenv @azure/identity @azure/arm-resources
17 | ```
18 |
19 | 3. Run code.
20 |
21 | ```
22 | node create-resource-default-credential.js
23 | ```
24 |
25 | References:
26 | * [Azure SDK Ref Docs for resource creation](https://docs.microsoft.com/en-us/javascript/api/@azure/arm-resources/resources?view=azure-node-latest)
27 | * [Resource provider names](https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/azure-services-resource-providers)
28 | * [Get versions](https://github.com/Azure/azure-rest-api-specs) - versions are used as subfolders in the REST API repo
29 |
30 |
31 | */
32 | require("dotenv").config();
33 | const subscriptionId = process.env["AZURE_SUBSCRIPTION_ID"];
34 | const resourceGroupName = process.env["AZURE-RESOURCE-GROUP-NAME"];
35 | const emailAlias = process.env["EMAIL-ALIAS"];
36 | const appName = process.env["APP-NAME"];
37 |
38 | const { DefaultAzureCredential } = require("@azure/identity");
39 | const { ResourceManagementClient } = require("@azure/arm-resources");
40 |
41 | // Use Azure Identity Default Credential
42 | const credentials = new DefaultAzureCredential();
43 |
44 | async function createAzureFaceResource(credentials) {
45 | try {
46 | // Use Azure SDK for Resource Management
47 | const resourceManagementClient = new ResourceManagementClient(
48 | credentials,
49 | subscriptionId
50 | );
51 | const resources = resourceManagementClient.resources;
52 |
53 | // These are specific to the Azure Cognitive Services Face API
54 | const resourceProviderNamespace = "Microsoft.CognitiveServices";
55 | const parentResourcePath = "";
56 | const apiVersion = "2017-04-18";
57 |
58 | let parameters = {
59 | type: "Microsoft.CognitiveServices/accounts",
60 | location: "eastus",
61 | tags: {
62 | alias: emailAlias,
63 | app: appName,
64 | },
65 | sku: {
66 | name: "F0",
67 | },
68 | kind: "Face",
69 | properties: {
70 | networkAcls: {
71 | defaultAction: "Allow",
72 | virtualNetworkRules: [],
73 | ipRules: [],
74 | },
75 | privateEndpointConnections: [],
76 | publicNetworkAccess: "Enabled",
77 | },
78 | };
79 |
80 | // Use Date as part of the resource name convention
81 | const date = new Date();
82 | const createdDate = date.toJSON().slice(0, 10);
83 |
84 | const resourceType = "accounts";
85 | const resourceName = `${parameters.tags.alias}-${resourceGroupName}-${resourceType}-${parameters.sku.name}-${createdDate}`;
86 | const longRunningOperationResult = await resources.beginCreateOrUpdate(
87 | resourceGroupName,
88 | resourceProviderNamespace,
89 | parentResourcePath,
90 | resourceType,
91 | resourceName,
92 | apiVersion,
93 | parameters
94 | );
95 | console.log(longRunningOperationResult);
96 | return longRunningOperationResult;
97 | } catch (err) {
98 | console.log(err);
99 | }
100 | }
101 |
102 | createAzureFaceResource()
103 | .then(() => {
104 | console.log("done");
105 | })
106 | .catch((err) => {
107 | console.error(err);
108 | });
109 |
--------------------------------------------------------------------------------
/resources/create-resource.js:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Create an Azure Cognitive Services Face resource.
4 |
5 | Requires:
6 |
7 | Azure subscription and Azure resource group already exists. Both are required in the code:
8 | * "REPLACE-WITH-YOUR-SUBSCRIPTION-ID"
9 | * "REPLACE-WITH-YOUR-RESOURCE-GROUP-NAME"
10 |
11 | Add your email alias, the part before the `@` symbol, to your naming convention:
12 | * "REPLACE-WITH-YOUR-EMAIL-ALIAS"
13 | * "REPLACE-WITH-YOUR-APP-NAME"
14 |
15 | References:
16 | * [Azure SDK Ref Docs for resource creation](https://docs.microsoft.com/en-us/javascript/api/@azure/arm-resources/resources?view=azure-node-latest)
17 | * [Resource provider names](https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/azure-services-resource-providers)
18 | * [Get versions](https://github.com/Azure/azure-rest-api-specs) - versions are used as subfolders in the REST API repo
19 |
20 |
21 | */
22 |
23 | const { InteractiveBrowserCredential } = require("@azure/identity");
24 | const { ResourceManagementClient } = require("@azure/arm-resources");
25 |
26 | // Use Azure Identity Default Credential
27 | const credentials = new InteractiveBrowserCredential();
28 |
29 | async function createAzureFaceResource(credentials) {
30 | // Use Azure SDK for Resource Management
31 | const client = new ResourceManagementClient(credential, subscriptionId);
32 | const resources = client.resources;
33 |
34 | // REPLACE WITH YOUR VALUES
35 | const subscriptionId = "REPLACE-WITH-YOUR-SUBSCRIPTION-ID";
36 | const resourceGroupName = "REPLACE-WITH-YOUR-RESOURCE-GROUP-NAME";
37 |
38 | // These are specific to the Azure Cognitive Services Face API
39 | const resourceProviderNamespace = "Microsoft.CognitiveServices";
40 | const parentResourcePath = "";
41 | const apiVersion = "2017-04-18";
42 |
43 | // REPLACE WITH YOUR VALUES
44 | let parameters = {
45 | type: "Microsoft.CognitiveServices/accounts",
46 | location: "eastus",
47 | tags: {
48 | alias: process.env["EMAIL-ALIAS"] || "REPLACE-WITH-YOUR-EMAIL-ALIAS",
49 | app: process.env["APP-NAME"] || "REPLACE-WITH-YOUR-APP-NAME",
50 | },
51 | sku: {
52 | name: "F0",
53 | },
54 | kind: "Face",
55 | properties: {
56 | networkAcls: {
57 | defaultAction: "Allow",
58 | virtualNetworkRules: [],
59 | ipRules: [],
60 | },
61 | privateEndpointConnections: [],
62 | publicNetworkAccess: "Enabled",
63 | },
64 | };
65 |
66 | // Use Date as part of the resource name convention
67 | const date = new Date();
68 | const createdDate = date.toJSON().slice(0, 10);
69 |
70 | const resourceType = "accounts";
71 | const resourceName = `${parameters.tags.alias}-${resourceGroupName}-${resourceType}-${parameters.sku.name}-${createdDate}`;
72 | const longRunningOperationResult = await resources.beginCreateOrUpdate(
73 | resourceGroupName,
74 | resourceProviderNamespace,
75 | parentResourcePath,
76 | resourceType,
77 | resourceName,
78 | apiVersion,
79 | parameters
80 | );
81 | return longRunningOperationResult;
82 | }
83 |
84 | createAzureFaceResource(credentials)
85 | .then((res) => {
86 | console.log(JSON.stringify(res));
87 | })
88 | .catch((err) => {
89 | console.log(err);
90 | });
91 |
--------------------------------------------------------------------------------
/resources/monitor/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "type": "pwa-node",
9 | "request": "launch",
10 | "name": "Launch Program",
11 | "skipFiles": [
12 | "/**"
13 | ],
14 | "program": "${workspaceFolder}\\${file}"
15 | }
16 | ]
17 | }
--------------------------------------------------------------------------------
/resources/monitor/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "monitor",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "@azure/arm-monitor": "^7.0.0",
14 | "@azure/identity": "^1.5.2",
15 | "@azure/monitor-query": "^1.0.0-beta.5",
16 | "@base2/pretty-print-object": "^1.0.1",
17 | "dayjs": "^1.10.7"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/resources/monitor/resource-creation-history.js:
--------------------------------------------------------------------------------
1 | const {
2 | ClientSecretCredential,
3 | DefaultAzureCredential,
4 | } = require("@azure/identity");
5 | const { MonitorManagementClient } = require("@azure/arm-monitor");
6 | const dayjs = require("dayjs");
7 | const { prettyPrint } = require("@base2/pretty-print-object");
8 |
9 | // resource group - returns all resource groups if not specified
10 | const resourceGroupName = "";
11 |
12 | // days needs to be less than or equal to 90
13 | const daysAgo = 10;
14 |
15 | // filter
16 | // https://docs.microsoft.com/en-us/javascript/api/@azure/arm-monitor/activitylogs?view=azure-node-latest#list_string__ActivityLogsListOptionalParams__ServiceCallback_EventDataCollection__
17 | const greaterThanIsoTime = dayjs().subtract(daysAgo, "day").toISOString();
18 | const lessThanIsoTime = new Date().toISOString();
19 | let filter = `eventTimestamp ge '${greaterThanIsoTime}' and eventTimestamp le '${lessThanIsoTime}'`;
20 | filter += resourceGroupName
21 | ? ` and resourceGroupName eq '${resourceGroupName}'`
22 | : null;
23 |
24 | // Azure authentication in environment variables for DefaultAzureCredential
25 | let credentials = null;
26 | const tenantId =
27 | process.env["AZURE_TENANT_ID"] || "REPLACE-WITH-YOUR-TENANT-ID";
28 | const clientId =
29 | process.env["AZURE_CLIENT_ID"] || "REPLACE-WITH-YOUR-CLIENT-ID";
30 | const secret =
31 | process.env["AZURE_CLIENT_SECRET"] || "REPLACE-WITH-YOUR-CLIENT-SECRET";
32 | const subscriptionId =
33 | process.env["AZURE_SUBSCRIPTION_ID"] || "REPLACE-WITH-YOUR-SUBSCRIPTION_ID";
34 |
35 | if (process.env.production) {
36 | // production
37 | credentials = new DefaultAzureCredential();
38 | } else {
39 | // development
40 | credentials = new ClientSecretCredential(tenantId, clientId, secret);
41 | console.log("development");
42 | }
43 |
44 | try {
45 | // use credential to authenticate with Azure SDKs
46 | const client = new MonitorManagementClient(credentials, subscriptionId);
47 |
48 | const arrObjects = new Array();
49 | for await (const element of client.activityLogs.list(filter)) {
50 | arrObjects.push({
51 | resourceGroupName: element?.resourceGroupName,
52 | action: element?.authorization?.action,
53 | user:
54 | element?.claims?.[
55 | "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"
56 | ],
57 | resourceProviderName: element?.resourceProviderName,
58 | resourceType: element?.resourceType,
59 | operationName: element.operationName,
60 | status: element.status,
61 | eventTimestamp: element.eventTimestamp,
62 | });
63 | }
64 | console.log(prettyPrint(arrObjects));
65 | } catch (err) {
66 | console.log("An error occurred:");
67 | console.log(err);
68 | }
69 |
70 | /*
71 |
72 | Example element:
73 |
74 | {
75 | resourceGroupName: 'johnsmith-temp',
76 | action: 'Microsoft.DocumentDB/databaseAccounts/listConnectionStrings/action',
77 | user: 'johnsmith@contoso.com',
78 | resourceProviderName: {
79 | value: 'Microsoft.DocumentDB',
80 | localizedValue: 'Microsoft.DocumentDB'
81 | },
82 | resourceType: {
83 | value: 'Microsoft.DocumentDB/databaseAccounts',
84 | localizedValue: 'Microsoft.DocumentDB/databaseAccounts'
85 | },
86 | operationName: {
87 | value: 'Microsoft.DocumentDB/databaseAccounts/listConnectionStrings/action',
88 | localizedValue: 'Get Connection Strings'
89 | },
90 | status: { value: 'Succeeded', localizedValue: 'Succeeded' },
91 | eventTimestamp: 2021-09-21T17:27:22.727Z
92 | },
93 |
94 | */
95 |
--------------------------------------------------------------------------------
/resources/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "azure-resources",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "resource-group.js",
6 | "scripts": {
7 | "start": "node resource-group.js",
8 | "test": "echo \"Error: no test specified\" && exit 1"
9 | },
10 | "author": "",
11 | "license": "MIT",
12 | "dependencies": {
13 | "@azure/arm-resources": "^5.0.0",
14 | "@azure/identity": "^1.3.0",
15 | "@azure/ms-rest-nodeauth": "^3.0.9",
16 | "dotenv": "^8.2.0"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/resources/resource-group-create/README.md:
--------------------------------------------------------------------------------
1 | # Create resource group in subscription with Azure SDK for JavaScript
2 |
3 | 1. Sign in to Azure CLI in terminal.
4 |
5 | ```bash
6 | az login
7 | ```
8 |
9 |
10 | 1. Create service principal with Azure CLI, replace `YOUR-SERVICE-PRINCIPAL-NAME` with a name
11 | such as `jsmith-quickstart-azure`:
12 |
13 | ```bash
14 | az ad sp create-for-rbac --name YOUR-SERVICE-PRINCIPAL-NAME
15 | ```
16 |
17 | 1. Save the output in a secure location such as Azure Key vault
18 |
19 | ```json
20 | {
21 | "appId": "717...",
22 | "displayName": "jsmith-quickstart-azure",
23 | "name": "http://jsmith-quickstart-azure",
24 | "password": "PEG...",
25 | "tenant": "72f..."
26 | }
27 | ```
28 |
29 | 1. Create new environment variables. These environment variables are REQUIRED for the context to use DefaultAzureCredential.
30 |
31 | ```
32 | AZURE_TENANT_ID: `tenant` from the service principal output above.
33 | AZURE_CLIENT_ID: `appId` from the service principal output above.
34 | AZURE_CLIENT_SECRET: `password` from the service principal output above.
35 | AZURE_SUBSCRIPTION_ID: Your default subscription containing your resource groups.
36 | ```
37 |
38 | 1. Complete the following commands from a bash terminal to install package dependencies:
39 |
40 | ```bash
41 | npm install @azure/identity @azure/arm-resources --save
42 | ```
43 |
44 | 1. Run this script from a bash terminal to see a list of resource groups in your default subscription:
45 |
46 | ```bash
47 | npm start
48 | ```
49 |
50 | 1. Output looks like
51 |
52 | ```JSON
53 | {
54 | "id": "/subscriptions/12345/resourceGroups/jsmith-ResourceGroup",
55 | "name": "jsmith-ResourceGroup",
56 | "type": "Microsoft.Resources/resourceGroups",
57 | "properties": { "provisioningState": "Succeeded" },
58 | "location": "westus",
59 | "tags": { "createdBy": "jsmith" }
60 | }
61 | ```
62 |
--------------------------------------------------------------------------------
/resources/resource-group-create/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "resource-group-create",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "@azure/arm-resources": "^5.0.0",
13 | "@azure/identity": "^1.5.2",
14 | "stringify-object": "^4.0.0"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/resources/resource-group-create/resource-group-create.js:
--------------------------------------------------------------------------------
1 | // Include npm dependencies
2 | const { DefaultAzureCredential } = require("@azure/identity");
3 | const { ResourceManagementClient } = require("@azure/arm-resources");
4 |
5 | // Get subscription from environment variables
6 | const subscriptionId = process.env["AZURE_SUBSCRIPTION_ID"];
7 | if (!subscriptionId)
8 | throw Error("Azure Subscription is missing from environment variables.");
9 |
10 | // The following code is only used to check you have environment
11 | // variables configured. The DefaultAzureCredential reads your
12 | // environment - it doesn't read these variables.
13 | const tenantId = process.env["AZURE_TENANT_ID"];
14 | if (!tenantId)
15 | throw Error("AZURE_TENANT_ID is missing from environment variables.");
16 | const clientId = process.env["AZURE_CLIENT_ID"];
17 | if (!clientId)
18 | throw Error("AZURE_CLIENT_ID is missing from environment variables.");
19 | const secret = process.env["AZURE_CLIENT_SECRET"];
20 | if (!secret)
21 | throw Error("AZURE_CLIENT_SECRET is missing from environment variables.");
22 |
23 | // Create Azure authentication credentials
24 | const credentials = new DefaultAzureCredential();
25 |
26 | try {
27 | // Create Azure SDK client for Resource Management such as resource groups
28 | const resourceManagement = new ResourceManagementClient(
29 | credentials,
30 | subscriptionId
31 | );
32 |
33 | const ownerAlias = "jsmith";
34 | const location = "westus";
35 |
36 | // Resource group definition
37 | const resourceGroupName = `${ownerAlias}-ResourceGroup`;
38 | const resourceGroupParameters = {
39 | location: location,
40 | tags: { createdBy: ownerAlias },
41 | };
42 |
43 | // Create resource groups in subscription
44 | await resourceManagement.resourceGroups
45 | .createOrUpdate(resourceGroupName, resourceGroupParameters)
46 | .then((result) => {
47 | console.log(result);
48 | });
49 |
50 | /*
51 | {
52 | id: '/subscriptions/12345/resourceGroups/jsmith-ResourceGroup',
53 | name: 'jsmith-ResourceGroup',
54 | type: 'Microsoft.Resources/resourceGroups',
55 | properties: { provisioningState: 'Succeeded' },
56 | location: 'westus',
57 | tags: { createdBy: 'jsmith' }
58 | }
59 | */
60 | } catch (err) {
61 | console.log(err);
62 | }
63 |
--------------------------------------------------------------------------------
/resources/resource-group-default-credential.js:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Create an Azure resource group.
4 |
5 | Requires:
6 |
7 | Azure subscription already exists. Value is required in the code:
8 | * "REPLACE-WITH-YOUR-SUBSCRIPTION-ID"
9 |
10 | Add your email alias, the part before the `@` symbol, to your naming convention:
11 | * "REPLACE-WITH-YOUR-EMAIL-ALIAS"
12 | * "REPLACE-WITH-YOUR-APP-NAME"
13 |
14 | References:
15 | * [Azure SDK Ref Docs for Resources](https://docs.microsoft.com/en-us/javascript/api/overview/azure/resources)
16 |
17 | */
18 |
19 | require("dotenv").config();
20 | const subscriptionId = process.env["AZURE_SUBSCRIPTION_ID"];
21 | const myEmailAlias = process.env["EMAIL-ALIAS"];
22 | const myAppName = process.env["APP-NAME"];
23 |
24 | const { DefaultAzureCredential } = require("@azure/identity");
25 | const { ResourceManagementClient } = require("@azure/arm-resources");
26 |
27 | const resourceCreatedDate = new Date().toISOString();
28 | const resourceGroupName = `${myAppName}-resource-group`;
29 | const resourceGroupLocation = "eastus";
30 |
31 | async function createResourceGroup() {
32 | try {
33 | // Use Azure Identity Default Credential
34 | const credentials = new DefaultAzureCredential();
35 |
36 | // Use Azure SDK for Resource Management
37 | const resourceManagement = new ResourceManagementClient(
38 | credentials,
39 | subscriptionId
40 | );
41 |
42 | // Create
43 | const parameters = {
44 | location: resourceGroupLocation,
45 | tags: {
46 | owner: myEmailAlias,
47 | created: resourceCreatedDate,
48 | },
49 | };
50 | console.log("Creating...");
51 | const createResult = await resourceManagement.resourceGroups.createOrUpdate(
52 | resourceGroupName,
53 | parameters
54 | );
55 | console.log(JSON.stringify(createResult));
56 |
57 | // Check existence - returns boolean
58 | console.log("Exists...");
59 | const checkExistenceResult = await resourceManagement.resourceGroups.checkExistence(
60 | resourceGroupName
61 | );
62 | console.log(JSON.stringify(checkExistenceResult));
63 | } catch (err) {
64 | console.log(err);
65 | }
66 | }
67 |
68 | createResourceGroup()
69 | .then(() => {
70 | console.log("done");
71 | })
72 | .catch((err) => {
73 | console.log(err);
74 | });
75 |
--------------------------------------------------------------------------------
/resources/resource-group.js:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Create an Azure resource group.
4 |
5 | Requires:
6 |
7 | Azure subscription already exists. Value is equired in the code:
8 | * "REPLACE-WITH-YOUR-SUBSCRIPTION-ID"
9 |
10 | Add your email alias, the part before the `@` symbol, to your naming convention:
11 | * "REPLACE-WITH-YOUR-EMAIL-ALIAS"
12 | * "REPLACE-WITH-YOUR-APP-NAME"
13 |
14 | References:
15 | * [Azure SDK Ref Docs for Resources](https://docs.microsoft.com/en-us/javascript/api/overview/azure/resources)
16 |
17 | */
18 |
19 | const { InteractiveBrowserCredential } = require("@azure/identity");
20 | const { ResourceManagementClient } = require("@azure/arm-resources");
21 |
22 | const myEmailAlias =
23 | process.env["EMAIL-ALIAS"] || "REPLACE-WITH-YOUR-EMAIL-ALIAS";
24 | const myAppName = process.env["APP-NAME"] || "REPLACE-WITH-YOUR-APP-NAME";
25 |
26 | const subscriptionId =
27 | process.env["SUBSCRIPTION-ID"] || "REPLACE-WITH-YOUR-SUBSCRIPTION-ID";
28 |
29 | const resourceCreatedDate = new Date().toISOString();
30 | const resourceGroupName = `${myAppName}-resource-group`;
31 | const resourceGroupLocation = "eastus";
32 | const resourceGroupFilter = `tagName eq 'owner' and tagValue eq '${myEmailAlias}'`;
33 | const resourceGroupTop = 10;
34 |
35 | const credential = new InteractiveBrowserCredential();
36 |
37 | async function resourceGroupActions(credential) {
38 | try {
39 | const resourceManagement = new ResourceManagementClient(
40 | credential,
41 | subscriptionId
42 | );
43 |
44 | // Create
45 | const parameters = {
46 | location: resourceGroupLocation,
47 | tags: {
48 | owner: myEmailAlias,
49 | created: resourceCreatedDate,
50 | },
51 | };
52 | console.log("Creating...");
53 | const createResult = await resourceManagement.resourceGroups.createOrUpdate(
54 | resourceGroupName,
55 | parameters
56 | );
57 | console.log(JSON.stringify(createResult));
58 |
59 | // Check existence - returns boolean
60 | console.log("Exists...");
61 | const checkExistenceResult = await resourceManagement.resourceGroups.checkExistence(
62 | resourceGroupName
63 | );
64 | console.log(JSON.stringify(checkExistenceResult));
65 |
66 | // List filtered by tag name and value
67 | const properties = {
68 | filter: resourceGroupFilter,
69 | top: resourceGroupTop,
70 | };
71 | console.log("Filtered...");
72 | const filteredListReturn = new Array();
73 | for await (const item of resourceManagement.resourceGroups.list(
74 | properties
75 | )) {
76 | filteredListReturn.push(item);
77 | }
78 | console.log(JSON.stringify(filteredListReturn));
79 |
80 | // List all
81 | console.log("All...");
82 | const allListResult = new Array();
83 | for await (const item of resourceManagement.resourceGroups.list()) {
84 | allListResult.push(item);
85 | }
86 | console.log(JSON.stringify(allListResult));
87 |
88 | // Delete - HTTP status 200 on success, no body
89 | console.log("Deleting...");
90 | const deleteResult = await resourceManagement.resourceGroups.deleteMethod(
91 | resourceGroupName
92 | );
93 | console.log(JSON.stringify(deleteResult));
94 | } catch (err) {
95 | console.log(err);
96 | }
97 | }
98 |
99 | resourceGroupActions(credential)
100 | .then((res) => {
101 | console.log(JSON.stringify(res));
102 | })
103 | .catch((err) => {
104 | console.log(err);
105 | });
--------------------------------------------------------------------------------
/resources/resource-groups-list/README.md:
--------------------------------------------------------------------------------
1 | # View resource groups in subscription
2 |
3 | 1. Sign in to Azure CLI in terminal.
4 |
5 | ```bash
6 | az login
7 | ```
8 |
9 |
10 | 1. Create service principal with Azure CLI, replace `YOUR-SERVICE-PRINCIPAL-NAME` with a name
11 | such as `joesmith-quickstart-azure`:
12 |
13 | ```bash
14 | az ad sp create-for-rbac --name YOUR-SERVICE-PRINCIPAL-NAME
15 | ```
16 |
17 | 1. Save the output in a secure location such as Azure Key vault
18 |
19 | ```json
20 | {
21 | "appId": "717...",
22 | "displayName": "joesmith-quickstart-azure",
23 | "name": "http://joesmith-quickstart-azure",
24 | "password": "PEG...",
25 | "tenant": "72f..."
26 | }
27 | ```
28 |
29 | 1. Create new environment variables. These environment variables are REQUIRED for the context to use DefaultAzureCredential.
30 |
31 | ```
32 | AZURE_TENANT_ID: `tenant` from the service principal output above.
33 | AZURE_CLIENT_ID: `appId` from the service principal output above.
34 | AZURE_CLIENT_SECRET: `password` from the service principal output above.
35 | AZURE_SUBSCRIPTION: Your default subscription containing your resource groups.
36 | ```
37 |
38 | 1. Complete the following commands from a bash terminal to install package dependencies:
39 |
40 | ```bash
41 | npm install @azure/identity @azure/arm-resources stringify-object
42 | ```
43 |
44 | Note: `stringify-object` is only used to provide readable JSON. It is
45 | not required to use Azure SDKs.
46 |
47 | 1. Run this script from a bash terminal to see a list of resource groups in your default subscription:
48 |
49 | ```bash
50 | npm start
51 | ```
52 |
53 | 1. Pretty output looks like
54 |
55 | ```JSON
56 | [
57 | {
58 | id: "/subscriptions/bb8.../resourceGroups/DefaultResourceGroup-WUS2",
59 | name: "DefaultResourceGroup-WUS2",
60 | type: "Microsoft.Resources/resourceGroups",
61 | properties: {
62 | provisioningState: "Succeeded"
63 | },
64 | location: "westus2",
65 | tags: {}
66 | },
67 | {
68 | ...
69 | }
70 | ]
71 | ```
--------------------------------------------------------------------------------
/resources/resource-groups-list/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "resource-groups-list",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "resource-groups-list.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "start": "node resource-groups-list.js"
9 | },
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "@azure/arm-resources": "^5.0.0",
14 | "@azure/identity": "^1.5.2"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/resources/resource-groups-list/resource-groups-list.js:
--------------------------------------------------------------------------------
1 | // Include npm dependencies
2 | const { DefaultAzureCredential } = require("@azure/identity");
3 | const { ResourceManagementClient } = require("@azure/arm-resources");
4 |
5 | // Get subscription from environment variables
6 | const subscriptionId = process.env["AZURE_SUBSCRIPTION"];
7 | if (!subscriptionId)
8 | throw Error("Azure Subscription is missing from environment variables.");
9 |
10 | // The following code is only used to check you have environment
11 | // variables configured. The DefaultAzureCredential reads your
12 | // environment - it doesn't read these variables.
13 | const tenantId = process.env["AZURE_TENANT_ID"];
14 | if (!tenantId)
15 | throw Error("AZURE_TENANT_ID is missing from environment variables.");
16 | const clientId = process.env["AZURE_CLIENT_ID"];
17 | if (!clientId)
18 | throw Error("AZURE_CLIENT_ID is missing from environment variables.");
19 | const secret = process.env["AZURE_CLIENT_SECRET"];
20 | if (!secret)
21 | throw Error("AZURE_CLIENT_SECRET is missing from environment variables.");
22 |
23 | // Create Azure authentication credentials
24 | const credentials = new DefaultAzureCredential();
25 |
26 | try {
27 | // Create Azure SDK client for Resource Management such as resource groups
28 | const resourceManagement = new ResourceManagementClient(
29 | credentials,
30 | subscriptionId
31 | );
32 |
33 | // List resource groups in subscription
34 | const result = new Array();
35 | for await (const item of resourceManagement.resourceGroups.list()) {
36 | result.push(item);
37 | }
38 | console.log(JSON.stringify(result));
39 | } catch (err) {
40 | console.log(err);
41 | }
42 |
--------------------------------------------------------------------------------
/resources/resources-list-in-subscription/list-resources-in-subscription.js:
--------------------------------------------------------------------------------
1 | // Include npm dependencies
2 | const { DefaultAzureCredential } = require("@azure/identity");
3 | const { ResourceManagementClient } = require("@azure/arm-resources");
4 |
5 | // Get subscription from environment variables
6 | const subscriptionId = process.env["AZURE_SUBSCRIPTION"];
7 | if (!subscriptionId)
8 | throw Error("Azure Subscription is missing from environment variables.");
9 |
10 | // The following code is only used to check you have environment
11 | // variables configured. The DefaultAzureCredential reads your
12 | // environment - it doesn't read these variables.
13 | const tenantId = process.env["AZURE_TENANT_ID"];
14 | if (!tenantId)
15 | throw Error("AZURE_TENANT_ID is missing from environment variables.");
16 | const clientId = process.env["AZURE_CLIENT_ID"];
17 | if (!clientId)
18 | throw Error("AZURE_CLIENT_ID is missing from environment variables.");
19 | const secret = process.env["AZURE_CLIENT_SECRET"];
20 | if (!secret)
21 | throw Error("AZURE_CLIENT_SECRET is missing from environment variables.");
22 |
23 | // Create Azure authentication credentials
24 | const credentials = new DefaultAzureCredential();
25 |
26 | try {
27 | // Create Azure SDK client for Resource Management such as resource groups
28 | const resourceManagement = new ResourceManagementClient(
29 | credentials,
30 | subscriptionId
31 | );
32 |
33 | // List resource groups in subscription
34 | const result = new Array();
35 | for await (const item of resourceManagement.resources.list()) {
36 | result.push(item);
37 | }
38 | console.log(JSON.stringify(result));
39 | } catch (err) {
40 | console.log(err);
41 | }
42 |
--------------------------------------------------------------------------------
/resources/subscriptions/list-locations.js:
--------------------------------------------------------------------------------
1 | const { DefaultAzureCredential } = require("@azure/identity");
2 | const { SubscriptionClient } = require("@azure/arm-subscriptions");
3 |
4 | // Get subscription from environment variables
5 | const subscriptionId = process.env["AZURE_SUBSCRIPTION"];
6 | if (!subscriptionId)
7 | throw Error("Azure Subscription is missing from environment variables.");
8 |
9 | // The following code is only used to check you have environment
10 | // variables configured. The DefaultAzureCredential reads your
11 | // environment - it doesn't read these variables.
12 | const tenantId = process.env["AZURE_TENANT_ID"];
13 | if (!tenantId)
14 | throw Error("AZURE_TENANT_ID is missing from environment variables.");
15 | const clientId = process.env["AZURE_CLIENT_ID"];
16 | if (!clientId)
17 | throw Error("AZURE_CLIENT_ID is missing from environment variables.");
18 | const secret = process.env["AZURE_CLIENT_SECRET"];
19 | if (!secret)
20 | throw Error("AZURE_CLIENT_SECRET is missing from environment variables.");
21 |
22 | if (!subscriptionId || !tenantId || !clientId || !secret) return;
23 |
24 | try {
25 | const credentials = new DefaultAzureCredential();
26 |
27 | // Create Azure SDK client for Resource Management such as resource groups
28 | const client = new SubscriptionClient(credentials, subscriptionId);
29 |
30 | // List resource groups in subscription
31 | const result = new Array();
32 | for await (const item of client.subscriptions.listLocations(subscriptionId)) {
33 | result.push(item);
34 | }
35 | console.log("The result is");
36 | console.log(JSON.stringify(result));
37 | } catch (err) {
38 | console.log("An error occurred:");
39 | console.error(err);
40 | }
41 |
--------------------------------------------------------------------------------
/resources/subscriptions/list.js:
--------------------------------------------------------------------------------
1 | const {
2 | ClientSecretCredential,
3 | DefaultAzureCredential,
4 | } = require("@azure/identity");
5 | const { SubscriptionClient } = require("@azure/arm-subscriptions");
6 | require("dotenv").config();
7 |
8 | let credentials = null;
9 |
10 | const tenantId = process.env["AZURE_TENANT_ID"];
11 | const clientId = process.env["AZURE_CLIENT_ID"];
12 | const secret = process.env["AZURE_CLIENT_SECRET"];
13 |
14 | if (process.env.NODE_ENV && process.env.NODE_ENV === "production") {
15 | // production
16 | credentials = new DefaultAzureCredential();
17 | } else {
18 | // development
19 | if (tenantId && clientId && secret) {
20 | console.log("development");
21 | credentials = new ClientSecretCredential(tenantId, clientId, secret);
22 | } else {
23 | credentials = new DefaultAzureCredential();
24 | }
25 | }
26 |
27 | async function listSubscriptions() {
28 | try {
29 | // use credential to authenticate with Azure SDKs
30 | const client = new SubscriptionClient(credentials);
31 |
32 | // get details of each subscription
33 | for await (const item of client.subscriptions.list()) {
34 | const subscriptionDetails = await client.subscriptions.get(
35 | item.subscriptionId
36 | );
37 | /*
38 | Each item looks like:
39 |
40 | {
41 | id: '/subscriptions/123456',
42 | subscriptionId: '123456',
43 | displayName: 'YOUR-SUBSCRIPTION-NAME',
44 | state: 'Enabled',
45 | subscriptionPolicies: {
46 | locationPlacementId: 'Internal_2014-09-01',
47 | quotaId: 'Internal_2014-09-01',
48 | spendingLimit: 'Off'
49 | },
50 | authorizationSource: 'RoleBased'
51 | },
52 | */
53 | console.log(subscriptionDetails);
54 | }
55 | } catch (err) {
56 | console.error(JSON.stringify(err));
57 | }
58 | }
59 |
60 | listSubscriptions()
61 | .then(() => {
62 | console.log("done");
63 | })
64 | .catch((ex) => {
65 | console.log(ex);
66 | });
67 |
--------------------------------------------------------------------------------
/resources/subscriptions/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "subscriptions",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "list-locations.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "@azure/arm-subscriptions": "^5.0.0",
13 | "@azure/identity": "^1.5.2",
14 | "dotenv": "^16.0.0"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/resources/virtual-machines/README.md:
--------------------------------------------------------------------------------
1 | # Create, manage, and delete a virtual machine
2 |
3 | A virtual machine is a collection of Azure resources. To use these scripts:
4 |
5 | * Create a service principal
6 | * Add Azure authentication environment variables or change variables in the code files.
7 | * Install dependences
8 |
9 | ```bash
10 | npm install
11 | ```
12 |
13 | * Change any variables specific to your use. For the VM creation script, the two variables are:
14 |
15 | ```javascript
16 | // CHANGE THIS - used as prefix for naming resources
17 | const yourAlias = "johnsmith";
18 |
19 | // CHANGE THIS - used to add tags to resources
20 | const projectName = "azure-samples-create-vm";
21 | ```
22 |
23 | ## Create a VM
24 |
25 | Use the [create vm](create-vm.js) file to create resources associated with a VM. Review the file to change any preset values such as pricing tier, user name and password.
26 |
27 | ## Manage a VM
28 |
29 | Use the management scripts to:
30 |
31 | * [Start a VM](start-vm.js)
32 | * [Stop a VM](stop-vm.js)
33 | * [Get VM information](vm-info.js)
34 | * [List VMs in subscription](list-vms.js)
35 |
36 | ## Delete a VM
37 |
38 | Because there are several resources associated with a VM, the easiest way to delete a VM is to delete the resource group. Use the [delete vm](delete-resources.js) file to delete the resource group.
39 |
--------------------------------------------------------------------------------
/resources/virtual-machines/delete-resources.js:
--------------------------------------------------------------------------------
1 | const {
2 | ClientSecretCredential,
3 | DefaultAzureCredential,
4 | } = require("@azure/identity");
5 | const { ResourceManagementClient } = require("@azure/arm-resources");
6 |
7 | // Azure authentication in environment variables for DefaultAzureCredential
8 | let credentials = null;
9 | const tenantId =
10 | process.env["AZURE_TENANT_ID"] || "REPLACE-WITH-YOUR-TENANT-ID";
11 | const clientId =
12 | process.env["AZURE_CLIENT_ID"] || "REPLACE-WITH-YOUR-CLIENT-ID";
13 | const secret =
14 | process.env["AZURE_CLIENT_SECRET"] || "REPLACE-WITH-YOUR-CLIENT-SECRET";
15 | const subscriptionId =
16 | process.env["AZURE_SUBSCRIPTION_ID"] || "REPLACE-WITH-YOUR-SUBSCRIPTION_ID";
17 |
18 | const resourceGroupName = "REPLACE-WITH-YOUR-RESOURCE_GROUP-NAME";
19 |
20 | if (process.env.production) {
21 | // production
22 | credentials = new DefaultAzureCredential();
23 | } else {
24 | // development
25 | credentials = new ClientSecretCredential(tenantId, clientId, secret);
26 | console.log("development");
27 | }
28 |
29 | async function deleteResourceGroup() {
30 | // Create Azure SDK client for Resource Management such as resource groups
31 | const resourceClient = new ResourceManagementClient(
32 | credentials,
33 | subscriptionId
34 | );
35 |
36 | const result = await resourceClient.resourceGroups.deleteMethod(
37 | resourceGroupName
38 | );
39 | console.log(JSON.stringify(result));
40 | }
41 |
42 | deleteResourceGroup()
43 | .then((result) => {
44 | console.log(result);
45 | })
46 | .catch((ex) => {
47 | console.log(ex);
48 | });
49 |
--------------------------------------------------------------------------------
/resources/virtual-machines/list-vms.js:
--------------------------------------------------------------------------------
1 | const {
2 | ClientSecretCredential,
3 | DefaultAzureCredential,
4 | } = require("@azure/identity");
5 | const { ComputeManagementClient } = require("@azure/arm-compute");
6 |
7 | // Azure authentication in environment variables for DefaultAzureCredential
8 | let credentials = null;
9 | const tenantId =
10 | process.env["AZURE_TENANT_ID"] || "REPLACE-WITH-YOUR-TENANT-ID";
11 | const clientId =
12 | process.env["AZURE_CLIENT_ID"] || "REPLACE-WITH-YOUR-CLIENT-ID";
13 | const secret =
14 | process.env["AZURE_CLIENT_SECRET"] || "REPLACE-WITH-YOUR-CLIENT-SECRET";
15 | const subscriptionId =
16 | process.env["AZURE_SUBSCRIPTION_ID"] || "REPLACE-WITH-YOUR-SUBSCRIPTION_ID";
17 |
18 | if (process.env.production) {
19 | // production
20 | credentials = new DefaultAzureCredential();
21 | } else {
22 | // development
23 | credentials = new ClientSecretCredential(tenantId, clientId, secret);
24 | console.log("development");
25 | }
26 |
27 | async function listVMs() {
28 | // use credential to authenticate with Azure SDKs
29 | const client = new ComputeManagementClient(credentials, subscriptionId);
30 |
31 | // get details of each subscription
32 | const listResult = new Array();
33 | for await (const item of client.virtualMachines.listAll()) {
34 | listResult.push(item);
35 | }
36 | return listResult;
37 |
38 | /*
39 | Result is an array of items. Each item looks something like:
40 |
41 | {
42 | "id": "/subscriptions/123456/resourceGroups/johnsmith-TESTRG3215/providers/Microsoft.Compute/virtualMachines/johnsmithvm6859",
43 | "name": "johnsmithvm6859",
44 | "type": "Microsoft.Compute/virtualMachines",
45 | "location": "eastus",
46 | "hardwareProfile": { "vmSize": "Standard_B1ls" },
47 | "storageProfile": {
48 | "imageReference": {
49 | "publisher": "Canonical",
50 | "offer": "UbuntuServer",
51 | "sku": "14.04.3-LTS",
52 | "version": "14.04.201805220",
53 | "exactVersion": "14.04.201805220"
54 | },
55 | "osDisk": {
56 | "osType": "Linux",
57 | "name": "johnsmithosdisk9293",
58 | "vhd": {
59 | "uri": "https://johnsmithac1195.blob.core.windows.net/nodejscontainer/osnodejslinux.vhd"
60 | },
61 | "caching": "None",
62 | "createOption": "FromImage",
63 | "diskSizeGB": 30,
64 | "deleteOption": "Detach"
65 | },
66 | "dataDisks": []
67 | },
68 | "osProfile": {
69 | "computerName": "johnsmithvm6859",
70 | "adminUsername": "notadmin",
71 | "linuxConfiguration": {
72 | "disablePasswordAuthentication": false,
73 | "provisionVMAgent": true,
74 | "patchSettings": {
75 | "patchMode": "ImageDefault",
76 | "assessmentMode": "ImageDefault"
77 | }
78 | },
79 | "secrets": [],
80 | "allowExtensionOperations": true,
81 | "requireGuestProvisionSignal": true
82 | },
83 | "networkProfile": {
84 | "networkInterfaces": [
85 | {
86 | "id": "/subscriptions/123456/resourceGroups/johnsmith-testrg3215/providers/Microsoft.Network/networkInterfaces/johnsmithnic7962",
87 | "primary": true
88 | }
89 | ]
90 | },
91 | "provisioningState": "Succeeded",
92 | "vmId": "987654"
93 | }
94 |
95 | */
96 | }
97 |
98 | listVMs()
99 | .then((result) => {
100 | console.log(result);
101 | })
102 | .catch((err) => {
103 | console.log(err);
104 | });
105 |
--------------------------------------------------------------------------------
/resources/virtual-machines/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "virtual-machines",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "create-vm.js",
6 | "dependencies": {
7 | "@azure/arm-compute": "^17.2.0",
8 | "@azure/arm-network": "^26.0.0",
9 | "@azure/arm-resources": "^5.0.0",
10 | "@azure/arm-storage": "^17.1.0",
11 | "@azure/identity": "^2.0.0"
12 | },
13 | "scripts": {
14 | "test": "echo \"Error: no test specified\" && exit 1"
15 | },
16 | "keywords": [],
17 | "author": "",
18 | "license": "ISC"
19 | }
20 |
--------------------------------------------------------------------------------
/resources/virtual-machines/start-vm.js:
--------------------------------------------------------------------------------
1 | const {
2 | ClientSecretCredential,
3 | DefaultAzureCredential,
4 | } = require("@azure/identity");
5 | const { ComputeManagementClient } = require("@azure/arm-compute");
6 |
7 | // Azure authentication in environment variables for DefaultAzureCredential
8 | let credentials = null;
9 | const tenantId =
10 | process.env["AZURE_TENANT_ID"] || "REPLACE-WITH-YOUR-TENANT-ID";
11 | const clientId =
12 | process.env["AZURE_CLIENT_ID"] || "REPLACE-WITH-YOUR-CLIENT-ID";
13 | const secret =
14 | process.env["AZURE_CLIENT_SECRET"] || "REPLACE-WITH-YOUR-CLIENT-SECRET";
15 | const subscriptionId =
16 | process.env["AZURE_SUBSCRIPTION_ID"] || "REPLACE-WITH-YOUR-SUBSCRIPTION_ID";
17 |
18 | const resourceGroupName = "REPLACE-WITHYOUR-RESOURCE_GROUP-NAME";
19 | const vmResourceName = "REPLACE-WITHYOUR-RESOURCE-NAME";
20 |
21 | if (process.env.production) {
22 | // production
23 | credentials = new DefaultAzureCredential();
24 | } else {
25 | // development
26 | credentials = new ClientSecretCredential(tenantId, clientId, secret);
27 | console.log("development");
28 | }
29 |
30 | async function startVM() {
31 | const computeClient = new ComputeManagementClient(
32 | credentials,
33 | subscriptionId
34 | );
35 | const result = await computeClient.virtualMachines.start(
36 | resourceGroupName,
37 | vmResourceName
38 | );
39 | return result;
40 | }
41 |
42 | startVM()
43 | .then((result) => {
44 | console.log(JSON.stringify(result));
45 | })
46 | .catch((err) => {
47 | console.log(err);
48 | });
49 |
50 | /*
51 |
52 | Start operation results:
53 |
54 | {
55 | "startTime":"2021-10-27T16:35:59.6006484+00:00",
56 | "endTime":"2021-10-27T16:35:59.850632+00:00",
57 | "status":"Succeeded",
58 | "name":"1773c5e7-d904-4f98-b2a6-6e2f2465407f"
59 | }
60 |
61 | */
62 |
--------------------------------------------------------------------------------
/resources/virtual-machines/status-vms-all.js:
--------------------------------------------------------------------------------
1 | const {
2 | ClientSecretCredential,
3 | DefaultAzureCredential,
4 | } = require("@azure/identity");
5 | const { ComputeManagementClient } = require("@azure/arm-compute");
6 |
7 | // Azure authentication in environment variables for DefaultAzureCredential
8 | let credentials = null;
9 | const tenantId =
10 | process.env["AZURE_TENANT_ID"] || "REPLACE-WITH-YOUR-TENANT-ID";
11 | const clientId =
12 | process.env["AZURE_CLIENT_ID"] || "REPLACE-WITH-YOUR-CLIENT-ID";
13 | const secret =
14 | process.env["AZURE_CLIENT_SECRET"] || "REPLACE-WITH-YOUR-CLIENT-SECRET";
15 | const subscriptionId =
16 | process.env["AZURE_SUBSCRIPTION_ID"] || "REPLACE-WITH-YOUR-SUBSCRIPTION_ID";
17 |
18 | if (process.env.production) {
19 | // production
20 | credentials = new DefaultAzureCredential();
21 | } else {
22 | // development
23 | credentials = new ClientSecretCredential(tenantId, clientId, secret);
24 | }
25 |
26 | const listVMsStatus = async () => {
27 |
28 | // Set params to only ask for status
29 | const virtualMachinesListAllOptionalParams = {
30 | statusOnly: "true",
31 | };
32 |
33 | const computeClient = new ComputeManagementClient(
34 | credentials,
35 | subscriptionId
36 | );
37 | const result = await computeClient.virtualMachines.listAll(
38 | virtualMachinesListAllOptionalParams
39 | );
40 | result.map((vm) => {
41 | console.log(`${vm.name}`);
42 | vm.instanceView.statuses.map((status) => {
43 | console.log(
44 | `---${status.displayStatus}${status.time && status.time.length > 0 ? status.time : ""}`
45 | );
46 | });
47 | });
48 | };
49 |
50 | listVMsStatus()
51 | .then((result) => {
52 | console.log(result);
53 | })
54 | .catch((ex) => {
55 | console.log(ex);
56 | });
57 |
58 | /*
59 | Result is an array of VMs with only status. Each item looks something like:
60 |
61 | {
62 | id: "/subscriptions/123456/resourceGroups/JohnSmith-TESTRG3215/providers/Microsoft.Compute/virtualMachines/JohnSmithvm6859",
63 | name: "JohnSmithvm6859",
64 | type: "Microsoft.Compute/virtualMachines",
65 | location: "eastus",
66 | hardwareProfile: {},
67 | provisioningState: "Succeeded",
68 | instanceView: {
69 | statuses: [
70 | {
71 | code: "ProvisioningState/succeeded",
72 | level: "Info",
73 | displayStatus: "Provisioning succeeded",
74 | time: "2021-10-28T17:41:03.453Z",
75 | },
76 | {
77 | code: "PowerState/running",
78 | level: "Info",
79 | displayStatus: "VM running",
80 | },
81 | ],
82 | },
83 | vmId: "987654",
84 | }
85 |
86 | */
87 |
--------------------------------------------------------------------------------
/resources/virtual-machines/status.js:
--------------------------------------------------------------------------------
1 | const {
2 | ClientSecretCredential,
3 | DefaultAzureCredential,
4 | } = require("@azure/identity");
5 | const { ComputeManagementClient } = require("@azure/arm-compute");
6 |
7 | // Azure authentication in environment variables for DefaultAzureCredential
8 | let credentials = null;
9 | const tenantId =
10 | process.env["AZURE_TENANT_ID"] || "REPLACE-WITH-YOUR-TENANT-ID";
11 | const clientId =
12 | process.env["AZURE_CLIENT_ID"] || "REPLACE-WITH-YOUR-CLIENT-ID";
13 | const secret =
14 | process.env["AZURE_CLIENT_SECRET"] || "REPLACE-WITH-YOUR-CLIENT-SECRET";
15 | const subscriptionId =
16 | process.env["AZURE_SUBSCRIPTION_ID"] || "REPLACE-WITH-YOUR-SUBSCRIPTION_ID";
17 |
18 | if (process.env.production) {
19 | // production
20 | credentials = new DefaultAzureCredential();
21 | } else {
22 | // development
23 | credentials = new ClientSecretCredential(tenantId, clientId, secret);
24 | }
25 |
26 | async function listVMsStatus() {
27 | // Set params to only ask for status
28 | const virtualMachinesListAllOptionalParams = { statusOnly: "true" };
29 |
30 | const computeClient = new ComputeManagementClient(
31 | credentials,
32 | subscriptionId
33 | );
34 |
35 | const result = new Array();
36 | for await (const item of computeClient.virtualMachines.listAll(
37 | virtualMachinesListAllOptionalParams
38 | )) {
39 | result.push(item);
40 | }
41 | result.map((vm) => {
42 | console.log(`${vm.name}`);
43 | vm.instanceView.statuses.map((status) => {
44 | console.log(
45 | `---${status.displayStatus} ${status.time ? status.time : ""}`
46 |
47 | /*
48 | Example:
49 | johnsmithvm6859
50 | ---Provisioning succeeded Thu Oct 28 2021 10:41:03 GMT-0700 (Pacific Daylight Time)
51 | ---VM running
52 | */
53 | );
54 | });
55 | });
56 | }
57 |
58 | listVMsStatus()
59 | .then((result) => {
60 | console.log("done");
61 | })
62 | .catch((ex) => {
63 | console.log(ex);
64 | });
65 |
66 | /*
67 | Result is an array of VMs with only status. Each item looks something like:
68 |
69 | {
70 | id: "/subscriptions/123456/resourceGroups/JohnSmith-TESTRG3215/providers/Microsoft.Compute/virtualMachines/JohnSmithvm6859",
71 | name: "JohnSmithvm6859",
72 | type: "Microsoft.Compute/virtualMachines",
73 | location: "eastus",
74 | hardwareProfile: {},
75 | provisioningState: "Succeeded",
76 | instanceView: {
77 | statuses: [
78 | {
79 | code: "ProvisioningState/succeeded",
80 | level: "Info",
81 | displayStatus: "Provisioning succeeded",
82 | time: "2021-10-28T17:41:03.453Z",
83 | },
84 | {
85 | code: "PowerState/running",
86 | level: "Info",
87 | displayStatus: "VM running",
88 | },
89 | ],
90 | },
91 | vmId: "987654",
92 | }
93 |
94 | */
95 |
--------------------------------------------------------------------------------
/resources/virtual-machines/stop-vm.js:
--------------------------------------------------------------------------------
1 | const {
2 | ClientSecretCredential,
3 | DefaultAzureCredential,
4 | } = require("@azure/identity");
5 | const { ComputeManagementClient } = require("@azure/arm-compute");
6 |
7 | // Azure authentication in environment variables for DefaultAzureCredential
8 | let credentials = null;
9 | const tenantId =
10 | process.env["AZURE_TENANT_ID"] || "REPLACE-WITH-YOUR-TENANT-ID";
11 | const clientId =
12 | process.env["AZURE_CLIENT_ID"] || "REPLACE-WITH-YOUR-CLIENT-ID";
13 | const secret =
14 | process.env["AZURE_CLIENT_SECRET"] || "REPLACE-WITH-YOUR-CLIENT-SECRET";
15 | const subscriptionId =
16 | process.env["AZURE_SUBSCRIPTION_ID"] || "REPLACE-WITH-YOUR-SUBSCRIPTION_ID";
17 |
18 | const resourceGroupName = "REPLACE-WITHYOUR-RESOURCE_GROUP-NAME";
19 | const vmResourceName = "REPLACE-WITHYOUR-RESOURCE-NAME";
20 |
21 | if (process.env.production) {
22 | // production
23 | credentials = new DefaultAzureCredential();
24 | } else {
25 | // development
26 | credentials = new ClientSecretCredential(tenantId, clientId, secret);
27 | console.log("development");
28 | }
29 |
30 | async function stopVM() {
31 | const computeClient = new ComputeManagementClient(
32 | credentials,
33 | subscriptionId
34 | );
35 | const result = await computeClient.virtualMachines.powerOff(
36 | resourceGroupName,
37 | vmResourceName
38 | );
39 | return result;
40 | }
41 |
42 | stopVM()
43 | .then((result) => {
44 | console.log(JSON.stringify(result));
45 | })
46 | .catch((err) => {
47 | console.log(err);
48 | });
49 | /*
50 |
51 | Stop operation results:
52 |
53 | {
54 | "startTime":"2021-10-27T16:35:59.6006484+00:00",
55 | "endTime":"2021-10-27T16:35:59.850632+00:00",
56 | "status":"Succeeded",
57 | "name":"1773c5e7-d904-4f98-b2a6-6e2f2465407f"
58 | }
59 |
60 | */
61 |
--------------------------------------------------------------------------------
/resources/virtual-machines/vm-info.js:
--------------------------------------------------------------------------------
1 | const {
2 | ClientSecretCredential,
3 | DefaultAzureCredential,
4 | } = require("@azure/identity");
5 | const { ComputeManagementClient } = require("@azure/arm-compute");
6 |
7 | // Azure authentication in environment variables for DefaultAzureCredential
8 | let credentials = null;
9 | const tenantId =
10 | process.env["AZURE_TENANT_ID"] || "REPLACE-WITH-YOUR-TENANT-ID";
11 | const clientId =
12 | process.env["AZURE_CLIENT_ID"] || "REPLACE-WITH-YOUR-CLIENT-ID";
13 | const secret =
14 | process.env["AZURE_CLIENT_SECRET"] || "REPLACE-WITH-YOUR-CLIENT-SECRET";
15 | const subscriptionId =
16 | process.env["AZURE_SUBSCRIPTION_ID"] || "REPLACE-WITH-YOUR-SUBSCRIPTION_ID";
17 |
18 | const resourceGroupName = "REPLACE-WITHYOUR-RESOURCE_GROUP-NAME";
19 | const vmResourceName = "REPLACE-WITHYOUR-RESOURCE-NAME";
20 |
21 | if (process.env.production) {
22 | // production
23 | credentials = new DefaultAzureCredential();
24 | } else {
25 | // development
26 | credentials = new ClientSecretCredential(tenantId, clientId, secret);
27 | console.log("development");
28 | }
29 |
30 | async function getVmInfo() {
31 | const computeClient = new ComputeManagementClient(
32 | credentials,
33 | subscriptionId
34 | );
35 | const result = await computeClient.virtualMachines.get(
36 | resourceGroupName,
37 | vmResourceName
38 | );
39 | return result;
40 | }
41 |
42 | getVmInfo()
43 | .then((result) => {
44 | console.log(JSON.stringify(result));
45 | })
46 | .catch((err) => {
47 | console.log(err);
48 | });
49 |
50 | /*
51 | {
52 | "id": "/subscriptions/123456/resourceGroups/johnsmith-testrg3215/providers/Microsoft.Compute/virtualMachines/johnsmithvm6859",
53 | "name": "johnsmithvm6859",
54 | "type": "Microsoft.Compute/virtualMachines",
55 | "location": "eastus",
56 | "hardwareProfile": { "vmSize": "Standard_B1ls" },
57 | "storageProfile": {
58 | "imageReference": {
59 | "publisher": "Canonical",
60 | "offer": "UbuntuServer",
61 | "sku": "14.04.3-LTS",
62 | "version": "14.04.201805220",
63 | "exactVersion": "14.04.201805220"
64 | },
65 | "osDisk": {
66 | "osType": "Linux",
67 | "name": "johnsmithosdisk9293",
68 | "vhd": {
69 | "uri": "https://johnsmithac1195.blob.core.windows.net/nodejscontainer/osnodejslinux.vhd"
70 | },
71 | "caching": "None",
72 | "createOption": "FromImage",
73 | "diskSizeGB": 30,
74 | "deleteOption": "Detach"
75 | },
76 | "dataDisks": []
77 | },
78 | "osProfile": {
79 | "computerName": "johnsmithvm6859",
80 | "adminUsername": "notadmin",
81 | "linuxConfiguration": {
82 | "disablePasswordAuthentication": false,
83 | "provisionVMAgent": true,
84 | "patchSettings": {
85 | "patchMode": "ImageDefault",
86 | "assessmentMode": "ImageDefault"
87 | }
88 | },
89 | "secrets": [],
90 | "allowExtensionOperations": true,
91 | "requireGuestProvisionSignal": true
92 | },
93 | "networkProfile": {
94 | "networkInterfaces": [
95 | {
96 | "id": "/subscriptions/123456/resourceGroups/johnsmith-testrg3215/providers/Microsoft.Network/networkInterfaces/johnsmithnic7962",
97 | "primary": true
98 | }
99 | ]
100 | },
101 | "provisioningState": "Succeeded",
102 | "vmId": "987654"
103 | }
104 | */
105 |
--------------------------------------------------------------------------------
/search/bulk-insert-books-from-csv/books.schema.json:
--------------------------------------------------------------------------------
1 | {
2 | "fields": [
3 | {
4 | "key": true,
5 | "name": "id",
6 | "type": "Edm.String",
7 | "retrievable": true
8 | },
9 | {
10 | "name": "goodreads_book_id",
11 | "type": "Edm.String",
12 | "retrievable": true
13 | },
14 | {
15 | "name": "best_book_id",
16 | "type": "Edm.String",
17 | "retrievable": true
18 | },
19 | {
20 | "name": "work_id",
21 | "type": "Edm.String",
22 | "retrievable": true
23 | },
24 | {
25 | "name": "books_count",
26 | "type": "Edm.Double",
27 | "retrievable": true
28 | },
29 | {
30 | "name": "isbn",
31 | "type": "Edm.String",
32 | "retrievable": true,
33 | "searchable": true,
34 | "analyzer": "standard.lucene"
35 | },
36 | {
37 | "name": "isbn13",
38 | "type": "Edm.String",
39 | "retrievable": true
40 | },
41 | {
42 | "name": "authors",
43 | "type": "Collection(Edm.String)",
44 | "retrievable": true,
45 | "filterable": true,
46 | "searchable": true,
47 | "facetable":true,
48 | "analyzer": "en.lucene"
49 | },
50 | {
51 | "name": "original_publication_year",
52 | "type": "Edm.Int32",
53 | "retrievable": true
54 | },
55 | {
56 | "name": "original_title",
57 | "type": "Edm.String",
58 | "retrievable": true,
59 | "searchable": true,
60 | "analyzer": "en.lucene"
61 | },
62 | {
63 | "name": "title",
64 | "type": "Edm.String",
65 | "retrievable": true,
66 | "searchable": true,
67 | "analyzer": "en.lucene"
68 | },
69 | {
70 | "name": "language_code",
71 | "type": "Edm.String",
72 | "retrievable": true,
73 | "filterable": true,
74 | "facetable": true
75 | },
76 | {
77 | "name": "average_rating",
78 | "type": "Edm.Int32",
79 | "retrievable": true,
80 | "filterable": true,
81 | "sortable": true
82 | },
83 | {
84 | "name": "ratings_count",
85 | "type": "Edm.Int32",
86 | "retrievable": true,
87 | "filterable": true,
88 | "facetable": true
89 | },
90 | {
91 | "name": "work_ratings_count",
92 | "type": "Edm.Int32",
93 | "retrievable": true
94 | },
95 | {
96 | "name": "work_text_reviews_count",
97 | "type": "Edm.Int32",
98 | "retrievable": true
99 | },
100 | {
101 | "name": "ratings_1",
102 | "type": "Edm.Int32",
103 | "retrievable": true
104 | },
105 | {
106 | "name": "ratings_2",
107 | "type": "Edm.Int32",
108 | "retrievable": true
109 | },
110 | {
111 | "name": "ratings_3",
112 | "type": "Edm.Int32",
113 | "retrievable": true
114 | },
115 | {
116 | "name": "ratings_4",
117 | "type": "Edm.Int32",
118 | "retrievable": true
119 | },
120 | {
121 | "name": "ratings_5",
122 | "type": "Edm.Int32",
123 | "retrievable": true
124 | },
125 | {
126 | "name": "image_url",
127 | "type": "Edm.String",
128 | "retrievable": true
129 | },
130 | {
131 | "name": "small_image_url",
132 | "type": "Edm.String",
133 | "retrievable": true
134 | }
135 | ],
136 | "suggesters": [
137 | {
138 | "name": "sg",
139 | "searchMode": "analyzingInfixMatching",
140 | "sourceFields": [
141 | "authors",
142 | "original_title"
143 | ]
144 | }
145 | ]
146 | }
--------------------------------------------------------------------------------
/search/bulk-insert-books-from-csv/bulk_insert_books.js:
--------------------------------------------------------------------------------
1 | // Works with Node.js 15+
2 |
3 | const fs = require('fs');
4 | const parse = require('csv-parser')
5 | const { finished } = require('stream/promises');
6 | const { SearchClient, SearchIndexClient, AzureKeyCredential } = require("@azure/search-documents");
7 |
8 | const SEARCH_ENDPOINT = "https://YOUR-RESOURCE-NAME.search.windows.net";
9 | const SEARCH_KEY = "YOUR-RESOURCE-KEY";
10 |
11 | const SEARCH_INDEX_NAME = "good-books";
12 | const csvFile = './books.csv'
13 | const schema = require("./books.schema.json");
14 |
15 | const client = new SearchClient(
16 | SEARCH_ENDPOINT,
17 | SEARCH_INDEX_NAME,
18 | new AzureKeyCredential(SEARCH_KEY)
19 | );
20 | const clientIndex = new SearchIndexClient(
21 | SEARCH_ENDPOINT,
22 | new AzureKeyCredential(SEARCH_KEY)
23 | );
24 |
25 |
26 | // insert each row into ...
27 | const insertData = async (readable) => {
28 |
29 | let i = 0;
30 |
31 | for await (const row of readable) {
32 | console.log(`${i++} = ${JSON.stringify(row)}`);
33 |
34 | const indexItem = {
35 | "id": row.book_id,
36 | "goodreads_book_id": row.goodreads_book_id,
37 | "best_book_id": row.best_book_id,
38 | "work_id": row.work_id,
39 | "books_count": !row.books_count ? 0 : parseInt(row.books_count),
40 | "isbn": row.isbn,
41 | "isbn13": row.isbn13,
42 | "authors": row.authors.split(",").map(name => name.trim()),
43 | "original_publication_year": !row.original_publication_year ? 0 : parseInt(row.original_publication_year),
44 | "original_title": row.original_title,
45 | "title": row.title,
46 | "language_code": row.language_code,
47 | "average_rating": !row.average_rating ? 0 : parseInt(row.average_rating),
48 | "ratings_count": !row.ratings_count ? 0 : parseInt(row.ratings_count),
49 | "work_ratings_count": !row.work_ratings_count ? 0 : parseInt(row.work_ratings_count),
50 | "work_text_reviews_count": !row.work_text_reviews_count ? 0 : parseInt(row.work_text_reviews_count),
51 | "ratings_1": !row.ratings_1 ? 0 : parseInt(row.ratings_1),
52 | "ratings_2": !row.ratings_2 ? 0 : parseInt(row.ratings_2),
53 | "ratings_3": !row.ratings_3 ? 0 : parseInt(row.ratings_3),
54 | "ratings_4": !row.ratings_4 ? 0 : parseInt(row.ratings_4),
55 | "ratings_5": !row.ratings_5 ? 0 : parseInt(row.ratings_5),
56 | "image_url": row.image_url,
57 | "small_image_url": row.small_image_url
58 | }
59 |
60 |
61 | const uploadResult = await client.uploadDocuments([indexItem]);
62 | }
63 |
64 | }
65 | const bulkInsert = async () => {
66 |
67 |
68 | // read file, parse CSV, each row is a chunk
69 | const readable = fs
70 | .createReadStream(csvFile)
71 | .pipe(parse());
72 |
73 | // Pipe rows to insert function
74 | await insertData(readable)
75 | }
76 | async function createIndex() {
77 |
78 | schema.name = SEARCH_INDEX_NAME;
79 | const result = await clientIndex.createIndex(schema);
80 |
81 | console.log(result);
82 | }
83 |
84 |
85 | const main = async () => {
86 |
87 | await createIndex();
88 | console.log("index created");
89 |
90 | await bulkInsert();
91 |
92 | }
93 |
94 |
95 | main()
96 | .then(() => console.log('done'))
97 | .catch((err) => {
98 | console.log(`done + failed ${err}`)
99 | });
100 |
--------------------------------------------------------------------------------
/search/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "search",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "@azure/search-documents": "^11.1.0",
14 | "csv-parser": "^3.0.0"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/search/readme.md:
--------------------------------------------------------------------------------
1 | # Azure Cognitive Search
2 |
3 | ## Create Search resource
4 |
5 | ```azurecli
6 |
7 | ```
8 |
9 |
10 | ## Bulk insert from CSV to Search
11 |
12 | Use `./bulk-insert-books-from-csv/bulk_insert_books.js` to bulk insert from `./bulk-insert-books-from-csv/books.csv` into a new Search index:
13 |
14 | * Get your resource name and key
15 | * Add/change in `./bulk-insert-books-from-csv/bulk_insert_books.js`
16 |
17 | ## Use Search in sample app
18 |
19 | * Use [azure-search-react-template](https://github.com/dereklegenzoff/azure-search-react-template) sample web site to use Search
20 |
21 |
--------------------------------------------------------------------------------
/storage/blob-paging/blob-paging.js:
--------------------------------------------------------------------------------
1 | const { BlobServiceClient } = require("@azure/storage-blob");
2 |
3 | const blobAccountConnectionString = "REPLACE-WITH-YOUR-STORAGE-CONNECTION-STRING";
4 | const blobAccountContainerName = "REPLACE-WITH-YOUR-STORAGE-CONTAINER-NAME";
5 |
6 | const pageSize = 2;
7 |
8 | const list = async () => {
9 |
10 | console.log(`List`);
11 |
12 | let continuationToken = "";
13 | let currentPage = 1;
14 | let containerClient=null;
15 | let currentItem = 1;
16 |
17 | // Get Blob Container - need to have items in container before running this code
18 | const blobServiceClient = BlobServiceClient.fromConnectionString(blobAccountConnectionString);
19 | containerClient = blobServiceClient.getContainerClient(blobAccountContainerName);
20 |
21 | do {
22 |
23 | // Get Page of Blobs
24 | iterator = (continuationToken != "")
25 | ? containerClient.listBlobsFlat().byPage({ maxPageSize: pageSize, continuationToken })
26 | : containerClient.listBlobsFlat().byPage({ maxPageSize: pageSize });
27 |
28 | page = (await iterator.next()).value;
29 |
30 | // Display list
31 | if (page.segment?.blobItems) {
32 | console.log(`\tPage [${currentPage}] `);
33 | for (const blob of page.segment.blobItems) {
34 | console.log(`\t\tItem [${currentItem++}] ${blob.name}`);
35 | }
36 | };
37 |
38 | // Move to next page
39 | continuationToken = page.continuationToken;
40 | if (continuationToken) {
41 | currentPage++;
42 | }
43 |
44 | } while (continuationToken != "")
45 | }
46 |
47 | list(() => {
48 | console.log("done");
49 | }).catch((ex) =>
50 | console.log(ex)
51 | );
52 |
--------------------------------------------------------------------------------
/storage/blob-paging/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "blob-paging",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "@azure/storage-blob": "^12.8.0"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/storage/file-paging/README.md:
--------------------------------------------------------------------------------
1 | # Storage samples
2 |
3 | ## page-through-files
4 |
5 | ### Create resource
6 |
7 | 1. Create an Azure Storage resource.
8 | 1. Create a file share and directory, then upload at least 5 files to the directory.
9 |
10 | ### Set up environment variables
11 |
12 | 1. Copy the following from the Azure portal for your Azure Storage resource, then set in the corresponding environment variables:
13 |
14 | |Object Type|Storage setting|Environment variable|
15 | |--|--|--|
16 | |Files| Storage Account Name|AzureStorageResourceNameForFiles|
17 | |Files| Storage Account Key|AzureStorageResourceKeyForFiles|
18 | |Files| Storage Account Share Name|AzureStorageResourceShareNameForFiles|
19 | |Files| Storage Account Directory Name (under the share)|AzureStorageResourceDirectoryNameForFiles|
20 |
21 |
22 | ### Run code
23 |
24 | 1. Install and run code:
25 |
26 | ```javascript
27 | npm install && node page-through-files.js
28 | ```
--------------------------------------------------------------------------------
/storage/file-paging/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "page-through-files",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "@azure/storage-file-share": "^12.8.0"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/storage/file-paging/page-through-files.js:
--------------------------------------------------------------------------------
1 | const {
2 | ShareClient,
3 | StorageSharedKeyCredential
4 | } = require("@azure/storage-file-share");
5 |
6 | // Page of Files
7 | const pageSize = 2;
8 |
9 | // RESOURCE
10 | const fileAccountName = process.env["AzureStorageResourceNameForFiles"] || "";
11 | const fileAccountKey = process.env["AzureStorageResourceKeyForFiles"] || "";
12 | const fileAccountShareName = process.env["AzureStorageResourceShareNameForFiles"] || "";
13 | const fileAccountDirectoryName = process.env["AzureStorageResourceDirectoryNameForFiles"] || "";
14 |
15 | // Create client
16 | const getFileDirectoryAccountClient = () => {
17 |
18 | // create account sas token for file service
19 | const fileCreds = new StorageSharedKeyCredential(
20 | fileAccountName,
21 | fileAccountKey
22 | );
23 |
24 | //get file share client
25 | const shareClient = new ShareClient(
26 | `https://${fileAccountName}.file.core.windows.net/${fileAccountShareName}`,
27 | fileCreds
28 | );
29 | const fileDirectoryClient = shareClient.getDirectoryClient(fileAccountDirectoryName);
30 | return { fileDirectoryClient };
31 | }
32 |
33 | const getPage = async (directoryClient, continuationToken) => {
34 |
35 | let pageIterator, pageResponse;
36 |
37 | if (continuationToken) {
38 |
39 | // Get next page
40 | pageIterator = directoryClient
41 | .listFilesAndDirectories()
42 | .byPage({ continuationToken, maxPageSize: pageSize });
43 |
44 | } else {
45 |
46 | // Get 1st page
47 | pageIterator = directoryClient
48 | .listFilesAndDirectories()
49 | .byPage({ maxPageSize: pageSize });
50 | }
51 |
52 | pageResponse = (await pageIterator.next()).value;
53 | return pageResponse;
54 | }
55 | const list = async () =>{
56 |
57 | // Get Azure SDK Storage clients for this task
58 | const { fileDirectoryClient } = getFileDirectoryAccountClient();
59 |
60 | // Keep continuation token for next page
61 | let continuationToken = null;
62 |
63 | // Track file count
64 | let i = 1;
65 | let pageCount = 1;
66 |
67 | do {
68 |
69 | // Get 1 page of data
70 | const listFiles = await getPage(fileDirectoryClient, continuationToken);
71 |
72 | // Store returned continuationToken for next Page
73 | continuationToken = listFiles.continuationToken;
74 |
75 | console.log(`Page ${pageCount++}\t\tContinuation token:${continuationToken}`);
76 |
77 | // List files in Page
78 | for (const fileItem of listFiles.segment.fileItems) {
79 | console.log(`${i++} - file\t: ${fileItem.name}`);
80 | }
81 |
82 | // stop when there are no more directories and no more pages
83 | } while (continuationToken !== "");
84 | }
85 |
86 | list()
87 | .then(() =>
88 | console.log(`done`)
89 | ).catch((ex) =>
90 | console.log(ex)
91 | );
--------------------------------------------------------------------------------
/storage/queue/convert-into-and-out-of-string.js:
--------------------------------------------------------------------------------
1 | // Message queue messages are strings. All data must eventuall
2 | // turn into a string. These functions are meant to move JSON
3 | // data into and out of base 64 format.
4 |
5 | function jsonToBase64(jsonObj) {
6 | const jsonString = JSON.stringify(jsonObj)
7 | return Buffer.from(jsonString).toString('base64')
8 | }
9 | function encodeBase64ToJson(base64String) {
10 | const jsonString = Buffer.from(base64String,'base64').toString()
11 | return JSON.parse(jsonString)
12 | }
13 |
--------------------------------------------------------------------------------
/storage/upload-files-from-url/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "type": "pwa-node",
9 | "request": "launch",
10 | "name": "Launch Program",
11 | "skipFiles": [
12 | "/**"
13 | ],
14 | "program": "${workspaceFolder}\\${file}"
15 | }
16 | ]
17 | }
--------------------------------------------------------------------------------
/storage/upload-files-from-url/README.md:
--------------------------------------------------------------------------------
1 | # Storage samples
2 |
3 | ## copy-from-files-to-blobs.js
4 |
5 | ### Create resources
6 |
7 | While this sample should work with two separate Azure Storage resources, it was tested with the same, single resource.
8 |
9 | 1. Create an Azure Storage resource.
10 | 1. Create a file share and directory, then upload at least 5 files to the directory.
11 | 1. Create a container directory. It can be the same name as the file directory.
12 |
13 | ### Set up environment variables
14 |
15 | 1. Copy the following from the Azure portal for your Azure Storage resource, then set in the corresponding environment variables:
16 |
17 | |Object Type|Storage setting|Environment variable|
18 | |--|--|--|
19 | |Files| Storage Account Name|AzureStorageResourceNameForFiles|
20 | |Files| Storage Account Key|AzureStorageResourceKeyForFiles|
21 | |Files| Storage Account Share Name|AzureStorageResourceShareNameForFiles|
22 | |Files| Storage Account Directory Name (under the share)|AzureStorageResourceDirectoryNameForFiles|
23 | |Blobs| Storage Account Connection String|AzureStorageResourceConnectionString|
24 | |Blobs| Storage Account Directory Name|AzureStorageResourceDirectoryNameForBlobs|
25 |
26 | ### Run code
27 |
28 | 1. Install and run code:
29 |
30 | ```javascript
31 | npm install && node copy-from-files-to-blobs.js
32 | ```
--------------------------------------------------------------------------------
/storage/upload-files-from-url/copy-from-files-to-blobs.js:
--------------------------------------------------------------------------------
1 | const { BlobServiceClient } = require("@azure/storage-blob");
2 | const {
3 | ShareClient,
4 | generateAccountSASQueryParameters,
5 | StorageSharedKeyCredential,
6 | AccountSASResourceTypes,
7 | AccountSASPermissions,
8 | AccountSASServices,
9 | } = require("@azure/storage-file-share");
10 |
11 | // Page of Files
12 | const pageSize = 2;
13 |
14 | // COPY FROM THIS RESOURCE
15 | const fileAccountName = process.env["AzureStorageResourceNameForFiles"] || "";
16 | const fileAccountKey = process.env["AzureStorageResourceKeyForFiles"] || "";
17 | const fileAccountShareName = process.env["AzureStorageResourceShareNameForFiles"] || "";
18 | const fileAccountDirectoryName = process.env["AzureStorageResourceDirectoryNameForFiles"] || "";
19 |
20 | // COPY TO THIS RESOURCE
21 | const blobAccountConnectionString = process.env["AzureStorageResourceConnectionString"] || "";
22 | const blobAccountDirectoryName = process.env["AzureStorageResourceDirectoryNameForBlobs"] || "";
23 |
24 | // Create From client
25 | const getFileDirectoryAccountClient = () => {
26 |
27 | // create account sas token for file service
28 | const fileCreds = new StorageSharedKeyCredential(
29 | fileAccountName,
30 | fileAccountKey
31 | );
32 | const accountSas = generateAccountSASQueryParameters(
33 | {
34 | startsOn: new Date(new Date().valueOf() - 8640),
35 | expiresOn: new Date(new Date().valueOf() + 86400000),
36 | resourceTypes: AccountSASResourceTypes.parse("sco").toString(),
37 | permissions: AccountSASPermissions.parse("rwdlc").toString(),
38 | services: AccountSASServices.parse("f").toString(),
39 | },
40 | fileCreds
41 | ).toString();
42 |
43 | console.log(`accountSas = ${accountSas}`)
44 |
45 | //get file share client
46 | const shareClient = new ShareClient(
47 | `https://${fileAccountName}.file.core.windows.net/${fileAccountShareName}`,
48 | fileCreds
49 | );
50 | const fileDirectoryClient = shareClient.getDirectoryClient(fileAccountDirectoryName);
51 | return { accountSas, fileDirectoryClient };
52 | }
53 |
54 | // Create To client
55 | const getBlobAccountClient = async () => {
56 |
57 | // get container client
58 | const blobServiceClient = BlobServiceClient.fromConnectionString(blobAccountConnectionString);
59 |
60 | // get container's directory client
61 | var containerClient = blobServiceClient.getContainerClient(blobAccountDirectoryName);
62 |
63 | // create container if it doesn't already exist
64 | await containerClient.createIfNotExists();
65 |
66 | return containerClient;
67 | }
68 |
69 | const copyFileToBlob = async (blobClient, toBlobName, fromSourceUrl) => {
70 |
71 | try {
72 |
73 |
74 | const res = await (
75 |
76 | // copy file to blob from URL
77 | await blobClient
78 | .getBlobClient(toBlobName)
79 | .beginCopyFromURL(fromSourceUrl)
80 |
81 | ).pollUntilDone(); // wait until finished with pollUntilDone
82 |
83 | console.log(res.copyStatus);
84 |
85 | } catch (error) {
86 |
87 | // Copy into Blob failed
88 | throw error;
89 | }
90 | }
91 |
92 | const getFilesPage = async (directoryClient, continuationToken) => {
93 |
94 | let pageIterator, pageResponse;
95 |
96 | if (continuationToken) {
97 |
98 | // Get next page
99 | pageIterator = directoryClient
100 | .listFilesAndDirectories()
101 | .byPage({ continuationToken, maxPageSize: pageSize });
102 |
103 | } else {
104 |
105 | // Get page
106 | pageIterator = directoryClient
107 | .listFilesAndDirectories()
108 | .byPage({ maxPageSize: pageSize });
109 | }
110 |
111 | pageResponse = (await pageIterator.next()).value;
112 | return pageResponse;
113 | }
114 | async function copy() {
115 |
116 | // Get Azure SDK Storage clients for this task
117 | const { accountSas, fileDirectoryClient } = getFileDirectoryAccountClient();
118 | const blobContainerClient = await getBlobAccountClient();
119 |
120 | // Keep a list of directories
121 | let arrFolders = [];
122 |
123 | // Keep continuation token for next page
124 | let continuationToken = null;
125 |
126 | // Track file count
127 | let i = 1;
128 |
129 | arrFolders.push(fileAccountShareName);
130 | do {
131 |
132 | let fileAccountDirectoryName = arrFolders.pop();
133 |
134 | console.log(`List directories and files under directory ${fileAccountDirectoryName}`);
135 |
136 | // Get 1 page of data
137 | const listFilesAndDirectoriesResponse = await getFilesPage(fileDirectoryClient, continuationToken);
138 |
139 | // Store returned continuationToken for next Page
140 | continuationToken = listFilesAndDirectoriesResponse.continuationToken;
141 |
142 | // Add returned directories to array to process
143 | for (const dirItem of listFilesAndDirectoriesResponse.segment.directoryItems) {
144 | console.log(`${i++} - directory\t: ${dirItem.name}`);
145 | arrFolders.push(
146 | fileAccountDirectoryName == "" ? dirItem.name : fileAccountDirectoryName + "\\" + dirItem.name
147 | );
148 | }
149 |
150 | // Copy files to blobs
151 | for (const fileItem of listFilesAndDirectoriesResponse.segment.fileItems) {
152 |
153 | console.log(`${i++} - file\t: ${fileItem.name}`);
154 |
155 | const fileClient = fileDirectoryClient.getFileClient(fileItem.name);
156 | const sourceURL = fileClient.url + "?" + accountSas;
157 | await copyFileToBlob(blobContainerClient, fileItem.name, sourceURL);
158 |
159 | }
160 |
161 | // stop when there are no more directories and no more pages
162 | } while (arrFolders.length > 0 || continuationToken !== "");
163 | }
164 |
165 | copy()
166 | .then(() =>
167 | console.log(`done`)
168 | ).catch((ex) =>
169 | console.log(ex)
170 | );
--------------------------------------------------------------------------------
/storage/upload-files-from-url/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "upload-files-from-url",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "@azure/storage-blob": "^12.8.0",
14 | "@azure/storage-file-share": "^12.8.0"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/storage/upload-string-to-file/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "upload-string-to-file",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "@azure/storage-file-share": "^12.8.0"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/storage/upload-string-to-file/upload-string-to-file.js:
--------------------------------------------------------------------------------
1 | const { ShareServiceClient, StorageSharedKeyCredential } = require("@azure/storage-file-share");
2 |
3 | // Enter your storage account name and shared key
4 | const account = process.env["AzureStorageResourceNameForFiles"] || "";
5 | const accountKey = process.env["AzureStorageResourceKeyForFiles"] || "";
6 |
7 | const main = async () => {
8 |
9 | // Use SharedKeyCredential with storage account and account key
10 | // SharedKeyCredential is only avaiable in Node.js runtime, not in browsers
11 | const sharedKeyCredential = new StorageSharedKeyCredential(account, accountKey);
12 | const serviceClient = new ShareServiceClient(
13 | // When using AnonymousCredential, following url should include a valid SAS
14 | `https://${account}.file.core.windows.net`,
15 | sharedKeyCredential
16 | );
17 |
18 | // Create new share and directory
19 | const shareName = `newshare${new Date().getTime()}`;
20 | const shareClient = serviceClient.getShareClient(shareName);
21 | await shareClient.create();
22 | console.log(`Create share ${shareName} successfully`);
23 |
24 | const directoryName = `newdirectory${new Date().getTime()}`;
25 | const directoryClient = shareClient.getDirectoryClient(directoryName);
26 | await directoryClient.create();
27 | console.log(`Create directory ${directoryName} successfully`);
28 |
29 | // Create an azure file then upload to it
30 | const content = "Hello World!";
31 | const fileName = "newfile" + new Date().getTime();
32 | const fileClient = directoryClient.getFileClient(fileName);
33 | await fileClient.create(content.length);
34 | console.log(`Create file ${fileName} successfully`);
35 |
36 | // Upload file range
37 | await fileClient.uploadRange(content, 0, content.length);
38 | console.log(`Upload file range "${content}" to ${fileName} successfully`);
39 |
40 | // List files and directories under a directory
41 | // Use DirectoryClient.listFilesAndDirectories() to iterator over files and directories, with the new for-await-of syntax. The kind property can be used to identify whether a iterm is a directory or a file.
42 |
43 | let dirIter1 = directoryClient.listFilesAndDirectories();
44 | let i = 1;
45 | for await (const item of dirIter1) {
46 | if (item.kind === "directory") {
47 | console.log(`${i} - directory\t: ${item.name}`);
48 | } else {
49 | console.log(`${i} - file\t: ${item.name}`);
50 | }
51 | i++;
52 | }
53 | }
54 |
55 |
56 | main()
57 | .then(() =>
58 | console.log(`done`)
59 | ).catch((ex) =>
60 | console.log(ex)
61 | );
62 |
--------------------------------------------------------------------------------
/storage/upload-url-to-blob-poll-until-done/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "type": "pwa-node",
9 | "request": "launch",
10 | "name": "Launch Program",
11 | "skipFiles": [
12 | "/**"
13 | ],
14 | "program": "${workspaceFolder}\\${file}"
15 | }
16 | ]
17 | }
--------------------------------------------------------------------------------
/storage/upload-url-to-blob-poll-until-done/README.md:
--------------------------------------------------------------------------------
1 | # Storage samples
2 |
3 | ## upload-url-to-blob-poll-until-done.js
4 |
5 | ### Create resources
6 |
7 | 1. Create an Azure Storage resource.
8 | 1. Copy connection string into variable.
9 |
10 | ### Run code
11 |
12 | 1. Install and run code:
13 |
14 | ```javascript
15 | npm install && node upload-url-to-blob-poll-until-done.js
16 | ```
--------------------------------------------------------------------------------
/storage/upload-url-to-blob-poll-until-done/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "upload-url-to-blob-poll-until-done",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "@azure/storage-blob": "^12.8.0"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/storage/upload-url-to-blob-poll-until-done/upload-url-to-blob-poll-until-done-by-page.js:
--------------------------------------------------------------------------------
1 | const { BlobServiceClient } = require("@azure/storage-blob");
2 |
3 | const blobAccountConnectionString = process.env["AzureStorageResourceConnectionString"] || "";
4 | const blobAccountDirectoryName = process.env["AzureStorageResourceDirectoryNameForBlobs"] || `test-${Date.now().toString()}`;
5 |
6 | const pageSize = 2;
7 |
8 | let containerClient=null;
9 | let currentItem = 1;
10 |
11 | // publicly accessible files
12 | const files = [
13 | {
14 | "url": "https://github.com/Azure/azure-sdk-for-js/blob/main/README.md",
15 | "fileName": "README.md"
16 | },
17 | {
18 | "url": "https://github.com/Azure/azure-sdk-for-js/blob/main/gulpfile.ts",
19 | "fileName": "gulpfile.ts"
20 | },
21 | {
22 | "url": "https://github.com/Azure/azure-sdk-for-js/blob/main/rush.json",
23 | "fileName": "rush.json"
24 | },
25 | {
26 | "url": "https://github.com/Azure/azure-sdk-for-js/blob/main/package.json",
27 | "fileName": "package.json"
28 | },
29 | {
30 | "url": "https://github.com/Azure/azure-sdk-for-js/blob/main/tsdoc.json",
31 | "fileName": "tsdoc.json"
32 | },
33 | ];
34 |
35 | const awaitTimeout = delay => new Promise(resolve => setTimeout(resolve, delay));
36 |
37 | const init = async() =>{
38 |
39 | // get container client
40 | const blobServiceClient = BlobServiceClient.fromConnectionString(blobAccountConnectionString);
41 |
42 | // get container's directory client
43 | containerClient = blobServiceClient.getContainerClient(blobAccountDirectoryName);
44 |
45 | // create container if it doesn't already exist
46 | await containerClient.createIfNotExists();
47 |
48 | }
49 | const upload = async () => {
50 |
51 | console.log(`Upload to ${blobAccountDirectoryName}`);
52 |
53 | files.forEach(async (file) => {
54 |
55 | console.log(`\t\t${currentItem++} - ${file.fileName}`);
56 |
57 | await (
58 |
59 | await containerClient
60 | .getBlobClient(file.fileName)
61 | .beginCopyFromURL(file.url)
62 |
63 | ).pollUntilDone();
64 | })
65 | }
66 |
67 | const list = async () => {
68 |
69 | console.log(`List`);
70 |
71 | let continuationToken = "";
72 |
73 | let currentPage = 1;
74 |
75 | do {
76 |
77 | // Get Page of Blobs
78 | iterator = (continuationToken != "") ? containerClient.listBlobsFlat().byPage({ maxPageSize: pageSize, continuationToken }) : containerClient.listBlobsFlat().byPage({ maxPageSize: pageSize });
79 | page = (await iterator.next()).value;
80 |
81 | // Display list
82 | if (page.segment?.blobItems) {
83 | console.log(`\tPage [${currentPage}] `);
84 | for (const blob of page.segment.blobItems) {
85 | console.log(`\t\tItem [${currentItem++}] ${blob.name}`);
86 | }
87 | };
88 |
89 | // Move to next page
90 | continuationToken = page.continuationToken;
91 | if (continuationToken) {
92 | currentPage++;
93 | }
94 |
95 | } while (continuationToken != "")
96 |
97 | }
98 |
99 | const main = async () =>{
100 |
101 | await init();
102 | await upload();
103 |
104 | currentItem=1;
105 |
106 | //awaitTimeout(5000).then(async() =>{
107 | await list();
108 | //});
109 |
110 | }
111 |
112 | main(() => {
113 | console.log("done");
114 | }).catch((ex) =>
115 | console.log(ex)
116 | );
117 |
118 |
--------------------------------------------------------------------------------
/storage/upload-url-to-blob-poll-until-done/upload-url-to-blob-poll-until-done.js:
--------------------------------------------------------------------------------
1 | const { BlobServiceClient } = require("@azure/storage-blob");
2 |
3 | const blobAccountConnectionString = "REPLACE-WITH-YOUR-STORAGE-CONNECTION-STRING";
4 | const blobAccountContainerName = `test-${Date.now().toString()}`;
5 |
6 | const files = [
7 | {
8 | "url": "https://github.com/Azure/azure-sdk-for-js/blob/main/README.md",
9 | "fileName": "README.md"
10 | },
11 | {
12 | "url": "https://github.com/Azure/azure-sdk-for-js/blob/main/gulpfile.ts",
13 | "fileName": "gulpfile.ts"
14 | },
15 | {
16 | "url": "https://github.com/Azure/azure-sdk-for-js/blob/main/rush.json",
17 | "fileName": "rush.json"
18 | },
19 | {
20 | "url": "https://github.com/Azure/azure-sdk-for-js/blob/main/package.json",
21 | "fileName": "package.json"
22 | },
23 | {
24 | "url": "https://github.com/Azure/azure-sdk-for-js/blob/main/tsdoc.json",
25 | "fileName": "tsdoc.json"
26 | },
27 | ];
28 |
29 | const upload = async() => {
30 |
31 | // get container client
32 | const blobServiceClient = BlobServiceClient.fromConnectionString(blobAccountConnectionString);
33 |
34 | // get container's directory client
35 | const containerClient = blobServiceClient.getContainerClient(blobAccountContainerName);
36 |
37 | files.forEach(async(file) =>{
38 | await (
39 |
40 | await containerClient
41 | .getBlobClient(file.fileName)
42 | .beginCopyFromURL(file.url)
43 |
44 | ).pollUntilDone();
45 | })
46 | }
47 |
48 | upload(() => {
49 | console.log("done");
50 | }).catch((ex) =>
51 | console.log(ex)
52 | );
53 |
--------------------------------------------------------------------------------
/vscode-docs-linter/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "eslint":{
3 | "plugins": [
4 | "prettier"
5 | ],
6 | "root": true,
7 | "extends": [
8 | "eslint:recommended",
9 | "airbnb-base",
10 | "prettier"
11 | ],
12 | "env": {
13 | "commonjs": true,
14 | "es2020": true,
15 | "node": true,
16 | "jest": true
17 | },
18 | "parserOptions": {
19 | "ecmaVersion": 11
20 | },
21 | "ignorePatterns": [
22 | ".vscode",
23 | ".devcontainer",
24 | "dist"
25 | ],
26 | "rules": {
27 | "semi": [
28 | "warn",
29 | "always"
30 | ],
31 | "quotes": [
32 | "error",
33 | "single"
34 | ],
35 | "no-console": [
36 | 0
37 | ],
38 | "no-return-await": [
39 | "warn"
40 | ]
41 | }
42 | },
43 | "prettier":{
44 | "trailingComma": "all",
45 | "tabWidth": 2,
46 | "semi": true,
47 | "singleQuote": false,
48 | "bracketSpacing": true,
49 | "printWidth": 120,
50 | "arrowParens": "avoid"
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/windows-terminal/readme.md:
--------------------------------------------------------------------------------
1 | # Windows Terminal
2 |
3 | ## Set default terminal to bash
4 |
5 | 1. Right-click on Settings
6 | 1. In the `settings.json` file that opens, change the `defaultProfile` value to the bash Id.
7 |
8 | ## Set default directory
9 |
10 | 1. Right-click on Settings
11 | 1. In the `settings.json` file that opens, add a property to the profile item named `startingDirectory` with the new value.
12 |
13 | ```json
14 | "startingDirectory": "C:\\repos\\",
15 | ```
16 |
--------------------------------------------------------------------------------