Creating snapshot and export in new Azure SDK .NET - Azure.ResourceManager - c#

Because old Azure SDK for .NET is deprecated, I'm trying to migrate it to new version. I've been stucked with finding substitions for old methods and properties in new SDK. We do a snapshot of existing database and export to Storage Account.
Snippet of old approach:
var sp = new ServicePrincipalLoginInformation()
{
ClientId = clientId,
ClientSecret = clientSecret
};
var credentials = new AzureCredentials(sp, tenantId, AzureEnvironment.AzureGlobalCloud);
var azureClient = Authenticate(credentials).WithSubscription(subscriptionId);
var sqlServer = await azureClient.SqlServers.GetByIdAsync(db.SourceServerId);
var serverDbs = await sqlServer.Databases.ListAsync();
var snapshotDb = serverDbs.FirstOrDefault(i => i.Name == snapshotDbName);
if(snapshotDb is not null)
return;
snapshotDb = await azureClient.SqlServers.Databases
.Define(snapshotDbName)
.WithExistingSqlServer(sqlServer)
.WithSourceDatabase(sourceDatabaseId)
.WithMode(CreateMode.Copy)
.CreateAsync(cancellationToken);
.
.
.
var storageAccount = azureClient.StorageAccounts.GetByIdAsync(storageId);
await snapshotDb.ExportTo(storageAccount, storageContainer, outputFileName)
.WithSqlAdministratorLoginAndPassword(user, password)
.ExecuteAsync(cancellationToken);
According to documentation, I was able to get this:
var sp = new ClientSecretCredential(tenantId, clientId, clientSecret);
var azureClient = new ArmClient(sp, subscriptionId);
var ri = new ResourceIdentifier(NOT SURE WHAT SHOULD BE HERE);
var resGroup = azure.GetResourceGroupResource(ri);
var sqlServerResponse = await resGroup.GetSqlServers().GetAsync(sourceServerId);
var sqlServer = sqlServers.Value;
var serverDBs = sqlServer.GetSqlDatabases();
var snapshotDB = serverDBs.FirstOrDefault(x => x.Data.Name == db.SnapshotDbName);
What are substitution commands, which handle creating snapshot and exporting to Storage Account base on parameters used in deprecated sample? Or do I miss some Package?

We have a general guidance for using our latest version of .NET SDK against resource management.
Regarding your issue, you can refer to code below
var resourceGroup = _client.GetDefaultSubscription().GetResourceGroup(resourceGroupName).Value;
var sqlServer = resourceGroup.GetSqlServer("mySqlServerName").Value;
var sqlDB = sqlServer.GetSqlDatabase("myDbName").Value;
var exportResult= sqlDB.Export(Azure.WaitUntil.Completed, new Azure.ResourceManager.Sql.Models.DatabaseExportDefinition("storageKeyType", "storageKey", new Uri("storageUri"), "adminLogin", "adminLoginPWD")).Value;
The _client here is ArmClient object,
your code var ri = new ResourceIdentifier(NOT SURE WHAT SHOULD BE HERE); is not necessary, may I know why do you want to create a resource identifier here?
Please make sure you are using 1.1.0 version of Azure SDK for SQL libirary in .NET
We are open to any feedback regarding our new SDK, feel free to let us know your thoughts on our new SDK in this survey

Related

Create a Cosmos Db and Container in C#

