Repository: Azure/ARO-RP
Pull request #1144 (2020-11-11 01:18:17)

Delete VMs before other resources
1. Delete VMs before other resources.
2. Delete all resources before deleting the RG, this is to try to help periodic problems that we see where RG deletions take forever.
3. Looked into an "increase internetreachable test timeout for worker" flake - the workers were rotating and the
operator was being rescheduled between them.  Bumping the timeout for now.


jim-minter: @hawkowl ptal.  I fast-tracked doing this because we're getting lots of e2e failures with deletions and I wanted this code to try to work around it.
jim-minter: /azp run CI
jim-minter: /azp run E2E
azure-pipelines[bot]: <samp>
Azure Pipelines successfully started running 1 pipeline(s).<br>

</samp>
azure-pipelines[bot]: <samp>
Azure Pipelines successfully started running 1 pipeline(s).<br>

</samp>

Patch:
diff --git a/deploy/env-development.json b/deploy/env-development.json
index 06b076c9e..21d2fa8fa 100644
--- a/deploy/env-development.json
+++ b/deploy/env-development.json
@@ -220,7 +220,7 @@
                                     "autoUpgradeMinorVersion": true,
                                     "settings": {},
                                     "protectedSettings": {
-                                        "script": "[base64(concat(base64ToString('c2V0IC1lCgo='),'CIAZPTOKEN=''',parameters('ciAzpToken'),'''\n','CIPOOLNAME=''',parameters('ciPoolName'),'''\n','\n',base64ToString('Cnl1bSAteSB1cGRhdGUgLXggV0FMaW51eEFnZW50CgpsdmV4dGVuZCAtbCArNTAlRlJFRSAvZGV2L3Jvb3R2Zy92YXJsdgp4ZnNfZ3Jvd2ZzIC92YXIKCmx2ZXh0ZW5kIC1sICsxMDAlRlJFRSAvZGV2L3Jvb3R2Zy9ob21lbHYKeGZzX2dyb3dmcyAvaG9tZQoKcnBtIC0taW1wb3J0IGh0dHBzOi8vZGwuZmVkb3JhcHJvamVjdC5vcmcvcHViL2VwZWwvUlBNLUdQRy1LRVktRVBFTC03CnJwbSAtLWltcG9ydCBodHRwczovL3BhY2thZ2VzLm1pY3Jvc29mdC5jb20va2V5cy9taWNyb3NvZnQuYXNjCgp5dW0gLXkgaW5zdGFsbCBodHRwczovL2RsLmZlZG9yYXByb2plY3Qub3JnL3B1Yi9lcGVsL2VwZWwtcmVsZWFzZS1sYXRlc3QtNy5ub2FyY2gucnBtCgpjYXQgPi9ldGMveXVtLnJlcG9zLmQvYXp1cmUucmVwbyA8PCdFT0YnClthenVyZS1jbGldCm5hbWU9YXp1cmUtY2xpCmJhc2V1cmw9aHR0cHM6Ly9wYWNrYWdlcy5taWNyb3NvZnQuY29tL3l1bXJlcG9zL2F6dXJlLWNsaQplbmFibGVkPXllcwpncGdjaGVjaz15ZXMKRU9GCgp5dW0gLS1lbmFibGVyZXBvPXJodWktcmhlbC03LXNlcnZlci1yaHVpLW9wdGlvbmFsLXJwbXMgLXkgaW5zdGFsbCBhenVyZS1jbGkgZG9ja2VyIGpxIGxpYmFzc3Vhbi1kZXZlbCBnY2MgZ3BnbWUtZGV2ZWwgcmgtZ2l0MjkgcmgtcHl0aG9uMzYgdG1wd2F0Y2gKCkdPX1ZFUlNJT049MS4xNC45CmN1cmwgaHR0cHM6Ly9kbC5nb29nbGUuY29tL2dvL2dvJHtHT19WRVJTSU9OfS5saW51eC1hbWQ2NC50YXIuZ3ogfCB0YXIgLUMgL3Vzci9sb2NhbCAteHoKbG4gLXMgL3Vzci9sb2NhbC9nby9iaW4vKiAvdXNyL2xvY2FsL2JpbgoKVlNUU19BR0VOVF9WRVJTSU9OPTIuMTc1LjIKbWtkaXIgL2hvbWUvY2xvdWQtdXNlci9hZ2VudApwdXNoZCAvaG9tZS9jbG91ZC11c2VyL2FnZW50CmN1cmwgaHR0cHM6Ly92c3RzYWdlbnRwYWNrYWdlLmF6dXJlZWRnZS5uZXQvYWdlbnQvJHtWU1RTX0FHRU5UX1ZFUlNJT059L3ZzdHMtYWdlbnQtbGludXgteDY0LSR7VlNUU19BR0VOVF9WRVJTSU9OfS50YXIuZ3ogfCB0YXIgLXh6CmNob3duIC1SIGNsb3VkLXVzZXI6Y2xvdWQtdXNlciAuCgouL2Jpbi9pbnN0YWxsZGVwZW5kZW5jaWVzLnNoCnN1ZG8gLXUgY2xvdWQtdXNlciAuL2NvbmZpZy5zaCAtLXVuYXR0ZW5kZWQgLS11cmwgaHR0cHM6Ly9kZXYuYXp1cmUuY29tL21zYXp1cmUgLS1hdXRoIHBhdCAtLXRva2VuICIkQ0lBWlBUT0tFTiIgLS1wb29sICIkQ0lQT09MTkFNRSIgLS1hZ2VudCAiQVJPLVJIRUwtJEhPU1ROQU1FIiAtLXJlcGxhY2UKLi9zdmMuc2ggaW5zdGFsbCBjbG91ZC11c2VyCnBvcGQKCiMgbWVyZ2UgaW4gL29wdC9yaC9yaC0qL2VuYWJsZQpjYXQgPi9ob21lL2Nsb3VkLXVzZXIvYWdlbnQvLnBhdGggPDwnRU9GJwovb3B0L3JoL3JoLXB5dGhvbjM2L3Jvb3QvdXNyL2Jpbjovb3B0L3JoL3JoLWdpdDI5L3Jvb3QvdXNyL2JpbjovdXNyL2xvY2FsL2JpbjovdXNyL2JpbjovdXNyL2xvY2FsL3NiaW46L3Vzci9zYmluOi9ob21lL2Nsb3VkLXVzZXIvLmxvY2FsL2JpbjovaG9tZS9jbG91ZC11c2VyL2JpbgpFT0YKCmNhdCA+L2hvbWUvY2xvdWQtdXNlci9hZ2VudC8uZW52IDw8J0VPRicKTERfTElCUkFSWV9QQVRIPS9vcHQvcmgvcmgtcHl0aG9uMzYvcm9vdC91c3IvbGliNjQ6L29wdC9yaC9odHRwZDI0L3Jvb3QvdXNyL2xpYjY0Ck1BTlBBVEg9L29wdC9yaC9yaC1weXRob24zNi9yb290L3Vzci9zaGFyZS9tYW46L29wdC9yaC9yaC1naXQyOS9yb290L3Vzci9zaGFyZS9tYW4KUEVSTDVMSUI9L29wdC9yaC9yaC1naXQyOS9yb290L3Vzci9zaGFyZS9wZXJsNS92ZW5kb3JfcGVybApQS0dfQ09ORklHX1BBVEg9L29wdC9yaC9yaC1weXRob24zNi9yb290L3Vzci9saWI2NC9wa2djb25maWcKWERHX0RBVEFfRElSUz0vb3B0L3JoL3JoLXB5dGhvbjM2L3Jvb3QvdXNyL3NoYXJlOi91c3IvbG9jYWwvc2hhcmU6L3Vzci9zaGFyZQpFT0YKCnNlZCAtaSAtZSAncy9eT1BUSU9OUz0nXCcnL09QVElPTlM9J1wnJy1HIGNsb3VkLXVzZXIgLycgL2V0Yy9zeXNjb25maWcvZG9ja2VyCgpzeXN0ZW1jdGwgZW5hYmxlIGRvY2tlcgoKY2F0ID4vZXRjL2Nyb24uaG91cmx5L3RtcHdhdGNoIDw8J0VPRicKIyEvYmluL2Jhc2gKCmV4ZWMgL3NiaW4vdG1wd2F0Y2ggMjRoIC90bXAKRU9GCmNobW9kICt4IC9ldGMvY3Jvbi5ob3VybHkvdG1wd2F0Y2gKCihzbGVlcCAzMDsgcmVib290KSAmCg==')))]"
+                                        "script": "[base64(concat(base64ToString('c2V0IC1lCgo='),'CIAZPTOKEN=''',parameters('ciAzpToken'),'''\n','CIPOOLNAME=''',parameters('ciPoolName'),'''\n','\n',base64ToString('Cnl1bSAteSB1cGRhdGUgLXggV0FMaW51eEFnZW50CgpsdmV4dGVuZCAtbCArNTAlRlJFRSAvZGV2L3Jvb3R2Zy92YXJsdgp4ZnNfZ3Jvd2ZzIC92YXIKCmx2ZXh0ZW5kIC1sICsxMDAlRlJFRSAvZGV2L3Jvb3R2Zy9ob21lbHYKeGZzX2dyb3dmcyAvaG9tZQoKcnBtIC0taW1wb3J0IGh0dHBzOi8vZGwuZmVkb3JhcHJvamVjdC5vcmcvcHViL2VwZWwvUlBNLUdQRy1LRVktRVBFTC03CnJwbSAtLWltcG9ydCBodHRwczovL3BhY2thZ2VzLm1pY3Jvc29mdC5jb20va2V5cy9taWNyb3NvZnQuYXNjCgp5dW0gLXkgaW5zdGFsbCBodHRwczovL2RsLmZlZG9yYXByb2plY3Qub3JnL3B1Yi9lcGVsL2VwZWwtcmVsZWFzZS1sYXRlc3QtNy5ub2FyY2gucnBtCgpjYXQgPi9ldGMveXVtLnJlcG9zLmQvYXp1cmUucmVwbyA8PCdFT0YnClthenVyZS1jbGldCm5hbWU9YXp1cmUtY2xpCmJhc2V1cmw9aHR0cHM6Ly9wYWNrYWdlcy5taWNyb3NvZnQuY29tL3l1bXJlcG9zL2F6dXJlLWNsaQplbmFibGVkPXllcwpncGdjaGVjaz15ZXMKRU9GCgp5dW0gLS1lbmFibGVyZXBvPXJodWktcmhlbC03LXNlcnZlci1yaHVpLW9wdGlvbmFsLXJwbXMgLXkgaW5zdGFsbCBhenVyZS1jbGkgZG9ja2VyIGpxIGxpYmFzc3Vhbi1kZXZlbCBnY2MgZ3BnbWUtZGV2ZWwgcmgtZ2l0MjkgcmgtcHl0aG9uMzYKCkdPX1ZFUlNJT049MS4xNC45CmN1cmwgaHR0cHM6Ly9kbC5nb29nbGUuY29tL2dvL2dvJHtHT19WRVJTSU9OfS5saW51eC1hbWQ2NC50YXIuZ3ogfCB0YXIgLUMgL3Vzci9sb2NhbCAteHoKbG4gLXMgL3Vzci9sb2NhbC9nby9iaW4vKiAvdXNyL2xvY2FsL2JpbgoKVlNUU19BR0VOVF9WRVJTSU9OPTIuMTc1LjIKbWtkaXIgL2hvbWUvY2xvdWQtdXNlci9hZ2VudApwdXNoZCAvaG9tZS9jbG91ZC11c2VyL2FnZW50CmN1cmwgaHR0cHM6Ly92c3RzYWdlbnRwYWNrYWdlLmF6dXJlZWRnZS5uZXQvYWdlbnQvJHtWU1RTX0FHRU5UX1ZFUlNJT059L3ZzdHMtYWdlbnQtbGludXgteDY0LSR7VlNUU19BR0VOVF9WRVJTSU9OfS50YXIuZ3ogfCB0YXIgLXh6CmNob3duIC1SIGNsb3VkLXVzZXI6Y2xvdWQtdXNlciAuCgouL2Jpbi9pbnN0YWxsZGVwZW5kZW5jaWVzLnNoCnN1ZG8gLXUgY2xvdWQtdXNlciAuL2NvbmZpZy5zaCAtLXVuYXR0ZW5kZWQgLS11cmwgaHR0cHM6Ly9kZXYuYXp1cmUuY29tL21zYXp1cmUgLS1hdXRoIHBhdCAtLXRva2VuICIkQ0lBWlBUT0tFTiIgLS1wb29sICIkQ0lQT09MTkFNRSIgLS1hZ2VudCAiQVJPLVJIRUwtJEhPU1ROQU1FIiAtLXJlcGxhY2UKLi9zdmMuc2ggaW5zdGFsbCBjbG91ZC11c2VyCnBvcGQKCiMgbWVyZ2UgaW4gL29wdC9yaC9yaC0qL2VuYWJsZQpjYXQgPi9ob21lL2Nsb3VkLXVzZXIvYWdlbnQvLnBhdGggPDwnRU9GJwovb3B0L3JoL3JoLXB5dGhvbjM2L3Jvb3QvdXNyL2Jpbjovb3B0L3JoL3JoLWdpdDI5L3Jvb3QvdXNyL2JpbjovdXNyL2xvY2FsL2JpbjovdXNyL2JpbjovdXNyL2xvY2FsL3NiaW46L3Vzci9zYmluOi9ob21lL2Nsb3VkLXVzZXIvLmxvY2FsL2JpbjovaG9tZS9jbG91ZC11c2VyL2JpbgpFT0YKCmNhdCA+L2hvbWUvY2xvdWQtdXNlci9hZ2VudC8uZW52IDw8J0VPRicKTERfTElCUkFSWV9QQVRIPS9vcHQvcmgvcmgtcHl0aG9uMzYvcm9vdC91c3IvbGliNjQ6L29wdC9yaC9odHRwZDI0L3Jvb3QvdXNyL2xpYjY0Ck1BTlBBVEg9L29wdC9yaC9yaC1weXRob24zNi9yb290L3Vzci9zaGFyZS9tYW46L29wdC9yaC9yaC1naXQyOS9yb290L3Vzci9zaGFyZS9tYW4KUEVSTDVMSUI9L29wdC9yaC9yaC1naXQyOS9yb290L3Vzci9zaGFyZS9wZXJsNS92ZW5kb3JfcGVybApQS0dfQ09ORklHX1BBVEg9L29wdC9yaC9yaC1weXRob24zNi9yb290L3Vzci9saWI2NC9wa2djb25maWcKWERHX0RBVEFfRElSUz0vb3B0L3JoL3JoLXB5dGhvbjM2L3Jvb3QvdXNyL3NoYXJlOi91c3IvbG9jYWwvc2hhcmU6L3Vzci9zaGFyZQpFT0YKCnNlZCAtaSAtZSAncy9eT1BUSU9OUz0nXCcnL09QVElPTlM9J1wnJy1HIGNsb3VkLXVzZXIgLycgL2V0Yy9zeXNjb25maWcvZG9ja2VyCgpzeXN0ZW1jdGwgZW5hYmxlIGRvY2tlcgoKKHNsZWVwIDMwOyByZWJvb3QpICYK')))]"
                                     }
                                 }
                             }
