Skip to content

Commit

Permalink
Add config options for creating global load balancers (#1521)
Browse files Browse the repository at this point in the history
* Vendor godo v1.111.0

* Support global lb configurations

* Adjust for pr feedback

- use string slice for parsing
- update help text for new flags

* Add beta release note in the helper text

* Add integration test cases

---------

Co-authored-by: Andrew Starr-Bochicchio <[email protected]>
  • Loading branch information
asaha2 and andrewsomething authored Apr 10, 2024
1 parent 6a03256 commit 26a3f33
Show file tree
Hide file tree
Showing 48 changed files with 859 additions and 14 deletions.
8 changes: 8 additions & 0 deletions args.go
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,14 @@ const (
ArgDenyList = "deny-list"
// ArgLoadBalancerType is the type of the load balancer.
ArgLoadBalancerType = "type"
// ArgLoadBalancerDomains is list of domains supported for global load balancer.
ArgLoadBalancerDomains = "domains"
// ArgGlobalLoadBalancerSettings is global load balancer settings.
ArgGlobalLoadBalancerSettings = "glb-settings"
// ArgGlobalLoadBalancerCDNSettings is global load balancer CDN settings.
ArgGlobalLoadBalancerCDNSettings = "glb-cdn-settings"
// ArgTargetLoadBalancerIDs is a list of target load balancer IDs.
ArgTargetLoadBalancerIDs = "target-lb-ids"

// ArgFirewallName is a name of the firewall.
ArgFirewallName = "name"
Expand Down
4 changes: 3 additions & 1 deletion commands/displayers/load_balancer.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ func (lb *LoadBalancer) KV() []map[string]any {
"Name": l.Name,
"Status": l.Status,
"Created": l.Created,
"Region": l.Region.Slug,
"VPCUUID": l.VPCUUID,
"Tag": l.Tag,
"DropletIDs": strings.Trim(strings.Replace(fmt.Sprint(l.DropletIDs), " ", ",", -1), "[]"),
Expand All @@ -99,6 +98,9 @@ func (lb *LoadBalancer) KV() []map[string]any {
"ForwardingRules": strings.Join(forwardingRules, " "),
"DisableLetsEncryptDNSRecords": toBool(l.DisableLetsEncryptDNSRecords),
}
if l.Region != nil {
o["Region"] = l.Region.Slug
}
if l.SizeSlug != "" {
o["Size"] = l.SizeSlug
}
Expand Down
131 changes: 125 additions & 6 deletions commands/load_balancers.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ With the load-balancer command, you can list, create, or delete load balancers,
AddStringFlag(cmdLoadBalancerCreate, doctl.ArgLoadBalancerName, "", "",
"The load balancer's name", requiredOpt())
AddStringFlag(cmdLoadBalancerCreate, doctl.ArgRegionSlug, "", "",
"The load balancer's region, e.g.: `nyc1`", requiredOpt())
"The load balancer's region, e.g.: `nyc1`")
AddStringFlag(cmdLoadBalancerCreate, doctl.ArgSizeSlug, "", "",
fmt.Sprintf("The load balancer's size, e.g.: `lb-small`. Only one of %s and %s should be used", doctl.ArgSizeSlug, doctl.ArgSizeUnit))
AddIntFlag(cmdLoadBalancerCreate, doctl.ArgSizeUnit, "", 0,
Expand Down Expand Up @@ -92,6 +92,18 @@ With the load-balancer command, you can list, create, or delete load balancers,
"A comma-separated list of ALLOW rules for the load balancer, e.g.: `ip:1.2.3.4,cidr:1.2.0.0/16`")
AddStringSliceFlag(cmdLoadBalancerCreate, doctl.ArgDenyList, "", []string{},
"A comma-separated list of DENY rules for the load balancer, e.g.: `ip:1.2.3.4,cidr:1.2.0.0/16`")
AddStringSliceFlag(cmdLoadBalancerCreate, doctl.ArgLoadBalancerDomains, "", []string{},
"A comma-separated list of domains required to ingress traffic to a global load balancer, e.g.: `name:test-domain-1 is_managed:true certificate_id:test-cert-id-1` "+
"(NOTE: this is a closed beta feature, contact DigitalOcean support to review its public availability.)")
AddStringFlag(cmdLoadBalancerCreate, doctl.ArgGlobalLoadBalancerSettings, "", "",
"Target protocol and port settings for ingressing traffic to a global load balancer, e.g.: `target_protocol:http,target_port:80` "+
"(NOTE: this is a closed beta feature, contact DigitalOcean support to review its public availability.)")
AddStringFlag(cmdLoadBalancerCreate, doctl.ArgGlobalLoadBalancerCDNSettings, "", "",
"CDN cache settings global load balancer, e.g.: `is_enabled:true` "+
"(NOTE: this is a closed beta feature, contact DigitalOcean support to review its public availability.)")
AddStringSliceFlag(cmdLoadBalancerCreate, doctl.ArgTargetLoadBalancerIDs, "", []string{},
"A comma-separated list of Load Balancer IDs to add as target to the global load balancer "+
"(NOTE: this is a closed beta feature, contact DigitalOcean support to review its public availability.)")
cmdLoadBalancerCreate.Flags().MarkHidden(doctl.ArgLoadBalancerType)

cmdRecordUpdate := CmdBuilder(cmd, RunLoadBalancerUpdate, "update <id>",
Expand Down Expand Up @@ -129,6 +141,18 @@ With the load-balancer command, you can list, create, or delete load balancers,
"A comma-separated list of ALLOW rules for the load balancer, e.g.: `ip:1.2.3.4,cidr:1.2.0.0/16`")
AddStringSliceFlag(cmdRecordUpdate, doctl.ArgDenyList, "", nil,
"A comma-separated list of DENY rules for the load balancer, e.g.: `ip:1.2.3.4,cidr:1.2.0.0/16`")
AddStringSliceFlag(cmdRecordUpdate, doctl.ArgLoadBalancerDomains, "", []string{},
"A comma-separated list of domains required to ingress traffic to a global load balancer, e.g.: `name:test-domain-1 is_managed:true certificate_id:test-cert-id-1` "+
"(NOTE: this is a closed beta feature, contact DigitalOcean support to review its public availability.)")
AddStringFlag(cmdRecordUpdate, doctl.ArgGlobalLoadBalancerSettings, "", "",
"Target protocol and port settings for ingressing traffic to a global load balancer, e.g.: `target_protocol:http,target_port:80` "+
"(NOTE: this is a closed beta feature, contact DigitalOcean support to review its public availability.)")
AddStringFlag(cmdRecordUpdate, doctl.ArgGlobalLoadBalancerCDNSettings, "", "",
"CDN cache settings global load balancer, e.g.: `is_enabled:true` "+
"(NOTE: this is a closed beta feature, contact DigitalOcean support to review its public availability.)")
AddStringSliceFlag(cmdRecordUpdate, doctl.ArgTargetLoadBalancerIDs, "", []string{},
"A comma-separated list of Load Balancer IDs to add as target to the global load balancer "+
"(NOTE: this is a closed beta feature, contact DigitalOcean support to review its public availability.)")

CmdBuilder(cmd, RunLoadBalancerList, "list", "List load balancers", "Use this command to get a list of the load balancers on your account, including the following information for each:\n\n"+lbDetail, Writer,
aliasOpt("ls"), displayerType(&displayers.LoadBalancer{}))
Expand Down Expand Up @@ -156,6 +180,12 @@ With the load-balancer command, you can list, create, or delete load balancers,
"remove-forwarding-rules <id>", "Remove forwarding rules from a load balancer", "Use this command to remove forwarding rules from a load balancer, specified with the `--forwarding-rules` flag. Valid rules include:\n"+forwardingDetail, Writer)
AddStringFlag(cmdRemoveForwardingRules, doctl.ArgForwardingRules, "", "", forwardingRulesTxt)

cmdRunCachePurge := CmdBuilder(cmd, RunLoadBalancerPurgeCache, "purge-cache <id>",
"Purges CDN cache for a global load balancer", `Use this command to purge the CDN cache for specified global load balancer.`, Writer)
AddBoolFlag(cmdRunCachePurge, doctl.ArgForce, doctl.ArgShortForce, false,
"Purge the global load balancer CDN cache without a confirmation prompt "+
"(NOTE: this is a closed beta feature, contact DigitalOcean support to review its public availability.)")

return cmd
}

