Aria Automation - Prices without Pricing Cards

Overview

Intro

Recently, I was asked to create several Blueprints that would display the resource price at the time of the request through the Service Broker. This had to be accomplished without using VMware Aria Automation Pricing Cards.

The need was to showcase templates with these features:

  • Template Azure
    • OS: Windows And Linux
    • 3 Flavours: Small, Medium and Large
    • Managed or Unamanged Machine (SLA)
    • In case the vm is managed you have Monitoring SLA - STD or H24
  • Template GCP
    • OS: Windows And Linux
    • 3 Flavours: Small, Medium And Large
    • Managed or Unamanged Machine (SLA)
    • In case the vm is managed you have Monitoring SLA - STD or H24
  • Template vCenter Windows
    • OS: Windows 2019 or 2022
    • 3 Flavours: Small, Medium And Large
    • Managed or Unamanged Machine (SLA)
    • In case the vm is managed you have Monitoring SLA - STD or H24

The price varies depending on the Flavour, the operating system, whether it is Managed or Unmanaged, and the type of SLA if the VM is managed.

To enable the most flexible management of future price updates, my solution was to read the prices from a CSV file using PowerShell.

Resource Preparation

Blueprints

Let's take a look at the 3 Blueprints I have prepared:

vCenter Windows Blueprint

This Blueprint involves deploying a VM, in this case, a Windows VM, and specifies which vCenter and Storage to allocate it to.

'Managed' refers to a production VM that needs to be monitored, backed up, etc. The SLA should be "Yes" only if the VM is Managed.

The inputs and thus the customization options are:

  • Name
  • Image
  • Flavour
  • SLA
  • Managed
  • Network

vCenter VM Blueprint

 1formatVersion: 1
 2inputs:
 3  Name:
 4    type: string
 5    title: Name
 6  Image:
 7    type: string
 8    title: Image
 9    oneOf:
10      - title: WIN-SRV-2019
11        const: WIN-2019-TEMPLATE
12      - title: WIN-SRV-2022
13        const: WIN-2022-TEMPLATE
14    default: WIN-2019-TEMPLATE
15  Flavour:
16    type: string
17    title: Flavour
18    oneOf:
19      - title: SMALL
20        const: SMALL
21      - title: MEDIUM
22        const: MEDIUM
23      - title: LARGE
24        const: LARGE
25  Managed:
26    type: string
27    titile: Manged
28    oneOf:
29      - title: 'Yes'
30        const: 'YES'
31      - title: 'No'
32        const: 'NO'
33  sla:
34    type: string
35    title: SLA
36    oneOf:
37      - title: H24
38        const: H24
39      - title: STD
40        const: STD
41  Network:
42    type: string
43    title: Network
44    oneOf:
45      - title: YOUR_NETWORK_NAME
46        const: network:YOUR_NETWORK_TAG
47resources:
48  Cloud_vSphere_Machine_1:
49    type: Cloud.vSphere.Machine
50    properties:
51      name: ${input.Name}
52      image: ${input.Image}
53      flavor: ${input.Flavour}
54      Managed: ${input.Managed}
55      sla: ${input.sla}
56      storage:
57        constraints:
58          - tag: Storage:YOUR_STORAGE_TAG
59      networks:
60        - network: ${resource.Cloud_vSphere_Network_1.id}
61      constraints:
62        - tag: Cluster:YOUR_CLUSTER_TAG
63  Cloud_vSphere_Network_1:
64    type: Cloud.vSphere.Network
65    properties:
66      networkType: existing
67      constraints:
68        - tag: ${input.Network}

GCP Blueprint

The GCP Blueprint includes Windows and Linux images. In this instance, as it's configured with only one Cloud Account, there's no need to specify details like the cluster. It's sufficient to add the tag associated with the Cloud Zone to the VM.

The inputs are:

  • Name
  • Image
  • Flavour
  • SLA
  • Managed

GCP VM Blueprint

 1
 2formatVersion: 1
 3inputs:
 4  Name:
 5    type: string
 6    title: Name
 7  Image:
 8    type: string
 9    title: System OS