diff --git a/pkg/cluster/cluster.go b/pkg/cluster/cluster.go
index 7d10107f4..52b5bef88 100644
--- a/pkg/cluster/cluster.go
+++ b/pkg/cluster/cluster.go
@@ -25,6 +25,7 @@ import (
 	"github.com/Azure/ARO-RP/pkg/util/azureclient/mgmt/compute"
 	"github.com/Azure/ARO-RP/pkg/util/azureclient/mgmt/features"
 	"github.com/Azure/ARO-RP/pkg/util/azureclient/mgmt/network"
+	"github.com/Azure/ARO-RP/pkg/util/azureclient/mgmt/privatedns"
 	"github.com/Azure/ARO-RP/pkg/util/azureclient/mgmt/storage"
 	"github.com/Azure/ARO-RP/pkg/util/billing"
 	"github.com/Azure/ARO-RP/pkg/util/dns"
@@ -55,15 +56,17 @@ type manager struct {
 	fpAuthorizer      refreshable.Authorizer
 	localFpAuthorizer refreshable.Authorizer
 
-	disks             compute.DisksClient
-	virtualmachines   compute.VirtualMachinesClient
-	interfaces        network.InterfacesClient
-	publicipaddresses network.PublicIPAddressesClient
-	loadbalancers     network.LoadBalancersClient
-	securitygroups    network.SecurityGroupsClient
-	deployments       features.DeploymentsClient
-	groups            features.ResourceGroupsClient
-	accounts          storage.AccountsClient
+	disks               compute.DisksClient
+	virtualmachines     compute.VirtualMachinesClient
+	interfaces          network.InterfacesClient
+	publicipaddresses   network.PublicIPAddressesClient
+	loadbalancers       network.LoadBalancersClient
+	securitygroups      network.SecurityGroupsClient
+	deployments         features.DeploymentsClient
+	groups              features.ResourceGroupsClient
+	resources           features.ResourcesClient
+	virtualnetworklinks privatedns.VirtualNetworkLinksClient
+	accounts            storage.AccountsClient
 
 	dns             dns.Manager
 	keyvault        keyvault.Manager
@@ -115,15 +118,17 @@ func New(ctx context.Context, log *logrus.Entry, _env env.Interface, db database
 		fpAuthorizer:      fpAuthorizer,
 		localFpAuthorizer: localFPAuthorizer,
 
-		disks:             compute.NewDisksClient(r.SubscriptionID, fpAuthorizer),
-		virtualmachines:   compute.NewVirtualMachinesClient(r.SubscriptionID, fpAuthorizer),
-		interfaces:        network.NewInterfacesClient(r.SubscriptionID, fpAuthorizer),
-		publicipaddresses: network.NewPublicIPAddressesClient(r.SubscriptionID, fpAuthorizer),
-		loadbalancers:     network.NewLoadBalancersClient(r.SubscriptionID, fpAuthorizer),
-		securitygroups:    network.NewSecurityGroupsClient(r.SubscriptionID, fpAuthorizer),
-		deployments:       features.NewDeploymentsClient(r.SubscriptionID, fpAuthorizer),
-		groups:            features.NewResourceGroupsClient(r.SubscriptionID, fpAuthorizer),
-		accounts:          storage.NewAccountsClient(r.SubscriptionID, fpAuthorizer),
+		disks:               compute.NewDisksClient(r.SubscriptionID, fpAuthorizer),
+		virtualmachines:     compute.NewVirtualMachinesClient(r.SubscriptionID, fpAuthorizer),
+		interfaces:          network.NewInterfacesClient(r.SubscriptionID, fpAuthorizer),
+		publicipaddresses:   network.NewPublicIPAddressesClient(r.SubscriptionID, fpAuthorizer),
+		loadbalancers:       network.NewLoadBalancersClient(r.SubscriptionID, fpAuthorizer),
+		securitygroups:      network.NewSecurityGroupsClient(r.SubscriptionID, fpAuthorizer),
+		deployments:         features.NewDeploymentsClient(r.SubscriptionID, fpAuthorizer),
+		groups:              features.NewResourceGroupsClient(r.SubscriptionID, fpAuthorizer),
+		resources:           features.NewResourcesClient(r.SubscriptionID, fpAuthorizer),
+		virtualnetworklinks: privatedns.NewVirtualNetworkLinksClient(r.SubscriptionID, fpAuthorizer),
+		accounts:            storage.NewAccountsClient(r.SubscriptionID, fpAuthorizer),
 
 		dns:             dns.NewManager(_env, localFPAuthorizer),
 		keyvault:        keyvault.NewManager(localFPKVAuthorizer, _env.ClustersKeyvaultURI()),
diff --git a/pkg/cluster/delete.go b/pkg/cluster/delete.go
index 8d4bf2544..df593cc45 100644
--- a/pkg/cluster/delete.go
+++ b/pkg/cluster/delete.go
@@ -8,100 +8,222 @@ import (
 	"encoding/json"
 	"fmt"
 	"net/http"
+	"sort"
 	"strings"
 
+	mgmtfeatures "github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2019-07-01/features"
 	"github.com/Azure/go-autorest/autorest"
+	"github.com/Azure/go-autorest/autorest/azure"
 
 	"github.com/Azure/ARO-RP/pkg/api"
 	"github.com/Azure/ARO-RP/pkg/util/acrtoken"
+	"github.com/Azure/ARO-RP/pkg/util/azureclient"
 	"github.com/Azure/ARO-RP/pkg/util/deployment"
 	"github.com/Azure/ARO-RP/pkg/util/dns"
 	"github.com/Azure/ARO-RP/pkg/util/stringutils"
 )
 
-func (m *manager) Delete(ctx context.Context) error {
-	resourceGroup := stringutils.LastTokenByte(m.doc.OpenShiftCluster.Properties.ClusterProfile.ResourceGroupID, '/')
+func (m *manager) deletePrivateDNSVirtualNetworkLinks(ctx context.Context, resourceID string) error {
+	r, err := azure.ParseResourceID(resourceID)
+	if err != nil {
+		return err
+	}
 
-	m.log.Printf("deleting dns")
-	err := m.dns.Delete(ctx, m.doc.OpenShiftCluster)
+	virtualnetworklinks, err := m.virtualnetworklinks.List(ctx, r.ResourceGroup, r.ResourceName, nil)
 	if err != nil {
 		return err
 	}
 
-	m.log.Print("looking for network security groups to remove from subnets")
-	nsgs, err := m.securitygroups.List(ctx, resourceGroup)
-	if detailedErr, ok := err.(autorest.DetailedError); ok &&
-		detailedErr.StatusCode == http.StatusNotFound {
-		err = nil
+	for _, virtualnetworklink := range virtualnetworklinks {
+		err = m.virtualnetworklinks.DeleteAndWait(ctx, r.ResourceGroup, r.ResourceName, *virtualnetworklink.Name, "")
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+func (m *manager) disconnectSecurityGroup(ctx context.Context, resourceID string) error {
+	r, err := azure.ParseResourceID(resourceID)
+	if err != nil {
+		return err
 	}
+
+	nsg, err := m.securitygroups.Get(ctx, r.ResourceGroup, r.ResourceName, "")
 	if err != nil {
 		return err
 	}
 
-	// TODO: ideally we would do this after all the VMs have been deleted
-	for _, nsg := range nsgs {
-		if nsg.SecurityGroupPropertiesFormat == nil ||
-			nsg.SecurityGroupPropertiesFormat.Subnets == nil {
+	if nsg.SecurityGroupPropertiesFormat == nil ||
+		nsg.SecurityGroupPropertiesFormat.Subnets == nil {
+		return nil
+	}
+
+	for _, subnet := range *nsg.SecurityGroupPropertiesFormat.Subnets {
+		// Note: subnet only has value in the ID field,
+		// so we have to make another API request to get full subnet struct
+		// TODO: there is probably an undesirable race condition here - check if etags can help.
+		s, err := m.subnet.Get(ctx, *subnet.ID)
+		if err != nil {
+			b, _ := json.Marshal(err)
+
+			return &api.CloudError{
+				StatusCode: http.StatusBadRequest,
+				CloudErrorBody: &api.CloudErrorBody{
+					Code:    api.CloudErrorCodeInvalidLinkedVNet,
+					Message: fmt.Sprintf("Failed to get subnet '%s'.", *subnet.ID),
+					Details: []api.CloudErrorBody{
+						{
+							Message: string(b),
+						},
+					},
+				},
+			}
+		}
+
+		if s.SubnetPropertiesFormat == nil ||
+			s.SubnetPropertiesFormat.NetworkSecurityGroup == nil ||
+			!strings.EqualFold(*s.SubnetPropertiesFormat.NetworkSecurityGroup.ID, *nsg.ID) {
 			continue
 		}
 
-		for _, subnet := range *nsg.SecurityGroupPropertiesFormat.Subnets {
-			// Note: subnet only has value in the ID field,
-			// so we have to make another API request to get full subnet struct
-			// TODO: there is probably an undesirable race condition here - check if etags can help.
-			s, err := m.subnet.Get(ctx, *subnet.ID)
-			if err != nil {
-				b, _ := json.Marshal(err)
-
-				return &api.CloudError{
-					StatusCode: http.StatusBadRequest,
-					CloudErrorBody: &api.CloudErrorBody{
-						Code:    api.CloudErrorCodeInvalidLinkedVNet,
-						Message: fmt.Sprintf("Failed to get subnet '%s'.", *subnet.ID),
-						Details: []api.CloudErrorBody{
-							{
-								Message: string(b),
-							},
+		s.SubnetPropertiesFormat.NetworkSecurityGroup = nil
+
+		m.log.Printf("disconnecting network security group from subnet %s", *s.ID)
+		err = m.subnet.CreateOrUpdate(ctx, *s.ID, s)
+		if err != nil {
+			b, _ := json.Marshal(err)
+
+			return &api.CloudError{
+				StatusCode: http.StatusBadRequest,
+				CloudErrorBody: &api.CloudErrorBody{
+					Code:    api.CloudErrorCodeInvalidLinkedVNet,
+					Message: fmt.Sprintf("Failed to update subnet '%s'.", *subnet.ID),
+					Details: []api.CloudErrorBody{
+						{
+							Message: string(b),
 						},
 					},
-				}
+				},
 			}
+		}
+	}
+
+	return nil
+}
+
+// keys must be lower case
+var deleteOrder = map[string]int{
+	"microsoft.compute/virtualmachines":     -1, // first, and before microsoft.compute/disks, microsoft.network/networkinterfaces
+	"microsoft.network/privatelinkservices": -1, // before microsoft.network/loadbalancers
+	"microsoft.network/privatednszones":     1,  // after everything else: get other deletions underway first
+}
 
-			if s.SubnetPropertiesFormat == nil ||
-				s.SubnetPropertiesFormat.NetworkSecurityGroup == nil ||
-				!strings.EqualFold(*s.SubnetPropertiesFormat.NetworkSecurityGroup.ID, *nsg.ID) {
+func (m *manager) deleteResources(ctx context.Context) error {
+	resourceGroup := stringutils.LastTokenByte(m.doc.OpenShiftCluster.Properties.ClusterProfile.ResourceGroupID, '/')
+
+	resources, err := m.resources.ListByResourceGroup(ctx, resourceGroup, "", "", nil)
+	if err != nil {
+		return err
+	}
+
+	resourceMap := map[int][]*mgmtfeatures.GenericResourceExpanded{}
+	for i, resource := range resources {
+		level := deleteOrder[strings.ToLower(*resource.Type)]
+		resourceMap[level] = append(resourceMap[level], &resources[i])
+	}
+
+	levels := make([]int, 0, len(resourceMap))
+	for level := range resourceMap {
+		levels = append(levels, level)
+	}
+	sort.Ints(levels)
+
+	for _, level := range levels {
+		sort.Slice(resourceMap[level], func(i, j int) bool {
+			return strings.Compare(
+				strings.ToLower(*resourceMap[level][i].ID),
+				strings.ToLower(*resourceMap[level][j].ID)) < 0
+		})
+
+		futures := make([]mgmtfeatures.ResourcesDeleteByIDFuture, 0, len(resourceMap[level]))
+		for _, resource := range resourceMap[level] {
+			apiVersion := azureclient.APIVersion(*resource.Type)
+			if apiVersion == "" {
+				m.log.Warnf("skipping resource %s", *resource.ID)
 				continue
 			}
 
-			s.SubnetPropertiesFormat.NetworkSecurityGroup = nil
+			switch strings.ToLower(*resource.Type) {
+			case "microsoft.network/networksecuritygroups":
+				m.log.Printf("disconnecting network security group %s", *resource.ID)
+				err = m.disconnectSecurityGroup(ctx, *resource.ID)
+				if err != nil {
+					return err
+				}
+
+			case "microsoft.network/privatednszones":
+				m.log.Printf("deleting private DNS nested resources of %s", *resource.ID)
+				err = m.deletePrivateDNSVirtualNetworkLinks(ctx, *resource.ID)
+				if err != nil {
+					return err
+				}
+			}
+
+			m.log.Printf("deleting %s", *resource.ID)
+			future, err := m.resources.DeleteByID(ctx, *resource.ID, apiVersion)
+			if err != nil {
+				return err
+			}
 
-			m.log.Printf("removing network security group from subnet %s", *s.ID)
-			err = m.subnet.CreateOrUpdate(ctx, *s.ID, s)
+			futures = append(futures, future)
+		}
+
+		for i, future := range futures {
+			m.log.Printf("waiting for deletion of %s", *resourceMap[level][i].ID)
+
+			err = future.WaitForCompletionRef(ctx, m.resources.Client())
 			if err != nil {
-				b, _ := json.Marshal(err)
-
-				return &api.CloudError{
-					StatusCode: http.StatusBadRequest,
-					CloudErrorBody: &api.CloudErrorBody{
-						Code:    api.CloudErrorCodeInvalidLinkedVNet,
-						Message: fmt.Sprintf("Failed to update subnet '%s'.", *subnet.ID),
-						Details: []api.CloudErrorBody{
-							{
-								Message: string(b),
-							},
-						},
-					},
-				}
+				return err
 			}
 		}
 	}
 
+	return nil
+}
+
+func (m *manager) Delete(ctx context.Context) error {
+	resourceGroup := stringutils.LastTokenByte(m.doc.OpenShiftCluster.Properties.ClusterProfile.ResourceGroupID, '/')
+
+	m.log.Printf("deleting dns")
+	err := m.dns.Delete(ctx, m.doc.OpenShiftCluster)
+	if err != nil {
+		return err
+	}
+
 	m.log.Print("deleting private endpoint")
 	err = m.privateendpoint.Delete(ctx, m.doc)
 	if err != nil {
 		return err
 	}
 
+	m.log.Printf("deleting resources")
+	err = m.deleteResources(ctx)
+	if err != nil {
+		return err
+	}
+
+	m.log.Printf("deleting resource group %s", resourceGroup)
+	err = m.groups.DeleteAndWait(ctx, resourceGroup)
+	if detailedErr, ok := err.(autorest.DetailedError); ok &&
+		(detailedErr.StatusCode == http.StatusForbidden || detailedErr.StatusCode == http.StatusNotFound) {
+		err = nil
+	}
+	if err != nil {
+		return err
+	}
+
 	if m.env.DeploymentMode() != deployment.Development {
 		managedDomain, err := dns.ManagedDomain(m.env, m.doc.OpenShiftCluster.Properties.ClusterProfile.Domain)
 		if err != nil {
@@ -121,19 +243,7 @@ func (m *manager) Delete(ctx context.Context) error {
 				return err
 			}
 		}
-	}
-
-	m.log.Printf("deleting resource group %s", resourceGroup)
-	err = m.groups.DeleteAndWait(ctx, resourceGroup)
-	if detailedErr, ok := err.(autorest.DetailedError); ok &&
-		(detailedErr.StatusCode == http.StatusForbidden || detailedErr.StatusCode == http.StatusNotFound) {
-		err = nil
-	}
-	if err != nil {
-		return err
-	}
 
-	if m.env.DeploymentMode() != deployment.Development {
 		acrManager, err := acrtoken.NewManager(m.env, m.localFpAuthorizer)
 		if err != nil {
 			return err
diff --git a/pkg/cluster/deployresources_resources.go b/pkg/cluster/deployresources_resources.go
index 84b1aeac3..89a129afd 100644
--- a/pkg/cluster/deployresources_resources.go
+++ b/pkg/cluster/deployresources_resources.go
@@ -26,7 +26,7 @@ func dnsPrivateZone(installConfig *installconfig.InstallConfig) *arm.Resource {
 			Type:     to.StringPtr("Microsoft.Network/privateDnsZones"),
 			Location: to.StringPtr("global"),
 		},
-		APIVersion: azureclient.APIVersions["Microsoft.Network/privateDnsZones"],
+		APIVersion: azureclient.APIVersion("Microsoft.Network/privateDnsZones"),
 	}
 }
 
@@ -39,12 +39,12 @@ func dnsPrivateRecordAPIINT(infraID string, installConfig *installconfig.Install
 				TTL: to.Int64Ptr(300),
 				ARecords: &[]mgmtprivatedns.ARecord{
 					{
-						Ipv4Address: to.StringPtr(fmt.Sprintf("[reference('Microsoft.Network/loadBalancers/%s-internal', '%s').frontendIpConfigurations[0].properties.privateIPAddress]", infraID, azureclient.APIVersions["Microsoft.Network"])),
+						Ipv4Address: to.StringPtr(fmt.Sprintf("[reference('Microsoft.Network/loadBalancers/%s-internal', '%s').frontendIpConfigurations[0].properties.privateIPAddress]", infraID, azureclient.APIVersion("Microsoft.Network"))),
 					},
 				},
 			},
 		},
-		APIVersion: azureclient.APIVersions["Microsoft.Network/privateDnsZones"],
+		APIVersion: azureclient.APIVersion("Microsoft.Network/privateDnsZones"),
 		DependsOn: []string{
 			"Microsoft.Network/loadBalancers/" + infraID + "-internal",
 			"Microsoft.Network/privateDnsZones/" + installConfig.Config.ObjectMeta.Name + "." + installConfig.Config.BaseDomain,
@@ -61,12 +61,12 @@ func dnsPrivateRecordAPI(infraID string, installConfig *installconfig.InstallCon
 				TTL: to.Int64Ptr(300),
 				ARecords: &[]mgmtprivatedns.ARecord{
 					{
-						Ipv4Address: to.StringPtr(fmt.Sprintf("[reference('Microsoft.Network/loadBalancers/%s-internal', '%s').frontendIpConfigurations[0].properties.privateIPAddress]", infraID, azureclient.APIVersions["Microsoft.Network"])),
+						Ipv4Address: to.StringPtr(fmt.Sprintf("[reference('Microsoft.Network/loadBalancers/%s-internal', '%s').frontendIpConfigurations[0].properties.privateIPAddress]", infraID, azureclient.APIVersion("Microsoft.Network"))),
 					},
 				},
 			},
 		},
-		APIVersion: azureclient.APIVersions["Microsoft.Network/privateDnsZones"],
+		APIVersion: azureclient.APIVersion("Microsoft.Network/privateDnsZones"),
 		DependsOn: []string{
 			"Microsoft.Network/loadBalancers/" + infraID + "-internal",
 			"Microsoft.Network/privateDnsZones/" + installConfig.Config.ObjectMeta.Name + "." + installConfig.Config.BaseDomain,
@@ -87,7 +87,7 @@ func dnsVirtualNetworkLink(vnetID string, installConfig *installconfig.InstallCo
 			Type:     to.StringPtr("Microsoft.Network/privateDnsZones/virtualNetworkLinks"),
 			Location: to.StringPtr("global"),
 		},
-		APIVersion: azureclient.APIVersions["Microsoft.Network/privateDnsZones"],
+		APIVersion: azureclient.APIVersion("Microsoft.Network/privateDnsZones"),
 		DependsOn: []string{
 			"Microsoft.Network/privateDnsZones/" + installConfig.Config.ObjectMeta.Name + "." + installConfig.Config.BaseDomain,
 		},
@@ -128,7 +128,7 @@ func networkPrivateLinkService(infraID, subscriptionID string, oc *api.OpenShift
 			Type:     to.StringPtr("Microsoft.Network/privateLinkServices"),
 			Location: &installConfig.Config.Azure.Region,
 		},
-		APIVersion: azureclient.APIVersions["Microsoft.Network"],
+		APIVersion: azureclient.APIVersion("Microsoft.Network"),
 		DependsOn: []string{
 			"Microsoft.Network/loadBalancers/" + infraID + "-internal",
 		},
@@ -148,7 +148,7 @@ func networkPublicIPAddress(infraID string, installConfig *installconfig.Install
 			Type:     to.StringPtr("Microsoft.Network/publicIPAddresses"),
 			Location: &installConfig.Config.Azure.Region,
 		},
-		APIVersion: azureclient.APIVersions["Microsoft.Network"],
+		APIVersion: azureclient.APIVersion("Microsoft.Network"),
 	}
 }
 
@@ -243,7 +243,7 @@ func networkInternalLoadBalancer(infraID string, oc *api.OpenShiftCluster, insta
 			Type:     to.StringPtr("Microsoft.Network/loadBalancers"),
 			Location: &installConfig.Config.Azure.Region,
 		},
-		APIVersion: azureclient.APIVersions["Microsoft.Network"],
+		APIVersion: azureclient.APIVersion("Microsoft.Network"),
 	}
 }
 
@@ -329,7 +329,7 @@ func networkPublicLoadBalancer(infraID string, oc *api.OpenShiftCluster, install
 
 	return &arm.Resource{
 		Resource:   lb,
-		APIVersion: azureclient.APIVersions["Microsoft.Network"],
+		APIVersion: azureclient.APIVersion("Microsoft.Network"),
 		DependsOn: []string{
 			"Microsoft.Network/publicIPAddresses/" + infraID + "-pip-v4",
 		},
@@ -363,7 +363,7 @@ func networkBootstrapNIC(infraID string, oc *api.OpenShiftCluster, installConfig
 			Type:     to.StringPtr("Microsoft.Network/networkInterfaces"),
 			Location: &installConfig.Config.Azure.Region,
 		},
-		APIVersion: azureclient.APIVersions["Microsoft.Network"],
+		APIVersion: azureclient.APIVersion("Microsoft.Network"),
 		DependsOn: []string{
 			"Microsoft.Network/loadBalancers/" + infraID + "-internal",
 			"Microsoft.Network/loadBalancers/" + infraID,
@@ -398,7 +398,7 @@ func networkMasterNICs(infraID string, oc *api.OpenShiftCluster, installConfig *
 			Type:     to.StringPtr("Microsoft.Network/networkInterfaces"),
 			Location: &installConfig.Config.Azure.Region,
 		},
-		APIVersion: azureclient.APIVersions["Microsoft.Network"],
+		APIVersion: azureclient.APIVersion("Microsoft.Network"),
 		Copy: &arm.Copy{
 			Name:  "networkcopy",
 			Count: int(*installConfig.Config.ControlPlane.Replicas),
@@ -461,7 +461,7 @@ func computeBoostrapVM(infraID string, oc *api.OpenShiftCluster, installConfig *
 			Type:     to.StringPtr("Microsoft.Compute/virtualMachines"),
 			Location: &installConfig.Config.Azure.Region,
 		},
-		APIVersion: azureclient.APIVersions["Microsoft.Compute"],
+		APIVersion: azureclient.APIVersion("Microsoft.Compute"),
 		DependsOn: []string{
 			"Microsoft.Network/networkInterfaces/" + infraID + "-bootstrap-nic",
 			"Microsoft.Network/privateDnsZones/" + installConfig.Config.ObjectMeta.Name + "." + installConfig.Config.BaseDomain + "/virtualNetworkLinks/" + installConfig.Config.ObjectMeta.Name + "-network-link",
@@ -521,7 +521,7 @@ func computeMasterVMs(infraID string, zones *[]string, machineMaster *machine.Ma
 			Type:     to.StringPtr("Microsoft.Compute/virtualMachines"),
 			Location: &installConfig.Config.Azure.Region,
 		},
-		APIVersion: azureclient.APIVersions["Microsoft.Compute"],
+		APIVersion: azureclient.APIVersion("Microsoft.Compute"),
 		Copy: &arm.Copy{
 			Name:  "computecopy",
 			Count: int(*installConfig.Config.ControlPlane.Replicas),
diff --git a/pkg/cluster/deploystorage.go b/pkg/cluster/deploystorage.go
index a6404804e..2a11f0f8b 100644
--- a/pkg/cluster/deploystorage.go
+++ b/pkg/cluster/deploystorage.go
@@ -168,14 +168,14 @@ func (m *manager) deployStorageTemplate(ctx context.Context, installConfig *inst
 					Location: &installConfig.Config.Azure.Region,
 					Type:     to.StringPtr("Microsoft.Storage/storageAccounts"),
 				},
-				APIVersion: azureclient.APIVersions["Microsoft.Storage"],
+				APIVersion: azureclient.APIVersion("Microsoft.Storage"),
 			},
 			{
 				Resource: &mgmtstorage.BlobContainer{
 					Name: to.StringPtr("cluster" + m.doc.OpenShiftCluster.Properties.StorageSuffix + "/default/ignition"),
 					Type: to.StringPtr("Microsoft.Storage/storageAccounts/blobServices/containers"),
 				},
-				APIVersion: azureclient.APIVersions["Microsoft.Storage"],
+				APIVersion: azureclient.APIVersion("Microsoft.Storage"),
 				DependsOn: []string{
 					"Microsoft.Storage/storageAccounts/cluster" + m.doc.OpenShiftCluster.Properties.StorageSuffix,
 				},
@@ -185,7 +185,7 @@ func (m *manager) deployStorageTemplate(ctx context.Context, installConfig *inst
 					Name: to.StringPtr("cluster" + m.doc.OpenShiftCluster.Properties.StorageSuffix + "/default/aro"),
 					Type: to.StringPtr("Microsoft.Storage/storageAccounts/blobServices/containers"),
 				},
-				APIVersion: azureclient.APIVersions["Microsoft.Storage"],
+				APIVersion: azureclient.APIVersion("Microsoft.Storage"),
 				DependsOn: []string{
 					"Microsoft.Storage/storageAccounts/cluster" + m.doc.OpenShiftCluster.Properties.StorageSuffix,
 				},
@@ -292,7 +292,7 @@ func (m *manager) denyAssignments(clusterSPObjectID string) *arm.Resource {
 				IsSystemProtected: to.BoolPtr(true),
 			},
 		},
-		APIVersion: azureclient.APIVersions["Microsoft.Authorization/denyAssignments"],
+		APIVersion: azureclient.APIVersion("Microsoft.Authorization/denyAssignments"),
 	}
 }
 
diff --git a/pkg/cluster/gatherlogs.go b/pkg/cluster/gatherlogs.go
index 47ce632c5..627232350 100644
--- a/pkg/cluster/gatherlogs.go
+++ b/pkg/cluster/gatherlogs.go
@@ -15,6 +15,7 @@ import (
 func (m *manager) gatherFailureLogs(ctx context.Context) {
 	for _, f := range []func(context.Context) (interface{}, error){
 		m.logClusterVersion,
+		m.logNodes,
 		m.logClusterOperators,
 		m.logIngressControllers,
 	} {
@@ -45,6 +46,14 @@ func (m *manager) logClusterVersion(ctx context.Context) (interface{}, error) {
 	return m.configcli.ConfigV1().ClusterVersions().Get(ctx, "version", metav1.GetOptions{})
 }
 
+func (m *manager) logNodes(ctx context.Context) (interface{}, error) {
+	if m.kubernetescli == nil {
+		return nil, nil
+	}
+
+	return m.kubernetescli.CoreV1().Nodes().List(ctx, metav1.ListOptions{})
+}
+
 func (m *manager) logClusterOperators(ctx context.Context) (interface{}, error) {
 	if m.configcli == nil {
 		return nil, nil
diff --git a/pkg/cluster/nsg.go b/pkg/cluster/nsg.go
index 0d5d68a73..0fedc83ab 100644
--- a/pkg/cluster/nsg.go
+++ b/pkg/cluster/nsg.go
@@ -41,6 +41,6 @@ func (m *manager) clusterNSG(infraID, location string) *arm.Resource {
 
 	return &arm.Resource{
 		Resource:   nsg,
-		APIVersion: azureclient.APIVersions["Microsoft.Network"],
+		APIVersion: azureclient.APIVersion("Microsoft.Network"),
 	}
 }
diff --git a/pkg/deploy/bindata.go b/pkg/deploy/bindata.go
index 45b3ce3f6..7add441d2 100644
--- a/pkg/deploy/bindata.go
+++ b/pkg/deploy/bindata.go
@@ -131,7 +131,7 @@ func databasesDevelopmentJson() (*asset, error) {
 	return a, nil
 }
 
-var _envDevelopmentJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5b\x7b\x6f\xa3\xc8\x96\xff\x7f\x3e\x45\x94\xbd\x52\xba\xb5\x9d\x04\x70\x9c\x0e\x57\xea\x3f\x30\xb6\x31\x36\x26\x06\xcc\x73\x6e\x6b\x04\x55\x04\x63\x17\x8f\x85\x02\x82\xaf\xe6\xbb\xaf\xc0\x8f\xf8\x6d\xa7\xd3\x23\xed\xde\x69\x5a\xe9\xc4\x70\xce\xa9\xaa\x53\xe7\x59\x3f\xfc\xef\xdf\xae\xae\xae\xae\xae\xff\x91\x82\x89\x1b\xd8\xd7\xff\xbc\xba\x9e\x60\x1c\xa7\xff\xbc\xbf\x5f\xdc\xb9\x0b\xec\xd0\xf6\xdc\xc0\x0d\xf1\x9d\x3d\xcf\x12\xf7\x0e\x44\xc1\xf2\x59\x7a\x4f\x11\x64\xf3\x96\x20\x6f\x09\xf2\x1e\xba\x31\x8a\xca\x8a\x6e\xec\x06\x31\xb2\xb1\x7b\x37\x4d\xa3\xf0\xbf\xae\xbf\x2c\x46\x00\x51\x88\xdd\x10\x6b\x6e\x92\xfa\x51\x58\x0d\x44\xde\x11\xd5\xbf\x15\x41\x6c\x27\x76\xe0\x62\x37\x49\xaf\xff\x79\xb5\x98\xd6\x82\xd1\x67\xe6\xf1\x38\x9a\xb9\xe1\xd6\xfd\xfa\x19\x2e\x63\xb7\x12\x95\xe2\xc4\x0f\xbd\xeb\xf5\xc3\x3f\xbf\x6c\xf2\xb3\x76\x6c\x03\x1f\x97\xc7\xf9\xfd\x10\x1f\x63\x6e\xd7\xeb\x1a\x47\x11\xaa\x46\x38\x2a\xc1\x89\x22\x74\xfd\x65\xfb\x19\x74\x5f\xec\x0c\x61\xcd\x46\x59\x45\xf3\x62\xa3\xd4\x3d\x32\xca\x28\x8a\x90\x68\x07\xee\x8f\x2d\x31\x4e\xa2\xd7\x92\x75\x13\xfc\x11\x76\xe4\xbb\x21\xfe\xa0\x90\x76\x14\xd8\x7e\x58\x2d\x44\xb0\x1d\x17\x7d\x40\x12\x1f\xd8\xde\x47\xb4\x51\xf3\x33\x19\x9e\x9c\x90\xe1\x82\x2c\x71\xcf\x4a\x1a\xb8\x27\x0c\xe7\x02\x19\x99\x83\x7c\xc0\x8f\x18\x08\x13\x37\x4d\x19\x84\x22\x60\x63\x3f\x0a\x87\x2e\x9e\x44\xf0\xec\x12\x4f\xdb\xd4\xb5\x82\x6d\xec\x83\x8b\x86\x56\x66\xd9\x45\x26\x76\x7e\xc4\x10\xda\x09\x3c\x3c\x66\x9a\x4e\x46\xf5\xb0\xa7\xd5\x76\x42\x61\x79\x1c\xb2\x4c\x65\x87\xfe\x8b\x0f\x6c\xfc\x1e\x23\xf8\x6d\x43\xd6\x75\xe2\xa6\x51\x96\x00\xb7\x0a\x27\xbf\xaf\x69\x76\x44\xa5\xb3\x6c\x4f\x7e\xfd\x20\x5c\x68\xea\xfa\xf7\xb7\xb0\xf4\xe9\xe6\xb0\x42\x6f\x3e\x7f\xbf\xde\x12\xf0\xe7\x8e\x06\xe3\x24\x8a\xab\xf5\xb8\xe9\xe1\xb1\xd6\x62\xf7\x6d\xe3\xe4\xf8\xbb\xf4\x67\x27\xb2\x5a\x14\x74\xf3\xdb\x3c\x0e\x6f\x63\x3f\xde\xdd\xed\x95\x6e\x87\x3e\x48\xa2\x34\x7a\xc1\x77\xa2\x8b\x8b\x28\x99\xdd\xef\x0c\xee\xa6\xbb\xac\xab\xc9\xd4\xd3\x5e\x69\x9f\x4b\xa2\x2c\xfe\xf4\xf9\x6e\xf5\xf0\xfb\x2e\x97\x1d\xfb\x1b\x39\x81\x22\x48\xfa\x96\xf8\x7a\x4b\x90\x07\x8d\xe3\xdf\xef\x53\xac\xbd\xdc\xa7\xd8\x06\xfb\x66\xb4\x4b\x35\x4a\xdc\x17\xff\x75\xc7\x5c\xf6\x88\x49\x62\x91\xb5\xee\xe9\xeb\x83\x44\xdf\xf7\xee\xee\x6c\x42\x2d\x25\xcd\x9c\xd0\xc5\xc7\x87\x3a\x3c\xd3\xab\x0b\xd6\x7c\x7c\x65\x75\xca\x5d\xcd\x9e\x7a\x38\x3c\xfd\x23\x13\x5e\x4b\x5c\x59\x10\x67\x63\xb7\xb0\x4b\xa5\x5e\xc7\x61\x51\x47\xc4\xfc\xa5\x4b\x23\x17\x4b\x3b\xbe\x80\xc5\x22\x16\x16\xad\x54\xb1\xdb\xc7\x65\x6d\xa2\x67\x47\xac\x39\x7d\xb8\x65\xdc\x3c\xfc\x74\xb3\xef\x28\x87\xc4\xa7\x37\x5f\xae\x6e\x92\xf8\x36\x4c\xbd\xca\x4b\x4f\x4f\xb0\x1e\x0a\xdb\x5e\xa5\x86\x30\x43\xe8\x24\xf1\x9f\x1f\xda\xc7\x65\x5d\x73\x72\x1f\xf7\xee\x7e\xbf\x3c\xc8\x54\x52\x2f\x8e\x30\xb9\x9f\xe0\xcc\x46\xcb\x8f\xff\x0f\xe2\x8b\x1f\xb3\x51\xf8\xe2\x7b\x59\x52\x8f\xfd\x97\xfb\xf3\x22\x6c\xfc\x44\x53\xdd\xd1\xf8\xfd\x32\x2e\x55\xc6\xba\xda\xbe\xea\xef\x2d\x6f\xdf\xcb\x32\xbb\xd7\x09\xbb\xbb\x3a\x50\x96\xfc\xc4\xe5\xec\xa5\xa8\xf5\x42\x16\xc9\xee\xfc\xd4\x3f\xe4\x4c\xcb\x4a\xe9\x62\x37\x3a\x90\x18\xf2\x38\x1c\x2f\xfd\x43\x8e\x32\xec\xb6\xec\xd4\x85\x07\xc2\xc5\xd1\xc2\x65\x6b\x42\x5a\x1c\x72\x05\x79\x24\xda\x5c\x63\xdf\x4d\x36\xa8\x2e\x4a\x5c\x55\x71\xb6\x68\x14\x36\x0d\xff\xf8\x4c\xd6\xf4\xcb\x2d\xa9\xfa\x9c\x93\x1b\xfe\xae\x6c\x5c\x33\x90\x34\x75\x47\x3e\x3e\xdd\x51\xcd\xe6\x99\xc4\xb6\x9f\x9b\x8f\x2c\x73\x7b\xea\x72\x14\xe1\x8d\x7a\xf4\xf4\x94\xce\x78\xf0\x3b\xbc\xfd\xea\xcd\x57\xaa\xd1\xdb\x36\xb6\xf7\x0a\xc2\xdd\x5a\xf9\xc3\xbe\xb9\x5b\x21\x02\xfb\x44\x9d\x70\xb8\x00\x3a\xa7\xce\x51\x12\xe1\x08\x44\xe8\x4c\xa1\xf5\x1c\xbb\xa1\x36\x12\x2f\xae\xb2\xde\x53\xf8\xfe\x68\x4a\x5a\xc6\xc1\xbf\x3a\x33\xed\x35\x60\xb1\x1b\xc2\xf4\x39\x3c\xa8\xb0\x9f\x11\x13\x0f\x38\xfa\xfb\x12\xc7\x56\xc2\xd8\xb5\xc1\xef\x17\x64\xda\xb3\x7d\xd8\xaa\xeb\xfc\xa3\x4d\xa5\x7f\xe4\x8d\x43\x53\x5e\xc5\xb3\x75\x83\x7a\x80\x06\xbc\x1d\x05\x5d\xff\xee\x87\xf8\xd3\xa6\x37\xbd\x9d\x14\xdd\x7c\xfe\x68\x4f\x97\xc5\x5e\x62\x43\x77\x14\x21\x1f\xec\x37\xc2\x6b\xb2\x20\x82\x0b\xcb\xb3\xc3\xcc\x46\x17\xc6\xe0\x85\xee\x87\x36\x98\xf8\xa1\x3b\x4a\xa2\x17\x1f\x9d\x68\x6f\xa2\xf4\x1c\xc9\x42\x33\x51\x10\x67\xd8\x4d\xaa\x8e\xf6\xad\xaa\x06\xfe\xed\x89\x62\xf5\xda\x86\x81\x1f\xaa\xa9\x9b\xac\xb6\x09\xa0\x28\x83\xb7\x59\xea\x26\xa7\xd8\x90\x1f\x66\xaf\x97\x65\x90\x35\x0f\xf4\x53\xdb\x41\xee\xc8\x4e\xd3\x22\x4a\x20\x93\xe1\x89\x1b\x62\x7f\xed\x78\x38\xc9\xdc\x33\xc1\x2d\x4d\xf7\x4f\x83\x0e\x12\xc6\xab\x13\x8c\xf3\xe9\x67\x75\x9d\x97\xfa\x26\xdd\xae\x4f\xa5\xae\xef\x27\x51\xe0\xde\xbf\x69\xec\xfe\x2e\x4d\x27\xf7\x76\x86\x27\x51\xe2\xcf\x5d\xf8\xc7\xcc\xdd\x0b\x35\x27\x05\xcf\xdc\xf2\x60\x96\xd8\x3c\x93\x39\x9b\x21\x56\xd7\xf1\x52\x68\x75\x1d\x4e\xa7\xe7\xf9\x0f\x3f\x39\x96\x86\x53\x1c\x25\xb6\x77\xd6\xcc\x6b\x5a\x3f\xb0\x3d\x57\x76\x5f\xdc\xc4\x0d\x4f\x74\xfc\x6b\xfa\x7a\x9f\xd3\xc9\x22\x6c\xc8\x2e\xec\xd9\xbb\xdd\xca\x1e\x4b\xf4\xf2\xb2\x24\xef\x75\x84\x73\xc4\x8b\xa8\x76\xfd\xf5\x56\xd0\x86\xe7\x68\xf3\xb7\x54\xf0\xf5\x8e\xbe\xa3\x08\x8a\x20\x09\x82\x24\x1f\x7f\xac\x51\x8f\xd2\xb6\x9f\xce\xce\xab\x00\x24\xae\x8d\xdd\xe7\x78\x95\xbe\xba\x49\x14\x2c\xce\x5e\xcf\xcc\x77\x81\x0b\xc0\x8b\x46\xb9\xda\xd8\x48\x06\x80\x28\x0b\xf1\xaa\xca\x1d\x25\x6e\xe0\x67\xc1\x1f\x82\xac\xfc\x70\x69\xfe\x2e\x7b\x5a\x76\xe7\x17\xd9\xd3\x92\x96\x0f\xb1\x9b\xbc\xd8\xc0\xbd\xb0\xdb\x5b\x5d\x17\x28\x65\x1d\x37\xfd\xdb\x3c\x48\xd3\xdb\xd0\x07\x97\x1c\x0e\xbc\xb3\x8c\x5c\xf2\xf8\x81\x9d\x94\x17\x85\xca\x35\xd3\xc5\x1d\xee\xa1\xeb\xf2\x98\x78\x75\x48\x17\x7e\x0c\xea\xb1\xdf\x11\x02\xaf\x7e\x50\x39\x5b\xfc\xef\xe8\xb2\x0f\xf2\xff\xcc\xce\x7b\xeb\x7c\xe6\xe2\xd8\xbd\x79\x9d\xa9\xf8\x0f\xae\xe0\x47\x4c\x65\x5b\xc0\x76\xd1\xf9\xbe\x54\x7f\x54\xea\xae\x81\xec\x1f\x5f\x5f\x3e\xc1\x8f\xd9\xc8\x5a\x0e\x0c\x53\xc5\xc5\xd8\x0f\xbd\x8f\x09\x5a\x08\xdb\x43\xcf\xae\xed\x24\xba\x05\xfe\xfb\x77\x7d\x75\x9d\xcf\xe2\x3f\x87\xeb\x7d\x1c\x97\x53\x5f\x46\x79\xba\x12\x39\x2f\xe7\xf8\xd3\xf7\x1d\x19\xb8\xaf\xd8\x0d\xab\x2c\x7e\x51\x76\x59\x53\xff\x25\x99\x04\xa4\xe7\x52\xf8\xd5\x0f\x67\x92\xcd\xb2\xe9\x2d\xb4\x31\xf5\xeb\x01\x9d\xb7\x55\x5d\x98\x63\x56\xdd\x37\x9b\xa5\x38\x0a\x14\x90\xf8\xf1\xb9\x32\x6c\x8b\xb7\x67\x87\x10\xb9\xc9\x66\x2f\xbd\x7e\xab\xe0\xac\x00\x3b\xc3\x91\xba\xe8\xd5\x86\x7e\x18\x6d\x48\x79\x47\x96\x4c\x37\x42\xc0\x85\xf1\xb6\x52\x3c\x76\x01\x76\xe1\x0f\xc5\x8f\xeb\x74\xa1\xa6\x2a\xd1\x38\x76\xea\x3e\x3e\x7c\x02\x51\x08\x6c\xfc\x69\xf1\x69\x1c\x29\x35\x38\xfa\xe9\x06\x50\x1a\xc1\xb3\x24\x62\xbd\xe8\xdb\xcd\xe7\x2f\x37\x2c\xcf\x58\xa3\xf1\xf3\xa0\x23\x7e\xbb\xb9\xb9\xf9\xb2\xdd\xff\xae\xde\xb4\xa8\x08\x6f\x6e\xfe\x15\xde\x54\xf4\xa3\xe7\x67\x41\x64\x86\x9d\x03\xf4\xab\xd7\x16\x36\xe8\xab\xff\x76\xe7\xc0\x86\x88\x74\x14\x06\xbb\x4a\x8b\x04\x9c\x3c\x81\x9c\xea\x09\x86\xe7\x69\x44\x77\x68\xeb\x4d\xd2\xed\x74\x43\x4b\x6f\x12\xac\x17\xa7\x30\xd0\x1e\x20\xa7\x65\x16\xcb\x60\x87\x65\x12\x71\xcc\x20\x19\xf5\xbb\xb2\xc2\xe4\x16\xa7\x51\x42\xa3\x9f\x3b\x0d\x99\xb2\x4a\x9a\x32\x8d\x7e\x0a\xbd\xf8\xc1\x0a\xc5\x17\xab\xd1\xcf\x21\x65\xcd\x79\xb6\xba\xcf\x0f\xd8\xe0\x95\xb2\x8c\x09\x61\xe9\xcd\x19\xcf\x92\x29\xcf\xa6\xaf\xc3\xf6\x51\x59\x91\x43\x91\xc8\xe9\x99\x03\x97\xb3\xe6\x06\x05\x4b\xa7\x01\x03\x50\x32\xb9\xcd\xd1\xd8\x92\xa2\x01\x08\x5b\x98\x67\x09\x6c\xeb\x64\xe1\x34\xfa\x04\xcf\x4d\x08\xd8\x6b\xcd\x9f\xfd\xa7\xdc\xe2\x8a\xcc\x0a\xb4\x99\xd3\xe8\x4f\x40\xaf\x9f\xdb\x81\x36\x85\x6c\x33\x07\x01\xc8\x41\x4f\xf3\x05\x4a\x2b\x2c\xbd\xc8\x55\xd4\x12\x05\x15\x4a\x72\x49\x0a\xb2\x36\xc3\xb2\xd6\xea\x8e\x59\xa2\xc1\x86\xfd\xa2\xd2\x8f\xa0\x23\x0c\x38\xba\x84\x6c\x2b\x82\x3d\xb9\x00\xf3\x28\x17\x1a\xad\x89\x49\xe1\x89\x45\x69\x73\x21\x20\x63\xb3\xd1\xcf\x01\x45\x07\x90\x6d\x4e\x1d\x8a\xc8\x6d\x4a\x6b\x82\x92\xc6\xb6\x2e\x96\x4e\x43\xcc\xad\x50\xca\x4c\x43\x9c\xb2\x5e\xdc\x84\x3a\xe1\x09\xc6\xcc\xb3\xf5\xe6\x1c\x72\xdd\xd4\xd9\x94\x4b\xc9\xa9\x10\x58\xc8\xe2\xe8\xd2\x34\x5a\xa5\x43\xc5\xc8\x6c\x48\x99\xd3\xe8\x87\x42\xa3\x45\x9a\x3e\x8d\x00\xa7\xa5\xcb\xb9\x63\x10\x68\xa9\xa5\x77\xe7\x96\x42\xa6\xa6\x21\x23\xd0\x90\xb0\x58\x36\x33\x87\xea\x96\x26\xe5\x65\x95\x7e\x58\x2f\x9e\x9a\x86\xe4\x8d\x7c\x1a\x41\x6e\x98\xbb\x86\x86\x85\xb0\x8f\x00\x47\xcf\x85\x40\xca\x4d\x23\x26\x41\xa0\x66\x20\xd0\x0a\xa7\x64\x9e\x46\x2c\xec\x8e\x09\x33\x64\x51\xd5\xcc\x6b\xa5\xa5\x90\x53\x87\x43\x90\x0d\x9a\x13\x47\x57\xe9\x25\x3d\x36\xa9\xd7\x98\x0d\xfa\x13\x40\x69\x24\x08\x0a\xda\xee\xc9\x04\xe8\x0d\x1f\x85\x92\x2e\x4c\x5d\x4c\x4c\x1d\x22\x50\x36\xb7\x75\x40\xd1\x58\x68\x20\xd2\x31\x96\xe3\x53\xdd\x47\x68\xf4\x91\xa0\x8b\xa9\x2d\xc5\xc8\x09\xba\xbe\xc3\x69\xb3\x91\x81\x10\x28\xe2\x10\x70\x70\x6a\x73\xda\xd4\x9e\x93\x4d\xcb\x18\x0e\x64\x95\xe6\xd6\x3a\x54\xc8\x15\x7d\x69\x19\xad\x7c\x64\xf4\x23\xa8\xcf\x30\x08\x26\xc8\x61\x89\x86\x60\x88\x08\x84\x16\x02\x3e\x59\xda\x3d\x2d\x16\x74\xba\x80\x1c\xca\x9d\xa0\x9b\x0a\x46\xbf\x70\x8c\xe1\xee\x3e\x6c\xac\x77\xe6\x59\x1c\x3d\xb5\x29\xad\xe4\xb9\xf8\x95\xe7\x5e\x63\x33\xe8\xce\x41\x43\x9b\x38\x3e\x39\xb3\x0c\x0b\x39\x6c\x2b\x34\xa9\xa1\x67\x35\x5a\xa1\xa3\xab\xb8\xb2\x5d\x4b\x2f\x3c\x10\x78\xd8\xa2\x10\x31\x9c\xce\xea\xbf\x41\x0f\x11\x36\x47\x67\xc3\xb9\xe9\x41\x8e\x2c\x20\xd5\x25\x4c\xca\x1b\xb0\x33\x38\x32\x48\xab\xab\x22\xb1\x3f\x26\x1e\xe8\xa1\xf2\xf0\x2a\xb2\x0f\x4d\x36\x10\x2b\x7d\x7a\x1b\xfa\x9c\x39\x6c\x33\x74\x28\x3a\x74\x38\x75\xa1\x43\x0a\xe6\xd5\x4f\xbf\x87\x7b\x63\x92\xd6\x65\xad\x3f\x56\x54\xfa\xf9\x45\x69\xa6\xb5\xef\xb2\xe4\xc4\xd1\x25\x4a\x64\x9b\x84\x69\xf0\x99\xd5\x88\xbc\x17\xb6\x55\xfd\xed\x09\xea\xd0\x13\x1a\xda\x1c\xf8\x74\xea\x50\xe2\xc4\x61\x19\xec\xf6\xa2\x81\xc3\x3d\x78\x82\xb1\xfb\x8c\x0e\x9d\x92\xf6\x6d\xfd\x21\x1f\xf8\x4c\x0e\x0d\xb1\x14\xa8\xd7\xdc\xa4\xba\xa9\x40\xf5\x63\xc7\x8b\x06\x1a\x12\x55\x95\xa4\x5b\x32\xa1\x3d\x6b\xdd\xb7\xb9\x8c\xc6\x7c\x36\x1c\x03\x52\x98\xf2\x03\x47\xc7\x33\xbb\x1a\x9b\x9a\xe4\x8e\xae\xe6\x26\xf5\x9a\x43\x5d\xc2\xb0\xda\x23\x9f\xae\xfc\x28\x83\x4c\x5c\x40\x43\x8c\x2c\x76\xe9\xdf\x0a\x3d\x75\x38\x9a\xb4\x58\x92\x04\x94\x56\x0a\xd4\x32\x1e\xed\xeb\x87\x02\x0d\x79\x5e\xd9\x9b\x13\xca\x6b\xdb\x13\x82\x85\x6d\x59\xba\x1c\x5a\x4a\x33\xb3\x0c\x29\x5f\xd0\x48\x95\xde\x74\x95\x94\xc7\x06\xd1\xed\xc9\x6a\x53\x7d\xdb\x87\x26\x2d\x34\xac\x39\xec\x0d\xf1\x92\x16\x3b\x1c\xca\xa0\xe1\x61\xb7\x6d\x12\x82\x22\x7f\x3d\xb6\xde\x17\xe5\x80\xae\x8d\xc9\x23\x1b\x88\x91\xd3\x80\x19\xcf\x92\x0a\xcf\x89\xa9\xd3\xd0\x66\x82\xa1\xcd\x2d\x83\x7f\xdc\xd6\x03\x93\xb1\x5e\x94\xd5\x7a\xf5\xe9\xd8\x09\x45\xc2\xd4\x5f\x53\x8b\xab\x7c\xbd\x39\xb3\xf4\xe6\xd4\xd6\xb5\xb9\x10\x8a\x11\x1b\x8a\xa4\xc5\x3d\x79\x82\xa1\x7a\xbb\x32\x04\x4a\xcc\x9d\xc0\x8a\xad\xb2\x39\xb7\x59\x06\x0b\x86\x96\x99\x86\x4c\x2c\x64\x48\x95\xdf\xec\xd9\x97\x65\x98\xd9\x2a\x0e\x2c\xec\x8b\x9c\x2f\x3f\x57\xf4\x13\x68\xc8\x11\xdf\x6b\x4d\x60\x2d\x4f\xae\xe2\x5b\xc6\xb3\xfc\x4c\x22\x50\x4b\x47\x2d\x75\x4c\xe0\xee\xd8\xe7\x2b\xda\xc2\xa1\xe8\x74\xf9\x4c\x1a\x13\xf4\x70\x3c\xeb\x8a\xb2\x52\x3f\x5b\xec\x33\xcb\xf8\x92\xd6\x1f\x09\x5a\x9f\x97\xd5\x02\xf7\x3b\x93\x91\x4a\xca\xcf\x92\x4a\x76\x79\xbf\x92\x5f\xc5\x86\xd7\x89\x49\xa9\x03\xc1\xa7\xe7\x30\x18\x66\x80\xf2\x36\xfd\x74\xcb\x2e\xd8\xb0\x95\x03\x4e\x1a\xb0\xfe\xd0\x73\x74\xad\xb4\x28\xd5\xb3\xf5\x07\x4f\xa0\xe8\x02\xb2\x74\x69\xd7\x3f\xc4\xff\x08\x94\x96\x99\x7a\x3f\xb5\xa4\x75\x3c\xac\xf3\x8b\x40\x6d\xed\xc9\xda\x46\x84\xb0\x35\x81\x9c\xe7\x8d\xda\x45\x58\xc5\x9d\x7e\x11\xe5\x4e\xa3\x45\x08\x8d\x7e\x54\xff\x18\xad\x26\xe4\x26\xb9\x33\x1d\x2e\x73\x96\xb4\xf4\x8f\x7e\xec\x4c\x77\x68\x75\x18\xc3\x36\xdf\x3c\x44\xb7\xe7\x53\xeb\x7b\x07\x9e\x37\xc4\xca\x17\x1f\x97\x3e\x3a\x37\x03\x94\x3d\x1f\x59\x87\x10\x6c\xcb\x3c\xec\x53\x95\x0f\xc7\x55\xbc\x1f\xb0\x81\x58\xed\xef\x7f\x9f\xf4\x51\xf6\x29\xb3\xf4\x26\xc5\xb7\x8b\xa7\x3e\xa1\x8d\x64\x1f\x0c\xc6\x1d\xf9\x65\xdc\x41\xac\x3a\xeb\x2a\xba\x46\x4b\x92\x26\xf3\x23\x85\xce\x41\x4f\xca\x41\xe0\xe5\x3b\x31\x30\x07\x01\x9d\x43\x96\x26\x41\x83\xcf\x1d\x0e\xf9\xe2\x54\x7a\xdc\xd8\xab\x3a\x17\x5a\x6d\x9e\xd8\xd6\xd5\x6b\x6c\x4e\x4d\x82\x9d\x91\xad\x31\x6a\xb5\xb4\x8e\x47\x6f\xef\x2f\x59\xb8\x86\x1c\x39\xd4\xc3\x5c\xf4\xe9\xd2\xa1\x68\x62\xa5\x23\x9b\xeb\x96\x96\x42\x63\xb3\xd2\xdb\x36\x4f\x68\x1b\x52\xf9\xac\x1c\xa5\x1f\xa8\x1d\x4d\x19\xb7\xb5\xa1\xa2\xf2\xbb\xe3\x9d\xe2\x2d\x2c\xa3\x9f\x8a\x0a\x4d\x55\x3e\xe7\x34\xfa\x2f\x80\xd3\x4a\x87\x89\x25\x85\x80\x2f\x12\x41\x3f\xcb\x33\xd4\x33\xc8\x77\xad\x23\xb5\x75\x9e\x12\x59\xba\xb0\x29\x38\x75\xa8\x66\x60\xeb\x60\xa0\x77\xe4\x9e\x41\xc8\x2d\xad\xd3\x7d\x91\x3b\x48\x51\xe7\xc4\x65\x36\xda\x10\x23\xd3\xe8\xa3\x67\x7f\xb5\x0f\xf4\xd4\xd4\x8b\x1c\x50\x93\x09\x08\xd4\xc7\xad\xf5\x48\x4b\xfb\x08\x45\x54\xd5\x7f\xb6\xc2\x60\x4b\x61\x42\x50\xd2\xee\x98\x6c\xa9\x55\xec\x53\xe7\x44\x68\xb0\x20\x14\x08\x5a\xd2\x3a\x68\x34\x46\x43\xba\x4f\x16\x61\xbf\x24\x7b\x3b\x31\xcf\x13\x4a\xe0\x09\x94\x46\x98\x25\x3d\x77\x0d\x71\xb5\x96\x7c\x95\x6f\x59\x2f\xae\xee\x13\x96\x4e\x4e\x21\x57\x78\x96\xde\x9c\x98\xc1\x2b\xe2\x39\x39\x37\x29\x8c\x80\x17\x0d\x4c\xaa\x4b\xf0\xed\x87\xdc\x32\xe4\xa9\x40\x89\xa5\x43\x3d\x64\x36\x47\x93\x20\x78\x6d\x0a\x0d\x19\x83\x1e\x9c\x40\x4e\x8c\x36\xed\x94\x2f\x3b\x79\xe5\x2f\x02\x55\xd5\x2c\xde\x80\x0d\xb4\x07\x4b\xaf\xf2\x5d\xed\x53\xf9\x46\x6e\xf6\x86\x53\x39\xe2\x59\x9a\x70\x0c\x66\x51\x73\x54\x31\x5c\xa7\x67\x3c\x8b\x1f\x78\x76\x51\x47\x55\x35\x9f\xe3\x37\x23\xa7\xa1\x95\x4e\x6f\x96\x6f\xe5\x76\x7f\x32\x77\x38\x0d\x01\x96\x99\x0f\xdb\xa9\x07\x02\xcd\xaf\xf6\x72\xa0\x30\x01\xeb\x7d\xfb\x76\xf3\x79\x0f\xcb\x3a\x76\x9d\x6f\xb6\x7f\x72\x1b\x7d\x11\xdc\x15\xe5\x6e\x12\x27\x51\xee\x2f\xfb\xb2\xed\xd7\xa8\x0f\x70\xed\xb6\xc2\xe7\xd1\x5e\x76\x81\x7d\xdd\x6f\x23\x6b\x0a\xb0\x91\xab\xb8\xf8\x27\xc1\xbd\x20\x0a\xa1\xbf\x66\xdb\xee\xa3\xb6\x5e\x32\xdf\x47\x64\x0f\x42\xc5\x8d\x9f\x0e\x15\xff\x07\x80\xba\xe4\x2f\xd0\x76\xf1\x96\x43\xfd\xea\xfa\x2f\xec\xf6\x17\x76\x7b\xf8\xfa\x85\xdd\xfe\xc2\x6e\x7f\x61\xb7\x27\xae\x77\x9c\xb8\xbf\x85\xdb\x5f\x10\xee\x61\x95\xfc\x5d\x91\xdc\x24\x5e\x03\xb9\x49\x7c\x9b\xfe\x02\x71\x8f\x9b\xc8\xdf\x00\xcb\xdd\xfe\x2a\xd7\x81\xaf\x4b\xfe\x90\x69\xac\xae\x5f\x48\xef\x25\x72\xfe\x93\x90\xde\x1d\x0f\xfa\x05\xf8\x5e\x24\xe0\x6f\x03\xf8\xba\x4c\x34\xb8\xf9\xfc\xe5\x66\x24\x3f\x1b\x26\x3f\x64\xb8\xce\xb7\x7f\x2c\x89\xaf\x6e\xe1\xd5\xbf\x32\x82\x68\x80\xcd\xff\x6f\x6e\x56\xc8\xed\xa7\xbd\x48\x55\x97\x95\x37\x9f\x6b\x98\xf7\x73\x8d\xf3\xbe\x89\x65\xd4\x71\xef\xa3\xa2\xab\x96\x70\x5f\x3c\xdb\x91\xc7\x7b\xa8\xf3\xfa\xcb\xee\x1b\xa0\xf3\x82\x5a\xe0\x3b\xe2\xf8\x04\xcf\xfa\x1b\xee\xbb\x9c\x83\x8e\x79\x98\xa5\x6e\xba\x4e\x42\xdb\xae\xa1\x61\x9e\x25\x9b\x7c\x4f\x2b\x2c\xae\x4b\x58\x0a\x83\x5d\xb6\x65\x48\xea\x6b\xec\x84\xda\x83\xb4\x38\xe2\x1f\xac\xe9\x38\x94\x81\x86\x3c\x71\xb8\xc2\xdb\x38\x86\x0c\x6c\xa3\x8f\x20\xd5\x4d\x1d\x96\x9c\x3a\x0b\xe8\x64\x62\x71\xd2\x02\x0e\x6e\x13\x84\xd8\x1e\xe6\x90\x13\x0b\x9e\x25\x70\x7d\xc4\xab\x77\xb3\x25\x64\x8e\x6d\x4a\x8e\x81\xcf\x2c\x8f\xbb\x9f\xb2\xb5\xdc\xd5\x31\xfb\xf2\x38\x56\x08\x96\xc7\x9a\x3e\xbd\x3a\x0a\xcd\xec\x50\xcc\x1d\x9f\x79\x1a\x75\xb4\x91\xec\xc5\x5f\x59\x6f\xe6\x9b\x86\x46\xd8\xbd\xa1\xff\xec\xb7\xaa\xcf\x7d\xde\x97\xbf\xaa\xdd\xfe\x48\xef\xa2\xfe\x58\xed\xf6\x64\x45\x45\x42\x19\xd3\xfc\x34\xf2\xdc\x22\xea\xb3\xd2\x92\x87\xe5\x1f\x79\x96\x9f\x6d\xd1\xaa\x5d\x4d\xeb\x78\x7e\x25\xe7\x45\x8a\xfa\x2f\x52\x4c\xb3\xb3\x7a\xac\xad\xa3\xd7\x4a\x27\x20\x94\xd6\x3a\x11\xc2\x1a\x52\x8d\x4d\x4a\x1d\xac\xe1\xd1\x5e\x8b\xac\xf4\xc6\xfb\xb2\xa4\xce\x68\x53\x57\x91\x28\xa9\xb0\xcb\x7b\xd1\x06\xec\x57\x1f\xf7\x16\x20\xa0\x1f\x5c\x29\xf6\x4d\x43\x44\xe2\x54\xf2\x04\x5d\xf2\x46\xed\xe2\xe9\x8d\x57\xec\xaa\x48\xf2\xd7\x47\xbb\x8d\x56\xe9\x34\x26\xcd\xf5\xef\x40\x2c\x21\x73\x8a\x1f\x77\x75\x85\x5f\x43\xdd\xa0\xd7\xcf\xdd\xde\x6c\xf5\x3b\xb3\x29\xad\xb9\x80\xac\x55\x4a\x64\x19\x6c\xb1\xcc\xd3\xa8\x5d\xf8\xfd\x6e\x4b\x19\x93\x13\x4b\x22\x5e\xfb\xb2\xda\x54\x25\x42\x53\x34\xf6\xa8\x9c\x1a\xfa\xae\xf6\x79\x39\x9f\xa9\xcd\xd1\x0d\xc7\x67\xb0\xea\x33\xaf\xc3\x36\x53\x3c\x4f\x3b\xc5\xb0\xcd\xec\xae\x7b\x6a\x73\x64\x6e\xb1\x4c\x21\x4e\x99\x62\x75\x8c\x7c\x70\x8e\x3b\x90\x3d\x68\xa0\xb9\x49\xd1\x99\x15\xa0\x70\xa5\x0b\xbe\x5d\x3c\xd5\x47\xd3\x68\x31\x77\x83\x58\xe8\x7d\xa4\x80\xed\xbd\x56\xc0\x0a\x36\xdf\x93\x09\x39\x0d\x5b\x2c\xbd\xdc\x73\x62\x3d\x07\x40\x69\x25\x0c\xd0\xd4\x52\xb6\x5e\x07\xd0\x9c\x00\x11\x86\x14\xb7\xac\x50\x46\x60\x4a\xce\x1c\x4a\x4c\x2c\x83\x7f\xa3\x97\x62\xc5\x32\xba\x64\xe5\x37\x60\x7e\xe8\x79\x34\xd0\xc9\x95\x0d\x69\x90\x9d\x69\x19\x0c\x50\xe9\x50\x4d\x5c\xe9\x53\x0e\x50\x6a\x8d\x89\xe5\xde\x8b\x4d\xb0\x86\x32\xd7\x3a\xec\xba\x9c\x36\x55\x6b\xbb\x94\x25\x10\xa8\xb4\xa0\x2c\x20\x8c\xc5\xd1\xfe\xca\x97\x5a\xa5\xa3\x30\xd8\xf2\x19\xe4\x78\x9b\x3c\x12\xbd\x84\x36\xea\x23\xff\x37\x1b\xee\x93\xce\x02\x7a\xac\x5f\x27\x71\x82\x2e\xb6\x14\x06\x55\xf7\x00\xcb\x54\x7e\xfe\xf8\xdc\x96\x88\x61\xc9\x60\xe8\x33\x5b\xb6\xf9\xec\xd3\x73\x4b\x17\x4b\xcb\x90\xe7\x3c\xbb\xb4\x43\x8d\x5e\xe8\xfe\x6d\xbe\x39\x68\x13\x6f\xb0\x9e\x4f\xaf\x74\x53\xf9\x58\x0e\xd8\x7a\x9e\x8a\x65\x88\x84\x69\xf4\x89\x91\xde\x4d\x21\xd5\x6d\x82\xe2\xed\x9e\x4a\x69\xd3\xd1\xb8\x33\x58\xae\x7d\x68\xeb\x64\x0c\x3b\x28\x83\x5c\xa5\xdb\x6e\x3a\x1a\x33\x03\x16\xe1\xfe\x0a\x36\x36\xa4\xd8\x30\xf5\x26\x61\xe9\x32\xeb\x8e\x49\x0c\xf5\x57\xc2\x56\x96\xb0\x5f\x28\x4f\x40\x00\x11\x64\xd6\xd0\x4e\x13\x34\x64\xe4\xe8\x22\xe1\xb0\xad\xe5\x6b\x15\xaa\xb7\x67\x0f\x52\x34\x18\xf4\xc4\xd4\xd2\xb5\x82\x6f\x0f\x8b\xe7\xb2\x55\x5a\x7a\x1d\xc7\x62\x9e\x35\x07\x7f\x63\x58\x63\xbb\xee\xfb\x3f\x82\x6e\x1c\x45\x28\x7e\xdb\x56\xcb\xf7\xdf\xfe\xfc\xed\x7f\x03\x00\x00\xff\xff\xfc\x05\xd8\x15\x74\x48\x00\x00")
+var _envDevelopmentJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5b\x7b\x6f\xa3\x4a\x96\xff\xff\x7e\x8a\x28\x3b\x52\xba\xb5\x9d\x04\x70\x9c\x0e\x23\xcd\x1f\x18\xdb\x18\x1b\x13\x03\xe6\x39\xd3\xba\x82\xa2\x82\xb1\x8b\xc7\x42\x01\xc1\xa3\xfb\xdd\x57\xe0\x47\xfc\xb6\xd3\xe9\x2b\xed\xce\x0d\xad\x74\x62\x38\xe7\x54\xd5\xa9\xf3\xac\x1f\xfe\xf7\x6f\x57\x57\x57\x57\xd7\x7f\x4b\xc1\x04\x06\xf6\xf5\xdf\xaf\xae\x27\x18\xc7\xe9\xdf\xef\xef\x17\x77\xee\x02\x3b\xb4\x3d\x18\xc0\x10\xdf\xd9\xf3\x2c\x81\x77\x20\x0a\x96\xcf\xd2\x7b\x8a\x20\x9b\xb7\x04\x79\x4b\x90\xf7\x2e\x8c\x51\x54\x56\x74\x63\x18\xc4\xc8\xc6\xf0\x6e\x9a\x46\xe1\x7f\x5d\x7f\x5b\x8c\x00\xa2\x10\xc3\x10\x6b\x30\x49\xfd\x28\xac\x06\x22\xef\x88\xea\xdf\x8a\x20\xb6\x13\x3b\x80\x18\x26\xe9\xf5\xdf\xaf\x16\xd3\x5a\x30\xfa\xcc\x3c\x1e\x47\x33\x18\x6e\xdd\xaf\x9f\xe1\x32\x86\x95\xa8\x14\x27\x7e\xe8\x5d\xaf\x1f\xfe\xf1\x6d\x93\x9f\xb5\x63\x1b\xf8\xb8\x3c\xce\xef\x87\xf8\x18\x73\xbb\x5e\xd7\x38\x8a\x50\x35\xc2\x51\x09\x4e\x14\xa1\xeb\x6f\xdb\xcf\x5c\xf8\x62\x67\x08\x6b\x36\xca\x2a\x9a\x17\x1b\xa5\xf0\xc8\x28\xa3\x28\x42\xa2\x1d\xc0\x9f\x5b\x62\x9c\x44\xaf\x25\x0b\x13\xfc\x11\x76\xe4\xc3\x10\x7f\x50\x48\x3b\x0a\x6c\x3f\xac\x16\x22\xd8\x0e\x44\x1f\x90\xc4\x07\xb6\xf7\x11\x6d\xd4\xfc\x4c\x86\x27\x27\x64\x40\x90\x25\xf0\xac\xa4\x01\x3c\x61\x38\x17\xc8\xc8\x1c\xe4\x03\x7e\xc4\xb8\x6e\x02\xd3\x94\x41\x28\x02\x36\xf6\xa3\x70\x08\xf1\x24\x72\xcf\x2e\xf1\xb4\x4d\x5d\x2b\xd8\xc6\x3e\xb8\x68\x68\x65\x96\x5d\x64\x62\xe7\x47\x0c\x5d\x3b\x71\x0f\x8f\x99\xa6\x93\x51\x3d\xec\x69\xb5\x9d\x50\x58\x1e\x87\x2c\x53\xd9\xa1\xff\xe2\x03\x1b\xbf\xc7\x08\x7e\xdb\x90\x75\x9d\xc0\x34\xca\x12\x00\xab\x70\xf2\xcf\x35\xcd\x8e\xa8\x74\x96\xed\xc9\xaf\x1f\x84\x0b\x4d\x5d\xff\xf3\x2d\x2c\x7d\xb9\x39\xac\xd0\x9b\xaf\x3f\xae\xb7\x04\xfc\xb1\xa3\xc1\x38\x89\xe2\x6a\x3d\x30\x3d\x3c\xd6\x5a\xec\xbe\x6d\x9c\x1c\x7f\x97\xfe\xec\x44\x56\x8b\x72\x61\x7e\x9b\xc7\xe1\x6d\xec\xc7\xbb\xbb\xbd\xd2\xed\xd0\x07\x49\x94\x46\x2f\xf8\x4e\x84\xb8\x88\x92\xd9\xfd\xce\xe0\x30\xdd\x65\x5d\x4d\xa6\x9e\xf6\x4a\xfb\x5c\x12\x65\xf1\x97\xaf\x77\xab\x87\x3f\x76\xb9\xec\xd8\xdf\xc8\x09\x14\x41\xd2\xb7\xc4\xf7\x5b\x82\x3c\x68\x1c\xff\x7e\x9f\x62\xed\xe5\x3e\xc5\x36\xd8\x37\xa3\x5d\xaa\x51\x02\x5f\xfc\xd7\x1d\x73\xd9\x23\x26\x89\x45\xd6\xba\xa7\xaf\x0f\x12\xfd\xd8\xbb\xbb\xb3\x09\xb5\x94\x34\x73\x42\x88\x8f\x0f\x75\x78\xa6\x57\x17\xac\xf9\xf8\xca\xea\x94\xbb\x9a\x3d\xf5\x70\x78\xfa\x47\x26\xbc\x96\xb8\xb2\x20\xce\xc6\xb0\xb0\x4b\xa5\x5e\xc7\x61\x51\x47\xc4\xfc\xa9\x4b\x23\x17\x4b\x3b\xbe\x80\xc5\x22\x16\x16\xad\x54\xb1\xdb\xc7\x65\x6d\xa2\x67\x47\xac\x39\x7d\x77\xcb\xb8\x79\xf7\xcb\xcd\xbe\xa3\x1c\x12\x9f\xde\x7c\xbb\xba\x49\xe2\xdb\x30\xf5\x2a\x2f\x3d\x3d\xc1\x7a\x28\x6c\x7b\x95\x1a\xc2\x0c\xa1\x93\xc4\x7f\x7c\x68\x1f\x97\x75\xcd\xc9\x7d\xdc\xbb\xfb\xe3\xf2\x20\x53\x49\xbd\x38\xc2\xe4\x7e\x82\x33\x1b\x2d\x3f\xfe\x3f\x88\x2f\x7e\xcc\x46\xe1\x8b\xef\x65\x49\x3d\xf6\x9f\xee\xcf\x8b\xb0\xf1\x0b\x4d\x75\x47\xe3\xf7\xcb\xb8\x54\x19\xeb\x6a\xfb\xaa\xbf\xb7\xbc\x7d\x2f\xcb\xec\x5e\x27\xec\xee\xea\x40\x59\xf2\x0b\x97\xb3\x97\xa2\xd6\x0b\x59\x24\xbb\xf3\x53\xff\x90\x33\x2d\x2b\xa5\x8b\xdd\xe8\x40\x62\xc8\xe3\x70\xbc\xf4\x0f\x39\xca\x30\x6c\xd9\x29\x74\x0f\x84\x8b\xa3\x85\xcb\xd6\x84\xb4\x38\xe4\x0a\xf2\x48\xb4\xb9\xc6\x3e\x4c\x36\xa8\x2e\x4a\x5c\x55\x71\xb6\x68\x14\x36\x0d\xff\xf8\x4c\xd6\xf4\xcb\x2d\xa9\xfa\x9c\x93\x1b\xfe\xae\x6c\x5c\x33\x90\x34\x75\x47\x3e\x3e\xdd\x51\xcd\xe6\x99\xc4\xb6\x9f\x9b\x8f\x2c\x73\x7b\xea\x72\x14\xe1\x8d\x7a\xf4\xf4\x94\xce\x78\xf0\x3b\xbc\xfd\xea\xcd\x57\xaa\xd1\xdb\x36\xb6\xf7\x0a\xc2\xdd\x5a\xf9\xc3\xbe\xb9\x5b\x21\x02\xfb\x44\x9d\x70\xb8\x00\x3a\xa7\xce\x51\x12\xe1\x08\x44\xe8\x4c\xa1\xf5\x1c\xc3\x50\x1b\x89\x17\x57\x59\xef\x29\x7c\x7f\x36\x25\x2d\xe3\xe0\x9f\x9d\x99\xf6\x1a\xb0\x18\x86\x6e\xfa\x1c\x1e\x54\xd8\xaf\x88\x89\x07\x1c\xfd\x7d\x89\x63\x2b\x61\xec\xda\xe0\x8f\x0b\x32\xed\xd9\x3e\x6c\xd5\x75\xfe\xde\xa6\xd2\xdf\xf3\xc6\xa1\x29\xaf\xe2\xd9\xba\x41\x3d\x40\x03\xde\x8e\x82\xae\xff\xe9\x87\xf8\xcb\xa6\x37\xbd\x9d\x14\xdd\x7c\xfd\x68\x4f\x97\xc5\x5e\x62\xbb\x70\x14\x21\x1f\xec\x37\xc2\x6b\xb2\x20\x72\x17\x96\x67\x87\x99\x8d\x2e\x8c\xc1\x0b\xdd\x0f\x6d\x30\xf1\x43\x38\x4a\xa2\x17\x1f\x9d\x68\x6f\xa2\xf4\x1c\xc9\x42\x33\x51\x10\x67\x18\x26\x55\x47\xfb\x56\x55\x03\xff\xf6\x44\xb1\x7a\x6d\xbb\x81\x1f\xaa\x29\x4c\x56\xdb\x04\x50\x94\xb9\xb7\x59\x0a\x93\x53\x6c\xc8\x0f\xb3\xd7\xcb\x32\xc8\x9a\xc7\xf5\x53\xdb\x41\x70\x64\xa7\x69\x11\x25\x2e\x93\xe1\x09\x0c\xb1\xbf\x76\x3c\x9c\x64\xf0\x4c\x70\x4b\xd3\xfd\xd3\xa0\x83\x84\xf1\xea\x04\xe3\x7c\xfa\x59\x5d\xe7\xa5\xbe\x49\xb7\xeb\x53\xa9\xeb\xfb\x49\x14\xc0\xfb\x37\x8d\xdd\xdf\xa5\xe9\xe4\xde\xce\xf0\x24\x4a\xfc\x39\x74\x7f\x9f\xc1\xbd\x50\x73\x52\xf0\x0c\x96\x07\xb3\xc4\xe6\x99\xcc\xd9\x0c\xb1\xba\x8e\x97\x42\xab\xeb\x70\x3a\x3d\xcf\x7f\xf8\xc9\xb1\x34\x9c\xe2\x28\xb1\xbd\xb3\x66\x5e\xd3\xfa\x81\xed\x41\x19\xbe\xc0\x04\x86\x27\x3a\xfe\x35\x7d\xbd\xcf\xe9\x64\x11\x36\x64\xe8\xf6\xec\xdd\x6e\x65\x8f\x25\x7a\x79\x59\x92\xf7\x3a\xc2\x39\xe2\x45\x54\xbb\xfe\x7e\x2b\x68\xc3\x73\xb4\xf9\x5b\x2a\xf8\x7e\x47\xdf\x51\x04\x45\x90\x04\x41\x92\x8f\x3f\xd7\xa8\x47\x69\xdb\x4f\x67\xe7\x55\x00\x12\x68\x63\xf8\x1c\xaf\xd2\x57\x37\x89\x82\xc5\xd9\xeb\x99\xf9\x2e\x70\x01\xf7\xa2\x51\xae\x36\x36\x92\x01\x20\xca\x42\xbc\xaa\x72\x47\x09\x0c\xfc\x2c\xf8\x5d\x90\x95\x9f\x2e\xcd\xdf\x65\x4f\xcb\xee\xfc\x22\x7b\x5a\xd2\xf2\x21\x86\xc9\x8b\x0d\xe0\x85\xdd\xde\xea\xba\x40\x29\xeb\xb8\xe9\xdf\xe6\x41\x9a\xde\x86\x3e\xb8\xe4\x70\xe0\x9d\x65\xe4\x92\xc7\x0f\xec\xa4\xbc\x28\x54\xae\x99\x2e\xee\x70\x0f\x5d\x97\xc7\xc4\xab\x43\xba\xf0\x63\x50\x8f\xfd\x8e\x10\x78\xf5\x93\xca\xd9\xe2\x7f\x47\x97\x7d\x90\xff\x57\x76\xde\x5b\xe7\x33\x17\xc7\xee\xcd\xeb\x4c\xc5\x7f\x70\x05\x3f\x63\x2a\xdb\x02\xb6\x8b\xce\xf7\xa5\xfa\xa3\x52\x77\x0d\x64\xff\xf8\xfa\xf2\x09\x7e\xcc\x46\xd6\x72\xdc\x30\x55\x20\xc6\x7e\xe8\x7d\x4c\xd0\x42\xd8\x1e\x7a\x76\x6d\x27\xd1\x2d\xf0\xdf\xbf\xeb\xab\xeb\x7c\x16\xff\x35\x5c\xef\xe3\xb8\x9c\xfa\x32\xca\xd3\x95\xc8\x79\x39\xc7\x9f\xbe\xef\xc8\x00\xbe\x62\x18\x56\x59\xfc\xa2\xec\xb2\xa6\xfe\x53\x32\x09\x48\xcf\xa5\xf0\xab\x9f\xce\x24\x9b\x65\xd3\x5b\x68\x63\xea\xd7\x03\x3a\x6f\xab\xba\x30\xc7\xac\xba\x6f\x36\x4b\x71\x14\x28\x20\xf1\xe3\x73\x65\xd8\x16\x6f\xcf\x0e\x5d\x04\x93\xcd\x5e\x7a\xfd\x56\xc1\x59\x01\x76\x86\x23\x75\xd1\xab\x0d\xfd\x30\xda\x90\xf2\x8e\x2c\x99\x6e\x84\x80\x0b\xe3\x6d\xa5\x78\x0c\x01\x86\xee\x4f\xc5\x8f\xeb\x74\xa1\xa6\x2a\xd1\x38\x76\x0a\x1f\x1f\xbe\x80\x28\x04\x36\xfe\xb2\xf8\x34\x8e\x94\x1a\x1c\xfd\x72\x03\x28\x8d\xe0\x59\x12\xb1\x5e\xf4\x8f\x9b\xaf\xdf\x6e\x58\x9e\xb1\x46\xe3\xe7\x41\x47\xfc\xc7\xcd\xcd\xcd\xb7\xed\xfe\x77\xf5\xa6\x45\x45\x78\x73\xf3\xaf\xf0\xa6\xa2\x1f\x3d\x3f\x0b\x22\x33\xec\x1c\xa0\x5f\xbd\xb6\xb0\x41\x5f\xfd\xb7\x3b\x07\x36\x44\xa4\xa3\x30\x18\x2a\x2d\x12\x70\xf2\xc4\xe5\x54\x4f\x30\x3c\x4f\x23\xba\x43\x5b\x6f\x92\xb0\xd3\x0d\x2d\xbd\x49\xb0\x5e\x9c\xba\x81\xf6\xe0\x72\x5a\x66\xb1\x0c\x76\x58\x26\x11\xc7\x0c\x92\x51\xbf\x2b\x2b\x4c\x6e\x71\x1a\x25\x34\xfa\xb9\xd3\x90\x29\xab\xa4\x29\xd3\xe8\xa7\xae\x17\x3f\x58\xa1\xf8\x62\x35\xfa\xb9\x4b\x59\x73\x9e\xad\xee\xf3\x03\x36\x78\xa5\x2c\x63\x42\x58\x7a\x73\xc6\xb3\x64\xca\xb3\xe9\xeb\xb0\x7d\x54\x56\xe4\x50\x24\x72\x7a\xe6\x00\x72\xd6\xdc\xa0\xdc\xd2\x69\xb8\x01\x28\x99\xdc\xe6\x68\x6c\x49\xd1\x00\x84\x2d\xcc\xb3\x04\xb6\x75\xb2\x70\x1a\x7d\x82\xe7\x26\x84\xdb\x6b\xcd\x9f\xfd\xa7\xdc\xe2\x8a\xcc\x0a\xb4\x99\xd3\xe8\x4f\x40\xaf\x9f\xdb\x81\x36\x75\xd9\x66\x0e\x02\x90\x83\x9e\xe6\x0b\x94\x56\x58\x7a\x91\xab\xa8\x25\x0a\xaa\x2b\xc9\x25\x29\xc8\xda\x0c\xcb\x5a\xab\x3b\x66\x89\x06\x1b\xf6\x8b\x4a\x3f\x82\x8e\x30\xe0\xe8\xd2\x65\x5b\x91\xdb\x93\x0b\x30\x8f\x72\xa1\xd1\x9a\x98\x14\x9e\x58\x94\x36\x17\x02\x32\x36\x1b\xfd\x1c\x50\x74\xe0\xb2\xcd\xa9\x43\x11\xb9\x4d\x69\x4d\x50\xd2\xd8\xd6\xc5\xd2\x69\x88\xb9\x15\x4a\x99\x69\x88\x53\xd6\x8b\x9b\xae\x4e\x78\x82\x31\xf3\x6c\xbd\x39\x77\xb9\x6e\xea\x6c\xca\xa5\xe4\x54\x08\x2c\x64\x71\x74\x69\x1a\xad\xd2\xa1\x62\x64\x36\xa4\xcc\x69\xf4\x43\xa1\xd1\x22\x4d\x9f\x46\x80\xd3\xd2\xe5\xdc\x31\x08\xb4\xd4\xd2\xbb\x73\x4b\x21\x53\xd3\x90\x11\x68\x48\x58\x2c\x9b\x99\x43\x75\x4b\x93\xf2\xb2\x4a\x3f\xac\x17\x4f\x4d\x43\xf2\x46\x3e\x8d\x5c\x6e\x98\x43\x43\xc3\x42\xd8\x47\x80\xa3\xe7\x42\x20\xe5\xa6\x11\x93\x20\x50\x33\x10\x68\x85\x53\x32\x4f\x23\xd6\xed\x8e\x09\x33\x64\x51\xd5\xcc\x6b\xa5\xa5\x90\x53\x87\x43\x2e\x1b\x34\x27\x8e\xae\xd2\x4b\x7a\x6c\x52\xaf\x31\x1b\xf4\x27\x80\xd2\x48\x10\x14\xb4\xdd\x93\x09\xd0\x1b\x3e\x0a\x25\x5d\x98\xba\x98\x98\xba\x8b\x40\xd9\xdc\xd6\x01\x45\x63\xa1\x81\x48\xc7\x58\x8e\x4f\x75\x1f\x5d\xa3\x8f\x04\x5d\x4c\x6d\x29\x46\x4e\xd0\xf5\x1d\x4e\x9b\x8d\x0c\x84\x40\x11\x87\x80\x73\xa7\x36\xa7\x4d\xed\x39\xd9\xb4\x8c\xe1\x40\x56\x69\x6e\xad\x43\x85\x5c\xd1\x97\x96\xd1\xca\x47\x46\x3f\x72\xf5\x19\x06\xc1\x04\x39\x2c\xd1\x10\x0c\x11\x81\xd0\x42\xc0\x27\x4b\xbb\xa7\xc5\x82\x4e\x17\x2e\x87\x72\x27\xe8\xa6\x82\xd1\x2f\x1c\x63\xb8\xbb\x0f\x1b\xeb\x9d\x79\x16\x47\x4f\x6d\x4a\x2b\x79\x2e\x7e\xe5\xb9\xd7\xd8\x0c\xba\x73\xd0\xd0\x26\x8e\x4f\xce\x2c\xc3\x42\x0e\xdb\x0a\x4d\x6a\xe8\x59\x8d\x56\xe8\xe8\x2a\xae\x6c\xd7\xd2\x0b\x0f\x04\x1e\xb6\x28\x44\x0c\xa7\xb3\xfa\x6f\xd0\x43\x84\xcd\xd1\xd9\x70\x6e\x0e\xd8\x99\x3b\x32\x48\xab\xab\x22\xb1\x3f\x26\x1e\xe8\xa1\xf2\xf0\x2a\xb2\x0f\x4d\x36\x10\x2b\x1d\x7a\x1b\x3a\x9c\x39\x6c\x33\x74\x28\x3a\x74\x38\x75\xa1\x37\xca\xcd\xab\x9f\x7e\x0f\xf7\xc6\x24\xad\xcb\x5a\x7f\xac\xa8\xf4\xf3\x8b\xd2\x4c\x6b\x7f\x65\xc9\x89\xa3\x4b\x94\xc8\x36\x09\xd3\xe0\x33\xab\x11\x79\x2f\x6c\xab\xfa\xdb\x13\xd4\xa1\x27\x34\xb4\x39\xf0\xe9\xd4\xa1\xc4\x89\xc3\x32\x18\xf6\xa2\x81\xc3\x3d\x78\x82\xb1\xfb\x8c\x0e\x9d\x92\xf6\x6d\xfd\x21\x1f\xf8\x4c\xee\x1a\x62\x29\x50\xaf\xb9\x49\x75\x53\x81\xea\xc7\x8e\x17\x0d\x34\x24\xaa\x2a\x49\xb7\x64\x42\x7b\xd6\xba\x6f\x73\x19\x8d\xf9\x6c\x38\x06\xa4\x30\xe5\x07\x8e\x8e\x67\x76\x35\x36\x35\xc9\x1d\x5d\xcd\x4d\xea\x35\x77\x75\x09\xbb\xd5\xbe\xf8\x74\xe5\x3b\x99\xcb\xc4\x85\x6b\x88\x91\xc5\x2e\x7d\x5a\xa1\xa7\x0e\x47\x93\x16\x4b\x92\x80\xd2\x4a\x81\x5a\xc6\xa0\x7d\xfd\x50\xa0\x21\xcf\x2b\x1b\x73\x42\x79\x6d\x6f\x42\xb0\xb0\x27\x4b\x97\x43\x4b\x69\x66\x96\x21\xe5\x0b\x1a\xa9\xd2\x9b\xae\x92\xf2\xd8\x20\xba\x3d\x59\x6d\xaa\x6f\xfb\xd0\xa4\x85\x86\x35\x77\x7b\x43\xbc\xa4\xc5\x0e\x87\x32\xd7\xf0\x30\x6c\x9b\x84\xa0\xc8\xdf\x8f\xad\xf7\x45\x39\xa0\x6b\x63\xf2\xc8\x06\x62\xe4\x34\xdc\x8c\x67\x49\x85\xe7\xc4\xd4\x69\x68\x33\xc1\xd0\xe6\x96\xc1\x3f\x6e\xeb\x81\xc9\x58\x2f\xca\x6a\xbd\xfa\x74\xec\x84\x22\x61\xea\xaf\xa9\xc5\x55\xfe\xdd\x9c\x59\x7a\x73\x6a\xeb\xda\x5c\x08\xc5\x88\x0d\x45\xd2\xe2\x9e\x3c\xc1\x50\xbd\x5d\x19\x02\x25\xe6\x4e\x60\xc5\x56\xd9\x9c\xdb\x2c\x83\x05\x43\xcb\x4c\x43\x26\x16\x32\xa4\xca\x57\xf6\xec\xcb\x32\xcc\x6c\xe5\xfb\x0b\xfb\x22\xe7\xcb\xcf\x15\xfd\xc4\x35\xe4\x88\xef\xb5\x26\x6e\x2d\x4f\xae\x62\x5a\xc6\xb3\xfc\x4c\x22\x50\x4b\x47\x2d\x75\x4c\xe0\xee\xd8\xe7\x2b\xda\xc2\xa1\xe8\x74\xf9\x4c\x1a\x13\xf4\x70\x3c\xeb\x8a\xb2\x52\x3f\x5b\xec\x33\xcb\xf8\x92\xd6\x1f\x09\x5a\x9f\x97\xd5\x02\xf7\x3b\x93\x91\x4a\xca\xcf\x92\x4a\x76\x79\xbf\x92\x5f\xc5\x83\xd7\x89\x49\xa9\x03\xc1\xa7\xe7\x6e\x30\xcc\x00\xe5\x6d\xfa\xe6\x96\x5d\xb0\x61\x2b\x07\x9c\x34\x60\xfd\xa1\xe7\xe8\x5a\x69\x51\xaa\x67\xeb\x0f\x9e\x40\xd1\x85\xcb\xd2\xa5\x5d\xff\x10\xff\x23\x50\x5a\x66\xea\xfd\xd4\x92\xd6\x31\xb0\xce\x29\x02\xb5\xb5\x27\x6b\x1b\x11\xc2\xd6\xc4\xe5\x3c\x6f\xd4\x2e\xc2\x2a\xd6\xf4\x8b\x28\x77\x1a\x2d\x42\x68\xf4\xa3\xfa\xc7\x68\x35\x5d\x6e\x92\x3b\xd3\xe1\x32\x4f\x49\x4b\xff\xe8\xc7\xce\x74\x87\x56\x77\x63\xb7\xcd\x37\x0f\xd1\xed\xf9\xd4\xfa\xde\x81\xe7\x0d\xb1\xf2\xc5\xc7\xa5\x8f\xce\xcd\x00\x65\xcf\x47\xd6\x21\x04\xdb\x32\x0f\xfb\x54\xe5\xc3\x71\x15\xe3\x07\x6c\x20\x56\xfb\xfb\xdf\x27\x7d\x94\x7d\xca\x2c\xbd\x49\xf1\xed\xe2\xa9\x4f\x68\x23\xd9\x07\x83\x71\x47\x7e\x19\x77\x10\xab\xce\xba\x8a\xae\xd1\x92\xa4\xc9\xfc\x48\xa1\x73\xd0\x93\x72\x10\x78\xf9\x4e\xdc\xcb\x41\x40\xe7\x2e\x4b\x93\xa0\xc1\xe7\x0e\x87\x7c\x71\x2a\x3d\x6e\xec\x55\x9d\xff\xac\x36\x4f\x6c\xeb\xea\x35\x36\xa7\x26\xc1\xce\xc8\xd6\x18\xb5\x5a\x5a\xc7\xa3\xb7\xf7\x97\x2c\xa0\x21\x47\x0e\xf5\x30\x17\x7d\xba\x74\x28\x9a\x58\xe9\xc8\xe6\xba\xa5\xa5\xd0\xd8\xac\xf4\xb6\xcd\x13\xda\x86\x54\x3e\x2b\x47\xe9\x07\x6a\x47\x53\xc6\x6d\x6d\xa8\xa8\xfc\xee\x78\xa7\x78\x0b\xcb\xe8\xa7\xa2\x42\x53\x95\xcf\x39\x8d\xfe\x0b\xe0\xb4\xd2\x61\x62\x49\x21\xdc\x17\x89\xa0\x9f\xe5\x19\xea\x19\xe4\xbb\xd6\x91\xda\x3a\x4f\x89\x2c\x5d\xd8\x94\x3b\x75\xa8\x66\x60\xeb\x60\xa0\x77\xe4\x9e\x41\xc8\x2d\xad\xd3\x7d\x91\x3b\x48\x51\xe7\xc4\x65\x36\xda\x10\x23\xd3\xe8\xa3\x67\x7f\xb5\x0f\xf4\xd4\xd4\x8b\x1c\x50\x93\x09\x08\xd4\xc7\xad\xf5\x48\x4b\xfb\x08\x45\x54\xd5\x7c\xb6\xc2\x60\x4b\x61\x42\x50\xd2\x70\x4c\xb6\xd4\x2a\xf6\xa9\x73\x22\x34\x58\x10\x0a\x04\x2d\x69\x1d\x34\x1a\xa3\x21\xdd\x27\x8b\xb0\x5f\x92\xbd\x9d\x98\xe7\x09\x25\xf0\x04\x4a\x23\xcc\x92\x9e\x43\x43\x5c\xad\x25\x5f\xe5\x58\xd6\x8b\xab\xfb\x84\xa5\x93\x53\x97\x2b\x3c\x4b\x6f\x4e\xcc\xe0\x15\xf1\x9c\x9c\x9b\x14\x46\xc0\x8b\x06\x83\x9e\x98\x5a\xba\x56\xf0\xed\x61\xf1\x5c\xb6\x4a\x4b\xaf\xd7\x16\xf3\xac\x39\xb8\xf9\xba\x87\x0d\x1d\xbb\xce\x37\xaf\xbf\xb8\x2d\xbd\x08\x3e\x8a\x72\x98\xc4\x49\x94\xfb\xcb\x3e\x67\xfb\xb5\xe4\x03\x5c\xbb\xad\xe5\x79\xf4\x94\x5d\x60\x49\xf7\xdb\x48\x95\x02\x6c\x04\x15\x88\x7f\x11\x7c\x0a\xa2\xd0\xf5\xd7\x6c\xdb\x7d\xc9\xd6\x4b\xdb\xfb\x08\xe7\x41\xe8\xb5\xf1\xcb\xa1\xd7\xff\x00\x90\x94\xfc\x04\x41\x17\x6f\x0d\xd4\xaf\x82\x7f\x62\xa1\x9f\x58\xe8\xe1\xeb\x13\x0b\xfd\xc4\x42\x3f\xb1\xd0\x13\xd7\x3b\x4e\xb0\xdf\xc2\xed\x27\x24\x7a\x58\x25\x7f\x55\x64\x34\x89\xd7\xc0\x68\x12\xdf\xa6\x9f\xa0\xe8\x71\x13\xf9\x0b\x60\xa3\xdb\x5f\x8d\x3a\xf0\xf5\xc3\x9f\x32\x8d\xd5\xf5\x89\x9c\x5e\x22\xe7\x3f\x09\x39\xdd\xf1\xa0\x4f\x00\xf5\x22\x01\x7f\x19\x00\x15\x32\xd1\xe0\xe6\xeb\xb7\x9b\x91\xfc\x6c\x98\xfc\x90\xe1\x3a\xff\xf8\xdb\x92\xf8\xea\xd6\xbd\xfa\x57\x46\x10\x0d\xb0\xf9\xff\xcd\xcd\x0a\x09\xfd\xb2\x17\xa9\xea\xb2\xf2\xe6\x6b\x0d\x9b\x7e\xad\x71\xd3\x37\xb1\x8c\x3a\xee\x7d\x54\x74\xd5\x12\xee\x8b\x67\x3b\xf2\x78\x0f\xc5\x5d\x7f\x79\x7c\x03\xc4\x5d\x50\x0b\x7c\x47\x1c\x9f\xe0\x59\x7f\x63\x7c\x97\x73\xd0\x31\x0f\xb3\xd4\x4d\xd7\x49\xa8\x18\x1a\x1a\xe6\x59\xb2\xc9\xf7\xb4\xc2\xe2\xba\x84\xa5\x30\x18\xb2\x2d\x43\x52\x5f\x63\x27\xd4\x1e\xa4\xc5\xf1\xf9\x60\x4d\xc7\xa1\x0c\x34\xe4\x89\xc3\x15\xde\xc6\x11\x5f\x60\x1b\x7d\xe4\x52\xdd\xd4\x61\xc9\xa9\xb3\x80\x25\x26\x16\x27\x2d\xe0\xd5\x36\x41\x88\xed\x61\xee\x72\x62\xc1\xb3\x04\xae\x8f\x4f\xf5\x6e\xb6\x84\xa0\xb1\x4d\xc9\x31\xf0\x99\xe5\x51\xf2\x53\xb6\x96\xbb\x3a\xc2\x5e\x1e\x75\x0a\xc1\xf2\xc8\xd0\xa7\x57\xc7\x8c\x99\x1d\x8a\xb9\xe3\x33\x4f\xa3\x8e\x36\x92\xbd\xf8\x3b\xeb\xcd\x7c\xd3\xd0\x08\xbb\x37\xf4\x9f\xfd\x56\xf5\xb9\xcf\xfb\xf2\x77\xb5\xdb\x1f\xe9\x5d\xd4\x1f\xab\xdd\x9e\xac\xa8\x48\x28\x63\x9a\x9f\x46\x1e\x2c\xa2\x3e\x2b\x2d\x79\x58\xfe\x91\x67\xf9\xd9\x16\xad\xda\xd5\xb4\x8e\xe7\x57\x72\x5e\xa4\xa8\xff\x22\xc5\x34\x3b\xab\xc7\xda\x3a\xd6\xac\x74\x02\x42\x69\xad\x13\x21\xac\x21\xca\xd8\xa4\xd4\xc1\x1a\x6e\xec\xb5\xc8\x4a\x6f\xbc\x2f\x4b\xea\x8c\x36\x75\x15\x89\x92\xea\x76\x79\x2f\xda\x80\xd4\xea\xa3\xd4\x02\x04\xf4\x03\x94\x62\xdf\x34\x44\x24\x4e\x25\x4f\xd0\x25\x6f\xd4\x2e\x9e\xde\x78\xc5\xae\x8a\x24\x9f\x6f\x3f\xe4\x96\x21\x4f\x85\x46\xab\x74\x1a\x93\xe6\xfa\x77\x20\x96\x2e\x73\x8a\x1f\x77\x75\x85\x5f\x43\xc7\xa0\xd7\xcf\x61\x6f\xb6\xfa\x9d\xd9\x94\xd6\x5c\x40\xc0\x2a\x25\xb2\x0c\xb6\x58\xe6\x69\xd4\x2e\xfc\x7e\xb7\xa5\x8c\xc9\x89\x25\x11\xaf\x7d\x59\x6d\xaa\x12\xa1\x29\x1a\x7b\x54\x4e\x0d\x25\x57\xfb\xbc\x9c\xcf\xd4\xe6\xe8\x86\xe3\x33\x58\xf5\x99\xd7\x61\x9b\x29\x9e\xa7\x9d\x62\xd8\x66\x76\xd7\x3d\xb5\x39\x32\xb7\x58\xa6\x10\xa7\x4c\xc1\xb3\x27\xe6\xb8\x03\x81\x83\x06\x9a\x9b\x14\x9d\x59\x01\x0a\x57\xba\xe0\xdb\xc5\x53\x0d\x2f\xa3\xc5\xdc\x0d\x62\xa1\xf7\x91\x02\xb6\xf7\x5a\x01\x2b\x18\x7a\x4f\xa6\xcb\x69\xd8\x62\xe9\xe5\x9e\x13\xeb\x39\x00\x4a\x2b\xdd\x00\x4d\x2d\x65\x0b\x5e\xd7\x9c\x00\x11\x86\x14\xb7\xac\x50\x46\x60\x4a\xce\x1c\x4a\x4c\x2c\x83\x7f\xa3\x97\x62\xc5\x32\xba\x64\xe5\x37\x60\x7e\xe8\x79\x34\xd0\xc9\x95\x0d\x69\x2e\x3b\xd3\x32\x37\x40\xa5\x43\x35\x71\xa5\x4f\x39\x40\xa9\x35\x26\x96\x7b\x2f\x36\xc1\x1a\x26\x5c\xeb\xb0\x0b\x39\x6d\xaa\xd6\x76\x29\x4b\x20\x50\x69\x41\x59\xc0\x03\x66\x80\x32\x81\x5a\xf9\x52\xab\x74\x14\x06\x5b\x3e\x83\x1c\x6f\x93\x47\xa2\x97\xb0\x41\x0d\x17\xbf\xd9\x70\x9f\x74\x16\xb0\x5e\xfd\x7a\x86\x13\x74\xb1\xa5\x30\xa8\xba\x07\x58\xa6\xf2\xf3\xc7\xe7\xb6\x44\x0c\x4b\x06\xbb\x3e\xb3\x65\x9b\xcf\x3e\x3d\xb7\x74\xb1\xb4\x0c\x79\xce\xb3\x4b\x3b\xd4\xe8\x85\xee\xdf\xe6\x9b\x83\x36\xf1\x06\x99\xf9\xf4\x4a\x37\x95\x8f\xe5\x80\xad\xe7\xa9\x58\x86\x48\x98\x46\x9f\x18\xe9\xdd\xd4\xa5\xba\x4d\x50\xbc\xdd\x53\x29\x6d\x3a\x1a\x77\x06\xcb\xb5\x0f\x6d\x9d\x8c\xdd\x0e\xca\x5c\xae\xd2\x6d\x37\x1d\x8d\x99\x01\x8b\x70\x7f\x05\xc9\x1a\x52\x6c\x98\x7a\x93\xb0\x74\x99\x85\x63\x12\xbb\xfa\x2b\x61\x2b\x4b\x48\x2d\x94\x27\x20\x70\x91\xcb\xac\x61\x93\x26\x68\xc8\xc8\xd1\x45\xc2\x61\x5b\xcb\xd7\x14\x54\x6f\xcf\x1e\xa4\x4f\x58\xe3\xc4\x97\xc2\xde\xea\xbe\xff\x23\xe8\xc6\x51\x84\xe2\xb7\x6d\xb5\xfc\xf8\xed\x8f\xdf\xfe\x37\x00\x00\xff\xff\x3d\x77\x1c\x81\xc4\x47\x00\x00")
 
 func envDevelopmentJsonBytes() ([]byte, error) {
 	return bindataRead(
diff --git a/pkg/deploy/generator/resources.go b/pkg/deploy/generator/resources.go
index e4adf5640..ae229aa09 100644
--- a/pkg/deploy/generator/resources.go
+++ b/pkg/deploy/generator/resources.go
@@ -46,7 +46,7 @@ func (g *generator) managedIdentity() *arm.Resource {
 			Location: to.StringPtr("[resourceGroup().location]"),
 		},
 		Condition:  g.conditionStanza("fullDeploy"),
-		APIVersion: azureclient.APIVersions["Microsoft.ManagedIdentity"],
+		APIVersion: azureclient.APIVersion("Microsoft.ManagedIdentity"),
 	}
 }
 
@@ -110,7 +110,7 @@ func (g *generator) securityGroupRP() *arm.Resource {
 	return &arm.Resource{
 		Resource:   nsg,
 		Condition:  g.conditionStanza("deployNSGs"),
-		APIVersion: azureclient.APIVersions["Microsoft.Network"],
+		APIVersion: azureclient.APIVersion("Microsoft.Network"),
 	}
 }
 
@@ -123,7 +123,7 @@ func (g *generator) securityGroupPE() *arm.Resource {
 			Location:                      to.StringPtr("[resourceGroup().location]"),
 		},
 		Condition:  g.conditionStanza("deployNSGs"),
-		APIVersion: azureclient.APIVersions["Microsoft.Network"],
+		APIVersion: azureclient.APIVersion("Microsoft.Network"),
 	}
 }
 
@@ -298,7 +298,7 @@ systemctl enable proxy.service
 			Type:     to.StringPtr("Microsoft.Compute/virtualMachineScaleSets"),
 			Location: to.StringPtr("[resourceGroup().location]"),
 		},
-		APIVersion: azureclient.APIVersions["Microsoft.Compute"],
+		APIVersion: azureclient.APIVersion("Microsoft.Compute"),
 	}
 }
 
@@ -315,7 +315,7 @@ func (g *generator) devVpnPip() *arm.Resource {
 			Type:     to.StringPtr("Microsoft.Network/publicIPAddresses"),
 			Location: to.StringPtr("[resourceGroup().location]"),
 		},
-		APIVersion: azureclient.APIVersions["Microsoft.Network"],
+		APIVersion: azureclient.APIVersion("Microsoft.Network"),
 	}
 }
 
@@ -350,7 +350,7 @@ func (g *generator) devVnet() *arm.Resource {
 			Type:     to.StringPtr("Microsoft.Network/virtualNetworks"),
 			Location: to.StringPtr("[resourceGroup().location]"),
 		},
-		APIVersion: azureclient.APIVersions["Microsoft.Network"],
+		APIVersion: azureclient.APIVersion("Microsoft.Network"),
 	}
 }
 
@@ -397,7 +397,7 @@ func (g *generator) devVPN() *arm.Resource {
 			Type:     to.StringPtr("Microsoft.Network/virtualNetworkGateways"),
 			Location: to.StringPtr("[resourceGroup().location]"),
 		},
-		APIVersion: azureclient.APIVersions["Microsoft.Network"],
+		APIVersion: azureclient.APIVersion("Microsoft.Network"),
 		DependsOn: []string{
 			"[resourceId('Microsoft.Network/publicIPAddresses', 'dev-vpn-pip')]",
 			"[resourceId('Microsoft.Network/virtualNetworks', 'dev-vnet')]",
@@ -421,7 +421,7 @@ func (g *generator) halfPeering(vnetA string, vnetB string) *arm.Resource {
 			Name: to.StringPtr(fmt.Sprintf("%s/peering-%s", vnetA, vnetB)),
 		},
 		Condition:  g.conditionStanza("fullDeploy"),
-		APIVersion: azureclient.APIVersions["Microsoft.Network"],
+		APIVersion: azureclient.APIVersion("Microsoft.Network"),
 		DependsOn: []string{
 			fmt.Sprintf("[resourceId('Microsoft.Network/virtualNetworks', '%s')]", vnetA),
 			fmt.Sprintf("[resourceId('Microsoft.Network/virtualNetworks', '%s')]", vnetB),
@@ -472,7 +472,7 @@ func (g *generator) rpvnet() *arm.Resource {
 			Location: to.StringPtr("[resourceGroup().location]"),
 		},
 		Condition:  g.conditionStanza("fullDeploy"),
-		APIVersion: azureclient.APIVersions["Microsoft.Network"],
+		APIVersion: azureclient.APIVersion("Microsoft.Network"),
 	}
 }
 
@@ -503,7 +503,7 @@ func (g *generator) pevnet() *arm.Resource {
 			Location: to.StringPtr("[resourceGroup().location]"),
 		},
 		Condition:  g.conditionStanza("fullDeploy"),
-		APIVersion: azureclient.APIVersions["Microsoft.Network"],
+		APIVersion: azureclient.APIVersion("Microsoft.Network"),
 	}
 }
 
@@ -521,7 +521,7 @@ func (g *generator) pip() *arm.Resource {
 			Location: to.StringPtr("[resourceGroup().location]"),
 		},
 		Condition:  g.conditionStanza("fullDeploy"),
-		APIVersion: azureclient.APIVersions["Microsoft.Network"],
+		APIVersion: azureclient.APIVersion("Microsoft.Network"),
 	}
 }
 
@@ -584,7 +584,7 @@ func (g *generator) lb() *arm.Resource {
 			Location: to.StringPtr("[resourceGroup().location]"),
 		},
 		Condition:  g.conditionStanza("fullDeploy"),
-		APIVersion: azureclient.APIVersions["Microsoft.Network"],
+		APIVersion: azureclient.APIVersion("Microsoft.Network"),
 		DependsOn: []string{
 			"[resourceId('Microsoft.Network/publicIPAddresses', 'rp-pip')]",
 		},
@@ -603,7 +603,7 @@ func (g *generator) actionGroup(name string, shortName string) *arm.Resource {
 			Location: to.StringPtr("Global"),
 		},
 		Condition:  g.conditionStanza("fullDeploy"),
-		APIVersion: azureclient.APIVersions["Microsoft.Insights"],
+		APIVersion: azureclient.APIVersion("Microsoft.Insights"),
 	}
 }
 
@@ -646,7 +646,7 @@ func (g *generator) lbAlert(threshold float64, severity int32, name string, eval
 			Location: to.StringPtr("global"),
 		},
 		Condition:  g.conditionStanza("fullDeploy"),
-		APIVersion: azureclient.APIVersions["Microsoft.Insights"],
+		APIVersion: azureclient.APIVersion("Microsoft.Insights"),
 		DependsOn: []string{
 			"[resourceId('Microsoft.Network/loadBalancers', 'rp-lb')]",
 		},
@@ -1073,7 +1073,7 @@ done
 			Type:     to.StringPtr("Microsoft.Compute/virtualMachineScaleSets"),
 			Location: to.StringPtr("[resourceGroup().location]"),
 		},
-		APIVersion: azureclient.APIVersions["Microsoft.Compute"],
+		APIVersion: azureclient.APIVersion("Microsoft.Compute"),
 		DependsOn: []string{
 			"[resourceId('Microsoft.Authorization/roleAssignments', guid(resourceGroup().id, parameters('rpServicePrincipalId'), 'RP / Reader'))]",
 			"[resourceId('Microsoft.Network/virtualNetworks', 'rp-vnet')]",
@@ -1092,7 +1092,7 @@ func (g *generator) zone() *arm.Resource {
 			Location:       to.StringPtr("global"),
 		},
 		Condition:  g.conditionStanza("fullDeploy"),
-		APIVersion: azureclient.APIVersions["Microsoft.Network/dnsZones"],
+		APIVersion: azureclient.APIVersion("Microsoft.Network/dnsZones"),
 	}
 }
 
@@ -1167,7 +1167,7 @@ func (g *generator) clustersKeyvault() *arm.Resource {
 	return &arm.Resource{
 		Resource:   vault,
 		Condition:  g.conditionStanza("fullDeploy"),
-		APIVersion: azureclient.APIVersions["Microsoft.KeyVault"],
+		APIVersion: azureclient.APIVersion("Microsoft.KeyVault"),
 	}
 }
 
@@ -1214,7 +1214,7 @@ func (g *generator) serviceKeyvault() *arm.Resource {
 	return &arm.Resource{
 		Resource:   vault,
 		Condition:  g.conditionStanza("fullDeploy"),
-		APIVersion: azureclient.APIVersions["Microsoft.KeyVault"],
+		APIVersion: azureclient.APIVersion("Microsoft.KeyVault"),
 	}
 }
 
@@ -1243,7 +1243,7 @@ func (g *generator) cosmosdb() []*arm.Resource {
 	r := &arm.Resource{
 		Resource:   cosmosdb,
 		Condition:  g.conditionStanza("fullDeploy"),
-		APIVersion: azureclient.APIVersions["Microsoft.DocumentDB"],
+		APIVersion: azureclient.APIVersion("Microsoft.DocumentDB"),
 	}
 
 	if g.production {
@@ -1287,7 +1287,7 @@ func (g *generator) database(databaseName string, addDependsOn bool) []*arm.Reso
 				Location: to.StringPtr("[resourceGroup().location]"),
 			},
 			Condition:  g.conditionStanza("fullDeploy"),
-			APIVersion: azureclient.APIVersions["Microsoft.DocumentDB"],
+			APIVersion: azureclient.APIVersion("Microsoft.DocumentDB"),
 		},
 		{
 			Resource: &mgmtdocumentdb.SQLContainerCreateUpdateParameters{
@@ -1309,7 +1309,7 @@ func (g *generator) database(databaseName string, addDependsOn bool) []*arm.Reso
 				Location: to.StringPtr("[resourceGroup().location]"),
 			},
 			Condition:  g.conditionStanza("fullDeploy"),
-			APIVersion: azureclient.APIVersions["Microsoft.DocumentDB"],
+			APIVersion: azureclient.APIVersion("Microsoft.DocumentDB"),
 			DependsOn: []string{
 				"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), " + databaseName + ")]",
 			},
@@ -1333,7 +1333,7 @@ func (g *generator) database(databaseName string, addDependsOn bool) []*arm.Reso
 				Location: to.StringPtr("[resourceGroup().location]"),
 			},
 			Condition:  g.conditionStanza("fullDeploy"),
-			APIVersion: azureclient.APIVersions["Microsoft.DocumentDB"],
+			APIVersion: azureclient.APIVersion("Microsoft.DocumentDB"),
 			DependsOn: []string{
 				"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), " + databaseName + ")]",
 			},
@@ -1358,7 +1358,7 @@ func (g *generator) database(databaseName string, addDependsOn bool) []*arm.Reso
 				Location: to.StringPtr("[resourceGroup().location]"),
 			},
 			Condition:  g.conditionStanza("fullDeploy"),
-			APIVersion: azureclient.APIVersions["Microsoft.DocumentDB"],
+			APIVersion: azureclient.APIVersion("Microsoft.DocumentDB"),
 			DependsOn: []string{
 				"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), " + databaseName + ")]",
 			},
@@ -1401,7 +1401,7 @@ func (g *generator) database(databaseName string, addDependsOn bool) []*arm.Reso
 				Location: to.StringPtr("[resourceGroup().location]"),
 			},
 			Condition:  g.conditionStanza("fullDeploy"),
