Repository: cloudflare/cloudflare-go
Pull request #3027 (2024-09-05 23:47:52)

Basic support for account load balancers
<!-- 
Provide a general summary of your changes in the title above. You should
remove this overview, any sections and any section descriptions you
don't need below before submitting. There isn't a strict requirement to
use this template if you can structure your description and still cover
these points. 
-->

## Description

Basic support for account level load balancers.

<!--
Describe your changes in detail through motivation and context. Why is
this change required? What problem does it solve? If it fixes an open
issue, link to the issue using GitHub's closing issues keywords[1].
-->
## Has your change been tested?

<!--
Explain how the change has been tested and what you ran to confirm your
change affects other parts of the code. Automated tests are generally
expected and changes without tests should explain why they aren't
required.
-->

Duplicated the existing zone tests and altered them for account based LB which are identical except they don't have a "name".

## Screenshots (if appropriate):

## Types of changes

What sort of change does your code introduce/modify?

- [ ] Bug fix (non-breaking change which fixes an issue)
- [X] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)

## Checklist:

- [X] My code follows the code style of this project.
- [ ] My change requires a change to the documentation.
- [ ] I have updated the documentation accordingly.
- [X] I have added tests to cover my changes.
- [X] All new and existing tests passed.
- [soon] This change is using publicly documented in [cloudflare/api-schemas](https://github.com/cloudflare/api-schemas) 
      and relies on stable APIs.

[1]: https://help.github.com/articles/closing-issues-using-keywords/


github-actions[bot]: Oops! It looks like no changelog entry is attached to this PR. Please include a release note as described in https://github.com/cloudflare/cloudflare-go/blob/master/docs/changelog-process.md.

Example: 

~~~
```release-note:TYPE
Release note
```
~~~

If you do not require a release note to be included, please add the `workflow/skip-changelog-entry` label.

Patch:
diff --git a/.changelog/3027.txt b/.changelog/3027.txt
new file mode 100644
index 000000000..a6d75bb37
--- /dev/null
+++ b/.changelog/3027.txt
@@ -0,0 +1,3 @@
+```release-note:enhancement
+load_balancing: add account load balancer support
+```
\ No newline at end of file
diff --git a/load_balancing.go b/load_balancing.go
index 44d7fd9fa..6100b5eaf 100644
--- a/load_balancing.go
+++ b/load_balancing.go
@@ -101,7 +101,7 @@ type LoadBalancer struct {
 	CreatedOn                 *time.Time                 `json:"created_on,omitempty"`
 	ModifiedOn                *time.Time                 `json:"modified_on,omitempty"`
 	Description               string                     `json:"description"`
-	Name                      string                     `json:"name"`
+	Name                      string                     `json:"name,omitempty"`
 	TTL                       int                        `json:"ttl,omitempty"`
 	FallbackPool              string                     `json:"fallback_pool"`
 	DefaultPools              []string                   `json:"default_pools"`
@@ -144,6 +144,11 @@ type LoadBalancer struct {
 	//
 	// "": Maps to "geo" if RegionPools or PopPools or CountryPools have entries otherwise "off".
 	SteeringPolicy string `json:"steering_policy,omitempty"`
+
+	// TunnelID is the ID of the tunnel associated with this load balancer.
+	// It is only used for account load balancers and has no relation to any
+	// tunnels used as origins for this load balancer.
+	TunnelID string `json:"tunnel_id,omitempty"`
 }
 
 // LoadBalancerLoadShedding contains the settings for controlling load shedding.
@@ -681,12 +686,15 @@ func (api *API) UpdateLoadBalancerMonitor(ctx context.Context, rc *ResourceConta
 //
 // API reference: https://api.cloudflare.com/#load-balancers-create-load-balancer
 func (api *API) CreateLoadBalancer(ctx context.Context, rc *ResourceContainer, params CreateLoadBalancerParams) (LoadBalancer, error) {
-	if rc.Level != ZoneRouteLevel {
+
+	var uri string
+	switch rc.Level {
+	case AccountRouteLevel, ZoneRouteLevel:
+		uri = fmt.Sprintf("/%s/%s/load_balancers", rc.Level, rc.Identifier)
+	default:
 		return LoadBalancer{}, fmt.Errorf(errInvalidResourceContainerAccess, rc.Level)
 	}
 
-	uri := fmt.Sprintf("/zones/%s/load_balancers", rc.Identifier)
-
 	res, err := api.makeRequestContext(ctx, http.MethodPost, uri, params.LoadBalancer)
 	if err != nil {
 		return LoadBalancer{}, err
@@ -702,11 +710,17 @@ func (api *API) CreateLoadBalancer(ctx context.Context, rc *ResourceContainer, p
 //
 // API reference: https://api.cloudflare.com/#load-balancers-list-load-balancers
 func (api *API) ListLoadBalancers(ctx context.Context, rc *ResourceContainer, params ListLoadBalancerParams) ([]LoadBalancer, error) {
-	if rc.Level != ZoneRouteLevel {
-		return []LoadBalancer{}, fmt.Errorf(errInvalidResourceContainerAccess, rc.Level)
+
+	var uri string
+	switch rc.Level {
+	case AccountRouteLevel, ZoneRouteLevel:
+		uri = fmt.Sprintf("/%s/%s/load_balancers", rc.Level, rc.Identifier)
+	default:
+		return nil, fmt.Errorf(errInvalidResourceContainerAccess, rc.Level)
 	}
 
-	uri := buildURI(fmt.Sprintf("/zones/%s/load_balancers", rc.Identifier), params.PaginationOptions)
+	// add pagination options to the URI
+	uri = buildURI(uri, params.PaginationOptions)
 
 	res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
 	if err != nil {
@@ -723,7 +737,12 @@ func (api *API) ListLoadBalancers(ctx context.Context, rc *ResourceContainer, pa
 //
 // API reference: https://api.cloudflare.com/#load-balancers-load-balancer-details
 func (api *API) GetLoadBalancer(ctx context.Context, rc *ResourceContainer, loadbalancerID string) (LoadBalancer, error) {
-	if rc.Level != ZoneRouteLevel {
+
+	var uri string
+	switch rc.Level {
+	case AccountRouteLevel, ZoneRouteLevel:
+		uri = fmt.Sprintf("/%s/%s/load_balancers/%s", rc.Level, rc.Identifier, loadbalancerID)
+	default:
 		return LoadBalancer{}, fmt.Errorf(errInvalidResourceContainerAccess, rc.Level)
 	}
 
@@ -731,8 +750,6 @@ func (api *API) GetLoadBalancer(ctx context.Context, rc *ResourceContainer, load
 		return LoadBalancer{}, ErrMissingLoadBalancerID
 	}
 
-	uri := fmt.Sprintf("/zones/%s/load_balancers/%s", rc.Identifier, loadbalancerID)
-
 	res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
 	if err != nil {
 		return LoadBalancer{}, err
@@ -748,7 +765,12 @@ func (api *API) GetLoadBalancer(ctx context.Context, rc *ResourceContainer, load
 //
 // API reference: https://api.cloudflare.com/#load-balancers-delete-load-balancer
 func (api *API) DeleteLoadBalancer(ctx context.Context, rc *ResourceContainer, loadbalancerID string) error {
-	if rc.Level != ZoneRouteLevel {
+
+	var uri string
+	switch rc.Level {
+	case AccountRouteLevel, ZoneRouteLevel:
+		uri = fmt.Sprintf("/%s/%s/load_balancers/%s", rc.Level, rc.Identifier, loadbalancerID)
+	default:
 		return fmt.Errorf(errInvalidResourceContainerAccess, rc.Level)
 	}
 
@@ -756,8 +778,6 @@ func (api *API) DeleteLoadBalancer(ctx context.Context, rc *ResourceContainer, l
 		return ErrMissingLoadBalancerID
 	}
 
-	uri := fmt.Sprintf("/zones/%s/load_balancers/%s", rc.Identifier, loadbalancerID)
-
 	if _, err := api.makeRequestContext(ctx, http.MethodDelete, uri, nil); err != nil {
 		return err
 	}
@@ -768,7 +788,12 @@ func (api *API) DeleteLoadBalancer(ctx context.Context, rc *ResourceContainer, l
 //
 // API reference: https://api.cloudflare.com/#load-balancers-update-load-balancer
 func (api *API) UpdateLoadBalancer(ctx context.Context, rc *ResourceContainer, params UpdateLoadBalancerParams) (LoadBalancer, error) {
-	if rc.Level != ZoneRouteLevel {
+
+	var uri string
+	switch rc.Level {
+	case AccountRouteLevel, ZoneRouteLevel:
+		uri = fmt.Sprintf("/%s/%s/load_balancers/%s", rc.Level, rc.Identifier, params.LoadBalancer.ID)
+	default:
 		return LoadBalancer{}, fmt.Errorf(errInvalidResourceContainerAccess, rc.Level)
 	}
 
@@ -776,8 +801,6 @@ func (api *API) UpdateLoadBalancer(ctx context.Context, rc *ResourceContainer, p
 		return LoadBalancer{}, ErrMissingLoadBalancerID
 	}
 
-	uri := fmt.Sprintf("/zones/%s/load_balancers/%s", rc.Identifier, params.LoadBalancer.ID)
-
 	res, err := api.makeRequestContext(ctx, http.MethodPut, uri, params.LoadBalancer)
 	if err != nil {
 		return LoadBalancer{}, err


Test patch:
diff --git a/load_balancing_test.go b/load_balancing_test.go
index 3a9ab5afb..e4e2ae204 100644
--- a/load_balancing_test.go
+++ b/load_balancing_test.go
@@ -1449,17 +1449,815 @@ func TestCreateLoadBalancer(t *testing.T) {
 	}
 }
 
-func TestCreateLoadBalancer_AccountIsNotSupported(t *testing.T) {
+func TestCreateAccountLoadBalancer(t *testing.T) {
 	setup()
 	defer teardown()
 
-	_, err := client.CreateLoadBalancer(context.Background(), AccountIdentifier(testAccountID), CreateLoadBalancerParams{})
-	if assert.Error(t, err) {
-		assert.Equal(t, fmt.Sprintf(errInvalidResourceContainerAccess, AccountRouteLevel), err.Error())
+	handler := func(w http.ResponseWriter, r *http.Request) {
+		assert.Equal(t, http.MethodPost, r.Method, "Expected method 'POST', got %s", r.Method)
+		w.Header().Set("content-type", "application/json")
+		b, err := io.ReadAll(r.Body)
+		defer r.Body.Close()
+		if assert.NoError(t, err) {
+			assert.JSONEq(t, `{
+              "description": "Account Load Balancer",
+              "ttl": 30,
+              "fallback_pool": "17b5962d775c646f3f9725cbc7a53df4",
+              "default_pools": [
+                "de90f38ced07c2e2f4df50b1f61d4194",
+                "9290f38c5d07c2e2f4df57b1f61d4196",
+                "00920f38ce07c2e2f4df50b1f61d4194"
+              ],
+              "region_pools": {
+                "WNAM": [
+                  "de90f38ced07c2e2f4df50b1f61d4194",
+                  "9290f38c5d07c2e2f4df57b1f61d4196"
+                ],
+                "ENAM": [
+                  "00920f38ce07c2e2f4df50b1f61d4194"
+                ]
+              },
+              "country_pools": {
+                "US": [
+                  "de90f38ced07c2e2f4df50b1f61d4194"
+                ],
+                "GB": [
+                  "abd90f38ced07c2e2f4df50b1f61d4194"
+                ]
+              },
+              "pop_pools": {
+                "LAX": [
+                  "de90f38ced07c2e2f4df50b1f61d4194",
+                  "9290f38c5d07c2e2f4df57b1f61d4196"
+                ],
+                "LHR": [
+                  "abd90f38ced07c2e2f4df50b1f61d4194",
+                  "f9138c5d07c2e2f4df57b1f61d4196"
+                ],
+                "SJC": [
+                  "00920f38ce07c2e2f4df50b1f61d4194"
+                ]
+			  },
+			  "random_steering": {
+			    "default_weight": 0.2,
+			    "pool_weights": {
+			        "9290f38c5d07c2e2f4df57b1f61d4196": 0.6,
+			        "de90f38ced07c2e2f4df50b1f61d4194": 0.4
+			    }
+			  },
+			  "adaptive_routing": {
+				"failover_across_pools": true
+			  },
+			  "location_strategy": {
+				"prefer_ecs": "always",
+				"mode": "resolver_ip"
+			  },
+			  "rules": [
+				  {
+					  "name": "example rule",
+					  "condition": "cf.load_balancer.region == \"SAF\"",
+					  "disabled": false,
+					  "priority": 0,
+					  "overrides": {
+						  "region_pools": {
+							  "SAF": ["de90f38ced07c2e2f4df50b1f61d4194"]
+						  },
+						  "adaptive_routing": {
+							"failover_across_pools": false
+						  },
+						  "location_strategy": {
+							"prefer_ecs": "never",
+							"mode": "pop"
+						  }
+					  }
+				  }
+			  ],
+              "proxied": true,
+              "session_affinity": "cookie",
+              "session_affinity_ttl": 5000,
+              "session_affinity_attributes": {
+                "samesite": "Strict",
+                "secure": "Always",
+                "drain_duration": 60,
+                "zero_downtime_failover": "sticky"
+              }
+            }`, string(b))
+		}
+
+		fmt.Fprint(w, `{
+            "success": true,
+            "errors": [],
+            "messages": [],
+            "result": {
+                "id": "699d98642c564d2e855e9661899b7252",
+                "created_on": "2014-01-01T05:20:00.12345Z",
+                "modified_on": "2014-02-01T05:20:00.12345Z",
+                "description": "Account Load Balancer",
+                "ttl": 30,
+                "fallback_pool": "17b5962d775c646f3f9725cbc7a53df4",
+                "default_pools": [
+                  "de90f38ced07c2e2f4df50b1f61d4194",
+                  "9290f38c5d07c2e2f4df57b1f61d4196",
+                  "00920f38ce07c2e2f4df50b1f61d4194"
+                ],
+                "region_pools": {
+                  "WNAM": [
+                    "de90f38ced07c2e2f4df50b1f61d4194",
+                    "9290f38c5d07c2e2f4df57b1f61d4196"
+                  ],
+                  "ENAM": [
+                    "00920f38ce07c2e2f4df50b1f61d4194"
+                  ]
+                },
+                "country_pools": {
+                  "US": [
+                    "de90f38ced07c2e2f4df50b1f61d4194"
+                  ],
+                  "GB": [
+                    "abd90f38ced07c2e2f4df50b1f61d4194"
+                  ]
+                },
+                "pop_pools": {
+                  "LAX": [
+                    "de90f38ced07c2e2f4df50b1f61d4194",
+                    "9290f38c5d07c2e2f4df57b1f61d4196"
+                  ],
+                  "LHR": [
+                    "abd90f38ced07c2e2f4df50b1f61d4194",
+                    "f9138c5d07c2e2f4df57b1f61d4196"
+                  ],
+                  "SJC": [
+                    "00920f38ce07c2e2f4df50b1f61d4194"
+                  ]
+				},
+				"random_steering": {
+				   "default_weight": 0.2,
+				    "pool_weights": {
+				        "9290f38c5d07c2e2f4df57b1f61d4196": 0.6,
+				        "de90f38ced07c2e2f4df50b1f61d4194": 0.4
+				    }
+				},
+				"adaptive_routing": {
+					"failover_across_pools": true
+				},
+				"location_strategy": {
+					"prefer_ecs": "always",
+					"mode": "resolver_ip"
+				},
+				"rules": [
+				  {
+					  "name": "example rule",
+					  "condition": "cf.load_balancer.region == \"SAF\"",
+					  "overrides": {
+						  "region_pools": {
+							  "SAF": ["de90f38ced07c2e2f4df50b1f61d4194"]
+						  },
+						  "adaptive_routing": {
+							"failover_across_pools": false
+						  },
+						  "location_strategy": {
+							"prefer_ecs": "never",
+							"mode": "pop"
+						  }
+					  }
+				  }
+			  ],
+                "proxied": true,
+                "session_affinity": "cookie",
+                "session_affinity_ttl": 5000,
+                "session_affinity_attributes": {
+                    "samesite": "Strict",
+                    "secure": "Always",
+                    "drain_duration": 60,
+	                "zero_downtime_failover": "sticky"
+                }
+            }
+        }`)
+	}
+
+	mux.HandleFunc("/accounts/"+testAccountID+"/load_balancers", handler)
+	createdOn, _ := time.Parse(time.RFC3339, "2014-01-01T05:20:00.12345Z")
+	modifiedOn, _ := time.Parse(time.RFC3339, "2014-02-01T05:20:00.12345Z")
+	want := LoadBalancer{
+		ID:           "699d98642c564d2e855e9661899b7252",
+		CreatedOn:    &createdOn,
+		ModifiedOn:   &modifiedOn,
+		Description:  "Account Load Balancer",
+		TTL:          30,
+		FallbackPool: "17b5962d775c646f3f9725cbc7a53df4",
+		DefaultPools: []string{
+			"de90f38ced07c2e2f4df50b1f61d4194",
+			"9290f38c5d07c2e2f4df57b1f61d4196",
+			"00920f38ce07c2e2f4df50b1f61d4194",
+		},
+		RegionPools: map[string][]string{
+			"WNAM": {
+				"de90f38ced07c2e2f4df50b1f61d4194",
+				"9290f38c5d07c2e2f4df57b1f61d4196",
+			},
+			"ENAM": {
+				"00920f38ce07c2e2f4df50b1f61d4194",
+			},
+		},
+		CountryPools: map[string][]string{
+			"US": {
+				"de90f38ced07c2e2f4df50b1f61d4194",
+			},
+			"GB": {
+				"abd90f38ced07c2e2f4df50b1f61d4194",
+			},
+		},
+		PopPools: map[string][]string{
+			"LAX": {
+				"de90f38ced07c2e2f4df50b1f61d4194",
+				"9290f38c5d07c2e2f4df57b1f61d4196",
+			},
+			"LHR": {
+				"abd90f38ced07c2e2f4df50b1f61d4194",
+				"f9138c5d07c2e2f4df57b1f61d4196",
+			},
+			"SJC": {
+				"00920f38ce07c2e2f4df50b1f61d4194",
+			},
+		},
+		RandomSteering: &RandomSteering{
+			DefaultWeight: 0.2,
+			PoolWeights: map[string]float64{
+				"9290f38c5d07c2e2f4df57b1f61d4196": 0.6,
+				"de90f38ced07c2e2f4df50b1f61d4194": 0.4,
+			},
+		},
+		AdaptiveRouting: &AdaptiveRouting{
+			FailoverAcrossPools: BoolPtr(true),
+		},
+		LocationStrategy: &LocationStrategy{
+			PreferECS: "always",
+			Mode:      "resolver_ip",
+		},
+		Rules: []*LoadBalancerRule{
+			{
+				Name:      "example rule",
+				Condition: "cf.load_balancer.region == \"SAF\"",
+				Overrides: LoadBalancerRuleOverrides{
+					RegionPools: map[string][]string{
+						"SAF": {"de90f38ced07c2e2f4df50b1f61d4194"},
+					},
+					AdaptiveRouting: &AdaptiveRouting{
+						FailoverAcrossPools: BoolPtr(false),
+					},
+					LocationStrategy: &LocationStrategy{
+						PreferECS: "never",
+						Mode:      "pop",
+					},
+				},
+			},
+		},
+		Proxied:        true,
+		Persistence:    "cookie",
+		PersistenceTTL: 5000,
+		SessionAffinityAttributes: &SessionAffinityAttributes{
+			SameSite:             "Strict",
+			Secure:               "Always",
+			DrainDuration:        60,
+			ZeroDowntimeFailover: "sticky",
+		},
+	}
+	request := LoadBalancer{
+		Description:  "Account Load Balancer",
+		TTL:          30,
+		FallbackPool: "17b5962d775c646f3f9725cbc7a53df4",
+		DefaultPools: []string{
+			"de90f38ced07c2e2f4df50b1f61d4194",
+			"9290f38c5d07c2e2f4df57b1f61d4196",
+			"00920f38ce07c2e2f4df50b1f61d4194",
+		},
+		RegionPools: map[string][]string{
+			"WNAM": {
+				"de90f38ced07c2e2f4df50b1f61d4194",
+				"9290f38c5d07c2e2f4df57b1f61d4196",
+			},
+			"ENAM": {
+				"00920f38ce07c2e2f4df50b1f61d4194",
+			},
+		},
+		CountryPools: map[string][]string{
+			"US": {
+				"de90f38ced07c2e2f4df50b1f61d4194",
+			},
+			"GB": {
+				"abd90f38ced07c2e2f4df50b1f61d4194",
+			},
+		},
+		PopPools: map[string][]string{
+			"LAX": {
+				"de90f38ced07c2e2f4df50b1f61d4194",
+				"9290f38c5d07c2e2f4df57b1f61d4196",
+			},
+			"LHR": {
+				"abd90f38ced07c2e2f4df50b1f61d4194",
+				"f9138c5d07c2e2f4df57b1f61d4196",
+			},
+			"SJC": {
+				"00920f38ce07c2e2f4df50b1f61d4194",
+			},
+		},
+		RandomSteering: &RandomSteering{
+			DefaultWeight: 0.2,
+			PoolWeights: map[string]float64{
+				"9290f38c5d07c2e2f4df57b1f61d4196": 0.6,
+				"de90f38ced07c2e2f4df50b1f61d4194": 0.4,
+			},
+		},
+		AdaptiveRouting: &AdaptiveRouting{
+			FailoverAcrossPools: BoolPtr(true),
+		},
+		LocationStrategy: &LocationStrategy{
+			PreferECS: "always",
+			Mode:      "resolver_ip",
+		},
+		Rules: []*LoadBalancerRule{
+			{
+				Name:      "example rule",
+				Condition: "cf.load_balancer.region == \"SAF\"",
+				Overrides: LoadBalancerRuleOverrides{
+					RegionPools: map[string][]string{
+						"SAF": {"de90f38ced07c2e2f4df50b1f61d4194"},
+					},
+					AdaptiveRouting: &AdaptiveRouting{
+						FailoverAcrossPools: BoolPtr(false),
+					},
+					LocationStrategy: &LocationStrategy{
+						PreferECS: "never",
+						Mode:      "pop",
+					},
+				},
+			},
+		},
+		Proxied:        true,
+		Persistence:    "cookie",
+		PersistenceTTL: 5000,
+		SessionAffinityAttributes: &SessionAffinityAttributes{
+			SameSite:             "Strict",
+			Secure:               "Always",
+			DrainDuration:        60,
+			ZeroDowntimeFailover: "sticky",
+		},
+	}
+
+	actual, err := client.CreateLoadBalancer(context.Background(), AccountIdentifier(testAccountID), CreateLoadBalancerParams{LoadBalancer: request})
+	if assert.NoError(t, err) {
+		assert.Equal(t, want, actual)
+	}
+}
+
+func TestListLoadBalancers(t *testing.T) {
+	setup()
+	defer teardown()
+
+	handler := func(w http.ResponseWriter, r *http.Request) {
+		assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method)
+		w.Header().Set("content-type", "application/json")
+		fmt.Fprint(w, `{
+            "success": true,
+            "errors": [],
+            "messages": [],
+            "result": [
+                {
+                    "id": "699d98642c564d2e855e9661899b7252",
+                    "created_on": "2014-01-01T05:20:00.12345Z",
+                    "modified_on": "2014-02-01T05:20:00.12345Z",
+                    "description": "Load Balancer for www.example.com",
+                    "name": "www.example.com",
+                    "ttl": 30,
+                    "fallback_pool": "17b5962d775c646f3f9725cbc7a53df4",
+                    "default_pools": [
+                      "de90f38ced07c2e2f4df50b1f61d4194",
+                      "9290f38c5d07c2e2f4df57b1f61d4196",
+                      "00920f38ce07c2e2f4df50b1f61d4194"
+                    ],
+                    "region_pools": {
+                      "WNAM": [
+                        "de90f38ced07c2e2f4df50b1f61d4194",
+                        "9290f38c5d07c2e2f4df57b1f61d4196"
+                      ],
+                      "ENAM": [
+                        "00920f38ce07c2e2f4df50b1f61d4194"
+                      ]
+                    },
+                    "country_pools": {
+                      "US": [
+                        "de90f38ced07c2e2f4df50b1f61d4194"
+                      ],
+                      "GB": [
+                        "abd90f38ced07c2e2f4df50b1f61d4194"
+                      ]
+                    },
+                    "pop_pools": {
+                      "LAX": [
+                        "de90f38ced07c2e2f4df50b1f61d4194",
+                        "9290f38c5d07c2e2f4df57b1f61d4196"
+                      ],
+                      "LHR": [
+                        "abd90f38ced07c2e2f4df50b1f61d4194",
+                        "f9138c5d07c2e2f4df57b1f61d4196"
+                      ],
+                      "SJC": [
+                        "00920f38ce07c2e2f4df50b1f61d4194"
+                      ]
+                    },
+                    "random_steering": {
+                        "default_weight": 0.2,
+                        "pool_weights": {
+                            "9290f38c5d07c2e2f4df57b1f61d4196": 0.6,
+                            "de90f38ced07c2e2f4df50b1f61d4194": 0.4
+                        }
+                    },
+					"adaptive_routing": {
+						"failover_across_pools": true
+					},
+					"location_strategy": {
+						"prefer_ecs": "always",
+						"mode": "resolver_ip"
+					},
+                    "proxied": true
+                }
+            ],
+            "result_info": {
+                "page": 1,
+                "per_page": 20,
+                "count": 1,
+                "total_count": 1
+            }
+        }`)
+	}
+
+	mux.HandleFunc("/zones/"+testZoneID+"/load_balancers", handler)
+	createdOn, _ := time.Parse(time.RFC3339, "2014-01-01T05:20:00.12345Z")
+	modifiedOn, _ := time.Parse(time.RFC3339, "2014-02-01T05:20:00.12345Z")
+	want := []LoadBalancer{
+		{
+			ID:           "699d98642c564d2e855e9661899b7252",
+			CreatedOn:    &createdOn,
+			ModifiedOn:   &modifiedOn,
+			Description:  "Load Balancer for www.example.com",
+			Name:         "www.example.com",
+			TTL:          30,
+			FallbackPool: "17b5962d775c646f3f9725cbc7a53df4",
+			DefaultPools: []string{
+				"de90f38ced07c2e2f4df50b1f61d4194",
+				"9290f38c5d07c2e2f4df57b1f61d4196",
+				"00920f38ce07c2e2f4df50b1f61d4194",
+			},
+			RegionPools: map[string][]string{
+				"WNAM": {
+					"de90f38ced07c2e2f4df50b1f61d4194",
+					"9290f38c5d07c2e2f4df57b1f61d4196",
+				},
+				"ENAM": {
+					"00920f38ce07c2e2f4df50b1f61d4194",
+				},
+			},
+			CountryPools: map[string][]string{
+				"US": {
+					"de90f38ced07c2e2f4df50b1f61d4194",
+				},
+				"GB": {
+					"abd90f38ced07c2e2f4df50b1f61d4194",
+				},
+			},
+			PopPools: map[string][]string{
+				"LAX": {
+					"de90f38ced07c2e2f4df50b1f61d4194",
+					"9290f38c5d07c2e2f4df57b1f61d4196",
+				},
+				"LHR": {
+					"abd90f38ced07c2e2f4df50b1f61d4194",
+					"f9138c5d07c2e2f4df57b1f61d4196",
+				},
+				"SJC": {
+					"00920f38ce07c2e2f4df50b1f61d4194",
+				},
+			},
+			RandomSteering: &RandomSteering{
+				DefaultWeight: 0.2,
+				PoolWeights: map[string]float64{
+					"9290f38c5d07c2e2f4df57b1f61d4196": 0.6,
+					"de90f38ced07c2e2f4df50b1f61d4194": 0.4,
+				},
+			},
+			AdaptiveRouting: &AdaptiveRouting{
+				FailoverAcrossPools: BoolPtr(true),
+			},
+			LocationStrategy: &LocationStrategy{
+				PreferECS: "always",
+				Mode:      "resolver_ip",
+			},
+			Proxied: true,
+		},
+	}
+
+	actual, err := client.ListLoadBalancers(context.Background(), ZoneIdentifier(testZoneID), ListLoadBalancerParams{})
+	if assert.NoError(t, err) {
+		assert.Equal(t, want, actual)
+	}
+}
+
+func TestListAccountLoadBalancers(t *testing.T) {
+	setup()
+	defer teardown()
+
+	handler := func(w http.ResponseWriter, r *http.Request) {
+		assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method)
+		w.Header().Set("content-type", "application/json")
+		fmt.Fprint(w, `{
+            "success": true,
+            "errors": [],
+            "messages": [],
+            "result": [
+                {
+                    "id": "699d98642c564d2e855e9661899b7252",
+                    "created_on": "2014-01-01T05:20:00.12345Z",
+                    "modified_on": "2014-02-01T05:20:00.12345Z",
+                    "description": "Account Load Balancer",
+                    "ttl": 30,
+                    "fallback_pool": "17b5962d775c646f3f9725cbc7a53df4",
+                    "default_pools": [
+                      "de90f38ced07c2e2f4df50b1f61d4194",
+                      "9290f38c5d07c2e2f4df57b1f61d4196",
+                      "00920f38ce07c2e2f4df50b1f61d4194"
+                    ],
+                    "region_pools": {
+                      "WNAM": [
+                        "de90f38ced07c2e2f4df50b1f61d4194",
+                        "9290f38c5d07c2e2f4df57b1f61d4196"
+                      ],
+                      "ENAM": [
+                        "00920f38ce07c2e2f4df50b1f61d4194"
+                      ]
+                    },
+                    "country_pools": {
+                      "US": [
+                        "de90f38ced07c2e2f4df50b1f61d4194"
+                      ],
+                      "GB": [
+                        "abd90f38ced07c2e2f4df50b1f61d4194"
+                      ]
+                    },
+                    "pop_pools": {
+                      "LAX": [
+                        "de90f38ced07c2e2f4df50b1f61d4194",
+                        "9290f38c5d07c2e2f4df57b1f61d4196"
+                      ],
+                      "LHR": [
+                        "abd90f38ced07c2e2f4df50b1f61d4194",
+                        "f9138c5d07c2e2f4df57b1f61d4196"
+                      ],
+                      "SJC": [
+                        "00920f38ce07c2e2f4df50b1f61d4194"
+                      ]
+                    },
+                    "random_steering": {
+                        "default_weight": 0.2,
+                        "pool_weights": {
+                            "9290f38c5d07c2e2f4df57b1f61d4196": 0.6,
+                            "de90f38ced07c2e2f4df50b1f61d4194": 0.4
+                        }
+                    },
+					"adaptive_routing": {
+						"failover_across_pools": true
+					},
+					"location_strategy": {
+						"prefer_ecs": "always",
+						"mode": "resolver_ip"
+					},
+                    "proxied": true
+                }
+            ],
+            "result_info": {
+                "page": 1,
+                "per_page": 20,
+                "count": 1,
+                "total_count": 1
+            }
+        }`)
+	}
+
+	mux.HandleFunc("/accounts/"+testAccountID+"/load_balancers", handler)
+	createdOn, _ := time.Parse(time.RFC3339, "2014-01-01T05:20:00.12345Z")
+	modifiedOn, _ := time.Parse(time.RFC3339, "2014-02-01T05:20:00.12345Z")
+	want := []LoadBalancer{
+		{
+			ID:           "699d98642c564d2e855e9661899b7252",
+			CreatedOn:    &createdOn,
+			ModifiedOn:   &modifiedOn,
+			Description:  "Account Load Balancer",
+			TTL:          30,
+			FallbackPool: "17b5962d775c646f3f9725cbc7a53df4",
+			DefaultPools: []string{
+				"de90f38ced07c2e2f4df50b1f61d4194",
+				"9290f38c5d07c2e2f4df57b1f61d4196",
+				"00920f38ce07c2e2f4df50b1f61d4194",
+			},
+			RegionPools: map[string][]string{
+				"WNAM": {
+					"de90f38ced07c2e2f4df50b1f61d4194",
+					"9290f38c5d07c2e2f4df57b1f61d4196",
+				},
+				"ENAM": {
+					"00920f38ce07c2e2f4df50b1f61d4194",
+				},
+			},
+			CountryPools: map[string][]string{
+				"US": {
+					"de90f38ced07c2e2f4df50b1f61d4194",
+				},
+				"GB": {
+					"abd90f38ced07c2e2f4df50b1f61d4194",
+				},
+			},
+			PopPools: map[string][]string{
+				"LAX": {
+					"de90f38ced07c2e2f4df50b1f61d4194",
+					"9290f38c5d07c2e2f4df57b1f61d4196",
+				},
+				"LHR": {
+					"abd90f38ced07c2e2f4df50b1f61d4194",
+					"f9138c5d07c2e2f4df57b1f61d4196",
+				},
+				"SJC": {
+					"00920f38ce07c2e2f4df50b1f61d4194",
+				},
+			},
+			RandomSteering: &RandomSteering{
+				DefaultWeight: 0.2,
+				PoolWeights: map[string]float64{
+					"9290f38c5d07c2e2f4df57b1f61d4196": 0.6,
+					"de90f38ced07c2e2f4df50b1f61d4194": 0.4,
+				},
+			},
+			AdaptiveRouting: &AdaptiveRouting{
+				FailoverAcrossPools: BoolPtr(true),
+			},
+			LocationStrategy: &LocationStrategy{
+				PreferECS: "always",
+				Mode:      "resolver_ip",
+			},
+			Proxied: true,
+		},
+	}
+
+	actual, err := client.ListLoadBalancers(context.Background(), AccountIdentifier(testAccountID), ListLoadBalancerParams{})
+	if assert.NoError(t, err) {
+		assert.Equal(t, want, actual)
+	}
+}
+
+func TestGetLoadBalancer(t *testing.T) {
+	setup()
+	defer teardown()
+
+	handler := func(w http.ResponseWriter, r *http.Request) {
+		assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method)
+		w.Header().Set("content-type", "application/json")
+		fmt.Fprint(w, `{
+            "success": true,
+            "errors": [],
+            "messages": [],
+            "result": {
+                "id": "699d98642c564d2e855e9661899b7252",
+                "created_on": "2014-01-01T05:20:00.12345Z",
+                "modified_on": "2014-02-01T05:20:00.12345Z",
+                "description": "Load Balancer for www.example.com",
+                "name": "www.example.com",
+                "ttl": 30,
+                "fallback_pool": "17b5962d775c646f3f9725cbc7a53df4",
+                "default_pools": [
+                  "de90f38ced07c2e2f4df50b1f61d4194",
+                  "9290f38c5d07c2e2f4df57b1f61d4196",
+                  "00920f38ce07c2e2f4df50b1f61d4194"
+                ],
+                "region_pools": {
+                  "WNAM": [
+                    "de90f38ced07c2e2f4df50b1f61d4194",
+                    "9290f38c5d07c2e2f4df57b1f61d4196"
+                  ],
+                  "ENAM": [
+                    "00920f38ce07c2e2f4df50b1f61d4194"
+                  ]
+                },
+                "country_pools": {
+                  "US": [
+                    "de90f38ced07c2e2f4df50b1f61d4194"
+                  ],
+                  "GB": [
+                    "abd90f38ced07c2e2f4df50b1f61d4194"
+                  ]
+                },
+                "pop_pools": {
+                  "LAX": [
+                    "de90f38ced07c2e2f4df50b1f61d4194",
+                    "9290f38c5d07c2e2f4df57b1f61d4196"
+                  ],
+                  "LHR": [
+                    "abd90f38ced07c2e2f4df50b1f61d4194",
+                    "f9138c5d07c2e2f4df57b1f61d4196"
+                  ],
+                  "SJC": [
+                    "00920f38ce07c2e2f4df50b1f61d4194"
+                  ]
+                },
+                "random_steering": {
+                    "default_weight": 0.2,
+                    "pool_weights": {
+                        "9290f38c5d07c2e2f4df57b1f61d4196": 0.6,
+                        "de90f38ced07c2e2f4df50b1f61d4194": 0.4
+                    }
+                },
+				"adaptive_routing": {
+					"failover_across_pools": true
+				},
+				"location_strategy": {
+					"prefer_ecs": "always",
+					"mode": "resolver_ip"
+				},
+                "proxied": true
+            }
+        }`)
+	}
+
+	mux.HandleFunc("/zones/"+testZoneID+"/load_balancers/699d98642c564d2e855e9661899b7252", handler)
+	createdOn, _ := time.Parse(time.RFC3339, "2014-01-01T05:20:00.12345Z")
+	modifiedOn, _ := time.Parse(time.RFC3339, "2014-02-01T05:20:00.12345Z")
+	want := LoadBalancer{
+		ID:           "699d98642c564d2e855e9661899b7252",
+		CreatedOn:    &createdOn,
+		ModifiedOn:   &modifiedOn,
+		Description:  "Load Balancer for www.example.com",
+		Name:         "www.example.com",
+		TTL:          30,
+		FallbackPool: "17b5962d775c646f3f9725cbc7a53df4",
+		DefaultPools: []string{
+			"de90f38ced07c2e2f4df50b1f61d4194",
+			"9290f38c5d07c2e2f4df57b1f61d4196",
+			"00920f38ce07c2e2f4df50b1f61d4194",
+		},
+		RegionPools: map[string][]string{
+			"WNAM": {
+				"de90f38ced07c2e2f4df50b1f61d4194",
+				"9290f38c5d07c2e2f4df57b1f61d4196",
+			},
+			"ENAM": {
+				"00920f38ce07c2e2f4df50b1f61d4194",
+			},
+		},
+		CountryPools: map[string][]string{
+			"US": {
+				"de90f38ced07c2e2f4df50b1f61d4194",
+			},
+			"GB": {
+				"abd90f38ced07c2e2f4df50b1f61d4194",
+			},
+		},
+		PopPools: map[string][]string{
+			"LAX": {
+				"de90f38ced07c2e2f4df50b1f61d4194",
+				"9290f38c5d07c2e2f4df57b1f61d4196",
+			},
+			"LHR": {
+				"abd90f38ced07c2e2f4df50b1f61d4194",
+				"f9138c5d07c2e2f4df57b1f61d4196",
+			},
+			"SJC": {
+				"00920f38ce07c2e2f4df50b1f61d4194",
+			},
+		},
+		RandomSteering: &RandomSteering{
+			DefaultWeight: 0.2,
+			PoolWeights: map[string]float64{
+				"9290f38c5d07c2e2f4df57b1f61d4196": 0.6,
+				"de90f38ced07c2e2f4df50b1f61d4194": 0.4,
+			},
+		},
+		AdaptiveRouting: &AdaptiveRouting{
+			FailoverAcrossPools: BoolPtr(true),
+		},
+		LocationStrategy: &LocationStrategy{
+			PreferECS: "always",
+			Mode:      "resolver_ip",
+		},
+		Proxied: true,
+	}
+
+	actual, err := client.GetLoadBalancer(context.Background(), ZoneIdentifier(testZoneID), "699d98642c564d2e855e9661899b7252")
+	if assert.NoError(t, err) {
+		assert.Equal(t, want, actual)
 	}
+
+	_, err = client.GetLoadBalancer(context.Background(), ZoneIdentifier(testZoneID), "bar")
+	assert.Error(t, err)
 }
 
-func TestListLoadBalancers(t *testing.T) {
+func TestGetAccountLoadBalancer(t *testing.T) {
 	setup()
 	defer teardown()
 
@@ -1470,164 +2268,250 @@ func TestListLoadBalancers(t *testing.T) {
             "success": true,
             "errors": [],
             "messages": [],
-            "result": [
-                {
-                    "id": "699d98642c564d2e855e9661899b7252",
-                    "created_on": "2014-01-01T05:20:00.12345Z",
-                    "modified_on": "2014-02-01T05:20:00.12345Z",
-                    "description": "Load Balancer for www.example.com",
-                    "name": "www.example.com",
-                    "ttl": 30,
-                    "fallback_pool": "17b5962d775c646f3f9725cbc7a53df4",
-                    "default_pools": [
-                      "de90f38ced07c2e2f4df50b1f61d4194",
-                      "9290f38c5d07c2e2f4df57b1f61d4196",
-                      "00920f38ce07c2e2f4df50b1f61d4194"
-                    ],
-                    "region_pools": {
-                      "WNAM": [
-                        "de90f38ced07c2e2f4df50b1f61d4194",
-                        "9290f38c5d07c2e2f4df57b1f61d4196"
-                      ],
-                      "ENAM": [
-                        "00920f38ce07c2e2f4df50b1f61d4194"
-                      ]
-                    },
-                    "country_pools": {
-                      "US": [
-                        "de90f38ced07c2e2f4df50b1f61d4194"
-                      ],
-                      "GB": [
-                        "abd90f38ced07c2e2f4df50b1f61d4194"
-                      ]
-                    },
-                    "pop_pools": {
-                      "LAX": [
-                        "de90f38ced07c2e2f4df50b1f61d4194",
-                        "9290f38c5d07c2e2f4df57b1f61d4196"
-                      ],
-                      "LHR": [
-                        "abd90f38ced07c2e2f4df50b1f61d4194",
-                        "f9138c5d07c2e2f4df57b1f61d4196"
-                      ],
-                      "SJC": [
-                        "00920f38ce07c2e2f4df50b1f61d4194"
-                      ]
-                    },
-                    "random_steering": {
-                        "default_weight": 0.2,
-                        "pool_weights": {
-                            "9290f38c5d07c2e2f4df57b1f61d4196": 0.6,
-                            "de90f38ced07c2e2f4df50b1f61d4194": 0.4
-                        }
-                    },
-					"adaptive_routing": {
-						"failover_across_pools": true
-					},
-					"location_strategy": {
-						"prefer_ecs": "always",
-						"mode": "resolver_ip"
-					},
-                    "proxied": true
-                }
-            ],
-            "result_info": {
-                "page": 1,
-                "per_page": 20,
-                "count": 1,
-                "total_count": 1
+            "result": {
+                "id": "699d98642c564d2e855e9661899b7252",
+                "created_on": "2014-01-01T05:20:00.12345Z",
+                "modified_on": "2014-02-01T05:20:00.12345Z",
+                "description": "Account Load Balancer",
+                "ttl": 30,
+                "fallback_pool": "17b5962d775c646f3f9725cbc7a53df4",
+                "default_pools": [
+                  "de90f38ced07c2e2f4df50b1f61d4194",
+                  "9290f38c5d07c2e2f4df57b1f61d4196",
+                  "00920f38ce07c2e2f4df50b1f61d4194"
+                ],
+                "region_pools": {
+                  "WNAM": [
+                    "de90f38ced07c2e2f4df50b1f61d4194",
+                    "9290f38c5d07c2e2f4df57b1f61d4196"
+                  ],
+                  "ENAM": [
+                    "00920f38ce07c2e2f4df50b1f61d4194"
+                  ]
+                },
+                "country_pools": {
+                  "US": [
+                    "de90f38ced07c2e2f4df50b1f61d4194"
+                  ],
+                  "GB": [
+                    "abd90f38ced07c2e2f4df50b1f61d4194"
+                  ]
+                },
+                "pop_pools": {
+                  "LAX": [
+                    "de90f38ced07c2e2f4df50b1f61d4194",
+                    "9290f38c5d07c2e2f4df57b1f61d4196"
+                  ],
+                  "LHR": [
+                    "abd90f38ced07c2e2f4df50b1f61d4194",
+                    "f9138c5d07c2e2f4df57b1f61d4196"
+                  ],
+                  "SJC": [
+                    "00920f38ce07c2e2f4df50b1f61d4194"
+                  ]
+                },
+                "random_steering": {
+                    "default_weight": 0.2,
+                    "pool_weights": {
+                        "9290f38c5d07c2e2f4df57b1f61d4196": 0.6,
+                        "de90f38ced07c2e2f4df50b1f61d4194": 0.4
+                    }
+                },
+				"adaptive_routing": {
+					"failover_across_pools": true
+				},
+				"location_strategy": {
+					"prefer_ecs": "always",
+					"mode": "resolver_ip"
+				},
+                "proxied": true
             }
         }`)
 	}
 
-	mux.HandleFunc("/zones/"+testZoneID+"/load_balancers", handler)
+	mux.HandleFunc("/accounts/"+testAccountID+"/load_balancers/699d98642c564d2e855e9661899b7252", handler)
 	createdOn, _ := time.Parse(time.RFC3339, "2014-01-01T05:20:00.12345Z")
 	modifiedOn, _ := time.Parse(time.RFC3339, "2014-02-01T05:20:00.12345Z")
-	want := []LoadBalancer{
-		{
-			ID:           "699d98642c564d2e855e9661899b7252",
-			CreatedOn:    &createdOn,
-			ModifiedOn:   &modifiedOn,
-			Description:  "Load Balancer for www.example.com",
-			Name:         "www.example.com",
-			TTL:          30,
-			FallbackPool: "17b5962d775c646f3f9725cbc7a53df4",
-			DefaultPools: []string{
+	want := LoadBalancer{
+		ID:           "699d98642c564d2e855e9661899b7252",
+		CreatedOn:    &createdOn,
+		ModifiedOn:   &modifiedOn,
+		Description:  "Account Load Balancer",
+		TTL:          30,
+		FallbackPool: "17b5962d775c646f3f9725cbc7a53df4",
+		DefaultPools: []string{
+			"de90f38ced07c2e2f4df50b1f61d4194",
+			"9290f38c5d07c2e2f4df57b1f61d4196",
+			"00920f38ce07c2e2f4df50b1f61d4194",
+		},
+		RegionPools: map[string][]string{
+			"WNAM": {
 				"de90f38ced07c2e2f4df50b1f61d4194",
 				"9290f38c5d07c2e2f4df57b1f61d4196",
+			},
+			"ENAM": {
 				"00920f38ce07c2e2f4df50b1f61d4194",
 			},
-			RegionPools: map[string][]string{
-				"WNAM": {
-					"de90f38ced07c2e2f4df50b1f61d4194",
-					"9290f38c5d07c2e2f4df57b1f61d4196",
-				},
-				"ENAM": {
-					"00920f38ce07c2e2f4df50b1f61d4194",
-				},
+		},
+		CountryPools: map[string][]string{
+			"US": {
+				"de90f38ced07c2e2f4df50b1f61d4194",
 			},
-			CountryPools: map[string][]string{
-				"US": {
-					"de90f38ced07c2e2f4df50b1f61d4194",
-				},
-				"GB": {
-					"abd90f38ced07c2e2f4df50b1f61d4194",
-				},
+			"GB": {
+				"abd90f38ced07c2e2f4df50b1f61d4194",
 			},
-			PopPools: map[string][]string{
-				"LAX": {
-					"de90f38ced07c2e2f4df50b1f61d4194",
-					"9290f38c5d07c2e2f4df57b1f61d4196",
-				},
-				"LHR": {
-					"abd90f38ced07c2e2f4df50b1f61d4194",
-					"f9138c5d07c2e2f4df57b1f61d4196",
-				},
-				"SJC": {
-					"00920f38ce07c2e2f4df50b1f61d4194",
-				},
+		},
+		PopPools: map[string][]string{
+			"LAX": {
+				"de90f38ced07c2e2f4df50b1f61d4194",
+				"9290f38c5d07c2e2f4df57b1f61d4196",
 			},
-			RandomSteering: &RandomSteering{
-				DefaultWeight: 0.2,
-				PoolWeights: map[string]float64{
-					"9290f38c5d07c2e2f4df57b1f61d4196": 0.6,
-					"de90f38ced07c2e2f4df50b1f61d4194": 0.4,
-				},
+			"LHR": {
+				"abd90f38ced07c2e2f4df50b1f61d4194",
+				"f9138c5d07c2e2f4df57b1f61d4196",
 			},
-			AdaptiveRouting: &AdaptiveRouting{
-				FailoverAcrossPools: BoolPtr(true),
+			"SJC": {
+				"00920f38ce07c2e2f4df50b1f61d4194",
 			},
-			LocationStrategy: &LocationStrategy{
-				PreferECS: "always",
-				Mode:      "resolver_ip",
+		},
+		RandomSteering: &RandomSteering{
+			DefaultWeight: 0.2,
+			PoolWeights: map[string]float64{
+				"9290f38c5d07c2e2f4df57b1f61d4196": 0.6,
+				"de90f38ced07c2e2f4df50b1f61d4194": 0.4,
 			},
-			Proxied: true,
 		},
+		AdaptiveRouting: &AdaptiveRouting{
+			FailoverAcrossPools: BoolPtr(true),
+		},
+		LocationStrategy: &LocationStrategy{
+			PreferECS: "always",
+			Mode:      "resolver_ip",
+		},
+		Proxied: true,
+	}
+
+	actual, err := client.GetLoadBalancer(context.Background(), AccountIdentifier(testAccountID), "699d98642c564d2e855e9661899b7252")
+	if assert.NoError(t, err) {
+		assert.Equal(t, want, actual)
+	}
+
+	_, err = client.GetLoadBalancer(context.Background(), AccountIdentifier(testAccountID), "bar")
+	assert.Error(t, err)
+}
+
+func TestDeleteLoadBalancer(t *testing.T) {
+	setup()
+	defer teardown()
+
+	handler := func(w http.ResponseWriter, r *http.Request) {
+		assert.Equal(t, http.MethodDelete, r.Method, "Expected method 'DELETE', got %s", r.Method)
+		w.Header().Set("content-type", "application/json")
+		fmt.Fprint(w, `{
+            "success": true,
+            "errors": [],
+            "messages": [],
+            "result": {
+              "id": "699d98642c564d2e855e9661899b7252"
+            }
+        }`)
 	}
 
-	actual, err := client.ListLoadBalancers(context.Background(), ZoneIdentifier(testZoneID), ListLoadBalancerParams{})
-	if assert.NoError(t, err) {
-		assert.Equal(t, want, actual)
-	}
+	mux.HandleFunc("/zones/"+testZoneID+"/load_balancers/699d98642c564d2e855e9661899b7252", handler)
+	assert.NoError(t, client.DeleteLoadBalancer(context.Background(), ZoneIdentifier(testZoneID), "699d98642c564d2e855e9661899b7252"))
+	assert.Error(t, client.DeleteLoadBalancer(context.Background(), ZoneIdentifier(testZoneID), "bar"))
 }
 
-func TestListLoadBalancer_AccountIsNotSupported(t *testing.T) {
+func TestDeleteAccountLoadBalancer(t *testing.T) {
 	setup()
 	defer teardown()
 
-	_, err := client.ListLoadBalancers(context.Background(), AccountIdentifier(testAccountID), ListLoadBalancerParams{})
-	if assert.Error(t, err) {
-		assert.Equal(t, fmt.Sprintf(errInvalidResourceContainerAccess, AccountRouteLevel), err.Error())
+	handler := func(w http.ResponseWriter, r *http.Request) {
+		assert.Equal(t, http.MethodDelete, r.Method, "Expected method 'DELETE', got %s", r.Method)
+		w.Header().Set("content-type", "application/json")
+		fmt.Fprint(w, `{
+            "success": true,
+            "errors": [],
+            "messages": [],
+            "result": {
+              "id": "699d98642c564d2e855e9661899b7252"
+            }
+        }`)
 	}
+
+	mux.HandleFunc("/accounts/"+testAccountID+"/load_balancers/699d98642c564d2e855e9661899b7252", handler)
+	assert.NoError(t, client.DeleteLoadBalancer(context.Background(), AccountIdentifier(testAccountID), "699d98642c564d2e855e9661899b7252"))
+	assert.Error(t, client.DeleteLoadBalancer(context.Background(), AccountIdentifier(testAccountID), "bar"))
 }
 
-func TestGetLoadBalancer(t *testing.T) {
+func TestUpdateLoadBalancer(t *testing.T) {
 	setup()
 	defer teardown()
 
 	handler := func(w http.ResponseWriter, r *http.Request) {
-		assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method)
+		assert.Equal(t, http.MethodPut, r.Method, "Expected method 'PUT', got %s", r.Method)
 		w.Header().Set("content-type", "application/json")
+		b, err := io.ReadAll(r.Body)
+		defer r.Body.Close()
+		if assert.NoError(t, err) {
+			assert.JSONEq(t, `{
+                "id": "699d98642c564d2e855e9661899b7252",
+                "description": "Load Balancer for www.example.com",
+                "name": "www.example.com",
+                "ttl": 30,
+                "fallback_pool": "17b5962d775c646f3f9725cbc7a53df4",
+                "default_pools": [
+                  "00920f38ce07c2e2f4df50b1f61d4194"
+                ],
+                "region_pools": {
+                  "WNAM": [
+                    "9290f38c5d07c2e2f4df57b1f61d4196"
+                  ],
+                  "ENAM": [
+                    "00920f38ce07c2e2f4df50b1f61d4194"
+                  ]
+                },
+                "country_pools": {
+                  "US": [
+                    "de90f38ced07c2e2f4df50b1f61d4194"
+                  ],
+                  "GB": [
+                    "f9138c5d07c2e2f4df57b1f61d4196"
+                  ]
+                },
+                "pop_pools": {
+                  "LAX": [
+                    "9290f38c5d07c2e2f4df57b1f61d4196"
+                  ],
+                  "LHR": [
+                    "f9138c5d07c2e2f4df57b1f61d4196"
+                  ],
+                  "SJC": [
+                    "00920f38ce07c2e2f4df50b1f61d4194"
+                  ]
+                },
+                "random_steering": {
+                    "default_weight": 0.5,
+                    "pool_weights": {
+                        "9290f38c5d07c2e2f4df57b1f61d4196": 0.2
+                    }
+                },
+				"adaptive_routing": {
+					"failover_across_pools": false
+				},
+				"location_strategy": {
+					"prefer_ecs": "never",
+					"mode": "pop"
+				},
+                "proxied": true,
+                "session_affinity": "none",
+                "session_affinity_attributes": {
+                  "samesite": "Strict",
+                  "secure": "Always",
+				  "zero_downtime_failover": "sticky"
+                }
+			}`, string(b))
+		}
 		fmt.Fprint(w, `{
             "success": true,
             "errors": [],
@@ -1635,19 +2519,16 @@ func TestGetLoadBalancer(t *testing.T) {
             "result": {
                 "id": "699d98642c564d2e855e9661899b7252",
                 "created_on": "2014-01-01T05:20:00.12345Z",
-                "modified_on": "2014-02-01T05:20:00.12345Z",
+                "modified_on": "2017-02-01T05:20:00.12345Z",
                 "description": "Load Balancer for www.example.com",
                 "name": "www.example.com",
                 "ttl": 30,
                 "fallback_pool": "17b5962d775c646f3f9725cbc7a53df4",
                 "default_pools": [
-                  "de90f38ced07c2e2f4df50b1f61d4194",
-                  "9290f38c5d07c2e2f4df57b1f61d4196",
                   "00920f38ce07c2e2f4df50b1f61d4194"
                 ],
                 "region_pools": {
                   "WNAM": [
-                    "de90f38ced07c2e2f4df50b1f61d4194",
                     "9290f38c5d07c2e2f4df57b1f61d4196"
                   ],
                   "ENAM": [
@@ -1659,16 +2540,14 @@ func TestGetLoadBalancer(t *testing.T) {
                     "de90f38ced07c2e2f4df50b1f61d4194"
                   ],
                   "GB": [
-                    "abd90f38ced07c2e2f4df50b1f61d4194"
+                    "f9138c5d07c2e2f4df57b1f61d4196"
                   ]
                 },
                 "pop_pools": {
                   "LAX": [
-                    "de90f38ced07c2e2f4df50b1f61d4194",
                     "9290f38c5d07c2e2f4df57b1f61d4196"
                   ],
                   "LHR": [
-                    "abd90f38ced07c2e2f4df50b1f61d4194",
                     "f9138c5d07c2e2f4df57b1f61d4196"
                   ],
                   "SJC": [
@@ -1676,27 +2555,32 @@ func TestGetLoadBalancer(t *testing.T) {
                   ]
                 },
                 "random_steering": {
-                    "default_weight": 0.2,
+                    "default_weight": 0.5,
                     "pool_weights": {
-                        "9290f38c5d07c2e2f4df57b1f61d4196": 0.6,
-                        "de90f38ced07c2e2f4df50b1f61d4194": 0.4
+                        "9290f38c5d07c2e2f4df57b1f61d4196": 0.2
                     }
                 },
 				"adaptive_routing": {
-					"failover_across_pools": true
+					"failover_across_pools": false
 				},
 				"location_strategy": {
-					"prefer_ecs": "always",
-					"mode": "resolver_ip"
+					"prefer_ecs": "never",
+					"mode": "pop"
 				},
-                "proxied": true
+                "proxied": true,
+                "session_affinity": "none",
+                "session_affinity_attributes": {
+                  "samesite": "Strict",
+                  "secure": "Always",
+	              "zero_downtime_failover": "sticky"
+                }
             }
         }`)
 	}
 
 	mux.HandleFunc("/zones/"+testZoneID+"/load_balancers/699d98642c564d2e855e9661899b7252", handler)
 	createdOn, _ := time.Parse(time.RFC3339, "2014-01-01T05:20:00.12345Z")
-	modifiedOn, _ := time.Parse(time.RFC3339, "2014-02-01T05:20:00.12345Z")
+	modifiedOn, _ := time.Parse(time.RFC3339, "2017-02-01T05:20:00.12345Z")
 	want := LoadBalancer{
 		ID:           "699d98642c564d2e855e9661899b7252",
 		CreatedOn:    &createdOn,
@@ -1706,13 +2590,10 @@ func TestGetLoadBalancer(t *testing.T) {
 		TTL:          30,
 		FallbackPool: "17b5962d775c646f3f9725cbc7a53df4",
 		DefaultPools: []string{
-			"de90f38ced07c2e2f4df50b1f61d4194",
-			"9290f38c5d07c2e2f4df57b1f61d4196",
 			"00920f38ce07c2e2f4df50b1f61d4194",
 		},
 		RegionPools: map[string][]string{
 			"WNAM": {
-				"de90f38ced07c2e2f4df50b1f61d4194",
 				"9290f38c5d07c2e2f4df57b1f61d4196",
 			},
 			"ENAM": {
@@ -1724,16 +2605,71 @@ func TestGetLoadBalancer(t *testing.T) {
 				"de90f38ced07c2e2f4df50b1f61d4194",
 			},
 			"GB": {
-				"abd90f38ced07c2e2f4df50b1f61d4194",
+				"f9138c5d07c2e2f4df57b1f61d4196",
 			},
 		},
 		PopPools: map[string][]string{
 			"LAX": {
+				"9290f38c5d07c2e2f4df57b1f61d4196",
+			},
+			"LHR": {
+				"f9138c5d07c2e2f4df57b1f61d4196",
+			},
+			"SJC": {
+				"00920f38ce07c2e2f4df50b1f61d4194",
+			},
+		},
+		RandomSteering: &RandomSteering{
+			DefaultWeight: 0.5,
+			PoolWeights: map[string]float64{
+				"9290f38c5d07c2e2f4df57b1f61d4196": 0.2,
+			},
+		},
+		AdaptiveRouting: &AdaptiveRouting{
+			FailoverAcrossPools: BoolPtr(false),
+		},
+		LocationStrategy: &LocationStrategy{
+			PreferECS: "never",
+			Mode:      "pop",
+		},
+		Proxied:     true,
+		Persistence: "none",
+		SessionAffinityAttributes: &SessionAffinityAttributes{
+			SameSite:             "Strict",
+			Secure:               "Always",
+			ZeroDowntimeFailover: "sticky",
+		},
+	}
+	request := LoadBalancer{
+		ID:           "699d98642c564d2e855e9661899b7252",
+		Description:  "Load Balancer for www.example.com",
+		Name:         "www.example.com",
+		TTL:          30,
+		FallbackPool: "17b5962d775c646f3f9725cbc7a53df4",
+		DefaultPools: []string{
+			"00920f38ce07c2e2f4df50b1f61d4194",
+		},
+		RegionPools: map[string][]string{
+			"WNAM": {
+				"9290f38c5d07c2e2f4df57b1f61d4196",
+			},
+			"ENAM": {
+				"00920f38ce07c2e2f4df50b1f61d4194",
+			},
+		},
+		CountryPools: map[string][]string{
+			"US": {
 				"de90f38ced07c2e2f4df50b1f61d4194",
+			},
+			"GB": {
+				"f9138c5d07c2e2f4df57b1f61d4196",
+			},
+		},
+		PopPools: map[string][]string{
+			"LAX": {
 				"9290f38c5d07c2e2f4df57b1f61d4196",
 			},
 			"LHR": {
-				"abd90f38ced07c2e2f4df50b1f61d4194",
 				"f9138c5d07c2e2f4df57b1f61d4196",
 			},
 			"SJC": {
@@ -1741,74 +2677,34 @@ func TestGetLoadBalancer(t *testing.T) {
 			},
 		},
 		RandomSteering: &RandomSteering{
-			DefaultWeight: 0.2,
+			DefaultWeight: 0.5,
 			PoolWeights: map[string]float64{
-				"9290f38c5d07c2e2f4df57b1f61d4196": 0.6,
-				"de90f38ced07c2e2f4df50b1f61d4194": 0.4,
+				"9290f38c5d07c2e2f4df57b1f61d4196": 0.2,
 			},
 		},
 		AdaptiveRouting: &AdaptiveRouting{
-			FailoverAcrossPools: BoolPtr(true),
+			FailoverAcrossPools: BoolPtr(false),
 		},
 		LocationStrategy: &LocationStrategy{
-			PreferECS: "always",
-			Mode:      "resolver_ip",
+			PreferECS: "never",
+			Mode:      "pop",
+		},
+		Proxied:     true,
+		Persistence: "none",
+		SessionAffinityAttributes: &SessionAffinityAttributes{
+			SameSite:             "Strict",
+			Secure:               "Always",
+			ZeroDowntimeFailover: "sticky",
 		},
-		Proxied: true,
 	}
 
-	actual, err := client.GetLoadBalancer(context.Background(), ZoneIdentifier(testZoneID), "699d98642c564d2e855e9661899b7252")
+	actual, err := client.UpdateLoadBalancer(context.Background(), ZoneIdentifier(testZoneID), UpdateLoadBalancerParams{LoadBalancer: request})
 	if assert.NoError(t, err) {
 		assert.Equal(t, want, actual)
 	}
-
-	_, err = client.GetLoadBalancer(context.Background(), ZoneIdentifier(testZoneID), "bar")
-	assert.Error(t, err)
-}
-
-func TestGetLoadBalancer_AccountIsNotSupported(t *testing.T) {
-	setup()
-	defer teardown()
-
-	_, err := client.GetLoadBalancer(context.Background(), AccountIdentifier(testAccountID), "foo")
-	if assert.Error(t, err) {
-		assert.Equal(t, fmt.Sprintf(errInvalidResourceContainerAccess, AccountRouteLevel), err.Error())
-	}
-}
-
-func TestDeleteLoadBalancer(t *testing.T) {
-	setup()
-	defer teardown()
-
-	handler := func(w http.ResponseWriter, r *http.Request) {
-		assert.Equal(t, http.MethodDelete, r.Method, "Expected method 'DELETE', got %s", r.Method)
-		w.Header().Set("content-type", "application/json")
-		fmt.Fprint(w, `{
-            "success": true,
-            "errors": [],
-            "messages": [],
-            "result": {
-              "id": "699d98642c564d2e855e9661899b7252"
-            }
-        }`)
-	}
-
-	mux.HandleFunc("/zones/"+testZoneID+"/load_balancers/699d98642c564d2e855e9661899b7252", handler)
-	assert.NoError(t, client.DeleteLoadBalancer(context.Background(), ZoneIdentifier(testZoneID), "699d98642c564d2e855e9661899b7252"))
-	assert.Error(t, client.DeleteLoadBalancer(context.Background(), ZoneIdentifier(testZoneID), "bar"))
-}
-
-func TestDeleteLoadBalancer_AccountIsNotSupported(t *testing.T) {
-	setup()
-	defer teardown()
-
-	err := client.DeleteLoadBalancer(context.Background(), AccountIdentifier(testAccountID), "foo")
-	if assert.Error(t, err) {
-		assert.Equal(t, fmt.Sprintf(errInvalidResourceContainerAccess, AccountRouteLevel), err.Error())
-	}
 }
 
-func TestUpdateLoadBalancer(t *testing.T) {
+func TestUpdateAccountLoadBalancer(t *testing.T) {
 	setup()
 	defer teardown()
 
@@ -1820,8 +2716,7 @@ func TestUpdateLoadBalancer(t *testing.T) {
 		if assert.NoError(t, err) {
 			assert.JSONEq(t, `{
                 "id": "699d98642c564d2e855e9661899b7252",
-                "description": "Load Balancer for www.example.com",
-                "name": "www.example.com",
+                "description": "Account Load Balancer",
                 "ttl": 30,
                 "fallback_pool": "17b5962d775c646f3f9725cbc7a53df4",
                 "default_pools": [
@@ -1884,8 +2779,7 @@ func TestUpdateLoadBalancer(t *testing.T) {
                 "id": "699d98642c564d2e855e9661899b7252",
                 "created_on": "2014-01-01T05:20:00.12345Z",
                 "modified_on": "2017-02-01T05:20:00.12345Z",
-                "description": "Load Balancer for www.example.com",
-                "name": "www.example.com",
+                "description": "Account Load Balancer",
                 "ttl": 30,
                 "fallback_pool": "17b5962d775c646f3f9725cbc7a53df4",
                 "default_pools": [
@@ -1942,15 +2836,14 @@ func TestUpdateLoadBalancer(t *testing.T) {
         }`)
 	}
 
-	mux.HandleFunc("/zones/"+testZoneID+"/load_balancers/699d98642c564d2e855e9661899b7252", handler)
+	mux.HandleFunc("/accounts/"+testAccountID+"/load_balancers/699d98642c564d2e855e9661899b7252", handler)
 	createdOn, _ := time.Parse(time.RFC3339, "2014-01-01T05:20:00.12345Z")
 	modifiedOn, _ := time.Parse(time.RFC3339, "2017-02-01T05:20:00.12345Z")
 	want := LoadBalancer{
 		ID:           "699d98642c564d2e855e9661899b7252",
 		CreatedOn:    &createdOn,
 		ModifiedOn:   &modifiedOn,
-		Description:  "Load Balancer for www.example.com",
-		Name:         "www.example.com",
+		Description:  "Account Load Balancer",
 		TTL:          30,
 		FallbackPool: "17b5962d775c646f3f9725cbc7a53df4",
 		DefaultPools: []string{
@@ -2006,8 +2899,7 @@ func TestUpdateLoadBalancer(t *testing.T) {
 	}
 	request := LoadBalancer{
 		ID:           "699d98642c564d2e855e9661899b7252",
-		Description:  "Load Balancer for www.example.com",
-		Name:         "www.example.com",
+		Description:  "Account Load Balancer",
 		TTL:          30,
 		FallbackPool: "17b5962d775c646f3f9725cbc7a53df4",
 		DefaultPools: []string{
@@ -2062,22 +2954,12 @@ func TestUpdateLoadBalancer(t *testing.T) {
 		},
 	}
 
-	actual, err := client.UpdateLoadBalancer(context.Background(), ZoneIdentifier(testZoneID), UpdateLoadBalancerParams{LoadBalancer: request})
+	actual, err := client.UpdateLoadBalancer(context.Background(), AccountIdentifier(testAccountID), UpdateLoadBalancerParams{LoadBalancer: request})
 	if assert.NoError(t, err) {
 		assert.Equal(t, want, actual)
 	}
 }
 
-func TestUpdateLoadBalancer_AccountIsNotSupported(t *testing.T) {
-	setup()
-	defer teardown()
-
-	_, err := client.UpdateLoadBalancer(context.Background(), AccountIdentifier(testAccountID), UpdateLoadBalancerParams{LoadBalancer: LoadBalancer{}})
-	if assert.Error(t, err) {
-		assert.Equal(t, fmt.Sprintf(errInvalidResourceContainerAccess, AccountRouteLevel), err.Error())
-	}
-}
-
 func TestLoadBalancerPoolHealthDetails(t *testing.T) {
 	setup()
 	defer teardown()