diff --git a/digitalocean/loadbalancer/datasource_loadbalancer.go b/digitalocean/loadbalancer/datasource_loadbalancer.go index 8e5e727fe..b79b9a4fd 100644 --- a/digitalocean/loadbalancer/datasource_loadbalancer.go +++ b/digitalocean/loadbalancer/datasource_loadbalancer.go @@ -254,6 +254,98 @@ func DataSourceDigitalOceanLoadbalancer() *schema.Resource { Computed: true, Description: "the type of the load balancer (GLOBAL or REGIONAL)", }, + "domains": { + Type: schema.TypeSet, + Required: false, + Computed: true, + MinItems: 1, + Description: "the list of domains required to ingress traffic to global load balancer", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.NoZeroValues, + Description: "domain name", + }, + "is_managed": { + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "flag indicating if domain is managed by DigitalOcean", + }, + "certificate_id": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.NoZeroValues, + Description: "certificate ID for TLS handshaking", + }, + "verification_error_reasons": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Optional: true, + Description: "list of domain verification errors", + }, + "ssl_validation_error_reasons": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Optional: true, + Description: "list of domain SSL validation errors", + }, + }, + }, + }, + "glb_settings": { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + Description: "configuration options for global load balancer", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "target_protocol": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + "http", + "https", + }, false), + Description: "target protocol rules", + }, + "target_port": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntInSlice([]int{80, 443}), + Description: "target port rules", + }, + "cdn": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Description: "CDN specific configurations", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "is_enabled": { + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "cache enable flag", + }, + }, + }, + }, + }, + }, + }, + "target_load_balancer_ids": { + Type: schema.TypeSet, + Elem: &schema.Schema{Type: schema.TypeString}, + Optional: true, + Computed: true, + Description: "list of load balancer IDs to put behind a global load balancer", + }, }, } } @@ -357,6 +449,23 @@ func dataSourceDigitalOceanLoadbalancerRead(ctx context.Context, d *schema.Resou return diag.Errorf("[DEBUG] Error setting Load Balancer firewall - error: %#v", err) } + domains, err := flattenDomains(foundLoadbalancer.Domains) + if err != nil { + return diag.Errorf("[DEBUG] Error building Load Balancer domains - error: %#v", err) + } + + if err := d.Set("domains", domains); err != nil { + return diag.Errorf("[DEBUG] Error setting Load Balancer domains - error: %#v", err) + } + + if err := d.Set("glb_settings", flattenGLBSettings(foundLoadbalancer.GLBSettings)); err != nil { + return diag.Errorf("[DEBUG] Error setting Load Balancer glb settings - error: %#v", err) + } + + if err := d.Set("target_load_balancer_ids", flattenLoadBalancerIds(foundLoadbalancer.TargetLoadBalancerIDs)); err != nil { + return diag.Errorf("[DEBUG] Error setting target Load Balancer ids - error: %#v", err) + } + return nil } diff --git a/digitalocean/loadbalancer/loadbalancer.go b/digitalocean/loadbalancer/loadbalancer.go index 7affdb09c..32c731b6e 100644 --- a/digitalocean/loadbalancer/loadbalancer.go +++ b/digitalocean/loadbalancer/loadbalancer.go @@ -256,3 +256,92 @@ func flattenForwardingRules(client *godo.Client, rules []godo.ForwardingRule) ([ return result, nil } + +func expandDomains(config []interface{}) ([]*godo.LBDomain, error) { + domains := make([]*godo.LBDomain, 0, len(config)) + + for _, rawDomain := range config { + domain := rawDomain.(map[string]interface{}) + r := &godo.LBDomain{Name: domain["name"].(string)} + + if v, ok := domain["is_managed"]; ok { + r.IsManaged = v.(bool) + } + + if v, ok := domain["certificate_id"]; ok { + r.CertificateID = v.(string) + } + + domains = append(domains, r) + } + + return domains, nil +} + +func expandGLBSettings(config []interface{}) *godo.GLBSettings { + glbConfig := config[0].(map[string]interface{}) + + glbSettings := &godo.GLBSettings{ + TargetProtocol: glbConfig["target_protocol"].(string), + TargetPort: uint32(glbConfig["target_port"].(int)), + } + + if v, ok := glbConfig["cdn"]; ok { + cdnConfig := v.(map[string]interface{}) + glbSettings.CDN = &godo.CDNSettings{ + IsEnabled: cdnConfig["is_enabled"].(bool), + } + } + + return glbSettings +} + +func flattenDomains(domains []*godo.LBDomain) ([]map[string]interface{}, error) { + if len(domains) == 0 { + return nil, nil + } + + result := make([]map[string]interface{}, 0, 1) + for _, domain := range domains { + r := make(map[string]interface{}) + + r["name"] = (*domain).Name + r["is_managed"] = (*domain).IsManaged + r["certificate_id"] = (*domain).CertificateID + r["verification_error_reasons"] = (*domain).VerificationErrorReasons + r["ssl_validation_error_reasons"] = (*domain).SSLValidationErrorReasons + + result = append(result, r) + } + + return result, nil +} + +func flattenGLBSettings(settings *godo.GLBSettings) []map[string]interface{} { + result := make([]map[string]interface{}, 0, 1) + + if settings != nil { + r := make(map[string]interface{}) + + r["target_protocol"] = (*settings).TargetProtocol + r["target_port"] = (*settings).TargetPort + + if settings.CDN != nil { + r["cdn"] = map[string]interface{}{ + "is_enabled": (*settings).CDN.IsEnabled, + } + } + + result = append(result, r) + } + + return result +} + +func flattenLoadBalancerIds(list []string) *schema.Set { + flatSet := schema.NewSet(schema.HashString, []interface{}{}) + for _, v := range list { + flatSet.Add(v) + } + return flatSet +} diff --git a/digitalocean/loadbalancer/resource_loadbalancer.go b/digitalocean/loadbalancer/resource_loadbalancer.go index 11dfd5a66..2a5a44797 100644 --- a/digitalocean/loadbalancer/resource_loadbalancer.go +++ b/digitalocean/loadbalancer/resource_loadbalancer.go @@ -432,6 +432,7 @@ func resourceDigitalOceanLoadBalancerV0() *schema.Resource { }, }, }, + "type": { Type: schema.TypeString, Optional: true, @@ -439,6 +440,101 @@ func resourceDigitalOceanLoadBalancerV0() *schema.Resource { ValidateFunc: validation.StringInSlice([]string{"REGIONAL", "GLOBAL"}, true), Description: "the type of the load balancer (GLOBAL or REGIONAL)", }, + + "domains": { + Type: schema.TypeSet, + Required: false, + Computed: true, + MinItems: 1, + Description: "the list of domains required to ingress traffic to global load balancer", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.NoZeroValues, + Description: "domain name", + }, + "is_managed": { + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "flag indicating if domain is managed by DigitalOcean", + }, + "certificate_id": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.NoZeroValues, + Description: "certificate ID for TLS handshaking", + }, + "verification_error_reasons": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Optional: true, + Description: "list of domain verification errors", + }, + "ssl_validation_error_reasons": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Optional: true, + Description: "list of domain SSL validation errors", + }, + }, + }, + }, + + "glb_settings": { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + Description: "configuration options for global load balancer", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "target_protocol": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + "http", + "https", + }, false), + Description: "target protocol rules", + }, + "target_port": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntInSlice([]int{80, 443}), + Description: "target port rules", + }, + "cdn": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Description: "CDN specific configurations", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "is_enabled": { + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "cache enable flag", + }, + }, + }, + }, + }, + }, + }, + + "target_load_balancer_ids": { + Type: schema.TypeSet, + Elem: &schema.Schema{Type: schema.TypeString}, + Optional: true, + Computed: true, + Description: "list of load balancer IDs to put behind a global load balancer", + }, }, } } @@ -533,6 +629,28 @@ func buildLoadBalancerRequest(client *godo.Client, d *schema.ResourceData) (*god opts.Type = v.(string) } + if v, ok := d.GetOk("domains"); ok { + domains, err := expandDomains(v.(*schema.Set).List()) + if err != nil { + return nil, err + } + + opts.Domains = domains + } + + if v, ok := d.GetOk("glb_settings"); ok { + opts.GLBSettings = expandGLBSettings(v.([]interface{})) + } + + if v, ok := d.GetOk("target_load_balancer_ids"); ok { + var lbIDs []string + for _, id := range v.(*schema.Set).List() { + lbIDs = append(lbIDs, id.(string)) + } + + opts.TargetLoadBalancerIDs = lbIDs + } + return opts, nil }