Use code snippets from managed identity credential samples in identity readme doc and fix minor generation issues (#6020)

* Use code snippets from managed identity credential samples in identity readme doc.

* Generate readme from snippets.

* Update snippet generation script to remove unnecessary indentation and extra new line at eof.

* Update Snippet Generation doc to show a concrete example on how to run it.

* Update other repo READMEs with the generation fixes.

* Fix KeyVault Secrets sample and use the snippets in its README

* Use the added sample snippet.
This commit is contained in:
Ahson Khan 2024-09-25 16:56:57 -07:00 committed by GitHub
parent f3119bd899
commit aa728eed6d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 143 additions and 49 deletions

View File

@ -110,9 +110,14 @@ The snippet generation tool, located in `eng\scripts\Generate-Snippets.ps1`, is
```bash ```bash
pwsh -f eng\scripts\Generate-Snippets.ps1 -source_dir <path to source code containing snippets> -output_dir <path to directory containing output files> pwsh -f eng\scripts\Generate-Snippets.ps1 -source_dir <path to source code containing snippets> -output_dir <path to directory containing output files>
``` ```
For example, you can run the snippet generation tool for all the packages in the repo, as follows:
```bash
pwsh -f .\eng\scripts\Generate-Snippets.ps1 -source_dir sdk -output_dir sdk
```
The tool will recursively search the source directory for snippet sources and parse the snippet sources in each The tool will recursively search the source directory for snippet sources and parse the snippet sources in each
source file. source file.

View File

@ -82,7 +82,28 @@ function ProcessSnippetsInFile {
# Insert the snippet text. # Insert the snippet text.
$snippet_text = $snippet_map[$snippet_name] $snippet_text = $snippet_map[$snippet_name]
$output_file_contents = $output_file_contents -replace "<!--\s+@insert_snippet:\s+$snippet_name\s*-->\s+", "<!-- @insert_snippet: $snippet_name -->`r`n``````cpp`r`n$snippet_text`r`n```````r`n`r`n"
# Remove leading spaces from each line, by first splitting the text into lines.
$lines = $snippet_text -split [Environment]::NewLine
# Then, find the minimum leading whitespace across all lines.
# This is done to trim the minimum amount of leading whitespace from each line while preserving the relative indentation for lines that are already indented.
# When calculating the min whitespace, we only consider lines that are not empty.
$minWhitespace = ($lines | Where-Object { $_.Trim() -ne '' } | ForEach-Object { $_.IndexOf($_.TrimStart()) }) | Measure-Object -Minimum | Select-Object -ExpandProperty Minimum
# Trim the minimum whitespace from each line
$trimmedLines = $lines | ForEach-Object {
if ($_.Length -gt $minWhitespace) {
$_.Substring($minWhitespace)
} else {
$_
}
}
# Join the lines back into a single string
$snippet_text_clean = $trimmedLines -join [Environment]::NewLine
$output_file_contents = $output_file_contents -replace "<!--\s+@insert_snippet:\s+$snippet_name\s*-->\s+", "<!-- @insert_snippet: $snippet_name -->`r`n``````cpp`r`n$snippet_text_clean`r`n```````r`n`r`n"
} }
elseif ($output_file.Extension -eq '.hpp') { elseif ($output_file.Extension -eq '.hpp') {
@ -98,8 +119,8 @@ function ProcessSnippetsInFile {
} }
# The Regex::Replace above inserts an extra newline at the end of the file. Remove it. # The Regex::Replace above inserts an extra newline at the end of the file. Remove it.
$output_file_contents = $output_file_contents -replace "`r`n\s*\Z", "`r`n" $output_file_contents = $output_file_contents -replace "`r`n\s*\Z", ""
$original_contents = $original_file_contents -replace "`r`n\s*\Z", "`r`n" $original_contents = $original_file_contents -replace "`r`n\s*\Z", ""
if ($verify) { if ($verify) {
if ($output_file_contents -ne $original_contents) { if ($output_file_contents -ne $original_contents) {

View File

@ -45,31 +45,31 @@ An AMQP Message Sender is responsible for sending messages to an AMQP server ove
<!-- @insert_snippet: CreateSender --> <!-- @insert_snippet: CreateSender -->
```cpp ```cpp
Azure::Core::Amqp::_internal::MessageSenderOptions senderOptions; Azure::Core::Amqp::_internal::MessageSenderOptions senderOptions;
senderOptions.Name = "sender-link"; senderOptions.Name = "sender-link";
senderOptions.MessageSource = "source"; senderOptions.MessageSource = "source";
senderOptions.SettleMode = Azure::Core::Amqp::_internal::SenderSettleMode::Unsettled; senderOptions.SettleMode = Azure::Core::Amqp::_internal::SenderSettleMode::Unsettled;
senderOptions.MaxMessageSize = (std::numeric_limits<uint16_t>::max)(); senderOptions.MaxMessageSize = (std::numeric_limits<uint16_t>::max)();
Azure::Core::Amqp::_internal::MessageSender sender( Azure::Core::Amqp::_internal::MessageSender sender(
session, credentials->GetEntityPath(), senderOptions, nullptr); session, credentials->GetEntityPath(), senderOptions, nullptr);
``` ```
Once the message sender has been created, it can be used to send messages to the remote server. Once the message sender has been created, it can be used to send messages to the remote server.
<!-- @insert_snippet: SendMessages --> <!-- @insert_snippet: SendMessages -->
```cpp ```cpp
Azure::Core::Amqp::Models::AmqpMessage message; Azure::Core::Amqp::Models::AmqpMessage message;
message.SetBody(Azure::Core::Amqp::Models::AmqpBinaryData{'H', 'e', 'l', 'l', 'o'}); message.SetBody(Azure::Core::Amqp::Models::AmqpBinaryData{'H', 'e', 'l', 'l', 'o'});
constexpr int maxMessageSendCount = 5; constexpr int maxMessageSendCount = 5;
int messageSendCount = 0; int messageSendCount = 0;
while (messageSendCount < maxMessageSendCount) while (messageSendCount < maxMessageSendCount)
{ {
auto result = sender.Send(message); auto result = sender.Send(message);
messageSendCount += 1; messageSendCount += 1;
} }
``` ```
## Next steps ## Next steps
@ -106,4 +106,3 @@ Azure SDK for C++ is licensed under the [MIT](https://github.com/Azure/azure-sdk
[cloud_shell_bash]: https://shell.azure.com/bash [cloud_shell_bash]: https://shell.azure.com/bash
![Impressions](https://azure-sdk-impressions.azurewebsites.net/api/impressions/azure-sdk-for-cpp%2Fsdk%2Fcore%2Fcore-opentelemetry%2FREADME.png) ![Impressions](https://azure-sdk-impressions.azurewebsites.net/api/impressions/azure-sdk-for-cpp%2Fsdk%2Fcore%2Fcore-opentelemetry%2FREADME.png)

View File

@ -75,24 +75,24 @@ Demonstrates writing messages to the Azure Event Hubs service using the AMQP pro
<!-- @insert_snippet: CreateSender --> <!-- @insert_snippet: CreateSender -->
```cpp ```cpp
Azure::Core::Amqp::_internal::MessageSenderOptions senderOptions; Azure::Core::Amqp::_internal::MessageSenderOptions senderOptions;
senderOptions.Name = "sender-link"; senderOptions.Name = "sender-link";
senderOptions.MessageSource = "source"; senderOptions.MessageSource = "source";
senderOptions.SettleMode = Azure::Core::Amqp::_internal::SenderSettleMode::Unsettled; senderOptions.SettleMode = Azure::Core::Amqp::_internal::SenderSettleMode::Unsettled;
senderOptions.MaxMessageSize = (std::numeric_limits<uint16_t>::max)(); senderOptions.MaxMessageSize = (std::numeric_limits<uint16_t>::max)();
Azure::Core::Amqp::_internal::MessageSender sender( Azure::Core::Amqp::_internal::MessageSender sender(
session, credentials->GetEntityPath(), senderOptions, nullptr); session, credentials->GetEntityPath(), senderOptions, nullptr);
``` ```
<!-- @insert_snippet: create_connection --> <!-- @insert_snippet: create_connection -->
```cpp ```cpp
Azure::Core::Amqp::_internal::ConnectionOptions connectionOptions; Azure::Core::Amqp::_internal::ConnectionOptions connectionOptions;
connectionOptions.ContainerId = "whatever"; connectionOptions.ContainerId = "whatever";
connectionOptions.EnableTrace = true; connectionOptions.EnableTrace = true;
connectionOptions.Port = credential->GetPort(); connectionOptions.Port = credential->GetPort();
Azure::Core::Amqp::_internal::Connection connection( Azure::Core::Amqp::_internal::Connection connection(
credential->GetHostName(), credential, connectionOptions); credential->GetHostName(), credential, connectionOptions);
``` ```
### eventhub_token_reader_sample ### eventhub_token_reader_sample
@ -112,4 +112,3 @@ Demonstrates receiving messages from a local AMQP server using the AMQP protocol
### eventhub_get_eventhub_properties_sample ### eventhub_get_eventhub_properties_sample
Demonstrates receiving messages from the Azure Event Hubs service using an AMQP Management API. Demonstrates receiving messages from the Azure Event Hubs service using an AMQP Management API.

View File

@ -104,16 +104,16 @@ Many Azure hosts allow the assignment of a user-assigned managed identity. The f
To use a client ID, create a `ManagedIdentityId` with `ManagedIdentityIdKind::ClientId`, set that as the `IdentityId` in the `ManagedIdentityCredentialOptions`, and pass that to the `ManagedIdentityCredential` constructor. For example: To use a client ID, create a `ManagedIdentityId` with `ManagedIdentityIdKind::ClientId`, set that as the `IdentityId` in the `ManagedIdentityCredentialOptions`, and pass that to the `ManagedIdentityCredential` constructor. For example:
<!-- @insert_snippet: UserAssignedManagedIdentityViaClientId -->
```cpp ```cpp
// When deployed to an Azure host, ManagedIdentityCredential will authenticate the specified user-assigned managed identity. // When deployed to an Azure host, ManagedIdentityCredential will authenticate the specified
// user-assigned managed identity.
std::string userAssignedClientId = "<your managed identity client ID>"; std::string userAssignedClientId = "<your managed identity client ID>";
ManagedIdentityCredentialOptions options; ManagedIdentityCredentialOptions options;
options.IdentityId = ManagedIdentityId(ManagedIdentityIdKind::ClientId, userAssignedClientId); options.IdentityId = ManagedIdentityId(ManagedIdentityIdKind::ClientId, userAssignedClientId);
auto credential = std::make_shared<ManagedIdentityCredential>(options); auto credential = std::make_shared<ManagedIdentityCredential>(options);
std::string blobUrl = "https://myaccount.blob.core.windows.net/mycontainer/myblob";
auto blobClient = BlobClient(blobUrl, credential); auto blobClient = BlobClient(blobUrl, credential);
``` ```
@ -121,13 +121,14 @@ auto blobClient = BlobClient(blobUrl, credential);
Similarly, to use a resource ID, create a `ManagedIdentityId` with `ManagedIdentityIdKind::ResourceId`, set that as the `IdentityId` in the `ManagedIdentityCredentialOptions`, and pass that to the `ManagedIdentityCredential` constructor. The resource ID takes the form `/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName}`. Because resource IDs can be built by convention, they can be more convenient when there are a large number of user-assigned managed identities in your environment. For example: Similarly, to use a resource ID, create a `ManagedIdentityId` with `ManagedIdentityIdKind::ResourceId`, set that as the `IdentityId` in the `ManagedIdentityCredentialOptions`, and pass that to the `ManagedIdentityCredential` constructor. The resource ID takes the form `/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName}`. Because resource IDs can be built by convention, they can be more convenient when there are a large number of user-assigned managed identities in your environment. For example:
<!-- @insert_snippet: UserAssignedManagedIdentityViaResourceId -->
```cpp ```cpp
std::string userAssignedResourceId = "<your managed identity resource ID>"; std::string userAssignedResourceId = "<your managed identity resource ID>";
ManagedIdentityCredentialOptions options; ManagedIdentityCredentialOptions options;
options.IdentityId = ManagedIdentityId(ManagedIdentityIdKind::ResourceId, userAssignedResourceId); options.IdentityId
= ManagedIdentityId(ManagedIdentityIdKind::ResourceId, userAssignedResourceId);
auto credential = std::make_shared<ManagedIdentityCredential>(options); auto credential = std::make_shared<ManagedIdentityCredential>(options);
auto blobClient = BlobClient(blobUrl, credential); auto blobClient = BlobClient(blobUrl, credential);
``` ```
@ -135,13 +136,13 @@ auto blobClient = BlobClient(blobUrl, credential);
Similarly, to use an object ID, create a `ManagedIdentityId` with `ManagedIdentityIdKind::ObjectId`, set that as the `IdentityId` in the `ManagedIdentityCredentialOptions`, and pass that to the `ManagedIdentityCredential` constructor. For example: Similarly, to use an object ID, create a `ManagedIdentityId` with `ManagedIdentityIdKind::ObjectId`, set that as the `IdentityId` in the `ManagedIdentityCredentialOptions`, and pass that to the `ManagedIdentityCredential` constructor. For example:
<!-- @insert_snippet: UserAssignedManagedIdentityViaObjectId -->
```cpp ```cpp
std::string userAssignedObjectId = "<your managed identity object ID>"; std::string userAssignedObjectId = "<your managed identity object ID>";
ManagedIdentityCredentialOptions options; ManagedIdentityCredentialOptions options;
options.IdentityId = ManagedIdentityId(ManagedIdentityIdKind::ObjectId, userAssignedObjectId); options.IdentityId = ManagedIdentityId(ManagedIdentityIdKind::ObjectId, userAssignedObjectId);
auto credential = std::make_shared<ManagedIdentityCredential>(options); auto credential = std::make_shared<ManagedIdentityCredential>(options);
auto blobClient = BlobClient(blobUrl, credential); auto blobClient = BlobClient(blobUrl, credential);
``` ```
@ -149,6 +150,7 @@ auto blobClient = BlobClient(blobUrl, credential);
You can express your intent to use a system-assigned managed identity, explicitly, by creating a `ManagedIdentityId` with `ManagedIdentityIdKind::SystemAssigned` and an empty ID value, set that as the `IdentityId` in the `ManagedIdentityCredentialOptions`, and pass that to the `ManagedIdentityCredential` constructor. For example: You can express your intent to use a system-assigned managed identity, explicitly, by creating a `ManagedIdentityId` with `ManagedIdentityIdKind::SystemAssigned` and an empty ID value, set that as the `IdentityId` in the `ManagedIdentityCredentialOptions`, and pass that to the `ManagedIdentityCredential` constructor. For example:
<!-- @insert_snippet: SystemAssignedManagedIdentity -->
```cpp ```cpp
ManagedIdentityCredentialOptions options; ManagedIdentityCredentialOptions options;
options.IdentityId = ManagedIdentityId(ManagedIdentityIdKind::SystemAssigned, {}); options.IdentityId = ManagedIdentityId(ManagedIdentityIdKind::SystemAssigned, {});
@ -159,6 +161,7 @@ auto blobClient = BlobClient(blobUrl, credential);
An alternative way to specify a system-assigned managed identity, implicitly, is by calling the default `ManagedIdentityCredential` constructor. For example: An alternative way to specify a system-assigned managed identity, implicitly, is by calling the default `ManagedIdentityCredential` constructor. For example:
<!-- @insert_snippet: SystemAssignedManagedIdentityBrief -->
```cpp ```cpp
auto credential = std::make_shared<ManagedIdentityCredential>(); auto credential = std::make_shared<ManagedIdentityCredential>();
auto blobClient = BlobClient(blobUrl, credential); auto blobClient = BlobClient(blobUrl, credential);

View File

@ -54,7 +54,7 @@ target_compile_definitions(environment_credential_sample PRIVATE _azure_BUILDING
create_per_service_target_build_for_sample(identity environment_credential_sample) create_per_service_target_build_for_sample(identity environment_credential_sample)
add_executable(managed_identity_credential_sample managed_identity_credential.cpp) add_executable(managed_identity_credential_sample managed_identity_credential.cpp)
target_link_libraries(managed_identity_credential_sample PRIVATE azure-identity service) target_link_libraries(managed_identity_credential_sample PRIVATE azure-identity service azure-storage-blobs)
target_include_directories(managed_identity_credential_sample PRIVATE .) target_include_directories(managed_identity_credential_sample PRIVATE .)
target_compile_definitions(managed_identity_credential_sample PRIVATE _azure_BUILDING_SAMPLES) target_compile_definitions(managed_identity_credential_sample PRIVATE _azure_BUILDING_SAMPLES)
create_per_service_target_build_for_sample(identity managed_identity_credential_sample) create_per_service_target_build_for_sample(identity managed_identity_credential_sample)

View File

@ -3,9 +3,67 @@
#include <azure/identity/managed_identity_credential.hpp> #include <azure/identity/managed_identity_credential.hpp>
#include <azure/service/client.hpp> #include <azure/service/client.hpp>
#include <azure/storage/blobs.hpp>
#include <iostream> #include <iostream>
static void ShowDifferentManagedIdentityApproaches()
{
using namespace Azure::Identity;
using namespace Azure::Storage::Blobs;
std::string blobUrl = "https://myaccount.blob.core.windows.net/mycontainer/myblob";
{
// @begin_snippet: UserAssignedManagedIdentityViaClientId
// When deployed to an Azure host, ManagedIdentityCredential will authenticate the specified
// user-assigned managed identity.
std::string userAssignedClientId = "<your managed identity client ID>";
ManagedIdentityCredentialOptions options;
options.IdentityId = ManagedIdentityId(ManagedIdentityIdKind::ClientId, userAssignedClientId);
auto credential = std::make_shared<ManagedIdentityCredential>(options);
auto blobClient = BlobClient(blobUrl, credential);
// @end_snippet
}
{
// @begin_snippet: UserAssignedManagedIdentityViaResourceId
std::string userAssignedResourceId = "<your managed identity resource ID>";
ManagedIdentityCredentialOptions options;
options.IdentityId
= ManagedIdentityId(ManagedIdentityIdKind::ResourceId, userAssignedResourceId);
auto credential = std::make_shared<ManagedIdentityCredential>(options);
auto blobClient = BlobClient(blobUrl, credential);
// @end_snippet
}
{
// @begin_snippet: UserAssignedManagedIdentityViaObjectId
std::string userAssignedObjectId = "<your managed identity object ID>";
ManagedIdentityCredentialOptions options;
options.IdentityId = ManagedIdentityId(ManagedIdentityIdKind::ObjectId, userAssignedObjectId);
auto credential = std::make_shared<ManagedIdentityCredential>(options);
auto blobClient = BlobClient(blobUrl, credential);
// @end_snippet
}
{
// @begin_snippet: SystemAssignedManagedIdentity
ManagedIdentityCredentialOptions options;
options.IdentityId = ManagedIdentityId(ManagedIdentityIdKind::SystemAssigned, {});
auto credential = std::make_shared<ManagedIdentityCredential>(options);
auto blobClient = BlobClient(blobUrl, credential);
// @end_snippet
}
{
// @begin_snippet: SystemAssignedManagedIdentityBrief
auto credential = std::make_shared<ManagedIdentityCredential>();
auto blobClient = BlobClient(blobUrl, credential);
// @end_snippet
}
}
int main() int main()
{ {
try try
@ -31,5 +89,7 @@ int main()
return 1; return 1;
} }
ShowDifferentManagedIdentityApproaches();
return 0; return 0;
} }

View File

@ -80,9 +80,11 @@ For detailed samples please review the samples provided.
First step is to create a SecretClient. First step is to create a SecretClient.
<!-- @insert_snippet: SecretSample1CreateCredential -->
```cpp ```cpp
auto const keyVaultUrl = std::getenv("AZURE_KEYVAULT_URL"); auto const keyVaultUrl = std::getenv("AZURE_KEYVAULT_URL");
auto credential = std::make_shared<Azure::Identity::DefaultAzureCredential>(); auto credential = std::make_shared<Azure::Identity::DefaultAzureCredential>();
// create client // create client
SecretClient secretClient(keyVaultUrl, credential); SecretClient secretClient(keyVaultUrl, credential);
``` ```
@ -91,6 +93,7 @@ SecretClient secretClient(keyVaultUrl, credential);
We call the secret client to create a secret. We call the secret client to create a secret.
<!-- @insert_snippet: SecretSample1CreateSecret -->
```cpp ```cpp
std::string secretName("MySampleSecret"); std::string secretName("MySampleSecret");
std::string secretValue("my secret value"); std::string secretValue("my secret value");
@ -102,34 +105,36 @@ secretClient.SetSecret(secretName, secretValue);
We retrieve a secret by name. We retrieve a secret by name.
<!-- @insert_snippet: SecretSample1GetSecret -->
```cpp ```cpp
// get secret // get secret
KeyVaultSecret secret = secretClient.GetSecret(secretName).Value; KeyVaultSecret secret = secretClient.GetSecret(secretName).Value;
std::string valueString = secret.Value.HasValue() ? secret.Value.Value() : "NONE RETURNED"; std::string valueString = secret.Value.HasValue() ? secret.Value.Value() : "NONE RETURNED";
std::cout << "Secret is returned with name " << secret.Name << " and value " std::cout << "Secret is returned with name " << secret.Name << " and value " << valueString
<< valueString << std::endl; << std::endl;
``` ```
### Update a secret ### Update a secret
Updating an existing secret Updating an existing secret
<!-- @insert_snippet: SecretSample1UpdateSecretProperties -->
```cpp ```cpp
// change one of the properties // change one of the properties
secret.Properties.ContentType = "my content"; secret.Properties.ContentType = "my content";
// update the secret // update the secret
KeyVaultSecret updatedSecret = secretClient.UpdateSecretProperties(secret.Properties).Value; KeyVaultSecret updatedSecret = secretClient.UpdateSecretProperties(secret.Properties).Value;
std::string updatedValueString = updatedSecret.Value.HasValue() ? updatedSecret.Value.Value() std::string updatedValueString
: "NONE RETURNED"; = updatedSecret.Value.HasValue() ? updatedSecret.Value.Value() : "NONE RETURNED";
std::cout << "Secret's content type is now " << updatedValueString std::cout << "Secret's content type is now " << updatedValueString << std::endl;
<< std::endl;
``` ```
### Delete a secret ### Delete a secret
Delete an existing secret. Delete an existing secret.
<!-- @insert_snippet: SecretSample1DeleteSecret -->
```cpp ```cpp
// start deleting the secret // start deleting the secret
DeleteSecretOperation operation = secretClient.StartDeleteSecret(secret.Name); DeleteSecretOperation operation = secretClient.StartDeleteSecret(secret.Name);
@ -147,6 +152,7 @@ secretClient.PurgeDeletedSecret(secret.Name);
Delete and Purge a secret. Delete and Purge a secret.
<!-- @insert_snippet: SecretSample1DeleteSecret -->
```cpp ```cpp
// start deleting the secret // start deleting the secret
DeleteSecretOperation operation = secretClient.StartDeleteSecret(secret.Name); DeleteSecretOperation operation = secretClient.StartDeleteSecret(secret.Name);
@ -164,6 +170,7 @@ secretClient.PurgeDeletedSecret(secret.Name);
List all the secrets in keyvault. List all the secrets in keyvault.
<!-- @insert_snippet: SecretSample4ListAllSecrets -->
```cpp ```cpp
// get all the versions of a secret // get all the versions of a secret
for (auto secretsVersion = secretClient.GetPropertiesOfSecretsVersions(secret1.Name); for (auto secretsVersion = secretClient.GetPropertiesOfSecretsVersions(secret1.Name);

View File

@ -21,8 +21,8 @@ using namespace std::chrono_literals;
int main() int main()
{ {
auto const keyVaultUrl = std::getenv("AZURE_KEYVAULT_URL");
// @begin_snippet: SecretSample1CreateCredential // @begin_snippet: SecretSample1CreateCredential
auto const keyVaultUrl = std::getenv("AZURE_KEYVAULT_URL");
auto credential = std::make_shared<Azure::Identity::DefaultAzureCredential>(); auto credential = std::make_shared<Azure::Identity::DefaultAzureCredential>();
// create client // create client