Saturday, July 29, 2023

 Using the Azure Database Migration Service to transfer data from source to destination MySQL database servers. 

When we want to transfer data and schema between databases whether they are on-premises or in the cloud, the azure data migration service instance comes helpful.  

Some highlights: 

  1. One instance works across all subscriptions. 

  1. Can transfer between on-premises and cloud and cloud to cloud. 

  1. Pay-per-use billing. 

  1. Provides a wizard to create data transfer activity. 

Some cons: 

  1. Limited features via IaC as compared to the portal but enough to get by. 

  1. Not recommended for developer instances or tiny databases that can be exported and imported via mysqldump. 

  1. binlog_expire_logs_seconds must be set to non-zero value on source server. 

The steps to perform the data transfer activity between the source and destination MySQL servers involves: 

  1. Create a source mysql instance mysql-src-1 in rg-mysql-1 

  1. Create a database and add a table to mysql-src-1 

  1. Create a destination mysql instance mysql-dest-1 in rg-mysql-1 

  1. Deploy the DMS service instance and project. 

  1. Create and run an activity to transfer data. 

  1. Verify the data. 

IaC: 

resource "azurerm_database_migration_service" "single-to-flexible-dms" { 

  name                = var.name 

  location            = var.location 

  resource_group_name = var.resource_group_name 

  subnet_id           = var.subnet_id 

  sku_name            = var.sku_name 

  tags                = var.tags 

} 

 

resource "azurerm_database_migration_project" "dms-project" { 

  name                = format("prj-%s", azurerm_database_migration_service.single-to-flexible-dms.name) 

  service_name        = azurerm_database_migration_service.single-to-flexible-dms.name 

  resource_group_name = azurerm_database_migration_service.single-to-flexible-dms.resource_group_name 

  location            = azurerm_database_migration_service.single-to-flexible-dms.location 

  source_platform     = try(var.source_platform, "SQL") 

  target_platform     = try(var.target_platform, "SQLDB") 

  tags                = azurerm_database_migration_service.single-to-flexible-dms.tags 

  depends_on = [ 

    azurerm_database_migration_service.single-to-flexible-dms 

  ] 

} 

Friday, July 28, 2023

Application Gateway and Location Header rewrites:


One of the previous articles described a problem about redirects from an application using the provided Host header which changes when an application gateway comes in between the client and the application. This article describes a fix.

When an application is reached directly, it gets the host as "context.Request.Host" and the remote IP address as "context.Connection.RemoteIpAddress" which the application uses to create redirects with Location header. With the introduction of the application gateways, these values are skewed but we get the original values in the X-Original-XX and X-Forwarded-XX headers. The app just needs to update its middleware to make use of these applications.

For example:         

public void Configure(IApplicationBuilder app)

{

   app.UseForwardedHeaders();

   app.Use(...);

}

The above works the same as setting a few options directly in various languages:

- options.ForwardedHeaders = ForwardedHeaders.All;

- options.ForwardedHostHeaderName = "X-Original-Host";

- options.ForwardLimit = 2;

The number 2 here signifies the hops between the client and the gateway and the gateway and the app service.

Another alternative is for the Application to specify the Location Uri to directly include the gateway endpoint. For example:

using System.Net;

using System.Net.Http;

using System.Threading;

using Microsoft.AspNetCore.Mvc;

using Microsoft.Extensions.Primitives;

using Newtonsoft.Json;

 

public static async Task<IActionResult> Run(HttpRequest req, ILogger log)

{

    log.LogInformation("C# HTTP trigger function processed a request.");

    string gateway = “gwy-demo-3.centralus.cloudapp.net”;

    string name = req.Query["name"];

 

    string requestBody = await new StreamReader(req.Body).ReadToEndAsync();

    dynamic data = JsonConvert.DeserializeObject(requestBody);

    name = name ?? data?.name;

 

    string responseMessage = string.IsNullOrEmpty(name)

        ? "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response."

                : $"Hello, {name}. This HTTP triggered function executed successfully for a request that came from: {req.Headers.Host}.";

  var result = new AcceptedResult($"https://{gateway}/", responseMessage);

  return result;

}

 

Finally, there is a conditional rewrite rule that we can author on the application gateway as an alternative to fixing all the responses from all the applications that are backend pool members of the application gateway.

 

Sample deployment: gwy3proof.zip

Reference: Article on how to author rewrite rules.