10    description: Choose OS
11    oneOf:
12      - title: Windows Server 2022
13        const: GCP-IMG_Win202022
14      - title: Windows Server 2019
15        const: GCP-IMG_Win2019
16      - title: UBUNTU-2210
17        const: GCP-UBUNTU-2210
18    default: GCP-IMG_Win2019
19  Flavour:
20    type: string
21    title: Flavour
22    oneOf:
23      - title: SMALL
24        const: SMALL-GCP-n2-standard-2
25      - title: MEDIUM
26        const: MEDIUM-GCP-n2-standard-4
27      - title: LARGE
28        const: LARGE-GCP-n2-standard-8
29  Managed:
30    type: string
31    titile: Manged
32    oneOf:
33      - title: 'Yes'
34        const: 'YES'
35      - title: 'No'
36        const: 'NO'
37  sla:
38    type: string
39    title: SLA
40    oneOf:
41      - title: H24
42        const: H24
43      - title: STD
44        const: STD
45resources:
46  Cloud_GCP_Machine_1:
47    type: Cloud.GCP.Machine
48    properties:
49      name: ${input.Name}
50      image: ${input.Image}
51      flavor: ${input.Flavour}
52      Managed: ${input.Managed}
53      sla: ${input.sla}
54      networks:
55        - assignPublicIpAddress: false
56      constraints:
57        - tag: platform:gcp #match only one gcp cloud zone and associated network

Azure Blueprint

In this case too, I have mapped both Windows and Linux images, and the rest of the template is very similar to the previous ones.

The inputs are the same as for GCP:

  • Name
  • Image
  • Flavour
  • SLA
  • Managed

AZURE VM Blueprint

 1formatVersion: 1
 2inputs:
 3  Name:
 4    type: string
 5    title: Name
 6  Image:
 7    type: string
 8    title: System OS
 9    description: Choose OS
10    oneOf:
11      - title: Windows Server 2019
12        const: Azure-WindowsServer:2019-Datacenter:lates
13      - title: UBUNTU-2204
14        const: AZURE-UBUNTU-2204
15    default: Azure-WindowsServer:2019-Datacenter:lates
16  Flavour:
17    type: string
18    title: Flavour
19    oneOf:
20      - title: SMALL
21        const: Azure-Standard_B2as_v2
22      - title: MEDIUM
23        const: Azure-Standard_B4als_v2
24      - title: LARGE
25        const: Azure-Standard_B8als_v2
26  Managed:
27    type: string
28    titile: Manged
29    oneOf:
30      - title: 'Yes'
31        const: 'YES'
32      - title: 'No'
33        const: 'NO'
34  sla:
35    type: string
36    title: SLA
37    oneOf:
38      - title: H24
39        const: H24
40      - title: STD
41        const: STD
42resources:
43  Cloud_Network_1:
44    type: Cloud.Network
45    properties:
46      networkType: existing
47      constraints:
48        - tag: Network:YOUR_AZURE_NETWORK_TAG
49  Cloud_Azure_Machine_1:
50    type: Cloud.Azure.Machine
51    properties:
52      image: ${input.Image}
53      flavor: ${input.Flavour}
54      Managed: ${input.Managed}
55      sla: ${input.sla}
56      constraints:
57        - tag: YOUR_AZURE_ZONE_TAG
58      networks:
59        - network: ${resource.Cloud_Network_1.id}
60        - assignPublicIpAddress: false
Warning

Warning: All the above examples are for demonstration purposes and must be adapted to your own configuration.

CSV file

The CSV file is quite straightforward, although it may not seem so at first glance. It contains a list of all the various possible combinations of VMs, their specifications, and prices.

