diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 1ba2e8052..dd83a08e0 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,6 +1,9 @@ Release Notes ============= +## 1.7.31 +* Subnets: Support for `depends_on` when defining standalone subnets. + ## 1.7.30 * Docker Images: Support parsing of tags with one or more colons in tag name. * Private DNS Zones: Support linking a Private DNS Zone to a Virtual Network to provide DNS resolution within the vnet. diff --git a/docs/content/api-overview/resources/vnet.md b/docs/content/api-overview/resources/vnet.md index 2221c2c04..b23c707d2 100644 --- a/docs/content/api-overview/resources/vnet.md +++ b/docs/content/api-overview/resources/vnet.md @@ -51,6 +51,7 @@ The Virtual Network module contains four builders | associate_service_endpoint_policies | Associates a subnet with an existing service policy. | | allow_private_endpoints | Enable or disable support for private endpoints, default is `Disabled` | | private_link_service_network_policies | Enable or disable support for private link service network polices, default is `Disabled` | +| depends_on | Add depdendencies on the deployment of another resource. | ##### Automatically build out an address space: `addressSpace` diff --git a/src/Farmer/Arm/Network.fs b/src/Farmer/Arm/Network.fs index 43719d156..b6bfe09f6 100644 --- a/src/Farmer/Arm/Network.fs +++ b/src/Farmer/Arm/Network.fs @@ -341,6 +341,7 @@ type Subnet = AssociatedServiceEndpointPolicies: ResourceId list PrivateEndpointNetworkPolicies: FeatureFlag option PrivateLinkServiceNetworkPolicies: FeatureFlag option + Dependencies: ResourceId Set } member internal this.JsonModelProperties = @@ -397,11 +398,11 @@ type Subnet = member this.JsonModel = match this.VirtualNetwork with | Some (Managed vnet) -> - {| subnets.Create(vnet.Name / this.Name, dependsOn = [ vnet ]) with + {| subnets.Create(vnet.Name / this.Name, dependsOn = (this.Dependencies |> Set.add vnet)) with properties = this.JsonModelProperties |} | Some (Unmanaged vnet) -> - {| subnets.Create(vnet.Name / this.Name) with + {| subnets.Create(vnet.Name / this.Name, dependsOn = this.Dependencies) with properties = this.JsonModelProperties |} | None -> raiseFarmer "Subnet record must be linked to a virtual network to properly assign the resourceId." diff --git a/src/Farmer/Builders/Builders.NetworkInterface.fs b/src/Farmer/Builders/Builders.NetworkInterface.fs index 4289f6d2c..c39838d4e 100644 --- a/src/Farmer/Builders/Builders.NetworkInterface.fs +++ b/src/Farmer/Builders/Builders.NetworkInterface.fs @@ -75,6 +75,7 @@ type NetworkInterfaceConfig = AssociatedServiceEndpointPolicies = [] PrivateEndpointNetworkPolicies = None PrivateLinkServiceNetworkPolicies = None + Dependencies = Set.empty } //ipConfig diff --git a/src/Farmer/Builders/Builders.RouteServer.fs b/src/Farmer/Builders/Builders.RouteServer.fs index 960c6392a..b463bdac1 100644 --- a/src/Farmer/Builders/Builders.RouteServer.fs +++ b/src/Farmer/Builders/Builders.RouteServer.fs @@ -85,6 +85,7 @@ type RouteServerConfig = AssociatedServiceEndpointPolicies = [] PrivateEndpointNetworkPolicies = None PrivateLinkServiceNetworkPolicies = None + Dependencies = Set.empty } //ip configuration diff --git a/src/Farmer/Builders/Builders.VirtualNetwork.fs b/src/Farmer/Builders/Builders.VirtualNetwork.fs index 8c3c4b8e4..c8f7672fe 100644 --- a/src/Farmer/Builders/Builders.VirtualNetwork.fs +++ b/src/Farmer/Builders/Builders.VirtualNetwork.fs @@ -23,6 +23,7 @@ type SubnetConfig = AssociatedServiceEndpointPolicies: ResourceId list AllowPrivateEndpoints: FeatureFlag option PrivateLinkServiceNetworkPolicies: FeatureFlag option + Dependencies: ResourceId Set } member internal this.AsSubnetResource = @@ -45,6 +46,7 @@ type SubnetConfig = // to ENable private endpoints we have to DISable PrivateEndpointNetworkPolicies PrivateEndpointNetworkPolicies = this.AllowPrivateEndpoints |> Option.map FeatureFlag.invert PrivateLinkServiceNetworkPolicies = this.PrivateLinkServiceNetworkPolicies + Dependencies = this.Dependencies } interface IBuilder with @@ -72,6 +74,7 @@ type SubnetBuilder() = AssociatedServiceEndpointPolicies = [] AllowPrivateEndpoints = None PrivateLinkServiceNetworkPolicies = None + Dependencies = Set.empty } /// Sets the name of the subnet @@ -220,6 +223,12 @@ type SubnetBuilder() = PrivateLinkServiceNetworkPolicies = Some flag } + interface IDependable with + member _.Add state newDeps = + { state with + Dependencies = state.Dependencies + newDeps + } + let subnet = SubnetBuilder() /// Specification for a subnet to build from an address space. @@ -665,6 +674,7 @@ type VirtualNetworkBuilder() = AssociatedServiceEndpointPolicies = serviceEndpointPolicies AllowPrivateEndpoints = allowPrivateEndpoints PrivateLinkServiceNetworkPolicies = privateLinkServiceNetworkPolicies + Dependencies = Set.empty })) let newAddressSpaces = diff --git a/src/Farmer/Builders/Builders.Vm.fs b/src/Farmer/Builders/Builders.Vm.fs index f3757b529..2e40b01a1 100644 --- a/src/Farmer/Builders/Builders.Vm.fs +++ b/src/Farmer/Builders/Builders.Vm.fs @@ -207,6 +207,7 @@ type VmConfig = AssociatedServiceEndpointPolicies = [] PrivateEndpointNetworkPolicies = None PrivateLinkServiceNetworkPolicies = None + Dependencies = Set.empty } ] Tags = this.Tags diff --git a/src/Tests/Network.fs b/src/Tests/Network.fs index 0907902e8..142420f25 100644 --- a/src/Tests/Network.fs +++ b/src/Tests/Network.fs @@ -590,13 +590,46 @@ let tests = jobj.SelectToken "resources[?(@.type=='Microsoft.Network/virtualNetworks/subnets')].dependsOn" :?> Newtonsoft.Json.Linq.JArray - Expect.isNull dependsOn "Linking to unmanaged vnet should have no dependencies" + Expect.isEmpty dependsOn "Linking to unmanaged vnet should have no dependencies" let subnet = jobj.SelectToken "resources[?(@.type=='Microsoft.Network/virtualNetworks/subnets')].name" Expect.equal (string subnet) "my-vnet/services" "Incorrect name on subnet" } + test "Add multiple subnets linked to existing (unmanaged) vnet with dependencies" { + let vnetName = "my-vnet" + + let template = + arm { + add_resources + [ + subnet { + name "subnet1" + link_to_unmanaged_vnet (virtualNetworks.resourceId vnetName) + prefix "10.28.0.0/24" + } + subnet { + name "subnet2" + link_to_unmanaged_vnet (virtualNetworks.resourceId vnetName) + prefix "10.28.1.0/24" + depends_on (subnets.resourceId (ResourceName vnetName / ResourceName "subnet1")) + } + ] + } + + let jobj = template.Template |> Writer.toJson |> Newtonsoft.Json.Linq.JObject.Parse + + let dependsOn = + jobj.SelectToken "resources[?(@.name=='my-vnet/subnet2')].dependsOn" :?> Newtonsoft.Json.Linq.JArray + + Expect.hasLength dependsOn 1 "subnet2 should have a single dependency" + + Expect.equal + (string dependsOn[0]) + "[resourceId('Microsoft.Network/virtualNetworks/subnets', 'my-vnet', 'subnet1')]" + "subnet2 should have a dependency on subnet1" + } test "Standalone subnet without linked vnet not allowed" { Expect.throws (fun _ ->