diff --git a/citrixadc/provider.go b/citrixadc/provider.go index 65ca2f1bd..1252f945f 100644 --- a/citrixadc/provider.go +++ b/citrixadc/provider.go @@ -186,6 +186,7 @@ func providerResources() map[string]*schema.Resource { "citrixadc_appfwprofile_cookieconsistency_binding": resourceCitrixAdcAppfwprofile_cookieconsistency_binding(), "citrixadc_appfwprofile_crosssitescripting_binding": resourceCitrixAdcAppfwprofile_crosssitescripting_binding(), "citrixadc_appfwprofile_sqlinjection_binding": resourceCitrixAdcAppfwprofile_sqlinjection_binding(), + "citrixadc_lbvserver_servicegroup_binding": resourceCitrixAdcLbvserver_servicegroup_binding(), } } diff --git a/citrixadc/resource_citrixadc_lbvserver_servicegroup_binding.go b/citrixadc/resource_citrixadc_lbvserver_servicegroup_binding.go new file mode 100644 index 000000000..b588f70a6 --- /dev/null +++ b/citrixadc/resource_citrixadc_lbvserver_servicegroup_binding.go @@ -0,0 +1,145 @@ +package citrixadc + +import ( + "github.com/chiradeep/go-nitro/config/lb" + + "github.com/chiradeep/go-nitro/netscaler" + "github.com/hashicorp/terraform/helper/schema" + + "fmt" + "log" + "strings" +) + +func resourceCitrixAdcLbvserver_servicegroup_binding() *schema.Resource { + return &schema.Resource{ + SchemaVersion: 1, + Create: createLbvserver_servicegroup_bindingFunc, + Read: readLbvserver_servicegroup_bindingFunc, + Delete: deleteLbvserver_servicegroup_bindingFunc, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "servicegroupname": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + } +} + +func createLbvserver_servicegroup_bindingFunc(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] citrixadc-provider: In createLbvserver_servicegroup_bindingFunc") + client := meta.(*NetScalerNitroClient).client + + name := d.Get("name").(string) + servicegroupname := d.Get("servicegroupname").(string) + + bindingId := fmt.Sprintf("%s,%s", name, servicegroupname) + + lbvserver_servicegroup_binding := lb.Lbvserverservicegroupbinding{ + Name: d.Get("name").(string), + Servicegroupname: d.Get("servicegroupname").(string), + } + + _, err := client.AddResource(netscaler.Lbvserver_servicegroup_binding.Type(), name, &lbvserver_servicegroup_binding) + if err != nil { + return err + } + + d.SetId(bindingId) + + err = readLbvserver_servicegroup_bindingFunc(d, meta) + if err != nil { + log.Printf("[ERROR] netscaler-provider: ?? we just created this lbvserver_servicegroup_binding but we can't read it ?? %s", bindingId) + return nil + } + return nil +} + +func readLbvserver_servicegroup_bindingFunc(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] citrixadc-provider: In readLbvserver_servicegroup_bindingFunc") + client := meta.(*NetScalerNitroClient).client + bindingId := d.Id() + + idSlice := strings.SplitN(bindingId, ",", 2) + name := idSlice[0] + servicegroupname := idSlice[1] + + findParams := netscaler.FindParams{ + ResourceType: "lbvserver_servicegroup_binding", + ResourceName: name, + ResourceMissingErrorCode: 258, + } + dataArr, err := client.FindResourceArrayWithParams(findParams) + + // Unexpected error + if err != nil { + log.Printf("[DEBUG] citrixadc-provider: Error during FindResourceArrayWithParams %s", err.Error()) + return err + } + + // Resource is missing + if len(dataArr) == 0 { + log.Printf("[DEBUG] citrixadc-provider: FindResourceArrayWithParams returned empty array") + log.Printf("[WARN] citrixadc-provider: Clearing lbvserver_servicegroup_binding state %s", bindingId) + d.SetId("") + return nil + } + + // Iterate through results to find the one with the right monitor name + foundIndex := -1 + for i, v := range dataArr { + if v["servicegroupname"].(string) == servicegroupname { + foundIndex = i + break + } + } + + // Resource is missing + if foundIndex == -1 { + log.Printf("[DEBUG] citrixadc-provider: FindResourceArrayWithParams monitor name not found in array") + log.Printf("[WARN] citrixadc-provider: Clearing lbvserver_servicegroup_binding state %s", bindingId) + d.SetId("") + return nil + } + // Fallthrough + + data := dataArr[foundIndex] + + log.Printf("[DEBUG] citrixadc-provider: Reading lbvserver_servicegroup_binding state %s", bindingId) + d.Set("name", data["name"]) + d.Set("servicegroupname", data["servicegroupname"]) + + return nil + +} + +func deleteLbvserver_servicegroup_bindingFunc(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] citrixadc-provider: In deleteLbvserver_servicegroup_bindingFunc") + client := meta.(*NetScalerNitroClient).client + bindingId := d.Id() + + idSlice := strings.SplitN(bindingId, ",", 2) + name := idSlice[0] + servicegroupname := idSlice[1] + + args := make([]string, 0) + args = append(args, fmt.Sprintf("servicegroupname:%s", servicegroupname)) + + err := client.DeleteResourceWithArgs("lbvserver_servicegroup_binding", name, args) + if err != nil { + return err + } + + d.SetId("") + + return nil +} diff --git a/citrixadc/resource_citrixadc_lbvserver_servicegroup_binding_test.go b/citrixadc/resource_citrixadc_lbvserver_servicegroup_binding_test.go new file mode 100644 index 000000000..211c97985 --- /dev/null +++ b/citrixadc/resource_citrixadc_lbvserver_servicegroup_binding_test.go @@ -0,0 +1,169 @@ +/* +Copyright 2016 Citrix Systems, Inc + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package citrixadc + +import ( + "fmt" + "github.com/chiradeep/go-nitro/netscaler" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + "strings" + "testing" +) + +const testAccLbvserver_servicegroup_binding_basic = ` +resource "citrixadc_lbvserver" "tf_lbvserver" { + ipv46 = "10.10.10.33" + name = "tf_lbvserver" + port = 80 + servicetype = "HTTP" +} + +resource "citrixadc_lbvserver" "tf_lbvserver2" { + ipv46 = "10.10.10.34" + name = "tf_lbvserver2" + port = 80 + servicetype = "HTTP" +} + +resource "citrixadc_servicegroup" "tf_servicegroup" { + servicegroupname = "tf_servicegroup" + servicetype = "HTTP" +} + +resource "citrixadc_servicegroup" "tf_servicegroup2" { + servicegroupname = "tf_servicegroup2" + servicetype = "HTTP" +} + +resource "citrixadc_lbvserver_servicegroup_binding" "tf_binding" { + name = citrixadc_lbvserver.tf_lbvserver.name + servicegroupname = citrixadc_servicegroup.tf_servicegroup.servicegroupname +} + +resource "citrixadc_lbvserver_servicegroup_binding" "tf_binding2" { + name = citrixadc_lbvserver.tf_lbvserver.name + servicegroupname = citrixadc_servicegroup.tf_servicegroup2.servicegroupname +} + +resource "citrixadc_lbvserver_servicegroup_binding" "tf_binding3" { + name = citrixadc_lbvserver.tf_lbvserver2.name + servicegroupname = citrixadc_servicegroup.tf_servicegroup.servicegroupname +} + +resource "citrixadc_lbvserver_servicegroup_binding" "tf_binding4" { + name = citrixadc_lbvserver.tf_lbvserver2.name + servicegroupname = citrixadc_servicegroup.tf_servicegroup2.servicegroupname +} + +` + +func TestAccLbvserver_servicegroup_binding_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckLbvserver_servicegroup_bindingDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccLbvserver_servicegroup_binding_basic, + Check: resource.ComposeTestCheckFunc( + testAccCheckLbvserver_servicegroup_bindingExist("citrixadc_lbvserver_servicegroup_binding.tf_binding", nil), + testAccCheckLbvserver_servicegroup_bindingExist("citrixadc_lbvserver_servicegroup_binding.tf_binding2", nil), + testAccCheckLbvserver_servicegroup_bindingExist("citrixadc_lbvserver_servicegroup_binding.tf_binding3", nil), + testAccCheckLbvserver_servicegroup_bindingExist("citrixadc_lbvserver_servicegroup_binding.tf_binding4", nil), + ), + }, + }, + }) +} + +func testAccCheckLbvserver_servicegroup_bindingExist(n string, id *string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No lbvserver_servicegroup_binding name is set") + } + + if id != nil { + if *id != "" && *id != rs.Primary.ID { + return fmt.Errorf("Resource ID has changed!") + } + + *id = rs.Primary.ID + } + + client := testAccProvider.Meta().(*NetScalerNitroClient).client + + bindingId := rs.Primary.ID + + idSlice := strings.SplitN(bindingId, ",", 2) + name := idSlice[0] + servicegroupname := idSlice[1] + + findParams := netscaler.FindParams{ + ResourceType: "lbvserver_servicegroup_binding", + ResourceName: name, + ResourceMissingErrorCode: 258, + } + dataArr, err := client.FindResourceArrayWithParams(findParams) + + if err != nil { + return err + } + + // Iterate through results to find the one with the right monitor name + foundIndex := -1 + for i, v := range dataArr { + if v["servicegroupname"].(string) == servicegroupname { + foundIndex = i + break + } + } + + // Resource is missing + if foundIndex == -1 { + return fmt.Errorf("lbvserver_servicegroup_binding %s not found", n) + } + + return nil + } +} + +func testAccCheckLbvserver_servicegroup_bindingDestroy(s *terraform.State) error { + nsClient := testAccProvider.Meta().(*NetScalerNitroClient).client + + for _, rs := range s.RootModule().Resources { + if rs.Type != "citrixadc_lbvserver_servicegroup_binding" { + continue + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No name is set") + } + + _, err := nsClient.FindResource(netscaler.Lbvserver_servicegroup_binding.Type(), rs.Primary.ID) + if err == nil { + return fmt.Errorf("lbvserver_servicegroup_binding %s still exists", rs.Primary.ID) + } + + } + + return nil +} diff --git a/citrixadc/resource_citrixadc_servicegroup.go b/citrixadc/resource_citrixadc_servicegroup.go index 5afb9fae8..72b73d000 100644 --- a/citrixadc/resource_citrixadc_servicegroup.go +++ b/citrixadc/resource_citrixadc_servicegroup.go @@ -677,16 +677,18 @@ 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) - lbvservers = append(lbvservers, boundVserver) + if _, ok := d.GetOk("lbvservers"); ok { + var boundVserver string + lbvservers := make([]string, 0, len(vserverBindings)) + for _, vserver := range vserverBindings { + vs, ok := vserver["vservername"] + if ok { + boundVserver = vs.(string) + lbvservers = append(lbvservers, boundVserver) + } } + d.Set("lbvservers", lbvservers) } - d.Set("lbvservers", lbvservers) var boundMonitor string for _, monitor := range boundMonitors { diff --git a/docs/resources/lbvserver_servicegroup_binding.md b/docs/resources/lbvserver_servicegroup_binding.md new file mode 100644 index 000000000..efd277bb5 --- /dev/null +++ b/docs/resources/lbvserver_servicegroup_binding.md @@ -0,0 +1,54 @@ +--- +subcategory: "Load Balancing" +--- + +# Resource: lbvserver\_servicegroup\_binding + +The lbvserver\_servicegroup\_binding resource is used to bind servicegroups to lb vservers. + +If a binding between lbvserver and servicegroup is set this way the `lbvservers` option +of `resource_citrixadc_servicegroup` should not be set for the same servicegroup. + + +## Example usage + +```hcl +resource "citrixadc_lbvserver" "tf_lbvserver" { + ipv46 = "10.10.10.33" + name = "tf_lbvserver" + port = 80 + servicetype = "HTTP" +} + +resource "citrixadc_servicegroup" "tf_servicegroup" { + servicegroupname = "tf_servicegroup" + servicetype = "HTTP" +} + +resource "citrixadc_lbvserver_servicegroup_binding" "tf_binding" { + name = citrixadc_lbvserver.tf_lbvserver.name + servicegroupname = citrixadc_servicegroup.tf_servicegroup.servicegroupname +} +``` + + +## Argument Reference + +* `servicegroupname` - (Required) The service group name bound to the selected load balancing virtual server. +* `name` - (Required) Name for the virtual server. Must begin with an ASCII alphanumeric or underscore (\_) character, and must contain only ASCII alphanumeric, underscore, hash (#), period (.), space, colon (:), at sign (@), equal sign (=), and hyphen (-) characters. Can be changed after the virtual server is created. CLI Users: If the name includes one or more spaces, enclose the name in double or single quotation marks (for example, "my vserver" or 'my vserver'). . + + +## Attribute Reference + +In addition to the arguments, the following attributes are available: + +* `id` - The id of the lbvserver\_servicegroup\_binding. It is the concatenation of the name and servicegroupname attributes separated by a comma. + + +## Import + +A lbvserver\_servicegroup\_binding can be imported using its id. + +```shell +terraform import citrixadc_lbvserver_servicegroup_binding.tf_binding tf_lbvserver,tf_servicegroupname +``` diff --git a/docs/resources/nslicense.md b/docs/resources/nslicense.md index 3138753a4..2bed69add 100644 --- a/docs/resources/nslicense.md +++ b/docs/resources/nslicense.md @@ -24,7 +24,7 @@ resource "citrixadc_nslicense" "tf_license" { * `ssh_username` - (Optional) The user name for the ssh connection. * `ssh_password` - (Optional) The password for the ssh connection. * `ssh_port` - (Optional) The port for the ssh connection. -* `ssh_host_pubkey` - (Optional) The ADC public ssh host key. +* `ssh_host_pubkey` - (Required) The ADC public ssh host key. * `reboot` - (Optional) Set this to true to reboot and wait for the ADC to become responsive. * `poll_delay` - (Optional) Time to wait before the first poll after reboot. Defaults to "60s". * `poll_interval` - (Optional) Interval between polls. Defaults to "60s".