As mentioned earlier, the fundamental values on which the price is calculated are:

  • Flavour
  • SLA
  • CloudZone
  • OS
  • Managed / Unamanged
 1Template;SLA;Flavour;OS;cloudzone;managed;vcpu;vram;vm price;managing price
 2vCenter managed windows (H24);H24;small;windows;vCenter;yes;2;8;65,22;46,67
 3vCenter managed windows (H24);H24;medium;windows;vCenter;yes;4;16;112,81;46,67
 4vCenter managed windows (H24);H24;large;windows;vCenter;yes;8;32;207,98;46,67
 5vCenter unmanaged windows;NULL;small;windows;vCenter;no;2;8;65,22;null
 6vCenter unmanaged windows;NULL;medium;windows;vCenter;no;4;16;112,81;null
 7vCenter unmanaged windows;NULL;large;windows;vCenter;no;8;32;207,98;null
 8vCenter managed windows (STD);STD;small;windows;vCenter;yes;2;8;65,22;42,50
 9vCenter managed windows (STD);STD;medium;windows;vCenter;yes;4;16;112,81;42,50
10vCenter managed windows (STD);STD;large;windows;vCenter;yes;8;32;207,98;42,50
11vCenter managed linux (H24);H24;small;linux;vCenter;yes;2;8;52,57;46,67
12vCenter managed linux (H24);H24;medium;linux;vCenter;yes;4;16;87,51;46,67
13vCenter managed linux (H24);H24;large;linux;vCenter;yes;8;32;157,38;46,67
14vCenter unmanaged linux;NULL;small;linux;vCenter;no;2;8;52,57;null
15vCenter unmanaged linux;NULL;medium;linux;vCenter;no;4;16;87,51;null
16vCenter unmanaged linux;NULL;large;linux;vCenter;no;8;32;157,38;null
17vCenter managed linux (STD);STD;small;linux;vCenter;yes;2;8;52,57;42,50
18vCenter managed linux (STD);STD;medium;linux;vCenter;yes;4;16;87,51;42,50
19vCenter managed linux (STD);STD;large;linux;vCenter;yes;8;32;157,38;42,50
20GCP managed windows (H24);H24;small;windows;GCP;yes;2;8;122,71;46,67
21GCP managed windows (H24);H24;medium;windows;GCP;yes;4;16;239,93;46,67
22GCP managed windows (H24);H24;large;windows;GCP;yes;8;32;474,37;46,67
23GCP unmanaged windows;NULL;small;windows;GCP;no;2;8;122,71;null
24GCP unmanaged windows;NULL;medium;windows;GCP;no;4;16;239,93;null
25GCP unmanaged windows;NULL;large;windows;GCP;no;8;32;474,37;null
26GCP managed windows (STD);STD;small;windows;GCP;yes;2;8;122,71;42,50
27GCP managed windows (STD);STD;medium;windows;GCP;yes;4;16;239,93;42,50
28GCP managed windows (STD);STD;large;windows;GCP;yes;8;32;474,37;42,50
29GCP managed linux (H24);H24;small;linux;GCP;yes;2;8;59,17;46,67
30GCP managed linux (H24);H24;medium;linux;GCP;yes;4;16;112,86;46,67
31GCP managed linux (H24);H24;large;linux;GCP;yes;8;32;220,22;46,67
32GCP unmanaged linux;NULL;small;linux;GCP;no;2;8;59,17;null
33GCP unmanaged linux;NULL;medium;linux;GCP;no;4;16;112,86;null
34GCP unmanaged linux;NULL;large;linux;GCP;no;8;32;220,22;null
35GCP managed linux (STD);STD;small;linux;GCP;yes;2;8;59,17;42,50
36GCP managed linux (STD);STD;medium;linux;GCP;yes;4;16;112,86;42,50
37GCP managed linux (STD);STD;large;linux;GCP;yes;8;32;220,22;42,50
38AZURE managed windows (H24);H24;small;windows;AZURE;yes;2;8;145,31;46,67
39AZURE managed windows (H24);H24;medium;windows;AZURE;yes;4;16;286,08;46,67
40AZURE managed windows (H24);H24;large;windows;AZURE;yes;8;32;567,62;46,67
41AZURE unmanaged windows;NULL;small;windows;AZURE;no;2;8;145,31;null
42AZURE unmanaged windows;NULL;medium;windows;AZURE;no;4;16;286,08;null
43AZURE unmanaged windows;NULL;large;windows;AZURE;no;8;32;567,62;null
44AZURE managed windows (STD);STD;small;windows;AZURE;yes;2;8;145,31;42,50
45AZURE managed windows (STD);STD;medium;windows;AZURE;yes;4;16;286,08;42,50
46AZURE managed windows (STD);STD;large;windows;AZURE;yes;8;32;567,62;42,50
47AZURE managed linux (H24);H24;small;linux;AZURE;yes;2;8;81,83;46,67
48AZURE managed linux (H24);H24;medium;linux;AZURE;yes;4;16;159,11;46,67
49AZURE managed linux (H24);H24;large;linux;AZURE;yes;8;32;313,68;46,67
50AZURE unmanaged linux;NULL;small;linux;AZURE;no;2;8;81,83;null
51AZURE unmanaged linux;NULL;medium;linux;AZURE;no;4;16;159,11;null
52AZURE unmanaged linux;NULL;large;linux;AZURE;no;8;32;313,68;null
53AZURE managed linux (STD);STD;small;linux;AZURE;yes;2;8;81,83;42,50
54AZURE managed linux (STD);STD;medium;linux;AZURE;yes;4;16;159,11;42,50
55AZURE managed linux (STD);STD;large;linux;AZURE;yes;8;32;313,68;42,50