I am trying to create a database and container using C# I am trying to use the newest version of Azure.ResourceManager.CosmosDB 1.2.0.
In a previos version I used:
var client = new CosmosDBManagementClient("someendpoint", new DefaultAzureCredential());
var database = await client.SqlResources.StartCreateUpdateSqlDatabaseAsync(
AzureResourceGroup, AccountName, DatabaseName,
new SqlDatabaseCreateUpdateParameters(
new SqlDatabaseResource(DatabaseName),
new CreateUpdateOptions()
)
);
var armcontainer = await client.SqlResources.StartCreateUpdateSqlContainerAsync(
AzureResourceGroup, AccountName, DatabaseName,
ContainerName,
GetContainerParameters()
);
However, the CosmosDBManagementClient is no longer in library.
I know there is:
var client = new CosmosClient(endpoint, new DefaultAzureCredential());
await client.CreateDatabaseIfNotExistsAsync("testing",
throughput: null, new RequestOptions());
I also can't get this to work due to 403 error, even with the contributor permissions, but I know this was an error because you are supposed to use the resource manager.
Any suggestions would be appreciated.
I haven't worked with passwordless access but have you tried providing the id explictely?
string userAssignedClientId = "<your managed identity client Id>";
var credential = new DefaultAzureCredential(new DefaultAzureCredentialOptions { ManagedIdentityClientId = userAssignedClientId });
var client = new CosmosClient(endpoint, new DefaultAzureCredential());
If this doesn't work you could try the connection string approach:
using CosmosClient client = new(
accountEndpoint: "endpoint here",
authKeyOrResourceToken: "key here");

Microsoft Graph - Update mailbox settings with SDK

I'm trying to set automatic replies for Microsoft users using the example here.
The difference from the docs is that I'm trying to do this not for me, but for another user using permissions. Getting error: The OData request is not supported
The issue is mentioned here and here. But both are closed.
The one solution mentioned is here but for this I'm getting the error Access is denied. Check credentials and try again.
Does anyone know of a way to set automatic replies / update mailbox settings in microsoft graph using the c# sdk using the users option - not me?
Using application api permission is right here and we may also refer to the workaround mentioned by OP which worked for him.
===========================================
According to the api document, it support Application permission,
So could you pls try this code:
using Azure.Identity;
using Microsoft.Graph;
var scopes = new[] { "https://graph.microsoft.com/.default" };
var tenantId = "your_tenant_name.onmicrosoft.com";
var clientId = "azure_ad_app_id";
var clientSecret = "client_secret";
var clientSecretCredential = new ClientSecretCredential(
tenantId, clientId, clientSecret);
var graphClient = new GraphServiceClient(clientSecretCredential, scopes);
var mailboxSettings = new MailboxSettings
{
AutomaticRepliesSetting = new AutomaticRepliesSetting
{
Status = AutomaticRepliesStatus.Scheduled,
ScheduledStartDateTime = new DateTimeTimeZone
{
DateTime = "2022-07-03T18:00:00",
TimeZone = "UTC"
},
ScheduledEndDateTime = new DateTimeTimeZone
{
DateTime = "2022-07-07T18:00:00",
TimeZone = "UTC"
},
ExternalReplyMessage = "I'm on vacation.",
InternalReplyMessage = "I'm on vacation."
}
};
var user = new User();
user.MailboxSettings = mailboxSettings;
await graphClient.Users["user_id"].Request().UpdateAsync(user);
And pls don't forget to add Application api permission MailboxSettings.ReadWrite in Azure AD.

.net Okta and AWS authentication

Trying authenticate via Okta to access AWS resource using c#/.net. Found this sdk for .net https://github.com/okta/okta-auth-dotnet. Following the examples but do not know how to procced to list all AWS resources. Any help will be appreciated it. (credentials are not real and part of the example)
var client = new AuthenticationClient(new OktaClientConfiguration
{
OktaDomain = "https://{{yourOktaDomain}}",
});
var authnOptions = new AuthenticateOptions()
{
Username = $"darth.vader#imperial-senate.gov",
Password = "D1sturB1ng!",
};
var authnResponse = await authClient.AuthenticateAsync(authnOptions);
Step 1: Install the NuGet package. It will install all the dependencies too.
install package 'Okta.Auth.Sdk.2.0.3'
The code you posted should work with one change (name of the variable). Since you copied the code directly from the GitHub site.
using Okta.Auth.Sdk;
using Okta.Sdk.Abstractions.Configuration;
public static class Program
{
static void Main(string[] args)
{
var client = new AuthenticationClient(new OktaClientConfiguration
{
OktaDomain = "https://{{yourOktaDomain}}",
});
var authnOptions = new AuthenticateOptions()
{
Username = $"darth.vader#imperial-senate.gov",
Password = "D1sturB1ng!",
};
//Asynchronous programming with async and await
//var authnResponse = await client.AuthenticateAsync(authnOptions);
//Synchromous Programming - use Result - which would wait until the task had completed.
var authnResponse = client.AuthenticateAsync(authnOptions).Result;
}
}
I did verify the code. and the AuthenticationStatus was SUCCESS