-			APIVersion: azureclient.APIVersions["Microsoft.DocumentDB"],
+			APIVersion: azureclient.APIVersion("Microsoft.DocumentDB"),
 			DependsOn: []string{
 				"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), " + databaseName + ")]",
 			},
@@ -1425,7 +1425,7 @@ func (g *generator) database(databaseName string, addDependsOn bool) []*arm.Reso
 				Location: to.StringPtr("[resourceGroup().location]"),
 			},
 			Condition:  g.conditionStanza("fullDeploy"),
-			APIVersion: azureclient.APIVersions["Microsoft.DocumentDB"],
+			APIVersion: azureclient.APIVersion("Microsoft.DocumentDB"),
 			DependsOn: []string{
 				"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), " + databaseName + ")]",
 			},
@@ -1466,7 +1466,7 @@ func (g *generator) roleDefinitionTokenContributor() *arm.Resource {
 			},
 		},
 		Condition:  g.conditionStanza("fullDeploy"),
-		APIVersion: azureclient.APIVersions["Microsoft.Authorization/roleDefinitions"],
+		APIVersion: azureclient.APIVersion("Microsoft.Authorization/roleDefinitions"),
 	}
 }
 
@@ -1524,7 +1524,7 @@ func (g *generator) acrReplica() *arm.Resource {
 			Location: to.StringPtr("[parameters('location')]"),
 		},
 		Condition:  g.conditionStanza("fullDeploy"),
