Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deployments: Default to resource group location rather than West Europe. #1138

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
Release Notes
=============

## 1.9.3
* Deployments: Default to resource group location rather than West Europe.

## 1.9.2
* Container Apps: Fix to container registry credential to not emit a secret for a managed identity.
* Container Groups: followup to #ff78f202dc - expand DNS config validation for profile-less vnet.
Expand Down
2 changes: 1 addition & 1 deletion src/Farmer/Builders/Builders.ResourceGroup.fs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ type DeploymentBuilder() =
Resources = List.empty
ParameterValues = List.empty
SubscriptionId = None
Location = Location.WestEurope
Location = Location.ResourceGroup
Mode = Incremental
Tags = Map.empty
}
Expand Down
3 changes: 3 additions & 0 deletions src/Farmer/Common.fs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ module LocationExtensions =
static member NorwayEast = Location "NorwayEast"
static member Global = Location "global"

static member ResourceGroup =
LocationExpression(ArmExpression.create "resourceGroup().location")

[<AutoOpen>]
module DataLocationExtensions =
type DataLocation with
Expand Down
39 changes: 23 additions & 16 deletions src/Farmer/Deploy.fs
Original file line number Diff line number Diff line change
Expand Up @@ -309,36 +309,43 @@ let private prepareForDeployment parameters resourceGroupName (deployment: IDepl
do! deployment |> validateParameters parameters

let! version = Az.checkVersion Az.MinimumVersion
printfn "Compatible version of Azure CLI %O detected" version
stdout.WriteLine $"Compatible version of Azure CLI {version} detected"

prepareDeploymentFolder ()

let! subscriptionDetails =
printf "Checking Azure CLI logged in status... "
stdout.Write "Checking Azure CLI logged in status... "

match Az.showAccount () with
| Ok response ->
printfn "you are already logged in, nothing to do."
stdout.WriteLine "you are already logged in, nothing to do."
Ok response
| Error _ ->
printfn "logging you in."
stdout.WriteLine "logging you in."
Az.login () |> Result.bind (fun _ -> Az.showAccount ())

let subscriptionDetails =
subscriptionDetails |> Serialization.ofJson<{| id: Guid; name: string |}>

printfn "Using subscription '%s' (%O)." subscriptionDetails.name subscriptionDetails.id
stdout.WriteLine $"Using subscription '%s{subscriptionDetails.name}' ({subscriptionDetails.id})."

let resourceGroups =
(resourceGroupName :: deployment.Deployment.RequiredResourceGroups)
|> List.distinct
// Filter out any resource groups that are an ARM expression calculated at deploy-time
|> List.filter (fun resGroupName -> not (resGroupName.StartsWith("[")))
|> List.mapi (fun i x -> i, x)
match deployment.Deployment.Location with
| Location _ ->
let resourceGroups =
(resourceGroupName :: deployment.Deployment.RequiredResourceGroups)
|> List.distinct
// Filter out any resource groups that are an ARM expression calculated at deploy-time
|> List.filter (fun resGroupName -> not (resGroupName.StartsWith("[")))
|> List.mapi (fun i x -> i, x)

for (i, rg) in resourceGroups do
printfn $"Creating resource group {rg} ({i + 1}/{resourceGroups.Length})..."
do! Az.createResourceGroup deployment.Deployment.Location.ArmValue deployment.Deployment.Tags rg
for (i, rg) in resourceGroups do
stdout.WriteLine $"Creating resource group {rg} ({i + 1}/{resourceGroups.Length})..."
do! Az.createResourceGroup deployment.Deployment.Location.ArmValue deployment.Deployment.Tags rg
| LocationExpression _ ->
stdout.WriteLine
"Deployment location is an ARM expression that cannot be evaluated by the CLI. Skipping resource group creation."

return () // Cannot evaluate an ARM expression in Az CLI.

return {|
DeploymentName = $"farmer-deploy-{generateDeployNumber ()}"
Expand Down Expand Up @@ -374,7 +381,7 @@ let tryWhatIf resourceGroupName parameters (deployment: IDeploymentSource) = res
let tryExecute resourceGroupName parameters (deployment: IDeploymentSource) = result {
let! deploymentParameters = deployment |> prepareForDeployment parameters resourceGroupName

printfn "Deploying ARM template (please be patient, this can take a while)..."
stdout.WriteLine "Deploying ARM template (please be patient, this can take a while)..."

let! response =
Az.deploy resourceGroupName deploymentParameters.DeploymentName deploymentParameters.TemplateFilename parameters
Expand All @@ -388,7 +395,7 @@ let tryExecute resourceGroupName parameters (deployment: IDeploymentSource) = re
|> Result.sequence
|> Result.ignore

printfn "All done, now parsing ARM response to get any outputs..."
stdout.WriteLine "All done, now parsing ARM response to get any outputs..."

let! response =
response
Expand Down
61 changes: 33 additions & 28 deletions src/Farmer/Types.fs
Original file line number Diff line number Diff line change
Expand Up @@ -55,20 +55,6 @@ module ResourceName =
| true, _ -> None
| false, _ -> Some Unparsed

type Location =
| Location of string

member this.ArmValue =
match this with
| Location location -> location.ToLower()

type DataLocation =
| DataLocation of string

member this.ArmValue =
match this with
| DataLocation dataLocation -> dataLocation

type ResourceType =
| ResourceType of path: string * version: string

Expand Down Expand Up @@ -134,20 +120,6 @@ module internal Patterns =
| t when t = expected -> Some(HasResourceType())
| _ -> None

/// An Azure ARM resource value which can be mapped into an ARM template.
type IArmResource =
/// The name of the resource, to uniquely identify against other resources in the template.
abstract member ResourceId: ResourceId
/// A raw object that is ready for serialization directly to JSON.
abstract member JsonModel: obj

/// Represents a high-level configuration that can create a set of ARM Resources.
type IBuilder =
/// Given a location and the currently-built resources, returns a set of resource actions.
abstract member BuildResources: Location -> IArmResource list
/// Provides the ResourceId that other resources should use when depending upon this builder.
abstract member ResourceId: ResourceId

/// Represents an expression used within an ARM template
type ArmExpression =
private
Expand Down Expand Up @@ -212,6 +184,39 @@ type ArmExpression =
static member string(value: ArmExpression) =
value.Value |> sprintf "string(%s)" |> ArmExpression.create

type Location =
| Location of string
| LocationExpression of ArmExpression

member this.ArmValue =
let v =
match this with
| Location location -> location.ToLower()
| LocationExpression expr -> expr.Eval()

v

type DataLocation =
| DataLocation of string

member this.ArmValue =
match this with
| DataLocation dataLocation -> dataLocation

/// An Azure ARM resource value which can be mapped into an ARM template.
type IArmResource =
/// The name of the resource, to uniquely identify against other resources in the template.
abstract member ResourceId: ResourceId
/// A raw object that is ready for serialization directly to JSON.
abstract member JsonModel: obj

/// Represents a high-level configuration that can create a set of ARM Resources.
type IBuilder =
/// Given a location and the currently-built resources, returns a set of resource actions.
abstract member BuildResources: Location -> IArmResource list
/// Provides the ResourceId that other resources should use when depending upon this builder.
abstract member ResourceId: ResourceId

type ResourceId with

member this.ArmExpression =
Expand Down
2 changes: 1 addition & 1 deletion src/Tests/LogAnalytics.fs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ let tests =

let workspace = asAzureResource config

Expect.equal workspace.Location "westeurope" "Incorrect Location"
Expect.equal workspace.Location "[resourceGroup().location]" "Incorrect Location"
Expect.equal workspace.Name "myFarmer" "Incorrect Name"
Expect.equal workspace.PublicNetworkAccessForIngestion "Enabled" "Incorrect IngestionSupport"
Expect.equal workspace.PublicNetworkAccessForQuery "Enabled" "QuerySupport"
Expand Down
20 changes: 20 additions & 0 deletions src/Tests/Types.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,32 @@ module Types

open Expecto
open Farmer
open Farmer.Builders
open System
open Newtonsoft.Json.Linq

let tests =
testList "Type Tests" [
test "Creates deterministic GUID correctly" {
let actual = DeterministicGuid.create "hello"
Expect.equal (Guid.Parse "4fbe461c-3438-55c4-941e-d1c2013210c5") actual "Incorrect GUID"
}
test "Location.ResourceGroup emits correct ARM expression" {
Expect.equal
Location.ResourceGroup.ArmValue
"[resourceGroup().location]"
"Incorrect expression emitted for Location.ResourceGroup"
}
ftest "Default location for 'arm' builder uses resourceGroup location" {
let deployment =
let dummyResource = storageAccount { name "mystorageaccount74785" }
arm { add_resource dummyResource }

let jobj = deployment.Template |> Writer.toJson |> JToken.Parse

Expect.equal
(jobj.SelectToken "resources[?(@.name=='mystorageaccount74785')].location")
(JValue "[resourceGroup().location]")
"Default location on resource should be resource group."
}
]