ElasticSearch.NET passing AWS Signature v4 in POST requests?

I am very new to ElasticSearch, and have set up an AWS Lambda function in c# to take the content of S3 object(s) (which contain JSON data) with the hopes of posting them to ES to be searchable.
I'm using the Elasticsearch.Net nuget library.
In the documentation here - https://github.com/elastic/elasticsearch-net there is samples of configuring the node URI etc, but my understanding is that any requests to ES need to be signed with AWS Signature V4 (based on Access/Secret key). I have created an IAM user for this purpose, but nowhere in the documentation can I find how to sign the POST requests. The samples show post methods, but no place to include the signature?
E.g.
var person = new Person
{
FirstName = "Martijn",
LastName = "Laarman"
};
var indexResponse = lowlevelClient.Index<BytesResponse>("people", "person", "1", PostData.Serializable(person));
byte[] responseBytes = indexResponse.Body;
var asyncIndexResponse = await lowlevelClient.IndexAsync<StringResponse>("people", "person", "1", PostData.Serializable(person));
string responseString = asyncIndexResponse.Body;
Even when instantiating the connection, nowhere is there a place to add your credentials?
var settings = new ConnectionConfiguration(new Uri("http://example.com:9200"))
.RequestTimeout(TimeSpan.FromMinutes(2));
var lowlevelClient = new ElasticLowLevelClient(settings);
I have checked ConnectionConfiguration object but there's no methods or properties that seem related. What have I missed?
Using the elasticsearch-net-aws package you should be able to set up the low level client like so:
var httpConnection = new AwsHttpConnection("us-east-1"); // or whatever region you're using
var pool = new SingleNodeConnectionPool(new Uri(TestConfig.Endpoint));
var config = new ConnectionConfiguration(pool, httpConnection);
config.DisableDirectStreaming();
var client = new ElasticLowLevelClient(config);
// ...
// if using an access key
var httpConnection = new AwsHttpConnection("us-east-1", new StaticCredentialsProvider(new AwsCredentials
{
AccessKey = "My AWS access key",
SecretKey = "My AWS secret key",
}));
// if using app.config, environment variables, or roles
var httpConnection = new AwsHttpConnection("us-east-1");
var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
var config = new ConnectionSettings(pool, httpConnection);
var client = new ElasticClient(config);

How to export SQL Database directly to blob storage programmatically

