Skip to content

Commit ff23be5

Browse files
flanakinclaude
andauthored
Add Deploy-Hub helper script (#2008)
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 83e45c8 commit ff23be5

2 files changed

Lines changed: 307 additions & 3 deletions

File tree

‎src/scripts/Deploy-Hub.ps1‎

Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
# Copyright (c) Microsoft Corporation.
2+
# Licensed under the MIT License.
3+
4+
<#
5+
.SYNOPSIS
6+
Deploys a FinOps hub instance for local testing.
7+
8+
.DESCRIPTION
9+
Wrapper around Deploy-Toolkit that simplifies FinOps hub deployments by providing scenario-based flags instead of requiring you to remember all the Bicep parameter names.
10+
11+
By default, deploys with Azure Data Explorer (dev SKU). Use -StorageOnly for storage-only or -Fabric for Fabric-based deployments.
12+
13+
All resources use an "{initials}-{name}" naming convention where initials are pulled from git config user.name and name defaults to "adx". Pass a name as the first positional parameter to use a custom value (e.g., "216" for Feb 16).
14+
15+
.EXAMPLE
16+
Deploy-Hub
17+
18+
Deploys a hub with ADX (e.g., RG "aa-adx", ADX "aa-adx").
19+
20+
.EXAMPLE
21+
Deploy-Hub 216
22+
23+
Deploys to a named environment (e.g., RG "aa-216", ADX "aa-216").
24+
25+
.EXAMPLE
26+
Deploy-Hub -StorageOnly
27+
28+
Deploys a storage-only hub (no ADX, no Fabric).
29+
30+
.EXAMPLE
31+
Deploy-Hub -Fabric "https://my-eventhouse.kusto.data.microsoft.com"
32+
33+
Deploys a hub connected to a Microsoft Fabric eventhouse.
34+
35+
.EXAMPLE
36+
Deploy-Hub -Remove 210
37+
38+
Deletes the resource group for the specified name (e.g., "aa-210").
39+
40+
.EXAMPLE
41+
Deploy-Hub -Remove
42+
43+
Lists all resource groups matching the "{initials}-*" naming convention.
44+
45+
.EXAMPLE
46+
Deploy-Hub -Build
47+
48+
Builds the template first, then deploys with ADX.
49+
50+
.EXAMPLE
51+
Deploy-Hub -WhatIf
52+
53+
Validates the deployment without making changes.
54+
55+
.PARAMETER Name
56+
Optional. First positional parameter. Suffix for the "{initials}-{name}" naming convention used for resource group and ADX cluster. Default: "adx".
57+
58+
.PARAMETER HubName
59+
Optional. Name of the hub instance. Default: "hub".
60+
61+
.PARAMETER ADX
62+
Optional. Name of the Azure Data Explorer cluster. Overrides the "{initials}-{name}" convention. Only used when not using -StorageOnly or -Fabric.
63+
64+
.PARAMETER ResourceGroup
65+
Optional. Name of the resource group. Overrides the "{initials}-{name}" convention.
66+
67+
.PARAMETER Fabric
68+
Deploy with Microsoft Fabric. Provide the eventhouse query URI.
69+
70+
.PARAMETER StorageOnly
71+
Deploy a storage-only hub (no Azure Data Explorer or Fabric).
72+
73+
.PARAMETER Remove
74+
Remove test environments. With a name, deletes the target resource group. Alone, lists all resource groups matching "{initials}-*".
75+
76+
.PARAMETER Location
77+
Optional. Azure location. Default: westus.
78+
79+
.PARAMETER Build
80+
Optional. Build the template before deploying.
81+
82+
.PARAMETER WhatIf
83+
Optional. Validate the deployment without making changes.
84+
85+
.LINK
86+
https://github.com/microsoft/finops-toolkit/blob/dev/src/scripts/README.md
87+
#>
88+
param(
89+
[Parameter(Position = 0)]
90+
[string]$Name,
91+
[string]$HubName,
92+
[string]$ADX,
93+
[string]$ResourceGroup,
94+
[string]$Fabric,
95+
[switch]$StorageOnly,
96+
[switch]$Remove,
97+
[string]$Location,
98+
[switch]$Build,
99+
[switch]$WhatIf
100+
)
101+
102+
# Get user initials from git config user.name (first letter of each word, lowercased)
103+
function Get-Initials()
104+
{
105+
$name = (git config user.name 2>$null)
106+
if ($name)
107+
{
108+
$parts = $name.Trim() -split '\s+'
109+
if ($parts.Count -ge 2)
110+
{
111+
return (($parts | ForEach-Object { $_[0] }) -join '').ToLower()
112+
}
113+
return $name.Substring(0, [Math]::Min(2, $name.Length)).ToLower()
114+
}
115+
116+
# Fall back to OS username
117+
$u = ($env:USERNAME ?? $env:USER ?? "xx").ToLower()
118+
$parts = $u -split '[\.\-_\s]'
119+
if ($parts.Count -ge 2)
120+
{
121+
return ($parts | ForEach-Object { $_[0] }) -join ''
122+
}
123+
return $u.Substring(0, [Math]::Min(2, $u.Length))
124+
}
125+
126+
$initials = Get-Initials
127+
128+
# Default name to "adx" when not specified
129+
if (-not $Name)
130+
{
131+
$Name = "adx"
132+
}
133+
134+
# Build the full name: {initials}-{name}
135+
$fullName = "$initials-$Name"
136+
137+
#------------------------------------------------------------------------------
138+
# Remove mode
139+
#------------------------------------------------------------------------------
140+
141+
if ($Remove)
142+
{
143+
if ($PSBoundParameters.ContainsKey('Name'))
144+
{
145+
# Delete the specific resource group
146+
$rgName = if ($ResourceGroup) { $ResourceGroup } else { $fullName }
147+
$rg = Get-AzResourceGroup -Name $rgName -ErrorAction SilentlyContinue
148+
if ($null -eq $rg)
149+
{
150+
Write-Host "Resource group '$rgName' not found."
151+
return
152+
}
153+
154+
Write-Host "Deleting resource group '$rgName'..."
155+
Remove-AzResourceGroup -Name $rgName -Force -WhatIf:$WhatIf
156+
if (-not $WhatIf) { Write-Host "Deleted '$rgName'." }
157+
}
158+
else
159+
{
160+
# List all resource groups matching the initials-* pattern
161+
$pattern = "$initials-*"
162+
$groups = Get-AzResourceGroup | Where-Object { $_.ResourceGroupName -like $pattern }
163+
if (-not $groups)
164+
{
165+
Write-Host "No resource groups found matching '$pattern'."
166+
}
167+
else
168+
{
169+
Write-Host "Resource groups matching '$pattern':"
170+
$groups | ForEach-Object {
171+
Write-Host " $($_.ResourceGroupName) ($($_.Location))"
172+
}
173+
Write-Host ""
174+
Write-Host "Use -Remove <name> to delete a specific one."
175+
}
176+
}
177+
return
178+
}
179+
180+
#------------------------------------------------------------------------------
181+
# Deploy mode
182+
#------------------------------------------------------------------------------
183+
184+
# Validate mutually exclusive options
185+
if ($StorageOnly -and $Fabric)
186+
{
187+
Write-Error "Cannot specify both -StorageOnly and -Fabric. Please choose one analytics backend."
188+
return
189+
}
190+
191+
# Build parameters
192+
$params = @{}
193+
194+
# Hub name
195+
if ($HubName) { $params.hubName = $HubName }
196+
else { $params.hubName = "hub" }
197+
198+
# Analytics backend
199+
if ($StorageOnly)
200+
{
201+
Write-Host "Scenario: Storage-only (no analytics engine)"
202+
}
203+
elseif ($Fabric)
204+
{
205+
$params.fabricQueryUri = $Fabric
206+
Write-Host "Scenario: Microsoft Fabric ($Fabric)"
207+
}
208+
else
209+
{
210+
# Default: Azure Data Explorer (dev SKU)
211+
if ($ADX) { $params.dataExplorerName = $ADX }
212+
else { $params.dataExplorerName = $fullName }
213+
Write-Host "Scenario: Azure Data Explorer ($($params.dataExplorerName))"
214+
}
215+
216+
Write-Host " Hub: $($params.hubName)"
217+
218+
# Resource group
219+
if (-not $ResourceGroup)
220+
{
221+
$ResourceGroup = $fullName
222+
}
223+
224+
# Forward to Deploy-Toolkit
225+
$deployArgs = @{
226+
Template = "finops-hub"
227+
Parameters = $params
228+
ResourceGroup = $ResourceGroup
229+
}
230+
if ($Location) { $deployArgs.Location = $Location }
231+
$deployArgs.Build = $Build
232+
$deployArgs.WhatIf = $WhatIf
233+
234+
& "$PSScriptRoot/Deploy-Toolkit" @deployArgs

‎src/scripts/README.md‎

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ On this page:
77
- [🆕 Init-Repo](#-init-repo)
88
- [🌐 Build-OpenData](#-build-opendata)
99
- [📦 Build-Toolkit](#-build-toolkit)
10+
- [🚀 Deploy-Hub](#-deploy-hub)
1011
- [🚀 Deploy-Toolkit](#-deploy-toolkit)
1112
- [🧪 Test-PowerShell](#-test-powershell)
1213
- [🏷️ Get-Version](#️-get-version)
@@ -139,6 +140,73 @@ Build-Toolkit runs the following scripts internally:
139140

140141
<br>
141142

143+
## 🚀 Deploy-Hub
144+
145+
[Deploy-Hub.ps1](./Deploy-Hub.ps1) is a wrapper around Deploy-Toolkit that simplifies FinOps hub deployments by providing scenario-based flags instead of requiring you to remember all the Bicep parameter names.
146+
147+
By default, deploys with Azure Data Explorer (dev SKU). Use `-StorageOnly` for storage-only or `-Fabric` for Fabric-based deployments.
148+
149+
All resources use an `{initials}-{name}` naming convention where initials are pulled from `git config user.name` and name defaults to `adx`. Pass a name as the first positional parameter to use a custom value (e.g., `216` for Feb 16).
150+
151+
| Parameter | Description |
152+
| ---------------- | ---------------------------------------------------------------------------------------------------------- |
153+
| `‑Name` | Optional. First positional parameter. Suffix for `{initials}-{name}` convention. Default: `adx`. |
154+
| `‑HubName` | Optional. Name of the hub instance. Default: `hub`. |
155+
| `‑ADX` | Optional. Name of the Azure Data Explorer cluster. Overrides the `{initials}-{name}` convention. |
156+
| `‑ResourceGroup` | Optional. Name of the resource group. Overrides the `{initials}-{name}` convention. |
157+
| `‑Fabric` | Optional. Deploy with Microsoft Fabric. Provide the eventhouse query URI. |
158+
| `‑StorageOnly` | Optional. Deploy a storage-only hub (no Azure Data Explorer or Fabric). |
159+
| `‑Remove` | Optional. Remove test environments. With a name, deletes the target RG. Alone, lists all `{initials}-*`. |
160+
| `‑Location` | Optional. Azure location. Default: `westus`. |
161+
| `‑Build` | Optional. Build the template before deploying. |
162+
| `‑WhatIf` | Optional. Validate the deployment without making changes. |
163+
164+
Examples:
165+
166+
- Deploy a hub with ADX (e.g., RG `aa-adx`, ADX `aa-adx`):
167+
168+
```powershell
169+
./Deploy-Hub
170+
```
171+
172+
- Deploy to a named environment (e.g., RG `aa-216`, ADX `aa-216`):
173+
174+
```powershell
175+
./Deploy-Hub 216
176+
```
177+
178+
- Deploy a storage-only hub:
179+
180+
```powershell
181+
./Deploy-Hub -StorageOnly
182+
```
183+
184+
- Deploy with Microsoft Fabric:
185+
186+
```powershell
187+
./Deploy-Hub -Fabric "https://my-eventhouse.kusto.data.microsoft.com"
188+
```
189+
190+
- Build the template first, then deploy:
191+
192+
```powershell
193+
./Deploy-Hub -Build
194+
```
195+
196+
- Clean up a specific test environment (e.g., `aa-210`):
197+
198+
```powershell
199+
./Deploy-Hub -Remove 210
200+
```
201+
202+
- List all test environments:
203+
204+
```powershell
205+
./Deploy-Hub -Remove
206+
```
207+
208+
<br>
209+
142210
## 🚀 Deploy-Toolkit
143211

144212
[Deploy-Toolkit.ps1](./Deploy-Toolkit.ps1) deploys toolkit templates for local testing purposes.
@@ -313,19 +381,19 @@ Examples:
313381
Examples:
314382

315383
- Builds and publishes the FinOps hub template to the Azure Quickstart Templates repo, commits changes, and pushes to the fork to prepare for a PR.
316-
384+
317385
```powershell
318386
./Publish-Toolkit "finops-hub" -Build -Commit
319387
```
320388

321389
- Builds and publishes the resource group scheduled action module to the Bicep Registry repo locally but does not commit.
322-
390+
323391
```powershell
324392
./Publish-Toolkit "resourcegroup-scheduled-action" -Build
325393
```
326394

327395
- Publishes documentation to the Microsoft Learn repo locally but does not commit.
328-
396+
329397
```powershell
330398
./Publish-Toolkit "docs"
331399
```
@@ -356,6 +424,8 @@ Examples:
356424
```powershell
357425
./Package-Toolkit -Build
358426
427+
```
428+
359429
- Builds the latest version of a specific template and updates the deployment files for the website.
360430

361431
```powershell

0 commit comments

Comments
 (0)