From 27b5d1b1318bf3a0a907625e1be0e7aa24334b3b Mon Sep 17 00:00:00 2001 From: Rohit Myali Date: Fri, 19 Apr 2024 10:13:35 +0530 Subject: [PATCH 1/2] Added gslbservicegroup_gslbservicegroupmember_binding resource Signed-off-by: Rohit Myali --- citrixadc/provider.go | 1 + ...icegroup_gslbservicegroupmember_binding.go | 249 ++++++++++++++++++ ...oup_gslbservicegroupmember_binding_test.go | 242 +++++++++++++++++ ...icegroup_gslbservicegroupmember_binding.md | 62 +++++ 4 files changed, 554 insertions(+) create mode 100644 citrixadc/resource_citrixadc_gslbservicegroup_gslbservicegroupmember_binding.go create mode 100644 citrixadc/resource_citrixadc_gslbservicegroup_gslbservicegroupmember_binding_test.go create mode 100644 docs/resources/gslbservicegroup_gslbservicegroupmember_binding.md diff --git a/citrixadc/provider.go b/citrixadc/provider.go index 3e1c72a3e..d9ee13ad1 100644 --- a/citrixadc/provider.go +++ b/citrixadc/provider.go @@ -861,6 +861,7 @@ func providerResources() map[string]*schema.Resource { "citrixadc_lbaction": resourceCitrixAdcLbaction(), "citrixadc_lbpolicy": resourceCitrixAdcLbpolicy(), "citrixadc_sslcrl": resourceCitrixAdcSslcrl(), + "citrixadc_gslbservicegroup_gslbservicegroupmember_binding": resourceCitrixAdcGslbservicegroup_gslbservicegroupmember_binding(), } } diff --git a/citrixadc/resource_citrixadc_gslbservicegroup_gslbservicegroupmember_binding.go b/citrixadc/resource_citrixadc_gslbservicegroup_gslbservicegroupmember_binding.go new file mode 100644 index 000000000..9a5e4b11e --- /dev/null +++ b/citrixadc/resource_citrixadc_gslbservicegroup_gslbservicegroupmember_binding.go @@ -0,0 +1,249 @@ +package citrixadc + +import ( + "strconv" + + "github.com/citrix/adc-nitro-go/resource/config/gslb" + "github.com/citrix/adc-nitro-go/service" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + + "fmt" + "log" + "strings" +) + +func resourceCitrixAdcGslbservicegroup_gslbservicegroupmember_binding() *schema.Resource { + return &schema.Resource{ + SchemaVersion: 1, + Create: createGslbservicegroup_gslbservicegroupmember_bindingFunc, + Read: readGslbservicegroup_gslbservicegroupmember_bindingFunc, + Delete: deleteGslbservicegroup_gslbservicegroupmember_bindingFunc, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "hashid": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ForceNew: true, + }, + "ip": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + "port": { + Type: schema.TypeInt, + Required: true, + Computed: false, + ForceNew: true, + }, + "publicip": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + "publicport": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ForceNew: true, + }, + "servername": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + "servicegroupname": { + Type: schema.TypeString, + Required: true, + Computed: false, + ForceNew: true, + }, + "siteprefix": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + "state": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + "weight": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ForceNew: true, + }, + }, + } +} + +func createGslbservicegroup_gslbservicegroupmember_bindingFunc(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] citrixadc-provider: In createGslbservicegroup_gslbservicegroupmember_bindingFunc") + client := meta.(*NetScalerNitroClient).client + + bindingIdSlice := make([]string, 0, 3) + + bindingIdSlice = append(bindingIdSlice, d.Get("servicegroupname").(string)) + + // Second id component will either be servername or ip + // ConflictsWith restriction ensures that only one of them is defined + if v, ok := d.GetOk("servername"); ok { + bindingIdSlice = append(bindingIdSlice, v.(string)) + } else if v, ok := d.GetOk("ip"); ok { + bindingIdSlice = append(bindingIdSlice, v.(string)) + } + + // Third component will be the port if defined + if v, ok := d.GetOk("port"); ok { + val := strconv.Itoa(v.(int)) + bindingIdSlice = append(bindingIdSlice, val) + } + + bindingId := strings.Join(bindingIdSlice, ",") + + gslbservicegroup_gslbservicegroupmember_binding := gslb.Gslbservicegroupgslbservicegroupmemberbinding{ + Hashid: d.Get("hashid").(int), + Ip: d.Get("ip").(string), + Port: d.Get("port").(int), + Publicip: d.Get("publicip").(string), + Publicport: d.Get("publicport").(int), + Servername: d.Get("servername").(string), + Servicegroupname: d.Get("servicegroupname").(string), + Siteprefix: d.Get("siteprefix").(string), + State: d.Get("state").(string), + Weight: d.Get("weight").(int), + } + + _, err := client.AddResource("gslbservicegroup_gslbservicegroupmember_binding", bindingId, &gslbservicegroup_gslbservicegroupmember_binding) + if err != nil { + return err + } + + d.SetId(bindingId) + + err = readGslbservicegroup_gslbservicegroupmember_bindingFunc(d, meta) + if err != nil { + log.Printf("[ERROR] netscaler-provider: ?? we just created this gslbservicegroup_gslbservicegroupmember_binding but we can't read it ?? %s", bindingId) + return nil + } + return nil +} + +func readGslbservicegroup_gslbservicegroupmember_bindingFunc(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] citrixadc-provider: In readGslbservicegroup_gslbservicegroupmember_bindingFunc") + client := meta.(*NetScalerNitroClient).client + bindingId := d.Id() + idSlice := strings.SplitN(bindingId, ",", 3) + + servicegroupname := idSlice[0] + + // When ip is defined ADC will create a server with name equal to the ip address + // So no matter what the user actually defined servername will always be valid search criterion + servername := idSlice[1] + + port := 0 + var err error + if port, err = strconv.Atoi(idSlice[2]); err != nil { + return err + } + + log.Printf("[DEBUG] citrixadc-provider: Reading gslbservicegroup_gslbservicegroupmember_binding state %s", bindingId) + + findParams := service.FindParams{ + ResourceType: "gslbservicegroup_gslbservicegroupmember_binding", + ResourceName: servicegroupname, + 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 gslbservicegroup_gslbservicegroupmember_binding state %s", bindingId) + d.SetId("") + return nil + } + + // Iterate through results to find the one with the right policy name + foundIndex := -1 + for i, v := range dataArr { + if port != 0 && v["port"] != nil { + portEqual := int(v["port"].(float64)) == port + servernameEqual := v["servername"] == servername + if servernameEqual && portEqual { + foundIndex = i + break + } + } else { + log.Printf("[WARN] citrixadc-provider: port is zero") + if v["servername"].(string) == servername { + foundIndex = i + break + } + } + } + // Resource is missing + if foundIndex == -1 { + log.Printf("[DEBUG] citrixadc-provider: FindResourceArrayWithParams secondIdComponent not found in array") + log.Printf("[WARN] citrixadc-provider: Clearing gslbservicegroup_gslbservicegroupmember_binding state %s", bindingId) + d.SetId("") + return nil + } + // Fallthrough + + data := dataArr[foundIndex] + + d.Set("hashid", data["hashid"]) + d.Set("ip", data["ip"]) + d.Set("port", data["port"]) + d.Set("publicip", data["publicip"]) + d.Set("publicport", data["publicport"]) + d.Set("servername", data["servername"]) + d.Set("servicegroupname", data["servicegroupname"]) + d.Set("siteprefix", data["siteprefix"]) + d.Set("state", data["state"]) + d.Set("weight", data["weight"]) + + return nil + +} + +func deleteGslbservicegroup_gslbservicegroupmember_bindingFunc(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] citrixadc-provider: In deleteGslbservicegroup_gslbservicegroupmember_bindingFunc") + client := meta.(*NetScalerNitroClient).client + + bindingId := d.Id() + idSlice := strings.SplitN(bindingId, ",", 3) + + name := idSlice[0] + servername := idSlice[1] + port := idSlice[2] + + args := make([]string, 0) + args = append(args, fmt.Sprintf("servername:%s", servername)) + args = append(args, fmt.Sprintf("port:%s", port)) + + err := client.DeleteResourceWithArgs("gslbservicegroup_gslbservicegroupmember_binding", name, args) + if err != nil { + return err + } + + d.SetId("") + + return nil +} diff --git a/citrixadc/resource_citrixadc_gslbservicegroup_gslbservicegroupmember_binding_test.go b/citrixadc/resource_citrixadc_gslbservicegroup_gslbservicegroupmember_binding_test.go new file mode 100644 index 000000000..2920738b1 --- /dev/null +++ b/citrixadc/resource_citrixadc_gslbservicegroup_gslbservicegroupmember_binding_test.go @@ -0,0 +1,242 @@ +/* +Copyright 2024 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" + "log" + "strconv" + "strings" + "testing" + + "github.com/citrix/adc-nitro-go/service" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" +) + +const testAccGslbservicegroup_gslbservicegroupmember_binding_basic = ` + + resource "citrixadc_gslbservicegroup" "tf_gslbservicegroup" { + servicegroupname = "test_gslbvservicegroup" + servicetype = "HTTP" + cip = "DISABLED" + healthmonitor = "NO" + sitename = citrixadc_gslbsite.site_local.sitename + } + resource "citrixadc_gslbsite" "site_local" { + sitename = "Site-Local" + siteipaddress = "172.31.96.234" + sessionexchange = "DISABLED" + } + + resource "citrixadc_gslbservicegroup_gslbservicegroupmember_binding" "tf_binding" { + servicegroupname = citrixadc_gslbservicegroup.tf_gslbservicegroup.servicegroupname + servername = "10.10.10.10" + port = 60 + } + +` + +const testAccGslbservicegroup_gslbservicegroupmember_binding_basic_step2 = ` + # Keep the above bound resources without the actual binding to check proper deletion + + resource "citrixadc_gslbservicegroup" "tf_gslbservicegroup" { + servicegroupname = "test_gslbvservicegroup" + servicetype = "HTTP" + cip = "DISABLED" + healthmonitor = "NO" + sitename = citrixadc_gslbsite.site_local.sitename + } + resource "citrixadc_gslbsite" "site_local" { + sitename = "Site-Local" + siteipaddress = "172.31.96.234" + sessionexchange = "DISABLED" + } +` + +func TestAccGslbservicegroup_gslbservicegroupmember_binding_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckGslbservicegroup_gslbservicegroupmember_bindingDestroy, + Steps: []resource.TestStep{ + { + Config: testAccGslbservicegroup_gslbservicegroupmember_binding_basic, + Check: resource.ComposeTestCheckFunc( + testAccCheckGslbservicegroup_gslbservicegroupmember_bindingExist("citrixadc_gslbservicegroup_gslbservicegroupmember_binding.tf_binding", nil), + ), + }, + { + Config: testAccGslbservicegroup_gslbservicegroupmember_binding_basic_step2, + Check: resource.ComposeTestCheckFunc( + testAccCheckGslbservicegroup_gslbservicegroupmember_bindingNotExist("citrixadc_gslbservicegroup_gslbservicegroupmember_binding.tf_binding", "test_gslbvservicegroup,10.10.10.10,60"), + ), + }, + }, + }) +} + +func testAccCheckGslbservicegroup_gslbservicegroupmember_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 gslbservicegroup_gslbservicegroupmember_binding id 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, ",", 3) + servicegroupname := idSlice[0] + + servername := idSlice[1] + + port := 0 + var err error + if len(idSlice) == 3 { + if port, err = strconv.Atoi(idSlice[2]); err != nil { + return err + } + } + + findParams := service.FindParams{ + ResourceType: "gslbservicegroup_gslbservicegroupmember_binding", + ResourceName: servicegroupname, + ResourceMissingErrorCode: 258, + } + dataArr, err := client.FindResourceArrayWithParams(findParams) + + // Unexpected error + if err != nil { + return err + } + + // Iterate through results to find the one with the right policy name + foundIndex := -1 + for i, v := range dataArr { + if port != 0 { + portEqual := int(v["port"].(float64)) == port + servernameEqual := v["servername"] == servername + if servernameEqual && portEqual { + foundIndex = i + break + } + } else { + log.Printf("[DEBUG] teh val sis %v, %v", v["servername"].(string), servername) + if v["servername"].(string) == servername { + foundIndex = i + break + } + } + log.Printf("[DEBUG] teh val sis %v, %v", v["servername"].(string), servername) + } + + if foundIndex == -1 { + return fmt.Errorf("gslbservicegroup_gslbservicegroupmember_binding %s not found", n) + } + + return nil + } +} + +func testAccCheckGslbservicegroup_gslbservicegroupmember_bindingNotExist(n string, id string) resource.TestCheckFunc { + return func(s *terraform.State) error { + client := testAccProvider.Meta().(*NetScalerNitroClient).client + + if !strings.Contains(id, ",") { + return fmt.Errorf("Invalid id string %v. The id string must contain a comma.", id) + } + + idSlice := strings.SplitN(id, ",", 3) + servicegroupname := idSlice[0] + + servername := idSlice[1] + + port := 0 + var err error + if len(idSlice) == 3 { + if port, err = strconv.Atoi(idSlice[2]); err != nil { + return err + } + } + + findParams := service.FindParams{ + ResourceType: "gslbservicegroup_gslbservicegroupmember_binding", + ResourceName: servicegroupname, + ResourceMissingErrorCode: 258, + } + dataArr, err := client.FindResourceArrayWithParams(findParams) + + // Unexpected error + if err != nil { + return err + } + + // Iterate through results to hopefully not find the one with the matching secondIdComponent + // Iterate through results to find the one with the right policy name + foundIndex := -1 + for i, v := range dataArr { + if port != 0 { + portEqual := int(v["port"].(float64)) == port + servernameEqual := v["servername"] == servername + if servernameEqual && portEqual { + foundIndex = i + break + } + } + } + + if foundIndex != -1 { + return fmt.Errorf("servicegroup_servicegroupmember_binding %s found. Should have been deleted", id) + } + + return nil + } +} + +func testAccCheckGslbservicegroup_gslbservicegroupmember_bindingDestroy(s *terraform.State) error { + nsClient := testAccProvider.Meta().(*NetScalerNitroClient).client + + for _, rs := range s.RootModule().Resources { + if rs.Type != "citrixadc_gslbservicegroup_gslbservicegroupmember_binding" { + continue + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No name is set") + } + + _, err := nsClient.FindResource("gslbservicegroup_gslbservicegroupmember_binding", rs.Primary.ID) + if err == nil { + return fmt.Errorf("gslbservicegroup_gslbservicegroupmember_binding %s still exists", rs.Primary.ID) + } + + } + + return nil +} diff --git a/docs/resources/gslbservicegroup_gslbservicegroupmember_binding.md b/docs/resources/gslbservicegroup_gslbservicegroupmember_binding.md new file mode 100644 index 000000000..517dce898 --- /dev/null +++ b/docs/resources/gslbservicegroup_gslbservicegroupmember_binding.md @@ -0,0 +1,62 @@ +--- +subcategory: "GSLB" +--- + +# Resource: gslbservicegroup_gslbservicegroupmember_binding + +The gslbservicegroup_gslbservicegroupmember_binding resource is used to bind gslbservicegroupmember to gslbservicegroup. + + +## Example usage + +```hcl +resource "citrixadc_gslbservicegroup" "tf_gslbservicegroup" { + servicegroupname = "test_gslbvservicegroup" + servicetype = "HTTP" + cip = "DISABLED" + healthmonitor = "NO" + sitename = citrixadc_gslbsite.site_local.sitename +} +resource "citrixadc_gslbsite" "site_local" { + sitename = "Site-Local" + siteipaddress = "172.31.96.234" + sessionexchange = "DISABLED" +} + +resource "citrixadc_gslbservicegroup_gslbservicegroupmember_binding" "name" { + servicegroupname = citrixadc_gslbservicegroup.tf_gslbservicegroup.servicegroupname + servername = "10.10.10.10" + port = 60 +} + +``` + + +## Argument Reference + +* `ip` - (Optional) IP Address. +* `port` - (Optional) Server port number. Range 1 - 65535 * in CLI is represented as 65535 in NITRO API +* `weight` - (Optional) Weight to assign to the servers in the service group. Specifies the capacity of the servers relative to the other servers in the load balancing configuration. The higher the weight, the higher the percentage of requests sent to the service. Minimum value = 1 Maximum value = 100 +* `servername` - (Optional) Name of the server to which to bind the service group. Minimum length = 1 +* `state` - (Optional) Initial state of the GSLB service group. Possible values: [ ENABLED, DISABLED ] +* `hashid` - (Optional) The hash identifier for the service. This must be unique for each service. This parameter is used by hash based load balancing methods. Minimum value = 1 +* `publicip` - (Optional) The public IP address that a NAT device translates to the GSLB service's private IP address. Optional. Minimum length = 1 +* `publicport` - (Optional) The public port associated with the GSLB service's public IP address. The port is mapped to the service's private port number. Applicable to the local GSLB service. Optional. Minimum value = 1 +* `siteprefix` - (Optional) The site's prefix string. When the GSLB service group is bound to a GSLB virtual server, a GSLB site domain is generated internally for each bound serviceitem-domain pair by concatenating the site prefix of the service item and the name of the domain. If the special string NONE is specified, the site-prefix string is unset. When implementing HTTP redirect site persistence, the Citrix ADC redirects GSLB requests to GSLB services by using their site domains. +* `servicegroupname` - (Optional) Name of the GSLB service group. Minimum length = 1 + + +## Attribute Reference + +In addition to the arguments, the following attributes are available: + +* `id` - The id of the gslbservicegroup_gslbservicegroupmember_binding. It has the same value as the `name` attribute. + + +## Import + +A gslbservicegroup_gslbservicegroupmember_binding can be imported using its name, e.g. + +```shell +terraform import citrixadc_gslbservicegroup_gslbservicegroupmember_binding.tf_bind test_gslbvservicegroup,10.10.10.10,60 +``` From eb49998bbc85a1e605a9be2ae770b4cf53d3e7c0 Mon Sep 17 00:00:00 2001 From: Rohit Myali Date: Fri, 19 Apr 2024 10:19:52 +0530 Subject: [PATCH 2/2] Updated gslbservicegroup_gslbservicegroupmember_binding resource Signed-off-by: Rohit Myali --- ...vicegroup_gslbservicegroupmember_binding.go | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/citrixadc/resource_citrixadc_gslbservicegroup_gslbservicegroupmember_binding.go b/citrixadc/resource_citrixadc_gslbservicegroup_gslbservicegroupmember_binding.go index 9a5e4b11e..ac5c8064d 100644 --- a/citrixadc/resource_citrixadc_gslbservicegroup_gslbservicegroupmember_binding.go +++ b/citrixadc/resource_citrixadc_gslbservicegroup_gslbservicegroupmember_binding.go @@ -182,19 +182,11 @@ func readGslbservicegroup_gslbservicegroupmember_bindingFunc(d *schema.ResourceD // Iterate through results to find the one with the right policy name foundIndex := -1 for i, v := range dataArr { - if port != 0 && v["port"] != nil { - portEqual := int(v["port"].(float64)) == port - servernameEqual := v["servername"] == servername - if servernameEqual && portEqual { - foundIndex = i - break - } - } else { - log.Printf("[WARN] citrixadc-provider: port is zero") - if v["servername"].(string) == servername { - foundIndex = i - break - } + portEqual := int(v["port"].(float64)) == port + servernameEqual := v["servername"] == servername + if servernameEqual && portEqual { + foundIndex = i + break } } // Resource is missing