I need to programmatically backup/export a SQL Database (either in Azure, or a compatible-one on-prem) to Azure Storage, and restore it to another SQL Database. I would like to use only NuGet packages for code dependencies, since I cannot guarantee that either the build or production servers will have the Azure SDK installed. I cannot find any code examples for something that I assume would be a common action. The closest I found was this:
https://blog.hompus.nl/2013/03/13/backup-your-azure-sql-database-to-blob-storage-using-code/
But, this code exports to a local bacpac file (requiring RoleEnvironment, an SDK-only object). I would think there should be a way to directly export to Blob Storage, without the intermediary file. One thought was to create a Stream, and then run:
services.ExportBacpac(stream, "dbnameToBackup")
And then write the stream to storage; however a Memory Stream wouldn't work--this could be a massive database (100-200 GB).
What would be a better way to do this?
Based on my test, the sql Microsoft Azure SQL Management Library 0.51.0-prerelease support directly export the sql database .bacpac file to the azure storage.
We could using sqlManagementClient.ImportExport.Export(resourceGroup, azureSqlServer, azureSqlDatabase,exportRequestParameters) to export the .bacpac file the azure storage.
But we couldn't find ImportExport in the lastest version of Microsoft Azure SQL Management Library SDK. So we could only use sql Microsoft Azure SQL Management Library 0.51.0-prerelease SDK.
More details about how to use sql Microsoft Azure SQL Management Library to export the sql backup to azure blob storage, you could refer to below steps and codes.
Prerequisites:
Registry an App in Azure AD and create service principle for it. More detail steps about how to registry app and get access token please refer to document.
Details codes:
Notice: Replace the clientId,tenantId,secretKey,subscriptionId with your registered azure AD information. Replace the azureSqlDatabase,resourceGroup,azureSqlServer,adminLogin,adminPassword,storageKey,storageAccount with your own sql database and storage.
static void Main(string[] args)
{
var subscriptionId = "xxxxxxxx";
var clientId = "xxxxxxxxx";
var tenantId = "xxxxxxxx";
var secretKey = "xxxxx";
var azureSqlDatabase = "data base name";
var resourceGroup = "Resource Group name";
var azureSqlServer = "xxxxxxx"; //testsqlserver
var adminLogin = "user";
var adminPassword = "password";
var storageKey = "storage key";
var storageAccount = "storage account";
var baseStorageUri = $"https://{storageAccount}.blob.core.windows.net/brandotest/";//with container name endwith "/"
var backName = azureSqlDatabase + "-" + $"{DateTime.UtcNow:yyyyMMddHHmm}" + ".bacpac"; //back up sql file name
var backupUrl = baseStorageUri + backName;
ImportExportOperationStatusResponse exportStatus = new ImportExportOperationStatusResponse();
try
{
ExportRequestParameters exportRequestParameters = new ExportRequestParameters
{
AdministratorLogin = adminLogin,
AdministratorLoginPassword = adminPassword,
StorageKey = storageKey,
StorageKeyType = "StorageAccessKey",
StorageUri = new Uri(backupUrl)
};
SqlManagementClient sqlManagementClient = new SqlManagementClient(new Microsoft.Azure.TokenCloudCredentials(subscriptionId, GetAccessToken(tenantId, clientId, secretKey)));
var export = sqlManagementClient.ImportExport.Export(resourceGroup, azureSqlServer, azureSqlDatabase,
exportRequestParameters); //do export operation
while (exportStatus.Status != Microsoft.Azure.OperationStatus.Succeeded) // until operation successed
{
Thread.Sleep(1000 * 60);
exportStatus = sqlManagementClient.ImportExport.GetImportExportOperationStatus(export.OperationStatusLink);
}
Console.WriteLine($"Export DataBase {azureSqlDatabase} to Storage {storageAccount} Succesfully");
}
catch (Exception exception)
{
//todo
}
}
private static string GetAccessToken(string tenantId, string clientId, string secretKey)
{
var authenticationContext = new AuthenticationContext($"https://login.windows.net/{tenantId}");
var credential = new ClientCredential(clientId, secretKey);
var result = authenticationContext.AcquireTokenAsync("https://management.core.windows.net/",
credential);
if (result == null)
{
throw new InvalidOperationException("Failed to obtain the JWT token");
}
var token = result.Result.AccessToken;
return token;
}
Result like this:
1.Send request to tell sql server start exporting to azure blob storage
2.Continue sending request to monitor the database exported operation status.
3.Finish exported operation.
Here's an idea:
Pass the stream to the .ExportBacPac method but hold a reference to it on a different thread where you regularly empty and reset the stream so that there's no memory overflow. I'm assuming here, that Dac does not have any means to access the stream while it is being filled.
The thing you have to take care of yourself though is thread safety - MemoryStreams are not thread safe by default. So you'd have to write your own locking mechanisms around .Position and .CopyTo. I've not tested this, but if you handle locking correctly I'd assume the .ExportBacPac method won't throw any errors while the other thread accesses the stream.
Here's a very simple example as pseudo-code just outlining my idea:
ThreadSafeStream stream = new ThreadSafeStream();
Task task = new Task(async (exitToken) => {
MemoryStream partialStream = new MemoryStream();
// Check if backup completed
if (...)
{
exitToken.Trigger();
}
stream.CopyToThreadSafe(partialStream);
stream.PositionThreadSafe = 0;
AzureService.UploadToStorage(partialStream);
await Task.Delay(500); // Play around with this - it shouldn't take too long to copy the stream
});
services.ExportBacpac(stream, "dbnameToBackup");
await TimerService.RunTaskPeriodicallyAsync(task, 500);
It's similiar to the Brando's answer but this one uses a stable package:
using Microsoft.WindowsAzure.Management.Sql;
Nuget
Using the same variables in the Brando's answer, the code will be like this:
var azureSqlServer = "xxxxxxx"+".database.windows.net";
var azureSqlServerName = "xxxxxxx";
SqlManagementClient managementClient = new SqlManagementClient(new TokenCloudCredentials(subscriptionId, GetAccessToken(tenantId, clientId, secretKey)));
var exportParams = new DacExportParameters()
{
BlobCredentials = new DacExportParameters.BlobCredentialsParameter()
{
StorageAccessKey = storageKey,
Uri = new Uri(baseStorageUri)
},
ConnectionInfo = new DacExportParameters.ConnectionInfoParameter()
{
ServerName = azureSqlServer,
DatabaseName = azureSqlDatabase,
UserName = adminLogin,
Password = adminPassword
}
};
var exportResult = managementClient.Dac.Export(azureSqlServerName, exportParams);
You can use Microsoft.Azure.Management.Fluent to export your database to a .bacpac file and store it in a blob. To do this, there are few things you need to do.
Create an AZAD (Azure Active Directory) application and Service Principal that can access resources. Follow this link for a comprehensive guide.
From the first step, you are going to need "Application (client) ID", "Client Secret", and "Tenant ID".
Install Microsoft.Azure.Management.Fluent NuGet packages, and import Microsoft.Azure.Management.Fluent, Microsoft.Azure.Management.ResourceManager.Fluent, and Microsoft.Azure.Management.ResourceManager.Fluent.Authentication namespaces.
Replace the placeholders in the code snippets below with proper values for your usecase.
Enjoy!
var principalClientID = "<Applicaiton (Client) ID>";
var principalClientSecret = "<ClientSecret>";
var principalTenantID = "<TenantID>";
var sqlServerName = "<SQL Server Name> (without '.database.windows.net'>";
var sqlServerResourceGroupName = "<SQL Server Resource Group>";
var databaseName = "<Database Name>";
var databaseLogin = "<Database Login>";
var databasePassword = "<Database Password>";
var storageResourceGroupName = "<Storage Resource Group>";
var storageName = "<Storage Account>";
var storageBlobName = "<Storage Blob Name>";
var bacpacFileName = "myBackup.bacpac";
var credentials = new AzureCredentialsFactory().FromServicePrincipal(principalClientID, principalClientSecret, principalTenantID, AzureEnvironment.AzureGlobalCloud);
var azure = await Azure.Authenticate(credentials).WithDefaultSubscriptionAsync();
var storageAccount = await azure.StorageAccounts.GetByResourceGroupAsync(storageResourceGroupName, storageName);
var sqlServer = await azure.SqlServers.GetByResourceGroupAsync(sqlServerResourceGroupName, sqlServerName);
var database = await sqlServer.Databases.GetAsync(databaseName);
await database.ExportTo(storageAccount, storageBlobName, bacpacFileName)
.WithSqlAdministratorLoginAndPassword(databaseLogin, databasePassword)
.ExecuteAsync();

Categories

Resources