Wednesday 29 October 2014

Automatically scaling an application cluster

https://gallery.technet.microsoft.com/CPU-Disk-and-Memory-a8a123bc First thing to do in a 'auto-scaling' script is to get the health of your cluster. There are a few ways you might wish to do this:
  • Create a request to the website and check its timelyness
  • Correlate the requests/sec from WMI or SNMP to the number or servers e.g. each server can deal with 300req/sec

Example 1 - Checking the performance of a endpoint


while (1 -eq 1){
    $request = Measure-Command { Invoke-WebRequest http://mywebsitecluster.com/ }
    if ($request.TotalSeconds -gt 4){
        Write-Warning "Website is running slowly"
        Scale-Up
    } 
    if ($request.TotalSeconds -lt 1){
        Write-Warning "Website is a bit too fast"
        Scale-Down
    }
     else {
        Write-Host "Website is happy"
        Start-Sleep -Seconds 30 
    }
}

Example 2 - Checking an WMI performance counter

For this example, you can use a safer metric. How many requests per second is each web server doing and what is the average. I've assumed we're looking at the Default Web Site in IIS and you have WMI allowed to the VPN connected clients.
I've also used a script that automates the Cisco VPN client to hop onto the network first. https://github.com/DimensionDataCBUSydney/DimensionData.ComputeClient/blob/master/PowerShell%20Examples/Connect%20to%20Cisco%20VPN%20endpoint.ps1 call this vpnConnect.ps1
# Connect to the Cisco VPN so we can read WMI data.
.\vpnConnect.ps1 -VPNHost "au1.cloud-vpn.net" -username "myUser" -password "myPassord"

while (1 -eq 1){
    $webNetwork = Get-CaasNetworks | Where name -like "Web Cluster"
    $servers = Get-CaasDeployedServer | Where networkId -eq $webNetwork.Id

    $totalAvg=0
    $totalTotal=0
    foreach ($server in $servers){
        # Get the number of requests per second.
        $counters = @("\Web Service(Default Web Site)\Get Requests/sec")
        $metrics = Get-Counter -ComputerName $server.privateIp -Counter $counters -SampleInterval 5 -MaxSamples 5

        $total = 0
        foreach($metric in $metrics)            
        {            
          $total += $metric.CookedValue            
        } 
        $avg = $total/5
        Write-Host "Server $($server.name) is doing $avg requests per second"
        $totalTotal += $avg
    }
    $totalAvg = $totalTotal/$servers.Count

    if ($totalAvg -gt 500){
        Write-Warning "Cluster is heavily loaded"
        Scale-Up
    } 
    if ($totalAvg -lt 100){
        Write-Warning "Website is quiet enough"
        Scale-Down
    } else {
        Write-Host "Cluster is happy"
        
    }
    Start-Sleep -Seconds 30 
}

Scale Up Action

Next up you need a way to quickly add a new server to a farm, the best method is to have a web template saved in your customer images then use a devops tool like puppet,chef,octopus or salt to configure the runtime settings.
function Scale-Up {
    $maxServers = 10
    $myTestNetwork  = Get-CaasNetworks | Where name -like "Web Cluster"

    # Get the template for the web server from our custom images
    $webServerTemplate = Get-CaasCustomerImages -NetworkWithLocations $myTestNetwork | Where name -eq "Web Server Template"

    #Get all the servers deployed using the web server template
    $myTestServers = Get-CaasDeployedServer | Where sourceImageId -eq $webServerTemplate.Id

    if ($myTestServers.Count -lt $maxServers){
        $newid = [guid]::NewGuid()
        $newServerDetails = New-CaasServerDetails -Name "WebServer $($newid)" -Description "Web server" -AdminPassword "MyPassword123!" -IsStarted $true -OsServerImage $webServerTemplate -Network $myTestNetwork
        New-CaasVM -ServerDetails $newServerDetails
        Write-Host "Created WebServer $($newid)"
    }
}

Scale down action

This is the same as the scale up but you have a minimum number of servers and you kill the first one over that amount.
function Scale-Down {
    $minServers = 3
    $myTestNetwork  = Get-CaasNetworks | Where name -like "Web Cluster"

    # Get the template for the web server from our custom images
    $webServerTemplate = Get-CaasCustomerImages -NetworkWithLocations $myTestNetwork | Where name -eq "Web Server Template"

    #Get all the servers deployed using the web server template
    $myTestServers = Get-CaasDeployedServer | Where sourceImageId -eq $webServerTemplate.Id

    if ($myTestServers.Count -gt $minServers){
        # Remove the first server in the cluster
        Remove-CaasVM -Server $myTestServers[0]
    }
}
Learnings - - You would need to consider here how you measure the health. VarnishCache has a requests per node metric, but no SNMP support. Apache Httpd can be scripted for SNMP but not out of the box. - You need to consider how you want each server to 'spin-up', I would recommend a configuration agent such as puppet agent, octopus tentacle or a SCCM agent. To setup the server. You could use PSExec or Putty.exe to remotely configure some basic commands e.g. service httpd start - You have to consider the load balancing here and how that works, this does not add the new server to the farm for you. You would need a software load balancer in this configuration. This is provided as an illustrative example, not a fully tested product. Enjoy!

Tuesday 28 October 2014

Don't panic! How to quickly backup all of your machines

In the Dimension Data Cloud, you can enable file and application backups for your Virtual Machines for Linux and Windows.

For this example I will show you how to use some of the commands to get a list of servers that have backup, find the machines that have a File System agent (Windows or Linux), check if they have a running job and start a new job if not.

The scenario for this example is you want to run an update on your servers, like a kernel patch or a Windows update. Before you do so, you want to run a backup of all your machines.

Load the module and connect to the API

Import-Module CaaS

$secpasswd = ConvertTo-SecureString "mySecure123Pa$$!" -AsPlainText -Force
$login= New-Object System.Management.Automation.PSCredential ("my-login-user", $secpasswd)

New-CaasConnection -ApiCredentials $login -ApiBaseUri "https://api-au.dimensiondata.com/oec/0.9/"

Now, you want to get a list of all the servers that have backup. Get the servers in your account and filter to those that have something in the backup field.
$serversWithBackup = Get-CaasDeployedServer | Where backup -NotLike $Null
foreach ( $server in $serversWithBackup) { 

For each of those servers, get a list of backup clients where the agent type (e.g. File System, SQL Server, MySQL) is the File System Agent. This is either FA.LINUX or FA.WIN.
    Write-Host $server.name is $server.backup.servicePlan 
    $fileClients = Get-CaasBackupClients -Server $server | Where type -Like "FA.%"

For each client, because you can have more than 1 file system client on a server, check if there is a running job by looking at the runningJob property of the client. If there is a job running, issue a warning (you can use this as an opportunity to cancel the job using " Remove-CaaSBackupJobAgent -Server $server -BackupClient $fileClient " but for my example I won't. Finally, issue a new request to start a backup using the New-CaasBackupJob command.
    foreach( $fileClient in $fileClients){
        
        if ($fileClient.runningJob.status -eq "Running") {
            Write-Warning "Another Job is already running for  $($server.name)" 
        } else { 
            Write-Host Starting backup of $server.name 
            New-CaasBackupJob -Server $server -BackupClient $fileClient 
        }
    }
}
So in summary, the script looks like:
Import-Module CaaS

$secpasswd = ConvertTo-SecureString "mySecure123Pa$$!" -AsPlainText -Force
$login= New-Object System.Management.Automation.PSCredential ("my-login-user", $secpasswd)

New-CaasConnection -ApiCredentials $login -ApiBaseUri "https://api-au.dimensiondata.com/oec/0.9/"

$serversWithBackup = Get-CaasDeployedServer | Where backup -NotLike $Null
foreach ( $server in $serversWithBackup) { 

    Write-Host $server.name is $server.backup.servicePlan 
    $fileClients = Get-CaasBackupClients -Server $server | Where type -Like "FA.%"

    foreach( $fileClient in $fileClients){
        
        if ($fileClient.runningJob.status -eq "Running") {
            Write-Warning "Another Job is already running for  $($server.name)" 
        } else { 
            Write-Host Starting backup of $server.name 
            New-CaasBackupJob -Server $server -BackupClient $fileClient 
        }
    }
}

Monday 27 October 2014

Turning out the lights- powering down your VM's overnight

In the last post I showed how to use the PowerShell module for CaaS to perform some basic operations.
A common benefit of cloud is touted as "you can save $ by turning off your servers when you're not using them".
So, to demonstrate how that can be done here with a quick recipe.
I'm assuming you only want to do this on your Development environments and not on production, so firstly, pick the network where your lab/testing servers are stored. I have a network called "Ant Dev" with my test servers inside. I don't need them to be running over the weekend.
$devNetwork = Get-CaasNetworks | Where name -like "Ant Dev"
Now, get all the servers in that network by searching for servers in that network Id.
$devServers = Get-CaasDeployedServer | Where networkId -eq $devNetwork.Id
 foreach ( $server in $devServers ) {
  Write-Host Shutting down $server.name 
  Set-CaasServerState -Action Shutdown -Server $server
}

Now, wrap this script up into a ps1 file and store somewhere you can call it from Scheduled tasks. I've used c:\Users\Anthony\Documents\caas-sleep.ps1 for this example
Copy the code below into ISE and set the user and file location to meet your requirements
$action = New-ScheduledTaskAction –Execute "powershell.exe" -Argument "c:\Users\Anthony\Documents\caas-sleep.ps1" -AsJob
$trigger = New-ScheduledTaskTrigger -Weekly -DaysOfWeek Friday -At 7pm
$user = "MyServer\Administrator"
$S = New-ScheduledTaskSettingsSet
$D = New-ScheduledTask -Action $action -Principal $user -Trigger $trigger -Settings $S
Register-ScheduledTask T1 -InputObject $D
This will create a Scheduled task in Windows to run the job at 6pm every Friday. Customise the script above to set the 'wake-up' version for late Sunday night. Set-CaasServerState takes -Action [PowerOff | PowerOn | Restart | Shutdown] PowerOff and PowerOn are the hard-off options and restart and shutdown use VMware tools to initiate a clean shutdown or reboot.

PowerShell for CaaS

The R&D team in Sydney have assembled a .NET client library for the CaaS REST API on Github (here), which is freely available and open source. We use this in day-to-day automation tasks such as spinning up lab environments, testing backup clients and the backup server (as a consumer) and scaling out our Virtual Machines. We have also assembled a set of PowerShell Cmdlets for doing simple tasks in CaaS and published this online free for any customers or internal usage.

Installing the Module for Windows desktop or server

Requirements First download the ZIP file to your desktop. CaaS-PowerShell.1.0.0.1.zip Extract this ZIP to the PowerShell modules folder on Windows (C:\Program Files\WindowsPowerShell\Modules) This will create a sub-directory called 'CaaS' with the module DLLs and a schema so that PowerShell knows what to do.
PS C:\Users\anthony> Get-Module -ListAvailable CaaS


    Directory: C:\Program Files\WindowsPowerShell\Modules


ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Binary     1.0.0.1    CaaS                                {Add-CaasBackupClient, Add-CaasAclRule, Add-CaasNatRule, R...

To get a list of commands available use the default PowerShell command Get-Command
PS C:\Users\anthony> Get-Command -Module CaaS

CommandType     Name                                               ModuleName
-----------     ----                                               ----------
Cmdlet          Add-CaasAclRule                                    CaaS
Cmdlet          Add-CaasBackupClient                               CaaS
Cmdlet          Add-CaasNatRule                                    CaaS
Cmdlet          Get-CaasAclRules                                   CaaS
Cmdlet          Get-CaasBackupClients                              CaaS
Cmdlet          Get-CaasBackupClientTypes                          CaaS
Cmdlet          Get-CaasBackupSchedulePolicies                     CaaS
Cmdlet          Get-CaasBackupStoragePolicies                      CaaS
Cmdlet          Get-CaasCustomerImageImports                       CaaS
Cmdlet          Get-CaasCustomerImages                             CaaS
Cmdlet          Get-CaasDataCentre                                 CaaS
Cmdlet          Get-CaasDeployedServer                             CaaS
Cmdlet          Get-CaasNatRules                                   CaaS
Cmdlet          Get-CaasNetworks                                   CaaS
Cmdlet          Get-CaasOsImages                                   CaaS
Cmdlet          Get-CaasOvfPackages                                CaaS
Cmdlet          New-CaasBackupJob                                  CaaS
Cmdlet          New-CaasConnection                                 CaaS
Cmdlet          New-CaasImportCustomerImage                        CaaS
Cmdlet          New-CaasNetwork                                    CaaS
Cmdlet          New-CaasServerDetails                              CaaS
Cmdlet          New-CaasVM                                         CaaS
Cmdlet          Remove-CaasAclRule                                 CaaS
Cmdlet          Remove-CaasBackupClient                            CaaS
Cmdlet          Remove-CaasBackupJob                               CaaS
Cmdlet          Remove-CaasNatRule                                 CaaS
Cmdlet          Remove-CaasNetwork                                 CaaS
Cmdlet          Remove-CaasVM                                      CaaS
Cmdlet          Set-CaasBackupClient                               CaaS
Cmdlet          Set-CaasBackupPlan                                 CaaS
Cmdlet          Set-CaasProvisionBackup                            CaaS
Cmdlet          Set-CaasServerState                                CaaS

As you can see there are some commands for basic utilities in CaaS, such as creating VMs, getting lists of servers, networks or datacenters. The first command you need to use is the New-CaaSConnection command, this creates a connection to the API with your credentials. Of course, you will need a CaaS account first. The CaaSConnection command takes a PSCredential object, you can initialize one by either prompting for a login in Windows, e.g.
PS C:\Users\anthony> $login = Get-Credential

cmdlet Get-Credential at command pipeline position 1
Supply values for the following parameters:
Credential
PS C:\Users\anthony> $login

UserName                                                                                                       Password
--------                                                                                                       --------
cbu-test-lab-01                                                                                System.Security.SecureString
Or by creating one in the script:
$secpasswd = ConvertTo-SecureString "myPassword123" -AsPlainText -Force
$login= New-Object System.Management.Automation.PSCredential ("cbu-test-lab-01", $secpasswd)
Once you have a login object, you need the API Base URI for your CaaS tenant, if this is a private hosted or private cloud, this will be published seperately. All public instances are listed on the REST API documentation For reference the Dimension Data URLs are: North America (NA) api-na.dimensiondata.com Europe (EU) api-eu.dimensiondata.com Australia (AU) api-au.dimensiondata.com Africa (AF) api-mea.dimensiondata.com Asia Pacific (AP) api-ap.dimensiondata.com South America (SA) api-latam.dimensiondata.com Canada(CA) api-canada.dimensiondata.com For this example, I will use the Dimension Data Australia instance as https://api-au.dimensiondata.com/oec/0.9/
PS C:\Users\anthony> New-CaasConnection -ApiCredentials $login -ApiBaseUri https://api-au.dimensiondata.com/oec/0.9/

Account
-------
DD.CBU.Compute.Api.Contracts.Directory.Account
So you see we now have a client connection object, this is used for the other commands to send the credentials and the API connection details. The client connection is stored in the runspace, so you don't have to pass it as a parameter. Now, we can run commands such as :
PS C:\Users\anthony> Get-CaasNetworks | Format-Table

id                  name                description         location            privateNet          multicast
--                  ----                -----------         --------            ----------          ---------
9eb09828-e2f7-11... My Example Network 1                     AU1                 10.208.253.0        false
9eb09f1c-e2f7-11... My Example Network 2                     AU1                 10.208.254.0        false

Commands can be chained, for example to get a list of your networks and then for each network a list of ACL rules:
PS C:\Users\anthony> Get-CaasNetworks | Get-CaasAclRules | Format-Table

id          name        status         position      action protocol    sourceIpRan destination portRange          type
                                                                        ge          IpRange
--          ----        ------         --------      ------ --------    ----------- ----------- ---------          ----
70818fcb... default-98  NORMAL               98        DENY TCP         IpRangeType IpRangeType PortRang...  INSIDE_ACL
82ef4a7e... default-99  NORMAL               99        DENY TCP         IpRangeType IpRangeType PortRang...  INSIDE_ACL
a650bbc2... default-100 NORMAL              100      PERMIT ICMP        IpRangeType IpRangeType PortRang... OUTSIDE_ACL

Servers can be listed using the Get-CaaSDeployedServer command
PS C:\Users\anthony> Get-CaasDeployedServer | Where name -eq "CMS"


backup          :
name            : CMS
description     :
operatingSystem : OSType
cpuCount        : 4
memoryMb        : 8192
disk            : {3f73f797-d72c-4c32-aa5a-933ea1c11974, 207d8751-0eec-4616-89d3-6e251610b3df}
softwareLabel   : {MSSQL2012R2E}
sourceImageId   : f1433fd7-957f-4940-ab00-873ff953f056
networkId       : e4cc9bde-59ba-11e1-9153-001b21cfdbe1
machineName     : 10-218-122-12
privateIp       : 10.218.122.12
publicIp        : 17.184.202.224
created         : 4/14/2014 5:34:27 AM
isDeployed      : True
isStarted       : True
state           : NORMAL
status          :
machineStatus   : {vmwareToolsVersionStatus, vmwareToolsRunningStatus, vmwareToolsApiVersion}
id              : 30515bba-d7a8-4a55-8a7b-4c71144876c4
location        : AU1
Here are some other examples: Get a list of virtual machines that have backup and print the service plan they are in:
$serversWithBackup = Get-CaasDeployedServer | Where backup -NotLike $Null
foreach ( $server in $serversWithBackup) { Write-Host $server.name is $server.backup.servicePlan }
Servers in a bad way
$badServers = Get-CaasDeployedServer | Where state -NotLike "NORMAL"
I will follow up with some additional posts on common tasks using the PowerShell commands. Anthony Shaw

First Post!!

Hi, This blog will be used to share experiments or utlities for automating Dimension Data's Compute-as-a-Service offering. Anthony