Save this CSV file as prices.csv.

Warning

Please note, the prices listed are only examples and do not represent real prices!!

vRo Action Script

The PowerShell script, taking the previously specified data as input, matches it with the data inside the CSV file and then calculates the price, which is then returned as a value.

In this case, the price format uses a comma to separate decimal values. For example, €60,45 (60 euros and 45 cents).

  1function Handler($context, $inputs) {
  2 
  3    function Get-CsvData {
  4        param (
  5            [string]$searchBasePath,
  6            [string]$fileName
  7        )
  8        
  9        Write-Host "Searching for the file '$fileName' starting from the base path: $searchBasePath"
 10
 11        # Listing files in the search directory (for debugging)
 12        Write-Host "List the files in the base path (for debugging)"
 13        Get-ChildItem -Path $searchBasePath -Recurse -File -ErrorAction SilentlyContinue | Select-Object -First 10 | ForEach-Object { Write-Host $_.FullName }
 14
 15        # Search for the file in the specified path and its subdirectories
 16        $fileFullPath = Get-ChildItem -Path $searchBasePath -Filter $fileName -Recurse -File | Select-Object -First 1
 17
 18        if ($fileFullPath -eq $null) {
 19            Write-Host "File not found: $fileName"
 20            return $null
 21        }
 22
 23        Write-Host "File path not found: $($fileFullPath.FullName)"
 24
 25        # Import data from the found CSV file
 26        $data = Import-Csv -Path $fileFullPath.FullName -Delimiter ';'
 27        return $data
 28    }
 29
 30    function get-Price {
 31        param (
 32            [string]$sla,
 33            [string]$Flavour,
 34            [string]$osInput,
 35            [string]$managed,
 36            [string]$cloudzone,
 37            [string]$filePath
 38        )
 39
 40        # Normalize the value of $Flavour
 41        $FlavourNormalized = $null
 42        switch -Regex ($Flavour) {
 43            "SMALL" { $FlavourNormalized = "small" }
 44            "MEDIUM" { $FlavourNormalized = "medium" }
 45            "LARGE" { $FlavourNormalized = "large" }
 46    }
 47    
 48        # Normalize the value of $os based on the input for linux match lx and ubuntu for windows win and windows
 49        $os = $null
 50        if ($osInput -match "win|windows") {
 51            $os = "windows"
 52        } elseif ($osInput -match "lx|ubuntu") {
 53            $os = "linux"
 54        }
 55    
 56        # Import data from the CSV file
 57        $data = Get-CsvData -searchBasePath $filePath -fileName "prices.csv"
 58        if ($data -eq $null) {
 59            return "File not found"
 60        }
 61    
 62        # Data filtering
 63        $filteredData = $data | Where-Object { 
 64            $_.SLA -eq $sla -and $_.Flavour -eq $FlavourNormalized -and 
 65            $_.OS -eq $os -and $_.managed -eq $managed -and 
 66            $_.cloudzone -eq $cloudzone
 67        } | Select-Object -First 1
 68    
 69        if ($filteredData) {
 70            # Use CultureInfo to correctly interpret numbers with a comma
 71            $culture = [System.Globalization.CultureInfo]::GetCultureInfo("it-IT")
 72    
 73            # Handle null values for vm price and managing price
 74            $priceVmStr = if ($filteredData."vm price" -eq "null" -or $filteredData."vm price" -eq $null) { "0" } else { $filteredData."vm price" }
 75            $priceGestioneStr = if ($filteredData."managing price" -eq "null" -or $filteredData."managing price" -eq $null) { "0" } else { $filteredData."managing price" }
 76    
 77            # Try to convert prices into decimal numbers
 78            try {
 79                $priceVm = [double]::Parse($priceVmStr, [System.Globalization.NumberStyles]::Any, $culture)
 80                $priceGestione = [double]::Parse($priceGestioneStr, [System.Globalization.NumberStyles]::Any, $culture)
 81            } catch {
 82                Write-Host "Error in price conversion: $_"
 83                return "Error in converting prices"
 84            }
 85    
 86            # Calculate the total cost
 87            $priceTotal = "{0:N2}" -f ($priceVm + $priceGestione)
 88    
 89            # Extract details from $filteredData
 90            $vcpu = $filteredData.vcpu
 91            $vram = $filteredData.vram
 92    
 93            # Create the output string with details
 94            $outputString = "• vCPU: $vcpu `n" + 
 95                            "• vRAM: ${vram}GB `n" +
 96                            "• vDisk Standard Performance: 60 GB `n" +
 97                            "• OS: $os `n" +
 98                            "• SLA: $sla `n" +
 99                            "• vm price: €$priceTotal / month"
100    
101            return $outputString
102        }
103    
104        return "Can't find prices"
105    }
106        
107    # Retrieve inputs from the passed parameters
108    $sla = $inputs.sla
109    $Flavour = $inputs.Flavour
110    $os = $inputs.os
111    $managed = $inputs.managed
112    $cloudzone = $inputs.cloudzone
113    
114    # Base path from which to start searching for the CSV file
115    $searchBasePath = "./"
116
117    # Calculate the price
118    $price = get-Price -sla $sla -Flavour $Flavour -osInput $os -managed $managed -cloudzone $cloudzone -filePath $searchBasePath
119
120    return $price
121}