-		APIVersion: azureclient.APIVersions["Microsoft.ContainerRegistry"],
+		APIVersion: azureclient.APIVersion("Microsoft.ContainerRegistry"),
 	}
 }
 
@@ -1570,7 +1570,7 @@ func (g *generator) rpVersionStorageAccount() []*arm.Resource {
 				},
 			},
 			Condition:  g.conditionStanza("fullDeploy"),
-			APIVersion: azureclient.APIVersions["Microsoft.Storage"],
+			APIVersion: azureclient.APIVersion("Microsoft.Storage"),
 		},
 		{
 			Resource: &mgmtstorage.BlobContainer{
@@ -1580,7 +1580,7 @@ func (g *generator) rpVersionStorageAccount() []*arm.Resource {
 					PublicAccess: mgmtstorage.PublicAccessContainer,
 				},
 			},
-			APIVersion: azureclient.APIVersions["Microsoft.Storage"],
+			APIVersion: azureclient.APIVersion("Microsoft.Storage"),
 			Condition:  g.conditionStanza("fullDeploy"),
 			DependsOn: []string{
 				"[resourceId('Microsoft.Storage/storageAccounts', parameters('rpVersionStorageAccountName'))]",
@@ -1600,7 +1600,7 @@ func (g *generator) storageAccount() *arm.Resource {
 			},
 		},
 		Condition:  g.conditionStanza("fullDeploy"),
-		APIVersion: azureclient.APIVersions["Microsoft.Storage"],
+		APIVersion: azureclient.APIVersion("Microsoft.Storage"),
 	}
 }
 
