func resourceLBMemberV1Create(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) networkingClient, err := config.networkingV2Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack networking client: %s", err) } createOpts := members.CreateOpts{ TenantID: d.Get("tenant_id").(string), PoolID: d.Get("pool_id").(string), Address: d.Get("address").(string), ProtocolPort: d.Get("port").(int), } log.Printf("[DEBUG] OpenStack LB Member Create Options: %#v", createOpts) m, err := members.Create(networkingClient, createOpts).Extract() if err != nil { return fmt.Errorf("Error creating OpenStack LB member: %s", err) } log.Printf("[INFO] LB member ID: %s", m.ID) log.Printf("[DEBUG] Waiting for OpenStack LB member (%s) to become available.", m.ID) stateConf := &resource.StateChangeConf{ Pending: []string{"PENDING_CREATE"}, Target: []string{"ACTIVE", "INACTIVE"}, Refresh: waitForLBMemberActive(networkingClient, m.ID), Timeout: 2 * time.Minute, Delay: 5 * time.Second, MinTimeout: 3 * time.Second, } _, err = stateConf.WaitForState() if err != nil { return err } d.SetId(m.ID) // Due to the way Gophercloud is currently set up, AdminStateUp must be set post-create asu := d.Get("admin_state_up").(bool) updateOpts := members.UpdateOpts{ AdminStateUp: &asu, } log.Printf("[DEBUG] OpenStack LB Member Update Options: %#v", createOpts) m, err = members.Update(networkingClient, m.ID, updateOpts).Extract() if err != nil { return fmt.Errorf("Error updating OpenStack LB member: %s", err) } return resourceLBMemberV1Read(d, meta) }
func TestCreate(t *testing.T) { th.SetupHTTP() defer th.TeardownHTTP() th.Mux.HandleFunc("/v2.0/lb/members", func(w http.ResponseWriter, r *http.Request) { th.TestMethod(t, r, "POST") th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) th.TestHeader(t, r, "Content-Type", "application/json") th.TestHeader(t, r, "Accept", "application/json") th.TestJSONRequest(t, r, ` { "member": { "tenant_id": "453105b9-1754-413f-aab1-55f1af620750", "pool_id": "foo", "address": "192.0.2.14", "protocol_port":8080 } } `) w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) fmt.Fprintf(w, ` { "member": { "id": "975592ca-e308-48ad-8298-731935ee9f45", "address": "192.0.2.14", "protocol_port": 8080, "tenant_id": "453105b9-1754-413f-aab1-55f1af620750", "admin_state_up":true, "weight": 1, "status": "DOWN" } } `) }) options := members.CreateOpts{ TenantID: "453105b9-1754-413f-aab1-55f1af620750", Address: "192.0.2.14", ProtocolPort: 8080, PoolID: "foo", } _, err := members.Create(fake.ServiceClient(), options).Extract() th.AssertNoErr(t, err) }
// CreateMember will create a load balancer member in a specified pool on a // random port. An error will be returned if the member could not be created. func CreateMember(t *testing.T, client *gophercloud.ServiceClient, poolID string) (*members.Member, error) { protocolPort := tools.RandomInt(100, 1000) address := tools.RandomInt(2, 200) t.Logf("Attempting to create member in port %d", protocolPort) createOpts := members.CreateOpts{ PoolID: poolID, ProtocolPort: protocolPort, Address: fmt.Sprintf("192.168.1.%d", address), } member, err := members.Create(client, createOpts).Extract() if err != nil { return member, err } t.Logf("Successfully created member %s") return member, nil }
func resourceLBPoolV1Update(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) networkingClient, err := config.networkingV2Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack networking client: %s", err) } var updateOpts pools.UpdateOpts // If either option changed, update both. // Gophercloud complains if one is empty. if d.HasChange("name") || d.HasChange("lb_method") { updateOpts.Name = d.Get("name").(string) lbMethod := resourceLBPoolV1DetermineLBMethod(d.Get("lb_method").(string)) updateOpts.LBMethod = lbMethod } log.Printf("[DEBUG] Updating OpenStack LB Pool %s with options: %+v", d.Id(), updateOpts) _, err = pools.Update(networkingClient, d.Id(), updateOpts).Extract() if err != nil { return fmt.Errorf("Error updating OpenStack LB Pool: %s", err) } if d.HasChange("monitor_ids") { oldMIDsRaw, newMIDsRaw := d.GetChange("security_groups") oldMIDsSet, newMIDsSet := oldMIDsRaw.(*schema.Set), newMIDsRaw.(*schema.Set) monitorsToAdd := newMIDsSet.Difference(oldMIDsSet) monitorsToRemove := oldMIDsSet.Difference(newMIDsSet) log.Printf("[DEBUG] Monitors to add: %v", monitorsToAdd) log.Printf("[DEBUG] Monitors to remove: %v", monitorsToRemove) for _, m := range monitorsToAdd.List() { _, err := pools.AssociateMonitor(networkingClient, d.Id(), m.(string)).Extract() if err != nil { return fmt.Errorf("Error associating monitor (%s) with OpenStack server (%s): %s", m.(string), d.Id(), err) } log.Printf("[DEBUG] Associated monitor (%s) with pool (%s)", m.(string), d.Id()) } for _, m := range monitorsToRemove.List() { _, err := pools.DisassociateMonitor(networkingClient, d.Id(), m.(string)).Extract() if err != nil { return fmt.Errorf("Error disassociating monitor (%s) from OpenStack server (%s): %s", m.(string), d.Id(), err) } log.Printf("[DEBUG] Disassociated monitor (%s) from pool (%s)", m.(string), d.Id()) } } if d.HasChange("member") { oldMembersRaw, newMembersRaw := d.GetChange("member") oldMembersSet, newMembersSet := oldMembersRaw.(*schema.Set), newMembersRaw.(*schema.Set) membersToAdd := newMembersSet.Difference(oldMembersSet) membersToRemove := oldMembersSet.Difference(newMembersSet) log.Printf("[DEBUG] Members to add: %v", membersToAdd) log.Printf("[DEBUG] Members to remove: %v", membersToRemove) for _, m := range membersToRemove.List() { oldMember := resourcePoolMemberV1(d, m) listOpts := members.ListOpts{ PoolID: d.Id(), Address: oldMember.Address, ProtocolPort: oldMember.ProtocolPort, } err = members.List(networkingClient, listOpts).EachPage(func(page pagination.Page) (bool, error) { extractedMembers, err := members.ExtractMembers(page) if err != nil { return false, err } for _, member := range extractedMembers { err := members.Delete(networkingClient, member.ID).ExtractErr() if err != nil { return false, fmt.Errorf("Error deleting member (%s) from OpenStack LB pool (%s): %s", member.ID, d.Id(), err) } log.Printf("[DEBUG] Deleted member (%s) from pool (%s)", member.ID, d.Id()) } return true, nil }) } for _, m := range membersToAdd.List() { createOpts := resourcePoolMemberV1(d, m) newMember, err := members.Create(networkingClient, createOpts).Extract() if err != nil { return fmt.Errorf("Error creating LB member: %s", err) } log.Printf("[DEBUG] Created member (%s) in OpenStack LB pool (%s)", newMember.ID, d.Id()) } } return resourceLBPoolV1Read(d, meta) }
func resourceLBPoolV1Create(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) networkingClient, err := config.networkingV2Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack networking client: %s", err) } createOpts := pools.CreateOpts{ Name: d.Get("name").(string), SubnetID: d.Get("subnet_id").(string), TenantID: d.Get("tenant_id").(string), Provider: d.Get("lb_provider").(string), } if v, ok := d.GetOk("protocol"); ok { protocol := resourceLBPoolV1DetermineProtocol(v.(string)) createOpts.Protocol = protocol } if v, ok := d.GetOk("lb_method"); ok { lbMethod := resourceLBPoolV1DetermineLBMethod(v.(string)) createOpts.LBMethod = lbMethod } log.Printf("[DEBUG] Create Options: %#v", createOpts) p, err := pools.Create(networkingClient, createOpts).Extract() if err != nil { return fmt.Errorf("Error creating OpenStack LB pool: %s", err) } log.Printf("[INFO] LB Pool ID: %s", p.ID) log.Printf("[DEBUG] Waiting for OpenStack LB pool (%s) to become available.", p.ID) stateConf := &resource.StateChangeConf{ Pending: []string{"PENDING_CREATE"}, Target: []string{"ACTIVE"}, Refresh: waitForLBPoolActive(networkingClient, p.ID), Timeout: 2 * time.Minute, Delay: 5 * time.Second, MinTimeout: 3 * time.Second, } _, err = stateConf.WaitForState() if err != nil { return err } d.SetId(p.ID) if mIDs := resourcePoolMonitorIDsV1(d); mIDs != nil { for _, mID := range mIDs { _, err := pools.AssociateMonitor(networkingClient, p.ID, mID).Extract() if err != nil { return fmt.Errorf("Error associating monitor (%s) with OpenStack LB pool (%s): %s", mID, p.ID, err) } } } if memberOpts := resourcePoolMembersV1(d); memberOpts != nil { for _, memberOpt := range memberOpts { _, err := members.Create(networkingClient, memberOpt).Extract() if err != nil { return fmt.Errorf("Error creating OpenStack LB member: %s", err) } } } return resourceLBPoolV1Read(d, meta) }
// Update load balancer func (os *OpenStack) UpdateLoadBalancer(name string, hosts []*provider.HostPort, externalIPs []string) (string, error) { if len(externalIPs) > 1 { return "", fmt.Errorf("multiple floatingips are not yet supported by openstack") } vip, err := os.getVipByName(name) if err != nil { return "", err } lb, err := os.GetLoadBalancer(name) if err != nil { return "", err } // Set of member (addresses) that _should_ exist addrs := make(map[string]*provider.HostPort) for _, host := range hosts { addrs[host.Ipaddress] = host } // Iterate over members that _do_ exist pager := members.List(os.network, members.ListOpts{PoolID: vip.PoolID}) err = pager.EachPage(func(page pagination.Page) (bool, error) { memList, err := members.ExtractMembers(page) if err != nil { return false, err } for _, member := range memList { if _, found := addrs[member.Address]; found { // Member already exists delete(addrs, member.Address) } else { // Member needs to be deleted err = members.Delete(os.network, member.ID).ExtractErr() if err != nil { return false, err } } } return true, nil }) if err != nil { return "", err } // Anything left in addrs is a new member that needs to be added for _, addr := range addrs { _, err := members.Create(os.network, members.CreateOpts{ TenantID: lb.TenantID, PoolID: vip.PoolID, Address: addr.Ipaddress, ProtocolPort: int(addr.TargetPort), }).Extract() if err != nil { return "", err } } // bind to external ip if len(externalIPs) > 0 { err := os.BindPortToFloatingip(vip.PortID, externalIPs[0], vip.TenantID) if err != nil { return "", err } } return lb.Vip, nil }
// Create load balancer func (os *OpenStack) CreateLoadBalancer(loadBalancer *provider.LoadBalancer, affinity string) (string, error) { if len(loadBalancer.ExternalIPs) > 1 { return "", fmt.Errorf("multiple floatingips are not yet supported by openstack") } servicePort := 0 for _, p := range loadBalancer.Hosts { if servicePort == 0 { servicePort = int(p.ServicePort) } else if int(p.ServicePort) != servicePort { return "", fmt.Errorf("multiple ports are not yet supported in openstack load balancers") } } var persistence *vips.SessionPersistence switch affinity { case ServiceAffinityNone: persistence = nil case ServiceAffinityClientIP: persistence = &vips.SessionPersistence{Type: "SOURCE_IP"} default: return "", fmt.Errorf("unsupported load balancer affinity: %v", affinity) } glog.V(2).Info("Checking if openstack load balancer already exists: ", loadBalancer.Name) _, err := os.getPoolByName(loadBalancer.Name) if err != nil && err != ErrNotFound { return "", fmt.Errorf("error checking if openstack load balancer already exists: %v", err) } if err == nil { err := os.DeleteLoadBalancer(loadBalancer.Name) if err != nil { return "", fmt.Errorf("error deleting existing openstack load balancer: %v", err) } } lbmethod := pools.LBMethodRoundRobin if os.lbOpts.LBMethod != "" { lbmethod = pools.LBMethod(os.lbOpts.LBMethod) } pool, err := pools.Create(os.network, pools.CreateOpts{ Name: loadBalancer.Name, Protocol: pools.ProtocolTCP, SubnetID: loadBalancer.Subnets[0].Uid, LBMethod: lbmethod, TenantID: loadBalancer.TenantID, }).Extract() if err != nil { return "", err } for _, host := range loadBalancer.Hosts { _, err = members.Create(os.network, members.CreateOpts{ PoolID: pool.ID, ProtocolPort: int(host.TargetPort), Address: host.Ipaddress, TenantID: loadBalancer.TenantID, }).Extract() if err != nil { pools.Delete(os.network, pool.ID) return "", err } } var mon *monitors.Monitor if os.lbOpts.CreateMonitor { mon, err = monitors.Create(os.network, monitors.CreateOpts{ Type: monitors.TypeTCP, TenantID: loadBalancer.TenantID, Delay: int(os.lbOpts.MonitorDelay.Duration.Seconds()), Timeout: int(os.lbOpts.MonitorTimeout.Duration.Seconds()), MaxRetries: int(os.lbOpts.MonitorMaxRetries), }).Extract() if err != nil { pools.Delete(os.network, pool.ID) return "", err } _, err = pools.AssociateMonitor(os.network, pool.ID, mon.ID).Extract() if err != nil { monitors.Delete(os.network, mon.ID) pools.Delete(os.network, pool.ID) return "", err } } createOpts := vips.CreateOpts{ Name: loadBalancer.Name, Description: fmt.Sprintf("Kubernetes service %s", loadBalancer.Name), Protocol: "TCP", ProtocolPort: servicePort, PoolID: pool.ID, SubnetID: loadBalancer.Subnets[0].Uid, Persistence: persistence, TenantID: loadBalancer.TenantID, } //if loadBalancer.Vip != "" { // createOpts.Address = loadBalancer.Vip //} vip, err := vips.Create(os.network, createOpts).Extract() if err != nil { if mon != nil { monitors.Delete(os.network, mon.ID) } pools.Delete(os.network, pool.ID) return "", err } // bind external ip if len(loadBalancer.ExternalIPs) > 0 { err := os.BindPortToFloatingip(vip.PortID, loadBalancer.ExternalIPs[0], vip.TenantID) if err != nil { vips.Delete(os.network, vip.ID) if mon != nil { monitors.Delete(os.network, mon.ID) } pools.Delete(os.network, pool.ID) return "", err } } return vip.Address, nil }