Skip to content

Commit

Permalink
Enable attaching vms to LBU with 'backendIps'
Browse files Browse the repository at this point in the history
  • Loading branch information
outscale-toa committed Oct 24, 2024
1 parent a846569 commit d30d7e9
Show file tree
Hide file tree
Showing 3 changed files with 190 additions and 133 deletions.
7 changes: 6 additions & 1 deletion outscale/data_source_outscale_load_balancer_vms.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,17 @@ func DataSourceOutscaleLoadBalancerVms() *schema.Resource {
ForceNew: true,
Required: true,
},

"backend_vm_ids": {
Type: schema.TypeList,
ForceNew: true,
Required: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
"backend_ips": {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
"request_id": {
Type: schema.TypeString,
Computed: true,
Expand All @@ -39,5 +43,6 @@ func DataSourceOutscaleLoadBalancerVmsRead(d *schema.ResourceData,
}

d.Set("backend_vm_ids", utils.StringSlicePtrToInterfaceSlice(lb.BackendVmIds))
d.Set("backend_ips", utils.StringSlicePtrToInterfaceSlice(lb.BackendIps))
return nil
}
251 changes: 181 additions & 70 deletions outscale/resource_outscale_load_balancer_vms.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/outscale/terraform-provider-outscale/utils"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

Expand All @@ -26,10 +27,14 @@ func ResourceLBUAttachment() *schema.Resource {
ForceNew: true,
Required: true,
},

"backend_vm_ids": {
Type: schema.TypeSet,
Required: true,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
"backend_ips": {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
"request_id": {
Expand All @@ -42,25 +47,34 @@ func ResourceLBUAttachment() *schema.Resource {
func ResourceLBUAttachmentCreate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*OutscaleClient).OSCAPI
lbuName := d.Get("load_balancer_name").(string)
vmIds := d.Get("backend_vm_ids").(*schema.Set)
vmIds := utils.SetToStringSlice(d.Get("backend_vm_ids").(*schema.Set))
vmIps := d.Get("backend_ips").(*schema.Set)
if len(vmIds) == 0 && vmIps.Len() == 0 {
return fmt.Errorf("Error: the 'backend_vm_ids' and 'backend_ips' parameters cannot both be empty")
}
if vmIps.Len() > 0 {
vm_ips, err := getVmIdsFromVmIps(conn, vmIps)
if err != nil {
return err
}
vmIds = append(vmIds, vm_ips...)
}

req := oscgo.RegisterVmsInLoadBalancerRequest{
LoadBalancerName: lbuName,
BackendVmIds: SetStringToListString(vmIds),
BackendVmIds: vmIds,
}
var err error
err = resource.Retry(5*time.Minute, func() *resource.RetryError {
_, httpResp, err := conn.LoadBalancerApi.
RegisterVmsInLoadBalancer(context.Background()).
RegisterVmsInLoadBalancerRequest(req).
Execute()

err := retry.Retry(5*time.Minute, func() *retry.RetryError {
_, httpResp, err := conn.LoadBalancerApi.RegisterVmsInLoadBalancer(
context.Background()).RegisterVmsInLoadBalancerRequest(req).Execute()
if err != nil {
return utils.CheckThrottling(httpResp, err)
}
return nil
})
if err != nil {
return fmt.Errorf("Failure registering backend_vm_ids with LBU: %s", err)
return fmt.Errorf("Failure Linking LoadBalancer backend_vm_ids/backend_ips with LBU: %w", err)
}
d.SetId(resource.PrefixedUniqueId(fmt.Sprintf("%s-", lbuName)))
return ResourceLBUAttachmentRead(d, meta)
Expand All @@ -69,121 +83,218 @@ func ResourceLBUAttachmentCreate(d *schema.ResourceData, meta interface{}) error
func ResourceLBUAttachmentRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*OutscaleClient).OSCAPI
lbuName := d.Get("load_balancer_name").(string)
lb, _, err := readResourceLb(conn, lbuName)
lbu, _, err := readResourceLb(conn, lbuName)
if err != nil {
return err
}
if lb == nil {
if lbu == nil {
utils.LogManuallyDeleted("LoadBalancerVms", d.Id())
d.SetId("")
return nil
}

expected := d.Get("backend_vm_ids").(*schema.Set)
all_backends := schema.Set{F: expected.F}
for _, v := range *lb.BackendVmIds {
all_backends.Add(v)
}
expectedVmIds := d.Get("backend_vm_ids").(*schema.Set)
all_backendVms := d.Get("backend_vm_ids").(*schema.Set)
expectedIps := d.Get("backend_ips").(*schema.Set)
all_backendIps := d.Get("backend_ips").(*schema.Set)

managed := all_backends.Intersection(expected)
d.Set("backend_vm_ids", managed)
for _, vmId := range lbu.GetBackendVmIds() {
all_backendVms.Add(vmId)
}
publicIps, err := getVmIpsFromVmIds(conn, all_backendVms)
if err != nil {
return err
}
for _, vmIp := range publicIps {
all_backendIps.Add(vmIp)
}
managedVmIds := all_backendVms.Intersection(expectedVmIds)
managedIps := all_backendIps.Intersection(expectedIps)

if managed.Len() == 0 {
if managedVmIds.Len() == 0 && managedIps.Len() == 0 {
log.Printf("[WARN] not expected attachments found in LBU %s", lbuName)
log.Printf("[WARN] lbu current attachments are %#v", &all_backends)
log.Printf("[WARN] we would manage only these attachments %#v", expected)
log.Printf("[WARN] no managed attachments are present.")
d.SetId("")
return nil
}
if err := d.Set("load_balancer_name", lbu.GetLoadBalancerName()); err != nil {
return err
}
if err := d.Set("backend_vm_ids", managedVmIds); err != nil {
return err
}
if err := d.Set("backend_ips", managedIps); err != nil {
return err
}

return nil
}

func ResourceLBUAttachmentUpdate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*OutscaleClient).OSCAPI
lbuName := d.Get("load_balancer_name").(string)
var err error

if !d.HasChange("backend_vm_ids") {
return nil
linkReq, unLinkReq, err := buildUpdateBackendsRequest(d, conn, lbuName)
if err != nil {
return err
}

oldBackends, newBackends := d.GetChange("backend_vm_ids")
inter := oldBackends.(*schema.Set).Intersection(newBackends.(*schema.Set))
created := newBackends.(*schema.Set).Difference(inter)
removed := oldBackends.(*schema.Set).Difference(inter)

if created.Len() > 0 {
err = resource.Retry(5*time.Minute, func() *resource.RetryError {
if linkReq.HasBackendVmIds() {
err := retry.Retry(5*time.Minute, func() *retry.RetryError {
_, httpResp, err := conn.LoadBalancerApi.
RegisterVmsInLoadBalancer(context.Background()).
RegisterVmsInLoadBalancerRequest(
oscgo.RegisterVmsInLoadBalancerRequest{
LoadBalancerName: lbuName,
BackendVmIds: SetStringToListString(created),
}).
Execute()
LinkLoadBalancerBackendMachines(context.Background()).
LinkLoadBalancerBackendMachinesRequest(*linkReq).Execute()
if err != nil {
return utils.CheckThrottling(httpResp, err)
}
return nil
})
if err != nil {
return fmt.Errorf("Failure registering new backend_vm_ids with LBU: %s", err)
return fmt.Errorf("Failure linking backends to LBU: %s", err)
}
}
if removed.Len() > 0 {
err = resource.Retry(5*time.Minute, func() *resource.RetryError {
if unLinkReq.HasBackendVmIds() {
err := retry.Retry(5*time.Minute, func() *retry.RetryError {
_, httpResp, err := conn.LoadBalancerApi.
DeregisterVmsInLoadBalancer(context.Background()).
DeregisterVmsInLoadBalancerRequest(
oscgo.DeregisterVmsInLoadBalancerRequest{
LoadBalancerName: lbuName,
BackendVmIds: SetStringToListString(removed),
}).
Execute()
UnlinkLoadBalancerBackendMachines(context.Background()).
UnlinkLoadBalancerBackendMachinesRequest(*unLinkReq).Execute()
if err != nil {
return utils.CheckThrottling(httpResp, err)
}
return nil
})
if err != nil {
return fmt.Errorf("Failure deregistering old backend_vm_ids from LBU: %s", err)
return fmt.Errorf("Failure unlinking backends from LBU: %s", err)
}
}
return ResourceLBUAttachmentRead(d, meta)
}

func buildUpdateBackendsRequest(d *schema.ResourceData, conn *oscgo.APIClient, lbuName string) (*oscgo.LinkLoadBalancerBackendMachinesRequest, *oscgo.UnlinkLoadBalancerBackendMachinesRequest, error) {
linkReq := oscgo.NewLinkLoadBalancerBackendMachinesRequest(lbuName)
unLinkReq := oscgo.NewUnlinkLoadBalancerBackendMachinesRequest(lbuName)
linkVmIds := make([]string, 0, 0)
unlinkVmIds := make([]string, 0, 0)
if d.HasChange("backend_vm_ids") {
oldBackends, newBackends := d.GetChange("backend_vm_ids")
inter := oldBackends.(*schema.Set).Intersection(newBackends.(*schema.Set))
created := newBackends.(*schema.Set).Difference(inter)
removed := oldBackends.(*schema.Set).Difference(inter)

if created.Len() > 0 {
linkVmIds = append(linkVmIds, utils.SetToStringSlice(created)...)
}
if removed.Len() > 0 {
unlinkVmIds = append(linkVmIds, utils.SetToStringSlice(removed)...)
}
}
if d.HasChange("backend_ips") {
oldBackends, newBackends := d.GetChange("backend_ips")
inter := oldBackends.(*schema.Set).Intersection(newBackends.(*schema.Set))
created := newBackends.(*schema.Set).Difference(inter)
removed := oldBackends.(*schema.Set).Difference(inter)

if created.Len() > 0 {
vmIds, err := getVmIdsFromVmIps(conn, created)
if err != nil {
return nil, nil, err
}
linkVmIds = append(linkVmIds, vmIds...)
}
if removed.Len() > 0 {
vmIds, err := getVmIdsFromVmIps(conn, removed)
if err != nil {
return nil, nil, err
}
unlinkVmIds = append(linkVmIds, vmIds...)
}
}
if len(linkVmIds) > 0 {
linkReq.SetBackendVmIds(linkVmIds)
}
if len(unlinkVmIds) > 0 {
unLinkReq.SetBackendVmIds(unlinkVmIds)
}
return linkReq, unLinkReq, nil
}

func ResourceLBUAttachmentDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*OutscaleClient).OSCAPI
lbuName := d.Get("load_balancer_name").(string)
vmIds := d.Get("backend_vm_ids").(*schema.Set)

req := oscgo.DeregisterVmsInLoadBalancerRequest{
LoadBalancerName: lbuName,
BackendVmIds: SetStringToListString(vmIds),
unlinkVmIds := utils.SetToStringSlicePtr(d.Get("backend_vm_ids").(*schema.Set))
if ips := d.Get("backend_ips").(*schema.Set); ips.Len() > 0 {
vmIps, err := getVmIdsFromVmIps(conn, ips)
if err != nil {
return err
}
*unlinkVmIds = append(*unlinkVmIds, vmIps...)
}
var err error
err = resource.Retry(5*time.Minute, func() *resource.RetryError {
err := retry.Retry(5*time.Minute, func() *retry.RetryError {
_, httpResp, err := conn.LoadBalancerApi.
DeregisterVmsInLoadBalancer(context.Background()).
DeregisterVmsInLoadBalancerRequest(req).
Execute()
UnlinkLoadBalancerBackendMachines(context.Background()).
UnlinkLoadBalancerBackendMachinesRequest(
oscgo.UnlinkLoadBalancerBackendMachinesRequest{
LoadBalancerName: lbuName,
BackendVmIds: unlinkVmIds,
}).Execute()
if err != nil {
return utils.CheckThrottling(httpResp, err)
}
return nil
})
if err != nil {
return fmt.Errorf("Failure deregistering backend_vm_ids from LBU: %s", err)
return fmt.Errorf("Failure unlinking backend_ips from LBU: %s", err)
}
return nil
}

func SetStringToListString(set *schema.Set) []string {
result := make([]string, 0, set.Len())
for _, val := range set.List() {
result = append(result, val.(string))
func getVmIdsFromVmIps(conn *oscgo.APIClient, vmIps *schema.Set) ([]string, error) {
filterIps := oscgo.NewFiltersVm()
filterIps.SetPublicIps(utils.SetToStringSlice(vmIps))
var resp oscgo.ReadVmsResponse
err := retry.Retry(30*time.Second, func() *retry.RetryError {
rp, httpResp, err := conn.VmApi.ReadVms(context.Background()).ReadVmsRequest(oscgo.ReadVmsRequest{
Filters: filterIps}).Execute()
if err != nil {
return utils.CheckThrottling(httpResp, err)
}
resp = rp
return nil
})
if err != nil {
return nil, err
}
vms := resp.GetVms()
if len(vms) == 0 {
return nil, fmt.Errorf("Not found Vms with public_ip [%v]", utils.SetToStringSlice(vmIps))
}
vmsIds := make([]string, 0, len(vms))
for _, vm := range vms {
vmsIds = append(vmsIds, vm.GetVmId())
}
return vmsIds, nil
}

func getVmIpsFromVmIds(conn *oscgo.APIClient, vmIds *schema.Set) ([]string, error) {
filters := oscgo.NewFiltersVm()
filters.SetVmIds(utils.SetToStringSlice(vmIds))
var resp oscgo.ReadVmsResponse
err := retry.Retry(30*time.Second, func() *retry.RetryError {
rp, httpResp, err := conn.VmApi.ReadVms(context.Background()).ReadVmsRequest(oscgo.ReadVmsRequest{
Filters: filters}).Execute()
if err != nil {
return utils.CheckThrottling(httpResp, err)
}
resp = rp
return nil
})
if err != nil {
return nil, err
}
vms := resp.GetVms()
if len(vms) == 0 {
return nil, fmt.Errorf("Not found Vms with vm_ids [%v]", utils.SetToStringSlice(vmIds))
}
publicIps := make([]string, 0, len(vms))
for _, vm := range vms {
publicIps = append(publicIps, vm.GetPublicIp())
}
return result
return publicIps, nil
}
Loading

0 comments on commit d30d7e9

Please sign in to comment.