@@ -1641,7 +1641,7 @@ enabled=yes
 gpgcheck=yes
 EOF
 
-yum --enablerepo=rhui-rhel-7-server-rhui-optional-rpms -y install azure-cli docker jq libassuan-devel gcc gpgme-devel rh-git29 rh-python36 tmpwatch
+yum --enablerepo=rhui-rhel-7-server-rhui-optional-rpms -y install azure-cli docker jq libassuan-devel gcc gpgme-devel rh-git29 rh-python36
 
 GO_VERSION=1.14.9
 curl https://dl.google.com/go/go${GO_VERSION}.linux-amd64.tar.gz | tar -C /usr/local -xz
@@ -1675,13 +1675,6 @@ sed -i -e 's/^OPTIONS='\''/OPTIONS='\''-G cloud-user /' /etc/sysconfig/docker
 
 systemctl enable docker
 
-cat >/etc/cron.hourly/tmpwatch <<'EOF'
-#!/bin/bash
-
-exec /sbin/tmpwatch 24h /tmp
-EOF
-chmod +x /etc/cron.hourly/tmpwatch
-
 (sleep 30; reboot) &
 `))
 
@@ -1783,7 +1776,7 @@ chmod +x /etc/cron.hourly/tmpwatch
 			Type:     to.StringPtr("Microsoft.Compute/virtualMachineScaleSets"),
 			Location: to.StringPtr("[resourceGroup().location]"),
 		},
-		APIVersion: azureclient.APIVersions["Microsoft.Compute"],
+		APIVersion: azureclient.APIVersion("Microsoft.Compute"),
 		Condition:  "[parameters('ciDeployTooling')]", // TODO(mj): Refactor g.conditionStanza for better usage
 		DependsOn: []string{
 			"[resourceId('Microsoft.Network/virtualNetworks', 'dev-vnet')]",
diff --git a/pkg/deploy/generator/resources_cluster.go b/pkg/deploy/generator/resources_cluster.go
index 1850f8ccf..3dc1ec772 100644
--- a/pkg/deploy/generator/resources_cluster.go
+++ b/pkg/deploy/generator/resources_cluster.go
@@ -26,7 +26,7 @@ func clusterVnet() *arm.Resource {
 			Location: to.StringPtr("[resourceGroup().location]"),
 		},
 		Condition:  "[parameters('fullDeploy')]",
-		APIVersion: azureclient.APIVersions["Microsoft.Network"],
+		APIVersion: azureclient.APIVersion("Microsoft.Network"),
 	}
 }
 
@@ -37,7 +37,7 @@ func clusterRouteTable() *arm.Resource {
 			Type:     to.StringPtr("Microsoft.Network/routeTables"),
 			Location: to.StringPtr("[resourceGroup().location]"),
 		},
-		APIVersion: azureclient.APIVersions["Microsoft.Network"],
+		APIVersion: azureclient.APIVersion("Microsoft.Network"),
 	}
 }
 
@@ -60,7 +60,7 @@ func clusterMasterSubnet() *arm.Resource {
 		},
 		Type:       "Microsoft.Network/virtualNetworks/subnets",
 		Location:   "[resourceGroup().location]",
-		APIVersion: azureclient.APIVersions["Microsoft.Network"],
+		APIVersion: azureclient.APIVersion("Microsoft.Network"),
 		DependsOn: []string{
 			"[resourceid('Microsoft.Network/virtualNetworks', 'dev-vnet')]",
 			"[resourceid('Microsoft.Network/routeTables', concat(parameters('clusterName'), '-rt'))]",
@@ -83,7 +83,7 @@ func clusterWorkerSubnet() *arm.Resource {
 		},
 		Type:       "Microsoft.Network/virtualNetworks/subnets",
 		Location:   "[resourceGroup().location]",
-		APIVersion: azureclient.APIVersions["Microsoft.Network"],
+		APIVersion: azureclient.APIVersion("Microsoft.Network"),
 		DependsOn: []string{
 			"[resourceid('Microsoft.Network/virtualNetworks/subnets', 'dev-vnet', concat(parameters('clusterName'), '-master'))]",
 		},
diff --git a/pkg/frontend/adminactions/resources_list.go b/pkg/frontend/adminactions/resources_list.go
index 49a033498..1dc165d66 100644
--- a/pkg/frontend/adminactions/resources_list.go
+++ b/pkg/frontend/adminactions/resources_list.go
@@ -18,10 +18,9 @@ import (
 )
 
 func (a *adminactions) ResourcesList(ctx context.Context) ([]byte, error) {
-
 	clusterRGName := stringutils.LastTokenByte(a.oc.Properties.ClusterProfile.ResourceGroupID, '/')
 
-	resources, err := a.resourcesClient.List(ctx, fmt.Sprintf("resourceGroup eq '%s'", clusterRGName), "", nil)
+	resources, err := a.resourcesClient.ListByResourceGroup(ctx, clusterRGName, "", "", nil)
 	if err != nil {
 		return nil, err
 	}
@@ -33,9 +32,9 @@ func (a *adminactions) ResourcesList(ctx context.Context) ([]byte, error) {
 	}
 
 	for _, res := range resources {
-		apiVersion, err := azureclient.APIVersionForType(*res.Type)
-		if err != nil {
-			return nil, err
+		apiVersion := azureclient.APIVersion(*res.Type)
+		if apiVersion == "" {
+			return nil, fmt.Errorf("API version not found for type %s", *res.Type)
 		}
 		switch *res.Type {
 		case "Microsoft.Compute/virtualMachines":
diff --git a/pkg/operator/controllers/routefix/routefix_controller.go b/pkg/operator/controllers/routefix/routefix_controller.go
index 88770b735..7fab908a7 100644
--- a/pkg/operator/controllers/routefix/routefix_controller.go
+++ b/pkg/operator/controllers/routefix/routefix_controller.go
@@ -14,13 +14,13 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
 	"k8s.io/client-go/kubernetes"
+	"k8s.io/client-go/kubernetes/scheme"
 	"k8s.io/client-go/rest"
 	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
 	"sigs.k8s.io/controller-runtime/pkg/reconcile"
 
 	arov1alpha1 "github.com/Azure/ARO-RP/pkg/operator/apis/aro.openshift.io/v1alpha1"
-	"github.com/Azure/ARO-RP/pkg/operator/clientset/versioned/scheme"
 	aroclient "github.com/Azure/ARO-RP/pkg/operator/clientset/versioned/typed/aro.openshift.io/v1alpha1"
 	"github.com/Azure/ARO-RP/pkg/operator/controllers"
 	"github.com/Azure/ARO-RP/pkg/util/dynamichelper"
diff --git a/pkg/util/azureclient/apiversions.go b/pkg/util/azureclient/apiversions.go
index ed7c463ee..cf33aa21b 100644
--- a/pkg/util/azureclient/apiversions.go
+++ b/pkg/util/azureclient/apiversions.go
@@ -4,33 +4,33 @@ package azureclient
 // Licensed under the Apache License 2.0.
 
 import (
-	"fmt"
 	"strings"
 )
 
-var APIVersions = map[string]string{
-	"Microsoft.Authorization":                 "2018-09-01-preview",
-	"Microsoft.Authorization/denyAssignments": "2018-07-01-preview",
-	"Microsoft.Authorization/roleDefinitions": "2018-01-01-preview",
-	"Microsoft.Compute":                       "2019-03-01",
-	"Microsoft.ContainerRegistry":             "2019-05-01",
-	"Microsoft.DocumentDB":                    "2019-08-01",
-	"Microsoft.Insights":                      "2018-03-01",
-	"Microsoft.KeyVault":                      "2016-10-01",
-	"Microsoft.ManagedIdentity":               "2018-11-30",
-	"Microsoft.Network":                       "2019-07-01",
-	"Microsoft.Network/dnsZones":              "2018-05-01",
-	"Microsoft.Network/privateDnsZones":       "2018-09-01",
-	"Microsoft.Storage":                       "2019-04-01",
+// keys must be lower case
+var apiVersions = map[string]string{
+	"microsoft.authorization":                 "2018-09-01-preview",
+	"microsoft.authorization/denyassignments": "2018-07-01-preview",
+	"microsoft.authorization/roledefinitions": "2018-01-01-preview",
+	"microsoft.compute":                       "2019-03-01",
+	"microsoft.containerregistry":             "2019-05-01",
+	"microsoft.documentdb":                    "2019-08-01",
+	"microsoft.insights":                      "2018-03-01",
+	"microsoft.keyvault":                      "2016-10-01",
+	"microsoft.managedidentity":               "2018-11-30",
+	"microsoft.network":                       "2019-07-01",
+	"microsoft.network/dnszones":              "2018-05-01",
+	"microsoft.network/privatednszones":       "2018-09-01",
+	"microsoft.storage":                       "2019-04-01",
 }
 
-// APIVersionForType gets the APIVersion from a full resource type
-func APIVersionForType(typ string) (string, error) {
-	t := typ
+// APIVersion gets the APIVersion from a full resource type
+func APIVersion(typ string) string {
+	t := strings.ToLower(typ)
 
 	for {
-		if apiVersion, ok := APIVersions[t]; ok {
-			return apiVersion, nil
+		if apiVersion, ok := apiVersions[t]; ok {
+			return apiVersion
 		}
 
 		i := strings.LastIndexByte(t, '/')
@@ -41,5 +41,5 @@ func APIVersionForType(typ string) (string, error) {
 		t = t[:i]
 	}
 
-	return "", fmt.Errorf("API version not found for type %s", typ)
+	return ""
 }
diff --git a/pkg/util/azureclient/mgmt/features/resources.go b/pkg/util/azureclient/mgmt/features/resources.go
index 8db5e04f5..acbc02b76 100644
--- a/pkg/util/azureclient/mgmt/features/resources.go
+++ b/pkg/util/azureclient/mgmt/features/resources.go
@@ -13,6 +13,7 @@ import (
 // ResourcesClient is a minimal interface for azure ResourcesClient
 type ResourcesClient interface {
 	GetByID(ctx context.Context, resourceID string, APIVersion string) (mgmtfeatures.GenericResource, error)
+	DeleteByID(ctx context.Context, resourceID string, APIVersion string) (mgmtfeatures.ResourcesDeleteByIDFuture, error)
 	ResourcesClientAddons
 }
 
diff --git a/pkg/util/azureclient/mgmt/features/resources_addons.go b/pkg/util/azureclient/mgmt/features/resources_addons.go
index 451ab5c4e..52fb56d77 100644
--- a/pkg/util/azureclient/mgmt/features/resources_addons.go
+++ b/pkg/util/azureclient/mgmt/features/resources_addons.go
@@ -7,29 +7,17 @@ import (
 	"context"
 
 	mgmtfeatures "github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2019-07-01/features"
+	"github.com/Azure/go-autorest/autorest"
 )
 
 // ResourcesClientAddons is a minimal interface for azure ResourcesClient
 type ResourcesClientAddons interface {
-	List(ctx context.Context, filter, expand string, top *int32) ([]mgmtfeatures.GenericResourceExpanded, error)
+	Client() autorest.Client
 	ListByResourceGroup(ctx context.Context, resourceGroupName string, filter string, expand string, top *int32) ([]mgmtfeatures.GenericResourceExpanded, error)
 }
 
-func (c *resourcesClient) List(ctx context.Context, filter, expand string, top *int32) (resources []mgmtfeatures.GenericResourceExpanded, err error) {
-	page, err := c.ResourcesClient.List(ctx, filter, expand, top)
-	if err != nil {
-		return nil, err
-	}
-
-	for page.NotDone() {
-		resources = append(resources, page.Values()...)
-		err = page.NextWithContext(ctx)
-		if err != nil {
-			return nil, err
-		}
-	}
-
-	return resources, nil
+func (c *resourcesClient) Client() autorest.Client {
+	return c.ResourcesClient.Client
 }
 
 func (c *resourcesClient) ListByResourceGroup(ctx context.Context, resourceGroupName string, filter string, expand string, top *int32) (resources []mgmtfeatures.GenericResourceExpanded, err error) {
diff --git a/pkg/util/azureclient/mgmt/privatedns/generate.go b/pkg/util/azureclient/mgmt/privatedns/generate.go
new file mode 100644
index 000000000..7a1b9c8a9
--- /dev/null
+++ b/pkg/util/azureclient/mgmt/privatedns/generate.go
@@ -0,0 +1,8 @@
+package privatedns
+
+// Copyright (c) Microsoft Corporation.
+// Licensed under the Apache License 2.0.
+
+//go:generate rm -rf ../../../../util/mocks/$GOPACKAGE
+//go:generate go run ../../../../../vendor/github.com/golang/mock/mockgen -destination=../../../../util/mocks/azureclient/mgmt/$GOPACKAGE/$GOPACKAGE.go github.com/Azure/ARO-RP/pkg/util/azureclient/mgmt/$GOPACKAGE VirtualNetworkLinksClient
+//go:generate go run ../../../../../vendor/golang.org/x/tools/cmd/goimports -local=github.com/Azure/ARO-RP -e -w ../../../../util/mocks/azureclient/mgmt/$GOPACKAGE/$GOPACKAGE.go
diff --git a/pkg/util/azureclient/mgmt/privatedns/virtualnetworklinks.go b/pkg/util/azureclient/mgmt/privatedns/virtualnetworklinks.go
new file mode 100644
index 000000000..3ac679234
--- /dev/null
+++ b/pkg/util/azureclient/mgmt/privatedns/virtualnetworklinks.go
@@ -0,0 +1,30 @@
+package privatedns
+
+// Copyright (c) Microsoft Corporation.
+// Licensed under the Apache License 2.0.
+
+import (
+	mgmtprivatedns "github.com/Azure/azure-sdk-for-go/services/privatedns/mgmt/2018-09-01/privatedns"
+	"github.com/Azure/go-autorest/autorest"
+)
+
+// VirtualNetworkLinksClient is a minimal interface for azure VirtualNetworkLinksClient
+type VirtualNetworkLinksClient interface {
+	VirtualNetworkLinksClientAddons
+}
+
+type virtualNetworkLinksClient struct {
+	mgmtprivatedns.VirtualNetworkLinksClient
+}
+
+var _ VirtualNetworkLinksClient = &virtualNetworkLinksClient{}
+
+// NewVirtualNetworkLinksClient creates a new VirtualNetworkLinksClient
+func NewVirtualNetworkLinksClient(subscriptionID string, authorizer autorest.Authorizer) VirtualNetworkLinksClient {
+	client := mgmtprivatedns.NewVirtualNetworkLinksClient(subscriptionID)
+	client.Authorizer = authorizer
+
+	return &virtualNetworkLinksClient{
+		VirtualNetworkLinksClient: client,
+	}
+}
diff --git a/pkg/util/azureclient/mgmt/privatedns/virtualnetworklinks_addons.go b/pkg/util/azureclient/mgmt/privatedns/virtualnetworklinks_addons.go
new file mode 100644
index 000000000..0c5555e4a
--- /dev/null
+++ b/pkg/util/azureclient/mgmt/privatedns/virtualnetworklinks_addons.go
@@ -0,0 +1,43 @@
+package privatedns
+
+// Copyright (c) Microsoft Corporation.
+// Licensed under the Apache License 2.0.
+
+import (
+	"context"
+
+	mgmtprivatedns "github.com/Azure/azure-sdk-for-go/services/privatedns/mgmt/2018-09-01/privatedns"
+)
+
+// VirtualNetworkLinksClientAddons contains addons for VirtualNetworkLinksClient
+type VirtualNetworkLinksClientAddons interface {
+	DeleteAndWait(ctx context.Context, resourceGroupName string, privateZoneName string, virtualNetworkLinkName string, ifMatch string) error
+	List(ctx context.Context, resourceGroupName string, privateZoneName string, top *int32) ([]mgmtprivatedns.VirtualNetworkLink, error)
+}
+
+func (c *virtualNetworkLinksClient) DeleteAndWait(ctx context.Context, resourceGroupName string, privateZoneName string, virtualNetworkLinkName string, ifMatch string) error {
+	future, err := c.VirtualNetworkLinksClient.Delete(ctx, resourceGroupName, privateZoneName, virtualNetworkLinkName, ifMatch)
+	if err != nil {
+		return err
+	}
+
+	return future.WaitForCompletionRef(ctx, c.Client)
+}
+
+func (c *virtualNetworkLinksClient) List(ctx context.Context, resourceGroupName string, privateZoneName string, top *int32) (virtualNetworkLinks []mgmtprivatedns.VirtualNetworkLink, err error) {
+	page, err := c.VirtualNetworkLinksClient.List(ctx, resourceGroupName, privateZoneName, top)
+	if err != nil {
+		return nil, err
+	}
+
+	for page.NotDone() {
+		virtualNetworkLinks = append(virtualNetworkLinks, page.Values()...)
+
+		err = page.NextWithContext(ctx)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	return virtualNetworkLinks, nil
+}
diff --git a/pkg/util/mocks/azureclient/mgmt/features/features.go b/pkg/util/mocks/azureclient/mgmt/features/features.go
index 03f5e8dcf..c7ab8beab 100644
--- a/pkg/util/mocks/azureclient/mgmt/features/features.go
+++ b/pkg/util/mocks/azureclient/mgmt/features/features.go
@@ -9,6 +9,7 @@ import (
 	reflect "reflect"
 
 	features "github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2019-07-01/features"
+	autorest "github.com/Azure/go-autorest/autorest"
 	gomock "github.com/golang/mock/gomock"
 )
 
@@ -264,34 +265,48 @@ func (m *MockResourcesClient) EXPECT() *MockResourcesClientMockRecorder {
 	return m.recorder
 }
 
-// GetByID mocks base method
-func (m *MockResourcesClient) GetByID(arg0 context.Context, arg1, arg2 string) (features.GenericResource, error) {
+// Client mocks base method
+func (m *MockResourcesClient) Client() autorest.Client {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "GetByID", arg0, arg1, arg2)
-	ret0, _ := ret[0].(features.GenericResource)
+	ret := m.ctrl.Call(m, "Client")
+	ret0, _ := ret[0].(autorest.Client)
+	return ret0
+}
+
+// Client indicates an expected call of Client
+func (mr *MockResourcesClientMockRecorder) Client() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Client", reflect.TypeOf((*MockResourcesClient)(nil).Client))
+}
+
+// DeleteByID mocks base method
+func (m *MockResourcesClient) DeleteByID(arg0 context.Context, arg1, arg2 string) (features.ResourcesDeleteByIDFuture, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "DeleteByID", arg0, arg1, arg2)
+	ret0, _ := ret[0].(features.ResourcesDeleteByIDFuture)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
-// GetByID indicates an expected call of GetByID
-func (mr *MockResourcesClientMockRecorder) GetByID(arg0, arg1, arg2 interface{}) *gomock.Call {
+// DeleteByID indicates an expected call of DeleteByID
+func (mr *MockResourcesClientMockRecorder) DeleteByID(arg0, arg1, arg2 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetByID", reflect.TypeOf((*MockResourcesClient)(nil).GetByID), arg0, arg1, arg2)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteByID", reflect.TypeOf((*MockResourcesClient)(nil).DeleteByID), arg0, arg1, arg2)
 }
 
-// List mocks base method
-func (m *MockResourcesClient) List(arg0 context.Context, arg1, arg2 string, arg3 *int32) ([]features.GenericResourceExpanded, error) {
+// GetByID mocks base method
+func (m *MockResourcesClient) GetByID(arg0 context.Context, arg1, arg2 string) (features.GenericResource, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "List", arg0, arg1, arg2, arg3)
-	ret0, _ := ret[0].([]features.GenericResourceExpanded)
+	ret := m.ctrl.Call(m, "GetByID", arg0, arg1, arg2)
+	ret0, _ := ret[0].(features.GenericResource)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
-// List indicates an expected call of List
-func (mr *MockResourcesClientMockRecorder) List(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
+// GetByID indicates an expected call of GetByID
+func (mr *MockResourcesClientMockRecorder) GetByID(arg0, arg1, arg2 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockResourcesClient)(nil).List), arg0, arg1, arg2, arg3)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetByID", reflect.TypeOf((*MockResourcesClient)(nil).GetByID), arg0, arg1, arg2)
 }
 
 // ListByResourceGroup mocks base method
diff --git a/pkg/util/mocks/azureclient/mgmt/privatedns/privatedns.go b/pkg/util/mocks/azureclient/mgmt/privatedns/privatedns.go
new file mode 100644
index 000000000..8e29d7ab9
--- /dev/null
+++ b/pkg/util/mocks/azureclient/mgmt/privatedns/privatedns.go
@@ -0,0 +1,65 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: github.com/Azure/ARO-RP/pkg/util/azureclient/mgmt/privatedns (interfaces: VirtualNetworkLinksClient)
+
+// Package mock_privatedns is a generated GoMock package.
+package mock_privatedns
+
+import (
+	context "context"
+	reflect "reflect"
+
+	privatedns "github.com/Azure/azure-sdk-for-go/services/privatedns/mgmt/2018-09-01/privatedns"
+	gomock "github.com/golang/mock/gomock"
+)
+
+// MockVirtualNetworkLinksClient is a mock of VirtualNetworkLinksClient interface
+type MockVirtualNetworkLinksClient struct {
+	ctrl     *gomock.Controller
+	recorder *MockVirtualNetworkLinksClientMockRecorder
+}
+
+// MockVirtualNetworkLinksClientMockRecorder is the mock recorder for MockVirtualNetworkLinksClient
+type MockVirtualNetworkLinksClientMockRecorder struct {
+	mock *MockVirtualNetworkLinksClient
+}
+
+// NewMockVirtualNetworkLinksClient creates a new mock instance
+func NewMockVirtualNetworkLinksClient(ctrl *gomock.Controller) *MockVirtualNetworkLinksClient {
+	mock := &MockVirtualNetworkLinksClient{ctrl: ctrl}
+	mock.recorder = &MockVirtualNetworkLinksClientMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use
+func (m *MockVirtualNetworkLinksClient) EXPECT() *MockVirtualNetworkLinksClientMockRecorder {
+	return m.recorder
+}
+
+// DeleteAndWait mocks base method
+func (m *MockVirtualNetworkLinksClient) DeleteAndWait(arg0 context.Context, arg1, arg2, arg3, arg4 string) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "DeleteAndWait", arg0, arg1, arg2, arg3, arg4)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// DeleteAndWait indicates an expected call of DeleteAndWait
+func (mr *MockVirtualNetworkLinksClientMockRecorder) DeleteAndWait(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAndWait", reflect.TypeOf((*MockVirtualNetworkLinksClient)(nil).DeleteAndWait), arg0, arg1, arg2, arg3, arg4)
+}
+
+// List mocks base method
+func (m *MockVirtualNetworkLinksClient) List(arg0 context.Context, arg1, arg2 string, arg3 *int32) ([]privatedns.VirtualNetworkLink, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "List", arg0, arg1, arg2, arg3)
+	ret0, _ := ret[0].([]privatedns.VirtualNetworkLink)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// List indicates an expected call of List
+func (mr *MockVirtualNetworkLinksClientMockRecorder) List(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockVirtualNetworkLinksClient)(nil).List), arg0, arg1, arg2, arg3)
+}
diff --git a/pkg/util/rbac/rbac.go b/pkg/util/rbac/rbac.go
index 3495ce581..f5f31ecd2 100644
--- a/pkg/util/rbac/rbac.go
+++ b/pkg/util/rbac/rbac.go
@@ -50,7 +50,7 @@ func ResourceRoleAssignmentWithName(roleID, spID, resourceType, resourceName, na
 			},
 		},
 		Condition:  condition,
-		APIVersion: azureclient.APIVersions["Microsoft.Authorization"],
+		APIVersion: azureclient.APIVersion("Microsoft.Authorization"),
 		DependsOn: []string{
 			"[" + resourceID + "]",
 		},
@@ -87,7 +87,7 @@ func ResourceGroupRoleAssignmentWithName(roleID, spID string, name string, condi
 				PrincipalType:    mgmtauthorization.ServicePrincipal,
 			},
 		},
-		APIVersion: azureclient.APIVersions["Microsoft.Authorization"],
+		APIVersion: azureclient.APIVersion("Microsoft.Authorization"),
 	}
 
 	if len(condition) > 0 {


Test patch:
diff --git a/pkg/cluster/install_test.go b/pkg/cluster/install_test.go
index f76c46316..8cf5ca659 100644
--- a/pkg/cluster/install_test.go
+++ b/pkg/cluster/install_test.go
@@ -17,11 +17,13 @@ import (
 	"github.com/onsi/gomega/types"
 	configv1 "github.com/openshift/api/config/v1"
 	operatorv1 "github.com/openshift/api/operator/v1"
-	"github.com/openshift/client-go/config/clientset/versioned/fake"
-	fakeoperatorv1 "github.com/openshift/client-go/operator/clientset/versioned/fake"
+	fakeconfig "github.com/openshift/client-go/config/clientset/versioned/fake"
+	fakeoperator "github.com/openshift/client-go/operator/clientset/versioned/fake"
 	"github.com/sirupsen/logrus"
+	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/util/wait"
+	"k8s.io/client-go/kubernetes/fake"
 
 	"github.com/Azure/ARO-RP/pkg/api"
 	"github.com/Azure/ARO-RP/pkg/util/arm"
@@ -34,7 +36,7 @@ import (
 
 func failingFunc(context.Context) error { return errors.New("oh no!") }
 
-var clusterOperators = &configv1.ClusterOperator{
+var clusterOperator = &configv1.ClusterOperator{
 	ObjectMeta: metav1.ObjectMeta{
 		Name: "console",
 	},
@@ -63,7 +65,13 @@ var clusterVersion = &configv1.ClusterVersion{
 	},
 }
 
-var ingressControllers = &operatorv1.IngressController{
+var node = &corev1.Node{
+	ObjectMeta: metav1.ObjectMeta{
+		Name: "node",
+	},
+}
+
+var ingressController = &operatorv1.IngressController{
 	ObjectMeta: metav1.ObjectMeta{
 		Namespace: "openshift-ingress-operator",
 	},
@@ -76,12 +84,13 @@ func TestStepRunnerWithInstaller(t *testing.T) {
 	ctx := context.Background()
 
 	for _, tt := range []struct {
-		name        string
-		steps       []steps.Step
-		wantEntries []map[string]types.GomegaMatcher
-		wantErr     string
-		configcli   *fake.Clientset
-		operatorcli *fakeoperatorv1.Clientset
+		name          string
+		steps         []steps.Step
+		wantEntries   []map[string]types.GomegaMatcher
+		wantErr       string
+		kubernetescli *fake.Clientset
+		configcli     *fakeconfig.Clientset
+		operatorcli   *fakeoperator.Clientset
 	}{
 		{
 			name: "Failed step run will log cluster version, cluster operator status, and ingress information if available",
@@ -102,6 +111,10 @@ func TestStepRunnerWithInstaller(t *testing.T) {
 					"level": gomega.Equal(logrus.InfoLevel),
 					"msg":   gomega.MatchRegexp(`github.com/Azure/ARO-RP/pkg/cluster.\(\*manager\).logClusterVersion\-fm: {.*"version":"1.2.3".*}`),
 				},
+				{
+					"level": gomega.Equal(logrus.InfoLevel),
+					"msg":   gomega.MatchRegexp(`github.com/Azure/ARO-RP/pkg/cluster.\(\*manager\).logNodes\-fm: {.*"name":"node".*}`),
+				},
 				{
 					"level": gomega.Equal(logrus.InfoLevel),
 					"msg":   gomega.MatchRegexp(`github.com/Azure/ARO-RP/pkg/cluster.\(\*manager\).logClusterOperators\-fm: {.*"versions":\[{"name":"operator","version":"4.3.0"},{"name":"operator\-good","version":"4.3.1"}\].*}`),
@@ -111,8 +124,9 @@ func TestStepRunnerWithInstaller(t *testing.T) {
 					"msg":   gomega.MatchRegexp(`github.com/Azure/ARO-RP/pkg/cluster.\(\*manager\).logIngressControllers\-fm: {.*"items":\[{.*"domain":"aroapp.io"}.*\]}`),
 				},
 			},
-			configcli:   fake.NewSimpleClientset(clusterVersion, clusterOperators),
-			operatorcli: fakeoperatorv1.NewSimpleClientset(ingressControllers),
+			kubernetescli: fake.NewSimpleClientset(node),
+			configcli:     fakeconfig.NewSimpleClientset(clusterVersion, clusterOperator),
+			operatorcli:   fakeoperator.NewSimpleClientset(ingressController),
 		},
 		{
 			name: "Failed step run will not crash if it cannot get the clusterversions, clusteroperators, ingresscontrollers",
@@ -133,6 +147,10 @@ func TestStepRunnerWithInstaller(t *testing.T) {
 					"level": gomega.Equal(logrus.ErrorLevel),
 					"msg":   gomega.Equal(`clusterversions.config.openshift.io "version" not found`),
 				},
+				{
+					"level": gomega.Equal(logrus.InfoLevel),
+					"msg":   gomega.Equal(`github.com/Azure/ARO-RP/pkg/cluster.(*manager).logNodes-fm: {"metadata":{},"items":null}`),
+				},
 				{
 					"level": gomega.Equal(logrus.InfoLevel),
 					"msg":   gomega.Equal(`github.com/Azure/ARO-RP/pkg/cluster.(*manager).logClusterOperators-fm: {"metadata":{},"items":null}`),
@@ -142,16 +160,18 @@ func TestStepRunnerWithInstaller(t *testing.T) {
 					"msg":   gomega.Equal(`github.com/Azure/ARO-RP/pkg/cluster.(*manager).logIngressControllers-fm: {"metadata":{},"items":null}`),
 				},
 			},
-			configcli:   fake.NewSimpleClientset(),
-			operatorcli: fakeoperatorv1.NewSimpleClientset(),
+			kubernetescli: fake.NewSimpleClientset(),
+			configcli:     fakeconfig.NewSimpleClientset(),
+			operatorcli:   fakeoperator.NewSimpleClientset(),
 		},
 	} {
 		t.Run(tt.name, func(t *testing.T) {
 			h, log := testlog.New()
 			m := &manager{
-				log:         log,
-				configcli:   tt.configcli,
-				operatorcli: tt.operatorcli,
+				log:           log,
+				kubernetescli: tt.kubernetescli,
+				configcli:     tt.configcli,
+				operatorcli:   tt.operatorcli,
 			}
 
 			err := m.runSteps(ctx, tt.steps)
diff --git a/pkg/frontend/adminactions/resources_list_test.go b/pkg/frontend/adminactions/resources_list_test.go
index 0111a41e6..fed90041c 100644
--- a/pkg/frontend/adminactions/resources_list_test.go
+++ b/pkg/frontend/adminactions/resources_list_test.go
@@ -44,7 +44,7 @@ func TestResourcesList(t *testing.T) {
 			resourceID: fmt.Sprintf("/subscriptions/%s/resourcegroups/resourceGroup/providers/Microsoft.RedHatOpenShift/openShiftClusters/resourceName", mockSubID),
 			mocks: func(tt *test, resourcesClient *mock_features.MockResourcesClient, vmClient *mock_compute.MockVirtualMachinesClient, vNetClient *mock_network.MockVirtualNetworksClient, routeTablesClient *mock_network.MockRouteTablesClient) {
 
-				resourcesClient.EXPECT().List(gomock.Any(), "resourceGroup eq 'test-cluster'", "", nil).Return([]mgmtfeatures.GenericResourceExpanded{
+				resourcesClient.EXPECT().ListByResourceGroup(gomock.Any(), "test-cluster", "", "", nil).Return([]mgmtfeatures.GenericResourceExpanded{
 					{
 						Name: to.StringPtr("vm-1"),
 						ID:   to.StringPtr("/subscriptions/id"),
@@ -82,7 +82,7 @@ func TestResourcesList(t *testing.T) {
 					Name: to.StringPtr("routetable1"),
 				}, nil)
 
-				resourcesClient.EXPECT().GetByID(gomock.Any(), "/subscriptions/id", azureclient.APIVersions["Microsoft.Storage"]).Return(mgmtfeatures.GenericResource{
+				resourcesClient.EXPECT().GetByID(gomock.Any(), "/subscriptions/id", azureclient.APIVersion("Microsoft.Storage")).Return(mgmtfeatures.GenericResource{
 					Name:     to.StringPtr("storage"),
 					ID:       to.StringPtr("/subscriptions/id"),
 					Type:     to.StringPtr("Microsoft.Storage/storageAccounts"),
@@ -104,8 +104,7 @@ func TestResourcesList(t *testing.T) {
 			name:       "vnet get error", //Get resources should continue on error from vNetClient.Get()
 			resourceID: fmt.Sprintf("/subscriptions/%s/resourcegroups/resourceGroup/providers/Microsoft.RedHatOpenShift/openShiftClusters/resourceName", mockSubID),
 			mocks: func(tt *test, resourcesClient *mock_features.MockResourcesClient, vmClient *mock_compute.MockVirtualMachinesClient, vNetClient *mock_network.MockVirtualNetworksClient, routeTablesClient *mock_network.MockRouteTablesClient) {
-
-				resourcesClient.EXPECT().List(gomock.Any(), "resourceGroup eq 'test-cluster'", "", nil).Return([]mgmtfeatures.GenericResourceExpanded{
+				resourcesClient.EXPECT().ListByResourceGroup(gomock.Any(), "test-cluster", "", "", nil).Return([]mgmtfeatures.GenericResourceExpanded{
 					{
 						Name: to.StringPtr("vm-1"),
 						ID:   to.StringPtr("/subscriptions/id"),
@@ -120,7 +119,7 @@ func TestResourcesList(t *testing.T) {
 
 				vNetClient.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mgmtnetwork.VirtualNetwork{}, fmt.Errorf("Any error during Get, expecting a permissions error"))
 
-				resourcesClient.EXPECT().GetByID(gomock.Any(), "/subscriptions/id", azureclient.APIVersions["Microsoft.Storage"]).Return(mgmtfeatures.GenericResource{
+				resourcesClient.EXPECT().GetByID(gomock.Any(), "/subscriptions/id", azureclient.APIVersion("Microsoft.Storage")).Return(mgmtfeatures.GenericResource{
 					Name:     to.StringPtr("storage"),
 					ID:       to.StringPtr("/subscriptions/id"),
 					Type:     to.StringPtr("Microsoft.Storage/storageAccounts"),
diff --git a/pkg/util/azureclient/apiversions_test.go b/pkg/util/azureclient/apiversions_test.go
index 3541b13fb..d0db97072 100644
--- a/pkg/util/azureclient/apiversions_test.go
+++ b/pkg/util/azureclient/apiversions_test.go
@@ -7,43 +7,37 @@ import (
 	"testing"
 )
 
-func TestAPIVersionForType(t *testing.T) {
+func TestAPIVersion(t *testing.T) {
 	tests := []struct {
-		typ     string
-		want    string
-		wantErr string
+		typ  string
+		want string
 	}{
 		{
 			typ:  "Microsoft.Network/dnsZones",
-			want: APIVersions["Microsoft.Network/dnsZones"],
+			want: apiVersions["microsoft.network/dnszones"],
 		},
 		{
 			typ:  "Microsoft.Network/loadBalancers",
-			want: APIVersions["Microsoft.Network"],
+			want: apiVersions["microsoft.network"],
 		},
 		{
 			typ:  "Microsoft.Network/privateDnsZones/virtualNetworkLinks",
-			want: APIVersions["Microsoft.Network/privateDnsZones"],
+			want: apiVersions["microsoft.network/privatednszones"],
 		},
 		{
 			typ:  "Microsoft.ContainerRegistry/registries/replications",
-			want: APIVersions["Microsoft.ContainerRegistry"],
+			want: apiVersions["microsoft.containerregistry"],
 		},
 		{
-			typ:     "Microsoft.Random/resources",
-			wantErr: "API version not found for type Microsoft.Random/resources",
+			typ: "Microsoft.Random/resources",
 		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.typ, func(t *testing.T) {
-			got, err := APIVersionForType(tt.typ)
+			got := APIVersion(tt.typ)
 			if got != tt.want {
 				t.Error(got)
 			}
-			if err != nil && err.Error() != tt.wantErr ||
-				err == nil && tt.wantErr != "" {
-				t.Error(err)
-			}
 		})
 	}
 }
diff --git a/test/e2e/adminapi_kubernetesobjects.go b/test/e2e/adminapi_kubernetesobjects.go
index f6f2725da..b51d0c76c 100644
--- a/test/e2e/adminapi_kubernetesobjects.go
+++ b/test/e2e/adminapi_kubernetesobjects.go
@@ -71,13 +71,13 @@ var _ = Describe("[Admin API] Kubernetes objects action", func() {
 				By("waiting for the test customer namespace to be deleted")
 				err = wait.PollImmediate(10*time.Second, 5*time.Minute, func() (bool, error) {
 					_, err := clients.Kubernetes.CoreV1().Namespaces().Get(context.Background(), namespace, metav1.GetOptions{})
-					if err == nil {
-						return false, nil
+					if errors.IsNotFound(err) {
+						return true, nil
 					}
-					if !errors.IsNotFound(err) {
-						return false, err
+					if err != nil {
+						log.Warn(err)
 					}
-					return true, nil
+					return false, nil // swallow error
 				})
 				Expect(err).NotTo(HaveOccurred())
 			}()
@@ -244,13 +244,13 @@ func testConfigMapDeleteOK(objName, namespace string) {
 	By("waiting for the configmap to be deleted")
 	err = wait.PollImmediate(10*time.Second, time.Minute, func() (bool, error) {
 		_, err = clients.Kubernetes.CoreV1().ConfigMaps(namespace).Get(context.Background(), objName, metav1.GetOptions{})
-		if err == nil {
-			return false, nil
+		if errors.IsNotFound(err) {
+			return true, nil
 		}
-		if !errors.IsNotFound(err) {
-			return false, err
+		if err != nil {
+			log.Warn(err)
 		}
-		return true, nil
+		return false, nil // swallow error
 	})
 	Expect(err).NotTo(HaveOccurred())
 }
diff --git a/test/e2e/adminapi_redeployvm.go b/test/e2e/adminapi_redeployvm.go
index 80b30f6e1..1d49b4b03 100644
--- a/test/e2e/adminapi_redeployvm.go
+++ b/test/e2e/adminapi_redeployvm.go
@@ -73,7 +73,8 @@ var _ = Describe("[Admin API] VM redeploy action", func() {
 		err = wait.PollImmediate(10*time.Second, 10*time.Minute, func() (bool, error) {
 			nodes, err := clients.Kubernetes.CoreV1().Nodes().List(context.Background(), metav1.ListOptions{})
 			if err != nil {
-				return false, err
+				log.Warn(err)
+				return false, nil // swallow error
 			}
 
 			for _, node := range nodes.Items {
diff --git a/test/e2e/operator.go b/test/e2e/operator.go
index 1f4fbc6b0..0c71c8da1 100644
--- a/test/e2e/operator.go
+++ b/test/e2e/operator.go
@@ -101,10 +101,11 @@ var _ = Describe("ARO Operator - Internet checking", func() {
 		Expect(err).NotTo(HaveOccurred())
 
 		// confirm the conditions are correct
-		err = wait.PollImmediate(10*time.Second, 2*time.Minute, func() (bool, error) {
+		err = wait.PollImmediate(10*time.Second, 10*time.Minute, func() (bool, error) {
 			co, err := clients.AROClusters.Clusters().Get(context.Background(), "cluster", metav1.GetOptions{})
 			if err != nil {
-				return false, err
+				log.Warn(err)
+				return false, nil // swallow error
 			}
 
 			log.Debugf("ClusterStatus.Conditions %s", co.Status.Conditions)
@@ -116,14 +117,14 @@ var _ = Describe("ARO Operator - Internet checking", func() {
 })
 
 var _ = Describe("ARO Operator - Geneva Logging", func() {
-	BeforeEach(func() {
-		_, err := clients.AROClusters.Clusters().Get(context.Background(), "cluster", metav1.GetOptions{})
-		if errors.IsNotFound(err) {
-			Skip("skipping tests as aro-operator is not deployed")
-		}
-	})
 	Specify("genevalogging must be repaired if deployment deleted", func() {
-		mdsdReady := ready.CheckDaemonSetIsReady(context.Background(), clients.Kubernetes.AppsV1().DaemonSets("openshift-azure-logging"), "mdsd")
+		mdsdReady := func() (bool, error) {
+			done, err := ready.CheckDaemonSetIsReady(context.Background(), clients.Kubernetes.AppsV1().DaemonSets("openshift-azure-logging"), "mdsd")()
+			if err != nil {
+				log.Warn(err)
+			}
+			return done, nil // swallow error
+		}
 
 		err := wait.PollImmediate(30*time.Second, 15*time.Minute, mdsdReady)
 		Expect(err).NotTo(HaveOccurred())
@@ -134,7 +135,7 @@ var _ = Describe("ARO Operator - Geneva Logging", func() {
 		err = clients.Kubernetes.AppsV1().DaemonSets("openshift-azure-logging").Delete(context.Background(), "mdsd", metav1.DeleteOptions{})
 		Expect(err).NotTo(HaveOccurred())
 
-		// Wait for it to be fixed
+		// wait for it to be fixed
 		err = wait.PollImmediate(30*time.Second, 15*time.Minute, mdsdReady)
 		Expect(err).NotTo(HaveOccurred())
 
@@ -150,26 +151,31 @@ var _ = Describe("ARO Operator - Geneva Logging", func() {
 })
 
 var _ = Describe("ARO Operator - Routefix Daemonset", func() {
-	BeforeEach(func() {
-		_, err := clients.AROClusters.Clusters().Get(context.Background(), "cluster", metav1.GetOptions{})
-		if errors.IsNotFound(err) {
-			Skip("skipping tests as aro-operator is not deployed")
+	// remove this once the change where the operator manages the routefix
+	// daemonset is in production
+	BeforeEach(skipIfNotInDevelopmentEnv)
+
+	Specify("routefix must be repaired if daemonset is deleted", func() {
+		dsReady := func() (bool, error) {
+			done, err := ready.CheckDaemonSetIsReady(context.Background(), clients.Kubernetes.AppsV1().DaemonSets("openshift-azure-routefix"), "routefix")()
+			if err != nil {
+				log.Warn(err)
+			}
+			return done, nil // swallow error
 		}
-		Specify("routefix must be repaired if daemonset is deleted", func() {
-			dsReady := ready.CheckDaemonSetIsReady(context.Background(), clients.Kubernetes.AppsV1().DaemonSets("openshift-azure-routefix"), "routefix")
-			err := wait.PollImmediate(30*time.Second, 15*time.Minute, dsReady)
-			Expect(err).NotTo(HaveOccurred())
 
-			//delete the routefix daemonset
-			err = clients.Kubernetes.AppsV1().DaemonSets("openshift-azure-routefix").Delete(context.Background(), "routefix", metav1.DeleteOptions{})
-			Expect(err).NotTo(HaveOccurred())
+		err := wait.PollImmediate(30*time.Second, 15*time.Minute, dsReady)
+		Expect(err).NotTo(HaveOccurred())
+
+		// delete the routefix daemonset
+		err = clients.Kubernetes.AppsV1().DaemonSets("openshift-azure-routefix").Delete(context.Background(), "routefix", metav1.DeleteOptions{})
+		Expect(err).NotTo(HaveOccurred())
 
-			//wait for it to be fixed
-			err = wait.PollImmediate(30*time.Second, 15*time.Minute, dsReady)
-			Expect(err).NotTo(HaveOccurred())
+		// wait for it to be fixed
+		err = wait.PollImmediate(30*time.Second, 15*time.Minute, dsReady)
+		Expect(err).NotTo(HaveOccurred())
 
-			_, err = clients.Kubernetes.AppsV1().DaemonSets("openshift-azure-routefix").Get(context.Background(), "routefix", metav1.GetOptions{})
-			Expect(err).NotTo(HaveOccurred())
-		})
+		_, err = clients.Kubernetes.AppsV1().DaemonSets("openshift-azure-routefix").Get(context.Background(), "routefix", metav1.GetOptions{})
+		Expect(err).NotTo(HaveOccurred())
 	})
 })
diff --git a/test/e2e/scalenodes.go b/test/e2e/scalenodes.go
index 069fe266f..fb55d7cd0 100644
--- a/test/e2e/scalenodes.go
+++ b/test/e2e/scalenodes.go
@@ -38,7 +38,8 @@ var _ = Describe("Scale nodes", func() {
 		err = wait.PollImmediate(10*time.Second, 30*time.Minute, func() (bool, error) {
 			nodes, err := clients.Kubernetes.CoreV1().Nodes().List(context.Background(), metav1.ListOptions{})
 			if err != nil {
-				return false, err
+				log.Warn(err)
+				return false, nil // swallow error
 			}
 
 			var nodeCount int
@@ -97,7 +98,8 @@ func waitForScale(name string) error {
 	return wait.PollImmediate(10*time.Second, 30*time.Minute, func() (bool, error) {
 		ms, err := clients.MachineAPI.MachineV1beta1().MachineSets("openshift-machine-api").Get(context.Background(), name, metav1.GetOptions{})
 		if err != nil {
-			return false, err
+			log.Warn(err)
+			return false, nil // swallow error
 		}
 
 		if ms.Spec.Replicas == nil {