Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion vultr/data_source_vultr_load_balancer.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ func dataSourceVultrLoadBalancer() *schema.Resource {
Computed: true,
Elem: &schema.Schema{Type: schema.TypeMap},
},
"auto_ssl_domain": {
Type: schema.TypeString,
Computed: true,
},
},
}
}
Expand Down Expand Up @@ -143,6 +147,9 @@ func dataSourceVultrLoadBalancerRead(ctx context.Context, d *schema.ResourceData
if err := d.Set("ssl_redirect", lbList[0].GenericInfo.SSLRedirect); err != nil {
return diag.Errorf("unable to set load_balancer `ssl_redirect` read value: %v", err)
}
if err := d.Set("auto_ssl_domain", lbList[0].AutoSSL.Domain); err != nil {
return diag.Errorf("unable to set load_balancer `auto_ssl_domain` read value: %v", err)
}
if err := d.Set("proxy_protocol", lbList[0].GenericInfo.ProxyProtocol); err != nil {
return diag.Errorf("unable to set load_balancer `proxy_protocol` read value: %v", err)
}
Expand Down Expand Up @@ -212,6 +219,5 @@ func dataSourceVultrLoadBalancerRead(ctx context.Context, d *schema.ResourceData
if err := d.Set("firewall_rules", fwrRules); err != nil {
return diag.Errorf("unable to set load_balancer `firewall_rules` read value: %v", err)
}

return nil
}
61 changes: 58 additions & 3 deletions vultr/resource_vultr_load_balancer.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"
"log"
"net/url"
"strings"
"time"

Expand Down Expand Up @@ -199,6 +200,10 @@ func resourceVultrLoadBalancer() *schema.Resource {
Type: schema.TypeBool,
Computed: true,
},
"auto_ssl_domain": {
Type: schema.TypeString,
Optional: true,
},
"attached_instances": {
Type: schema.TypeList,
Optional: true,
Expand Down Expand Up @@ -255,6 +260,16 @@ func resourceVultrLoadBalancerCreate(ctx context.Context, d *schema.ResourceData
ssl = nil
}

var autoSSL *govultr.AutoSSL
if autoSSLDomainData, autoSSLDomainOk := d.GetOk("auto_ssl_domain"); autoSSLDomainOk {
domain := autoSSLDomainData.(string)
if autoSSLDomain, err := generateAutoSSL(domain); err != nil {
return diag.Errorf("failed to parse auto SSL domain: %v", err)
} else {
autoSSL = autoSSLDomain
}
}

cookieName, cookieOk := d.GetOk("cookie_name")
stickySessions := &govultr.StickySessions{}
if cookieOk {
Expand All @@ -278,6 +293,7 @@ func resourceVultrLoadBalancerCreate(ctx context.Context, d *schema.ResourceData
StickySessions: stickySessions,
ForwardingRules: fwMap,
SSL: ssl,
AutoSSL: autoSSL,
SSLRedirect: govultr.BoolToBoolPtr(d.Get("ssl_redirect").(bool)),
ProxyProtocol: govultr.BoolToBoolPtr(d.Get("proxy_protocol").(bool)),
BalancingAlgorithm: d.Get("balancing_algorithm").(string),
Expand Down Expand Up @@ -357,7 +373,9 @@ func resourceVultrLoadBalancerRead(ctx context.Context, d *schema.ResourceData,
"healthy_threshold": lb.HealthCheck.HealthyThreshold,
}
hc = append(hc, hcInfo)

if err := d.Set("auto_ssl_domain", lb.AutoSSL.Domain); err != nil {
return diag.Errorf("unable to set resource load_balancer `auto_ssl_domain` read value: %v", err)
}
if err := d.Set("health_check", hc); err != nil {
return diag.Errorf("unable to set resource load_balancer `health_check` read value: %v", err)
}
Expand Down Expand Up @@ -397,7 +415,6 @@ func resourceVultrLoadBalancerRead(ctx context.Context, d *schema.ResourceData,
if err := d.Set("vpc", lb.GenericInfo.VPC); err != nil {
return diag.Errorf("unable to set resource load_balancer `vpc` read value: %v", err)
}

return nil
}

Expand Down Expand Up @@ -426,7 +443,20 @@ func resourceVultrLoadBalancerUpdate(ctx context.Context, d *schema.ResourceData
req.SSL = nil
}
}

if d.HasChange("auto_ssl_domain") {
if autoSSLData, ok := d.GetOk("auto_ssl_domain"); ok && autoSSLData.(string) != "" {
autoSSL, err := generateAutoSSL(autoSSLData.(string))
if err != nil {
return diag.Errorf("failed to parse auto SSL domain: %v", err)
}
req.AutoSSL = autoSSL
} else {
log.Printf("[INFO] Disabled load balancer auto SSL certificate (%v)", d.Id())
if err := client.LoadBalancer.DeleteAutoSSL(ctx, d.Id()); err != nil {
return diag.Errorf("error disabling load balancer auto SSL certificate (%v): %v", d.Id(), err)
}
}
}
if d.HasChange("forwarding_rules") {
_, newFR := d.GetChange("forwarding_rules")

Expand Down Expand Up @@ -622,3 +652,28 @@ func generateSSL(sslData interface{}) *govultr.SSL {
Chain: config["chain"].(string),
}
}

func generateAutoSSL(domain string) (*govultr.AutoSSL, error) {
parsedDomain, err := url.Parse(domain)
if err != nil || parsedDomain.Scheme != "" {
return nil, fmt.Errorf("invalid domain %q: must not include URL scheme (http:// or https://)", domain)
}

hostname := parsedDomain.Hostname()
if hostname == "" {
hostname = domain
}

parts := strings.Split(hostname, ".")
if len(parts) < 2 {
return nil, fmt.Errorf("invalid domain %q: must contain a dot (example.com)", domain)
}

domainParts := parts[len(parts)-2:]
subParts := parts[:len(parts)-2]

return &govultr.AutoSSL{
DomainZone: strings.Join(domainParts, "."),
DomainSub: strings.Join(subParts, "."),
}, nil
}
2 changes: 2 additions & 0 deletions website/docs/d/load_balancer.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ The following attributes are exported:
* `cookie_name` - Name for your given sticky session.
* `ssl_redirect` - Boolean value that indicates if HTTP calls will be redirected to HTTPS.
* `has_ssl` - Boolean value that indicates if SSL is enabled.
* `auto_ssl_domain` - The auto SSL domain configuration for a load balancer. This can be a root domain (example.com) or include a subdomain (sub.example.com).
* `attached_instances` - Array of instances that are currently attached to the load balancer.
* `status` - Current status for the load balancer
* `ipv4` - IPv4 address for your load balancer.
Expand Down Expand Up @@ -75,3 +76,4 @@ The following attributes are exported:
* `frontend_port` - (Required) Port on load balancer side.
* `ip_type` - (Required) The type of ip this rule is - may be either v4 or v6.
* `source` - (Required) IP address with subnet that is allowed through the firewall. You may also pass in `cloudflare` which will allow only CloudFlares IP range.

2 changes: 2 additions & 0 deletions website/docs/r/load_balancer.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ The follow arguments are supported:
* `attached_instances` - (Optional) Array of instances that are currently attached to the load balancer.
* `health_check` - (Optional) A block that defines the way load balancers should check for health. The configuration of a `health_check` is listed below.
* `ssl` - (Optional) A block that supplies your ssl configuration to be used with HTTPS. The configuration of a `ssl` is listed below.
* `auto_ssl_domain` - (Optional) The auto SSL domain configuration for a load balancer. This can be a root domain (example.com) or include a subdomain (sub.example.com).
* `private_network` (Optional) (Deprecated: use `vpc` instead) A private network ID that the load balancer should be attached to.
* `vpc` (Optional)- A VPC ID that the load balancer should be attached to.

Expand Down Expand Up @@ -95,6 +96,7 @@ The following attributes are exported:
* `cookie_name` - Name for your given sticky session.
* `ssl_redirect` - Boolean value that indicates if HTTP calls will be redirected to HTTPS.
* `has_ssl` - Boolean value that indicates if SSL is enabled.
* `auto_ssl_domain` - The auto SSL domain configuration for a load balancer.
* `attached_instances` - Array of instances that are currently attached to the load balancer.
* `status` - Current status for the load balancer
* `ipv4` - IPv4 address for your load balancer.
Expand Down