Over the past three articles in this series, we’ve defined a business problem and broken it down into components in order to create a simple high-level design, we’ve written some initial code to perform some of the fundamental operations, and using that initial design and some abstraction, we’ve incorporated some of the rest of the design objectives.

We have some automation code now that in the usual happy case probably works just fine. But we’re not done yet. The article after this will help us to take care of issues as they arise and in this article, we’ll look at making this automation even more flexible and portable and cloud-like.

Detached Configuration

In our last article, we ended up calling our Sync-ProdRep function with the names of a production and a reporting VM to process. It looked like this in our script:

Sync-ProdRep -ProdName "sqlprod1" -ReportName "sqlrep1"
Sync-ProdRep -ProdName "sqlprod2" -ReportName "sqlrep2"
Sync-ProdRep -ProdName "sqlprod3" -ReportName "sqlrep3"

This is fine given that we have only a handful of pairs. But what about cases where we have many more? Or if we want to allow others to use our automation script? In the latter case, the instructions will be to open the script in a text editor and change all of the VM names.

Here, we’ll create a simple configuration file that contains only the host mappings, and we’ll teach our script how to parse it and call the Sync-ProdRep function for each VM pair. It may sound complication, but we’ll create the file as a JSON format file and use the in-built JSON magic that PowerShell already has.

First create a file called host-mappings.json in a text editor and add this as the contents:

{
 "mappings": [
 { "prod": "sqlprod1", "report": "sqlrep1" },
 { "prod": "sqlprod2", "report": "sqlrep2" },
 { "prod": "sqlprod3", "report": "sqlrep3" }
 ]
}

The JSON format is well-documented across the web, but what we have is a JSON object called “mappings” that is an array (a set) of production and reporting VM name mappings.

Now we’ll replace all three Sync-ProdRep lines above with this little PowerShell excerpt:

$mappings = ConvertFrom-Json "$(Get-Content 'host-mappings.json')"
$mappings.mappings | `
   Foreach-Object { Sync-ProdRep -Prod $_.prod -Report $_.report }

This may seem daunting, there’s nothing there that you won’t find in any of the standard PowerShell corners of the interwebs. Here’s a breakdown:

  1. We’re using Get-Content to read our JSON file into a string.
  2. ConvertFrom-Json is turning our JSON text into a PowerShell object that we’re storing in a variable called $mappings.
  3. The $mappings object contains an array called ‘mappings’ (see line 2 of our JSON file).
  4. We’re using Foreach-Object to take each item in that array (each item is the name of a production and the name of a reporting VM) and pass each in to Sync-ProdRep as a production and a reporting VM name.

This achieves exactly the same thing as the code we ended the last article with. The difference is that to add, remove or modify the list of VM pairs we process, we simply modify the JSON file and not the code itself.

Why?

This kind of abstraction allows us to grant control over different parts of the process to different users. In its simplest form, that JSON file could be modified by someone without any PowerShell experience and our code would work unchanged.

Extend that with another business case and the JSON file could be automatically generated from a list of VMs from SCVMM that have particular tags for example.

Or could be created carefully by some automation behind a System Center (or other) Self-Service Portal. The synchronisation automation code doesn’t need to change as the business needs grow over time.

Homework

You’ll notice that the Tintri VMstore hostname is still a hard-coded string in our Sync-ProdRep function. If we had VMs spread across multiple VM-aware storage appliances, this wouldn’t work. How would you move that hostname into the JSON configuration file and pass it into the Sync-ProdRep function?

Summary

Here’s a snapshot of where our automation code is at this point:

function Sync-ProdRep {
    [CmdletBinding()]
    param(
      [parameter(Mandatory=$true)][String]$prodname,
      [parameter(Mandatory=$true)][String]$reportname
    )
    # Connect to our VMstore
    $vmstore = "vmstore01.vmlevel.com"
    Connect-TintriServer -UseCurrentUserCredentials $vmstore

    # Retrieve a VM object for both VMs by name
    $report = Get-TintriVM -Name $reportname
    $prod = Get-TintriVM -Name $prodname

    # Take a snapshot of our production VM and using the
    # Returned snapshot ID, retrieve the snapshot object
    $snapshotIdNew-TintriVMSnapshot `
       -SnapshotDescription "Reporting snapshot" `
       -VM $prod `
       -SnapshotConsistency CRASH_CONSISTENT
    $snapshot = Get-TintriVMSnapshot -VM $prod `
       -SnapshotId $snapshotId

    # Use SyncVM's vDisk sync to synchronise the data and
    # log vDisks from the prod snapshot to the reporting VM
    $result = Sync-TintriVDisk -VM $report `
       -SourceSnapshot $snapshot `
       -AllButFirstVDisk
}

$mappings = ConvertFrom-Json "$(Get-Content 'host-mappings.json')"
$mappings.mappings | `
   Foreach-Object { Sync-ProdRep -Prod $_.prod -Report $_.report }

 

[Image created by Wolfgang Maslo and used unmodified under CC 2.0]

3 thoughts on “Automation and Private Cloud part IV

Leave a comment