Expand Down Expand Up @@ -359,6 +389,31 @@ func RunLoadBalancerRemoveForwardingRules(c *CmdConfig) error {
return c.LoadBalancers().RemoveForwardingRules(lbID, forwardingRules...)
}

// RunLoadBalancerPurgeCache purges cache for a global load balancer by its identifier.
func RunLoadBalancerPurgeCache(c *CmdConfig) error {
err := ensureOneArg(c)
if err != nil {
return err
}
lbID := c.Args[0]

force, err := c.Doit.GetBool(c.NS, doctl.ArgForce)
if err != nil {
return err
}

if force || AskForConfirm("purge CDN cache for global load balancer") == nil {
lbs := c.LoadBalancers()
if err := lbs.PurgeCache(lbID); err != nil {
return err
}
} else {
return errOperationAborted
}

return nil
}

func extractForwardingRules(s string) (forwardingRules []godo.ForwardingRule, err error) {
if len(s) == 0 {
return forwardingRules, err
Expand All @@ -368,7 +423,7 @@ func extractForwardingRules(s string) (forwardingRules []godo.ForwardingRule, er

for _, v := range list {
forwardingRule := new(godo.ForwardingRule)
if err := fillStructFromStringSliceArgs(forwardingRule, v); err != nil {
if err := fillStructFromStringSliceArgs(forwardingRule, v, ","); err != nil {
return nil, err
}

Expand All @@ -378,12 +433,29 @@ func extractForwardingRules(s string) (forwardingRules []godo.ForwardingRule, er
return forwardingRules, err
}

func fillStructFromStringSliceArgs(obj any, s string) error {
func extractDomains(s []string) (domains []*godo.LBDomain, err error) {
if len(s) == 0 {
return domains, err
}

for _, v := range s {
domain := new(godo.LBDomain)
if err := fillStructFromStringSliceArgs(domain, v, " "); err != nil {
return nil, err
}

domains = append(domains, domain)
}

return domains, err
}

func fillStructFromStringSliceArgs(obj any, s string, delimiter string) error {
if len(s) == 0 {
return nil
}

kvs := strings.Split(s, ",")
kvs := strings.Split(s, delimiter)
m := map[string]string{}

for _, v := range kvs {
Expand Down Expand Up @@ -412,6 +484,10 @@ func fillStructFromStringSliceArgs(obj any, s string) error {
if v, err := strconv.Atoi(val); err == nil {
f.Set(reflect.ValueOf(v))
}
case reflect.Uint32:
if v64, err := strconv.ParseUint(val, 10, 32); err == nil {
f.Set(reflect.ValueOf(uint32(v64)))
}
case reflect.String:
f.Set(reflect.ValueOf(val))
default:
Expand Down Expand Up @@ -513,7 +589,7 @@ func buildRequestFromArgs(c *CmdConfig, r *godo.LoadBalancerRequest) error {
}

stickySession := new(godo.StickySessions)
if err := fillStructFromStringSliceArgs(stickySession, ssa); err != nil {
if err := fillStructFromStringSliceArgs(stickySession, ssa, ","); err != nil {
return err
}
r.StickySessions = stickySession
Expand All @@ -524,7 +600,7 @@ func buildRequestFromArgs(c *CmdConfig, r *godo.LoadBalancerRequest) error {
}

healthCheck := new(godo.HealthCheck)
if err := fillStructFromStringSliceArgs(healthCheck, hca); err != nil {
if err := fillStructFromStringSliceArgs(healthCheck, hca, ","); err != nil {
return err
}
r.HealthCheck = healthCheck
Expand Down Expand Up @@ -574,6 +650,49 @@ func buildRequestFromArgs(c *CmdConfig, r *godo.LoadBalancerRequest) error {
r.Firewall = firewall
}

dms, err := c.Doit.GetStringSlice(c.NS, doctl.ArgLoadBalancerDomains)
if err != nil {
return err
}

domains, err := extractDomains(dms)
if err != nil {
return err
}
r.Domains = domains

glbs, err := c.Doit.GetString(c.NS, doctl.ArgGlobalLoadBalancerSettings)
if err != nil {
return err
}

glbSettings := new(godo.GLBSettings)
if err := fillStructFromStringSliceArgs(glbSettings, glbs, ","); err != nil {
return err
}
if glbSettings.TargetProtocol != "" && glbSettings.TargetPort != 0 {
r.GLBSettings = glbSettings
}

cdns, err := c.Doit.GetString(c.NS, doctl.ArgGlobalLoadBalancerCDNSettings)
if err != nil {
return err
}

cdnSettings := new(godo.CDNSettings)
if err := fillStructFromStringSliceArgs(cdnSettings, cdns, ","); err != nil {
return err
}
if r.GLBSettings != nil {
r.GLBSettings.CDN = cdnSettings
}

lbIDsList, err := c.Doit.GetStringSlice(c.NS, doctl.ArgTargetLoadBalancerIDs)
if err != nil {
return err
}
r.TargetLoadBalancerIDs = lbIDsList

return nil
}

Expand Down
Loading

0 comments on commit 26a3f33

Please sign in to comment.