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:
Родитель
f3119bd899
Коммит
aa728eed6d
|
@ -110,9 +110,14 @@ The snippet generation tool, located in `eng\scripts\Generate-Snippets.ps1`, is
|
|||
|
||||
```bash
|
||||
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
|
||||
source file.
|
||||
|
||||
|
|
|
@ -82,7 +82,28 @@ function ProcessSnippetsInFile {
|
|||
|
||||
# Insert the snippet text.
|
||||
$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') {
|
||||
|
@ -98,8 +119,8 @@ function ProcessSnippetsInFile {
|
|||
|
||||
}
|
||||
# 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"
|
||||
$original_contents = $original_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", ""
|
||||
|
||||
if ($verify) {
|
||||
if ($output_file_contents -ne $original_contents) {
|
||||
|
|
|
@ -45,31 +45,31 @@ An AMQP Message Sender is responsible for sending messages to an AMQP server ove
|
|||
|
||||
<!-- @insert_snippet: CreateSender -->
|
||||
```cpp
|
||||
Azure::Core::Amqp::_internal::MessageSenderOptions senderOptions;
|
||||
senderOptions.Name = "sender-link";
|
||||
senderOptions.MessageSource = "source";
|
||||
senderOptions.SettleMode = Azure::Core::Amqp::_internal::SenderSettleMode::Unsettled;
|
||||
senderOptions.MaxMessageSize = (std::numeric_limits<uint16_t>::max)();
|
||||
Azure::Core::Amqp::_internal::MessageSenderOptions senderOptions;
|
||||
senderOptions.Name = "sender-link";
|
||||
senderOptions.MessageSource = "source";
|
||||
senderOptions.SettleMode = Azure::Core::Amqp::_internal::SenderSettleMode::Unsettled;
|
||||
senderOptions.MaxMessageSize = (std::numeric_limits<uint16_t>::max)();
|
||||
|
||||
Azure::Core::Amqp::_internal::MessageSender sender(
|
||||
session, credentials->GetEntityPath(), senderOptions, nullptr);
|
||||
Azure::Core::Amqp::_internal::MessageSender sender(
|
||||
session, credentials->GetEntityPath(), senderOptions, nullptr);
|
||||
```
|
||||
|
||||
Once the message sender has been created, it can be used to send messages to the remote server.
|
||||
|
||||
<!-- @insert_snippet: SendMessages -->
|
||||
```cpp
|
||||
Azure::Core::Amqp::Models::AmqpMessage message;
|
||||
message.SetBody(Azure::Core::Amqp::Models::AmqpBinaryData{'H', 'e', 'l', 'l', 'o'});
|
||||
Azure::Core::Amqp::Models::AmqpMessage message;
|
||||
message.SetBody(Azure::Core::Amqp::Models::AmqpBinaryData{'H', 'e', 'l', 'l', 'o'});
|
||||
|
||||
constexpr int maxMessageSendCount = 5;
|
||||
constexpr int maxMessageSendCount = 5;
|
||||
|
||||
int messageSendCount = 0;
|
||||
while (messageSendCount < maxMessageSendCount)
|
||||
{
|
||||
auto result = sender.Send(message);
|
||||
messageSendCount += 1;
|
||||
}
|
||||
int messageSendCount = 0;
|
||||
while (messageSendCount < maxMessageSendCount)
|
||||
{
|
||||
auto result = sender.Send(message);
|
||||
messageSendCount += 1;
|
||||
}
|
||||
```
|
||||
|
||||
## 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
|
||||
|
||||
![Impressions](https://azure-sdk-impressions.azurewebsites.net/api/impressions/azure-sdk-for-cpp%2Fsdk%2Fcore%2Fcore-opentelemetry%2FREADME.png)
|
||||
|
||||
|
|
|
@ -75,24 +75,24 @@ Demonstrates writing messages to the Azure Event Hubs service using the AMQP pro
|
|||
|
||||
<!-- @insert_snippet: CreateSender -->
|
||||
```cpp
|
||||
Azure::Core::Amqp::_internal::MessageSenderOptions senderOptions;
|
||||
senderOptions.Name = "sender-link";
|
||||
senderOptions.MessageSource = "source";
|
||||
senderOptions.SettleMode = Azure::Core::Amqp::_internal::SenderSettleMode::Unsettled;
|
||||
senderOptions.MaxMessageSize = (std::numeric_limits<uint16_t>::max)();
|
||||
Azure::Core::Amqp::_internal::MessageSenderOptions senderOptions;
|
||||
senderOptions.Name = "sender-link";
|
||||
senderOptions.MessageSource = "source";
|
||||
senderOptions.SettleMode = Azure::Core::Amqp::_internal::SenderSettleMode::Unsettled;
|
||||
senderOptions.MaxMessageSize = (std::numeric_limits<uint16_t>::max)();
|
||||
|
||||
Azure::Core::Amqp::_internal::MessageSender sender(
|
||||
session, credentials->GetEntityPath(), senderOptions, nullptr);
|
||||
Azure::Core::Amqp::_internal::MessageSender sender(
|
||||
session, credentials->GetEntityPath(), senderOptions, nullptr);
|
||||
```
|
||||
|
||||
<!-- @insert_snippet: create_connection -->
|
||||
```cpp
|
||||
Azure::Core::Amqp::_internal::ConnectionOptions connectionOptions;
|
||||
connectionOptions.ContainerId = "whatever";
|
||||
connectionOptions.EnableTrace = true;
|
||||
connectionOptions.Port = credential->GetPort();
|
||||
Azure::Core::Amqp::_internal::Connection connection(
|
||||
credential->GetHostName(), credential, connectionOptions);
|
||||
Azure::Core::Amqp::_internal::ConnectionOptions connectionOptions;
|
||||
connectionOptions.ContainerId = "whatever";
|
||||
connectionOptions.EnableTrace = true;
|
||||
connectionOptions.Port = credential->GetPort();
|
||||
Azure::Core::Amqp::_internal::Connection connection(
|
||||
credential->GetHostName(), credential, connectionOptions);
|
||||
```
|
||||
|
||||
### 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
|
||||
Demonstrates receiving messages from the Azure Event Hubs service using an AMQP Management API.
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
||||
<!-- @insert_snippet: UserAssignedManagedIdentityViaClientId -->
|
||||
```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>";
|
||||
ManagedIdentityCredentialOptions options;
|
||||
options.IdentityId = ManagedIdentityId(ManagedIdentityIdKind::ClientId, userAssignedClientId);
|
||||
|
||||
auto credential = std::make_shared<ManagedIdentityCredential>(options);
|
||||
|
||||
std::string blobUrl = "https://myaccount.blob.core.windows.net/mycontainer/myblob";
|
||||
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:
|
||||
|
||||
<!-- @insert_snippet: UserAssignedManagedIdentityViaResourceId -->
|
||||
```cpp
|
||||
std::string userAssignedResourceId = "<your managed identity resource ID>";
|
||||
ManagedIdentityCredentialOptions options;
|
||||
options.IdentityId = ManagedIdentityId(ManagedIdentityIdKind::ResourceId, userAssignedResourceId);
|
||||
options.IdentityId
|
||||
= ManagedIdentityId(ManagedIdentityIdKind::ResourceId, userAssignedResourceId);
|
||||
|
||||
auto credential = std::make_shared<ManagedIdentityCredential>(options);
|
||||
|
||||
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:
|
||||
|
||||
<!-- @insert_snippet: UserAssignedManagedIdentityViaObjectId -->
|
||||
```cpp
|
||||
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);
|
||||
```
|
||||
|
||||
|
@ -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:
|
||||
|
||||
<!-- @insert_snippet: SystemAssignedManagedIdentity -->
|
||||
```cpp
|
||||
ManagedIdentityCredentialOptions options;
|
||||
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:
|
||||
|
||||
<!-- @insert_snippet: SystemAssignedManagedIdentityBrief -->
|
||||
```cpp
|
||||
auto credential = std::make_shared<ManagedIdentityCredential>();
|
||||
auto blobClient = BlobClient(blobUrl, credential);
|
||||
|
|
|
@ -54,7 +54,7 @@ target_compile_definitions(environment_credential_sample PRIVATE _azure_BUILDING
|
|||
create_per_service_target_build_for_sample(identity environment_credential_sample)
|
||||
|
||||
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_compile_definitions(managed_identity_credential_sample PRIVATE _azure_BUILDING_SAMPLES)
|
||||
create_per_service_target_build_for_sample(identity managed_identity_credential_sample)
|
||||
|
|
|
@ -3,9 +3,67 @@
|
|||
|
||||
#include <azure/identity/managed_identity_credential.hpp>
|
||||
#include <azure/service/client.hpp>
|
||||
#include <azure/storage/blobs.hpp>
|
||||
|
||||
#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()
|
||||
{
|
||||
try
|
||||
|
@ -31,5 +89,7 @@ int main()
|
|||
return 1;
|
||||
}
|
||||
|
||||
ShowDifferentManagedIdentityApproaches();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -80,9 +80,11 @@ For detailed samples please review the samples provided.
|
|||
|
||||
First step is to create a SecretClient.
|
||||
|
||||
<!-- @insert_snippet: SecretSample1CreateCredential -->
|
||||
```cpp
|
||||
auto const keyVaultUrl = std::getenv("AZURE_KEYVAULT_URL");
|
||||
auto credential = std::make_shared<Azure::Identity::DefaultAzureCredential>();
|
||||
|
||||
// create client
|
||||
SecretClient secretClient(keyVaultUrl, credential);
|
||||
```
|
||||
|
@ -91,6 +93,7 @@ SecretClient secretClient(keyVaultUrl, credential);
|
|||
|
||||
We call the secret client to create a secret.
|
||||
|
||||
<!-- @insert_snippet: SecretSample1CreateSecret -->
|
||||
```cpp
|
||||
std::string secretName("MySampleSecret");
|
||||
std::string secretValue("my secret value");
|
||||
|
@ -102,34 +105,36 @@ secretClient.SetSecret(secretName, secretValue);
|
|||
|
||||
We retrieve a secret by name.
|
||||
|
||||
<!-- @insert_snippet: SecretSample1GetSecret -->
|
||||
```cpp
|
||||
// get secret
|
||||
KeyVaultSecret secret = secretClient.GetSecret(secretName).Value;
|
||||
|
||||
std::string valueString = secret.Value.HasValue() ? secret.Value.Value() : "NONE RETURNED";
|
||||
std::cout << "Secret is returned with name " << secret.Name << " and value "
|
||||
<< valueString << std::endl;
|
||||
std::cout << "Secret is returned with name " << secret.Name << " and value " << valueString
|
||||
<< std::endl;
|
||||
```
|
||||
|
||||
### Update a secret
|
||||
|
||||
Updating an existing secret
|
||||
|
||||
<!-- @insert_snippet: SecretSample1UpdateSecretProperties -->
|
||||
```cpp
|
||||
// change one of the properties
|
||||
secret.Properties.ContentType = "my content";
|
||||
// update the secret
|
||||
KeyVaultSecret updatedSecret = secretClient.UpdateSecretProperties(secret.Properties).Value;
|
||||
std::string updatedValueString = updatedSecret.Value.HasValue() ? updatedSecret.Value.Value()
|
||||
: "NONE RETURNED";
|
||||
std::cout << "Secret's content type is now " << updatedValueString
|
||||
<< std::endl;
|
||||
std::string updatedValueString
|
||||
= updatedSecret.Value.HasValue() ? updatedSecret.Value.Value() : "NONE RETURNED";
|
||||
std::cout << "Secret's content type is now " << updatedValueString << std::endl;
|
||||
```
|
||||
|
||||
### Delete a secret
|
||||
|
||||
Delete an existing secret.
|
||||
|
||||
<!-- @insert_snippet: SecretSample1DeleteSecret -->
|
||||
```cpp
|
||||
// start deleting the secret
|
||||
DeleteSecretOperation operation = secretClient.StartDeleteSecret(secret.Name);
|
||||
|
@ -147,6 +152,7 @@ secretClient.PurgeDeletedSecret(secret.Name);
|
|||
|
||||
Delete and Purge a secret.
|
||||
|
||||
<!-- @insert_snippet: SecretSample1DeleteSecret -->
|
||||
```cpp
|
||||
// start deleting the secret
|
||||
DeleteSecretOperation operation = secretClient.StartDeleteSecret(secret.Name);
|
||||
|
@ -164,6 +170,7 @@ secretClient.PurgeDeletedSecret(secret.Name);
|
|||
|
||||
List all the secrets in keyvault.
|
||||
|
||||
<!-- @insert_snippet: SecretSample4ListAllSecrets -->
|
||||
```cpp
|
||||
// get all the versions of a secret
|
||||
for (auto secretsVersion = secretClient.GetPropertiesOfSecretsVersions(secret1.Name);
|
||||
|
|
|
@ -21,8 +21,8 @@ using namespace std::chrono_literals;
|
|||
|
||||
int main()
|
||||
{
|
||||
auto const keyVaultUrl = std::getenv("AZURE_KEYVAULT_URL");
|
||||
// @begin_snippet: SecretSample1CreateCredential
|
||||
auto const keyVaultUrl = std::getenv("AZURE_KEYVAULT_URL");
|
||||
auto credential = std::make_shared<Azure::Identity::DefaultAzureCredential>();
|
||||
|
||||
// create client
|
||||
|
|
Загрузка…
Ссылка в новой задаче