Now, let's create a zip file containing both the CSV file and the PowerShell script. The zipped file should be imported into the vRo action set with Type Zip:

vRo Action Script
Note

Note that the entry handler value should be entered as PS1__FILE__NAME.YOUR__HandlerFunction (In my case, pricefromfile.Handler).

Warning

Warning: The script mentioned above is for illustrative purposes and may need to be adapted to your own environment and needs.

Service Broker

Using vRo Action in Service Broker

Now we need to integrate our newly created Action in vRo into the Service Broker to display the output of our script that calculates prices.

To do this, after publishing the Blueprint inside the Service Broker, we create a Custom Form.

As the last block, we add a text element, changing the value from Constant to External and then selecting the name of the vRo Action we just created.

Service Broker Custom Form

In this case, the CloudZone is entered as a Constant instead of a Field of the Blueprint. Before proceeding to save, we also need to insert a custom CSS, otherwise, the output text will be written all on the same line, whereas we want a more readable formatting.

To do this, click on Actions and then on Import CSS. The CSS code is really super simple:

1cf-text {
2    white-space: pre;
3}
Warning

Warning: This CSS will modify all the text-type elements you have added. It might cause some issues if you have multiple text fields.

After importing the CSS file, everything is ready! Click on 'Create', then 'Enable', and we can proceed with a test. After that, we'll need to do the same for the remaining Blueprints.

Service Broker Request

Notes

Output

The script's output displays the following information: some details like vCPU and vRAM are calculated from the CSV file. Others, such as vDisk, are constants (this is because, for simplicity, the Blueprint templates have been customized to have the OS disk of the same size). This can also be modified if necessary.

  • "• vCPU: $vcpu "
  • "• vRAM: ${vram}GB "
  • "• vDisk Standard Performance: 60 GB "
  • "• OS: $os "
  • "• SLA: $sla "
  • "• vm price: €$priceTotal / month"
comments powered by Disqus