Skip to content

Commit

Permalink
Support for multiple lb vservers per servicegroup
Browse files Browse the repository at this point in the history
  • Loading branch information
chiradeep committed Jun 1, 2017
1 parent da72ea4 commit 92a3004
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 64 deletions.
2 changes: 1 addition & 1 deletion config.tf
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ resource "netscaler_lbmonitor" "foo-monitor-2" {

resource "netscaler_servicegroup" "backend_group" {
servicegroupname = "backend_group_1"
lbvserver = "${netscaler_lbvserver.sample_lb2.name}"
lbvservers = ["${netscaler_lbvserver.sample_lb.name}"]
servicetype = "HTTP"
lbmonitor = "${netscaler_lbmonitor.foo-monitor.monitorname}"
servicegroupmembers = ["172.20.0.20:200:50","172.20.0.101:80:10", "172.20.0.10:80:40"]
Expand Down
4 changes: 2 additions & 2 deletions examples/content_switch_ssl_lb_mon/resources.tf
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ resource "netscaler_lbvserver" "lb_catalog" {

resource "netscaler_servicegroup" "backend_cart" {
servicegroupname = "${lookup(var.backend_service_config_cart, "name")}"
lbvserver = "${netscaler_lbvserver.lb_cart.name}"
lbvservers = ["${netscaler_lbvserver.lb_cart.name}"]
lbmonitor = "${netscaler_lbmonitor.cart_monitor.monitorname}"
servicetype = "${lookup(var.backend_service_config_cart, "servicetype")}"
clttimeout = "${lookup(var.backend_service_config_cart, "client_timeout")}"
Expand All @@ -54,7 +54,7 @@ resource "netscaler_servicegroup" "backend_cart" {

resource "netscaler_servicegroup" "backend_catalog" {
servicegroupname = "${lookup(var.backend_service_config_catalog, "name")}"
lbvserver = "${netscaler_lbvserver.lb_catalog.name}"
lbvservers = ["${netscaler_lbvserver.lb_catalog.name}"]
lbmonitor = "${netscaler_lbmonitor.catalog_monitor.monitorname}"
servicegroupmembers = "${var.backend_services_catalog}"
servicetype = "${lookup(var.backend_service_config_catalog, "servicetype")}"
Expand Down
2 changes: 1 addition & 1 deletion examples/simple_lb/provider.tf
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
provider "netscaler" {
endpoint = "http://localhost:32772/"
endpoint = "http://localhost:32783/"
}
2 changes: 1 addition & 1 deletion examples/simple_lb/resources.tf
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ resource "netscaler_lbvserver" "production_lb" {

resource "netscaler_servicegroup" "backend" {
servicegroupname = "productionBackend"
lbvserver = "${netscaler_lbvserver.production_lb.name}"
lbvservers = ["${netscaler_lbvserver.production_lb.name}"]
servicetype = "HTTP"
clttimeout = "${lookup(var.backend_service_config, "clttimeout")}"
servicegroupmembers = "${formatlist("%s:%s", var.backend_services, var.backend_service_config["backend_port"])}"
Expand Down
123 changes: 68 additions & 55 deletions netscaler/resource_servicegroup.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,10 +246,11 @@ func resourceNetScalerServicegroup() *schema.Resource {
Optional: true,
Computed: true,
},

"lbvserver": &schema.Schema{
Type: schema.TypeString,
Required: true,
"lbvservers": &schema.Schema{
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
},
"lbmonitor": &schema.Schema{
Type: schema.TypeString,
Expand Down Expand Up @@ -284,11 +285,15 @@ func createServicegroupFunc(d *schema.ResourceData, meta interface{}) error {
}
}

lbvserver, lok := d.GetOk("lbvserver")
var lbvservers []string
l, lok := d.GetOk("lbvservers")
if lok {
exists := client.ResourceExists(netscaler.Lbvserver.Type(), lbvserver.(string))
if !exists {
return fmt.Errorf("[ERROR] netscaler-provider: Specified lb vserver does not exist on netscaler!")
lbvservers = expandStringList(l.(*schema.Set).List())
for _, lbvserver := range lbvservers {
exists := client.ResourceExists(netscaler.Lbvserver.Type(), lbvserver)
if !exists {
return fmt.Errorf("[ERROR] netscaler-provider: Specified lb vserver %s does not exist on netscaler!", lbvserver)
}
}
}

Expand Down Expand Up @@ -350,22 +355,10 @@ func createServicegroupFunc(d *schema.ResourceData, meta interface{}) error {
if err != nil {
return err
}
if lok { //lbvserver is specified
lbvserverName := d.Get("lbvserver").(string)
binding := lb.Lbvserverservicegroupbinding{
Name: lbvserverName,
Servicegroupname: servicegroupName,
}
log.Printf("[INFO] netscaler-provider: Binding servicegroup %s to lbvserver %s", servicegroupName, lbvserverName)
err = client.BindResource(netscaler.Lbvserver.Type(), lbvserverName, netscaler.Servicegroup.Type(), servicegroupName, &binding)
if lok { //lbvservers is specified
err = addLbvserverBindings(client, servicegroupName, lbvservers)
if err != nil {
log.Printf("[ERROR] netscaler-provider: Failed to bind servicegroup %s to lbvserver %s", servicegroupName, lbvserverName)
err2 := client.DeleteResource(netscaler.Servicegroup.Type(), servicegroupName)
if err2 != nil {
log.Printf("[ERROR] netscaler-provider: Failed to delete servicegroup %s after bind to lb vserver failed", servicegroupName)
return fmt.Errorf("[ERROR] netscaler-provider: Failed to delete servicegroup %s after bind to lbvserver failed", servicegroupName)
}
return fmt.Errorf("[ERROR] netscaler-provider: Failed to bind servicegroup %s to lbvserver %s", servicegroupName, lbvserverName)
return err
}
}

Expand Down Expand Up @@ -470,6 +463,33 @@ func removeServicegroupMemberBindings(client *netscaler.NitroClient, servicegrou
return nil
}

func addLbvserverBindings(client *netscaler.NitroClient, servicegroupName string, lbvservers []string) error {
for _, lbvserverName := range lbvservers {
binding := lb.Lbvserverservicegroupbinding{
Name: lbvserverName,
Servicegroupname: servicegroupName,
}
log.Printf("[INFO] netscaler-provider: Binding servicegroup %s to lbvserver %s", servicegroupName, lbvserverName)
err := client.BindResource(netscaler.Lbvserver.Type(), lbvserverName, netscaler.Servicegroup.Type(), servicegroupName, &binding)
if err != nil {
log.Printf("[ERROR] netscaler-provider: Failed to bind servicegroup %s to lbvserver %s", servicegroupName, lbvserverName)
return fmt.Errorf("[ERROR] netscaler-provider: Failed to bind servicegroup %s to lbvserver %s", servicegroupName, lbvserverName)
}
}
return nil
}

func removeLbvserverBindings(client *netscaler.NitroClient, servicegroupName string, lbvservers []string) error {
for _, lbvserverName := range lbvservers {
err := client.UnbindResource(netscaler.Lbvserver.Type(), lbvserverName, netscaler.Servicegroup.Type(), servicegroupName, "servicegroupname")
if err != nil {
log.Printf("[ERROR] netscaler-provider: Error unbinding lbvserver %s from servicegroup %s", lbvserverName, servicegroupName)
return fmt.Errorf("[ERROR] netscaler-provider: Error unbinding lbvserver %s from servicegroup %s", lbvserverName, servicegroupName)
}
}
return nil
}

func readServicegroupFunc(d *schema.ResourceData, meta interface{}) error {
log.Printf("[DEBUG] netscaler-provider: In readServicegroupFunc")
client := meta.(*NetScalerNitroClient).client
Expand All @@ -488,7 +508,7 @@ func readServicegroupFunc(d *schema.ResourceData, meta interface{}) error {
d.SetId("")
return nil
}
//read bound vserver.
//read bound vservers.
vserverBindings, err := client.FindResourceArray(netscaler.Servicegroupbindings.Type(), servicegroupName)
if err != nil {
log.Printf("[WARN] netscaler-provider: Clearing servicegroup state %s", servicegroupName)
Expand Down Expand Up @@ -564,14 +584,15 @@ func readServicegroupFunc(d *schema.ResourceData, meta interface{}) error {

//vserverBindings is of type []map[string]interface{}
var boundVserver string
lbvservers := make([]string, 0, len(vserverBindings))
for _, vserver := range vserverBindings {
vs, ok := vserver["vservername"]
if ok {
boundVserver = vs.(string)
break
lbvservers = append(lbvservers, boundVserver)
}
}
d.Set("lbvserver", boundVserver)
d.Set("lbvservers", lbvservers)

var boundMonitor string
for _, monitor := range boundMonitors {
Expand All @@ -597,7 +618,7 @@ func updateServicegroupFunc(d *schema.ResourceData, meta interface{}) error {
}

hasChange := false
lbvserverChanged := false
lbvserversChanged := false
lbmonitorChanged := false
servicegroupmembersChanged := false

Expand Down Expand Up @@ -826,9 +847,9 @@ func updateServicegroupFunc(d *schema.ResourceData, meta interface{}) error {
servicegroup.Weight = d.Get("weight").(int)
hasChange = true
}
if d.HasChange("lbvserver") {
log.Printf("[DEBUG] netscaler-provider: lb vserver has changed for servicegroup %s, starting update", servicegroupName)
lbvserverChanged = true
if d.HasChange("lbvservers") {
log.Printf("[DEBUG] netscaler-provider: lb vservers has changed for servicegroup %s, starting update", servicegroupName)
lbvserversChanged = true
}
if d.HasChange("lbmonitor") {
log.Printf("[DEBUG] netscaler-provider: lb monitor has changed for servicegroup %s, starting update", servicegroupName)
Expand All @@ -840,18 +861,26 @@ func updateServicegroupFunc(d *schema.ResourceData, meta interface{}) error {
servicegroupmembersChanged = true
}

lbvserverName := d.Get("lbvserver").(string)
if lbvserverChanged {
if lbvserversChanged {
//Binding has to be updated
//First we unbind from lb vserver
oldLbvserver, _ := d.GetChange("lbvserver")
oldLbvserverName := oldLbvserver.(string)
if oldLbvserverName != "" {
err := client.UnbindResource(netscaler.Lbvserver.Type(), oldLbvserverName, netscaler.Servicegroup.Type(), servicegroupName, "servicegroupname")
o, n := d.GetChange("lbvservers")
os := o.(*schema.Set)
ns := n.(*schema.Set)

remove := expandStringList(os.Difference(ns).List())
add := expandStringList(ns.Difference(os).List())

if len(remove) > 0 {
err := removeLbvserverBindings(client, servicegroupName, remove)
if err != nil {
return fmt.Errorf("[ERROR] netscaler-provider: Error unbinding lbvserver from servicegroup %s", oldLbvserverName)
return err
}
}
if len(add) > 0 {
err := addLbvserverBindings(client, servicegroupName, add)
if err != nil {
return err
}
log.Printf("[DEBUG] netscaler-provider: lbvserver has been unbound from servicegroup for lb vserver %s ", oldLbvserverName)
}
}

Expand All @@ -878,22 +907,6 @@ func updateServicegroupFunc(d *schema.ResourceData, meta interface{}) error {
}
}

if lbvserverChanged && lbvserverName != "" {
//Binding has to be updated
//rebind
binding := lb.Lbvserverservicegroupbinding{
Name: lbvserverName,
Servicegroupname: servicegroupName,
}
log.Printf("[INFO] netscaler-provider: Binding vserver %s to servicegroup %s", lbvserverName, servicegroupName)
err := client.BindResource(netscaler.Lbvserver.Type(), lbvserverName, netscaler.Servicegroup.Type(), servicegroupName, &binding)
if err != nil {
log.Printf("[ERROR] netscaler-provider: Failed to bind lbvserver %s to servicegroup %s", lbvserverName, servicegroupName)
return fmt.Errorf("[ERROR] netscaler-provider: Failed to bind lb vserver %s to servicegroup %s", lbvserverName, servicegroupName)
}
log.Printf("[DEBUG] netscaler-provider: new lbvserver has been bound to servicegroup lbvserver %s servicegroup %s", lbvserverName, servicegroupName)
}

if lbmonitorChanged && lbmonitorName != "" {
//Binding has to be updated
//rebind
Expand Down
16 changes: 12 additions & 4 deletions netscaler/resource_servicegroup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,21 +102,29 @@ func testAccCheckServicegroupDestroy(s *terraform.State) error {

const testAccServicegroup_basic = `
resource "netscaler_lbvserver" "foo" {
resource "netscaler_lbvserver" "foo1" {
name = "foo_lb"
name = "foo_lb_1"
ipv46 = "10.202.11.11"
port = 80
servicetype = "HTTP"
}
resource "netscaler_lbvserver" "foo2" {
name = "foo_lb_2"
ipv46 = "10.202.11.12"
port = 80
servicetype = "HTTP"
}
resource "netscaler_servicegroup" "foo" {
servicegroupname = "test_servicegroup"
servicetype = "HTTP"
servicegroupmembers = ["172.20.0.9:80:10", "172.20.0.10:80:10", "172.20.0.11:8080:20"]
lbvserver = "foo_lb"
depends_on = ["netscaler_lbvserver.foo"]
lbvservers = ["foo_lb_1", "foo_lb_2"]
depends_on = ["netscaler_lbvserver.foo1", "netscaler_lbvserver.foo2"]
}
`

0 comments on commit 92a3004

Please sign in to comment.