Merge pull request #55393 from jamiehannaford/octavia

Automatic merge from submit-queue (batch tested with PRs 55868, 55393, 55152, 55849). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.

Adds Octavia v2 as LoadBalancer provider

**What this PR does / why we need it**:

Adds support for using Octavia as the OpenStack LB provider.  

**Which issue(s) this PR fixes**:

Although some LB providers can be specified using the [lb-provider](https://github.com/kubernetes/kubernetes/pull/54176/files#diff-694c675fe77b09923cc453e7228f8fa8R85) JSON request field, other installations which use Octavia by default rely on it being discovered via the service catalog. When a user specifies the `load-balancer` service type, it will get back the root Octavia endpoint URL, which needs to have `v2.0` appended to it.

To facilitate this change, gophercloud recently added the `NewLoadBalancerV2` helper in https://github.com/gophercloud/gophercloud/pull/591.

**Release note**:

```release-note
Octavia v2 now supported as a LB provider
```

/cc @xgerman
pull/6/head
Kubernetes Submit Queue 2017-11-16 06:32:19 -08:00 committed by GitHub
commit 403055cbe9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 76 additions and 51 deletions

View File

@ -74,11 +74,13 @@ func (d *MyDuration) UnmarshalText(text []byte) error {
type LoadBalancer struct {
network *gophercloud.ServiceClient
compute *gophercloud.ServiceClient
lb *gophercloud.ServiceClient
opts LoadBalancerOpts
}
type LoadBalancerOpts struct {
LBVersion string `gcfg:"lb-version"` // overrides autodetection. Only support v2.
UseOctavia bool `gcfg:"use-octavia"` // uses Octavia V2 service catalog endpoint
SubnetId string `gcfg:"subnet-id"` // overrides autodetection.
FloatingNetworkId string `gcfg:"floating-network-id"` // If specified, will create floating ip for loadbalancer, or do not create floating ip.
LBMethod string `gcfg:"lb-method"` // default to ROUND_ROBIN.
@ -507,6 +509,11 @@ func (os *OpenStack) LoadBalancer() (cloudprovider.LoadBalancer, bool) {
return nil, false
}
lb, err := os.NewLoadBalancerV2()
if err != nil {
return nil, false
}
// LBaaS v1 is deprecated in the OpenStack Liberty release.
// Currently kubernetes OpenStack cloud provider just support LBaaS v2.
lbVersion := os.lbOpts.LBVersion
@ -517,7 +524,7 @@ func (os *OpenStack) LoadBalancer() (cloudprovider.LoadBalancer, bool) {
glog.V(1).Info("Claiming to support LoadBalancer")
return &LbaasV2{LoadBalancer{network, compute, os.lbOpts}}, true
return &LbaasV2{LoadBalancer{network, compute, lb, os.lbOpts}}, true
}
func isNotFound(err error) bool {

View File

@ -62,3 +62,21 @@ func (os *OpenStack) NewBlockStorageV2() (*gophercloud.ServiceClient, error) {
}
return storage, nil
}
func (os *OpenStack) NewLoadBalancerV2() (*gophercloud.ServiceClient, error) {
var lb *gophercloud.ServiceClient
var err error
if os.lbOpts.UseOctavia {
lb, err = openstack.NewLoadBalancerV2(os.provider, gophercloud.EndpointOpts{
Region: os.region,
})
} else {
lb, err = openstack.NewNetworkV2(os.provider, gophercloud.EndpointOpts{
Region: os.region,
})
}
if err != nil {
return nil, fmt.Errorf("failed to find load-balancer v2 endpoint for region %s: %v", os.region, err)
}
return lb, nil
}

View File

@ -442,7 +442,7 @@ func (lbaas *LbaasV2) createLoadBalancer(service *v1.Service, name string, inter
createOpts.VipAddress = loadBalancerIP
}
loadbalancer, err := loadbalancers.Create(lbaas.network, createOpts).Extract()
loadbalancer, err := loadbalancers.Create(lbaas.lb, createOpts).Extract()
if err != nil {
return nil, fmt.Errorf("error creating loadbalancer %v: %v", createOpts, err)
}
@ -451,7 +451,7 @@ func (lbaas *LbaasV2) createLoadBalancer(service *v1.Service, name string, inter
func (lbaas *LbaasV2) GetLoadBalancer(clusterName string, service *v1.Service) (*v1.LoadBalancerStatus, bool, error) {
loadBalancerName := cloudprovider.GetLoadBalancerName(service)
loadbalancer, err := getLoadbalancerByName(lbaas.network, loadBalancerName)
loadbalancer, err := getLoadbalancerByName(lbaas.lb, loadBalancerName)
if err == ErrNotFound {
return nil, false, nil
}
@ -639,7 +639,7 @@ func (lbaas *LbaasV2) EnsureLoadBalancer(clusterName string, apiService *v1.Serv
}
name := cloudprovider.GetLoadBalancerName(apiService)
loadbalancer, err := getLoadbalancerByName(lbaas.network, name)
loadbalancer, err := getLoadbalancerByName(lbaas.lb, name)
if err != nil {
if err != ErrNotFound {
return nil, fmt.Errorf("error getting loadbalancer %s: %v", name, err)
@ -654,14 +654,14 @@ func (lbaas *LbaasV2) EnsureLoadBalancer(clusterName string, apiService *v1.Serv
glog.V(2).Infof("LoadBalancer %s already exists", name)
}
waitLoadbalancerActiveProvisioningStatus(lbaas.network, loadbalancer.ID)
waitLoadbalancerActiveProvisioningStatus(lbaas.lb, loadbalancer.ID)
lbmethod := v2pools.LBMethod(lbaas.opts.LBMethod)
if lbmethod == "" {
lbmethod = v2pools.LBMethodRoundRobin
}
oldListeners, err := getListenersByLoadBalancerID(lbaas.network, loadbalancer.ID)
oldListeners, err := getListenersByLoadBalancerID(lbaas.lb, loadbalancer.ID)
if err != nil {
return nil, fmt.Errorf("error getting LB %s listeners: %v", name, err)
}
@ -669,7 +669,7 @@ func (lbaas *LbaasV2) EnsureLoadBalancer(clusterName string, apiService *v1.Serv
listener := getListenerForPort(oldListeners, port)
if listener == nil {
glog.V(4).Infof("Creating listener for port %d", int(port.Port))
listener, err = listeners.Create(lbaas.network, listeners.CreateOpts{
listener, err = listeners.Create(lbaas.lb, listeners.CreateOpts{
Name: fmt.Sprintf("listener_%s_%d", name, portIndex),
Protocol: listeners.Protocol(port.Protocol),
ProtocolPort: int(port.Port),
@ -679,7 +679,7 @@ func (lbaas *LbaasV2) EnsureLoadBalancer(clusterName string, apiService *v1.Serv
// Unknown error, retry later
return nil, fmt.Errorf("error creating LB listener: %v", err)
}
waitLoadbalancerActiveProvisioningStatus(lbaas.network, loadbalancer.ID)
waitLoadbalancerActiveProvisioningStatus(lbaas.lb, loadbalancer.ID)
}
glog.V(4).Infof("Listener for %s port %d: %s", string(port.Protocol), int(port.Port), listener.ID)
@ -687,14 +687,14 @@ func (lbaas *LbaasV2) EnsureLoadBalancer(clusterName string, apiService *v1.Serv
// After all ports have been processed, remaining listeners are removed as obsolete.
// Pop valid listeners.
oldListeners = popListener(oldListeners, listener.ID)
pool, err := getPoolByListenerID(lbaas.network, loadbalancer.ID, listener.ID)
pool, err := getPoolByListenerID(lbaas.lb, loadbalancer.ID, listener.ID)
if err != nil && err != ErrNotFound {
// Unknown error, retry later
return nil, fmt.Errorf("error getting pool for listener %s: %v", listener.ID, err)
}
if pool == nil {
glog.V(4).Infof("Creating pool for listener %s", listener.ID)
pool, err = v2pools.Create(lbaas.network, v2pools.CreateOpts{
pool, err = v2pools.Create(lbaas.lb, v2pools.CreateOpts{
Name: fmt.Sprintf("pool_%s_%d", name, portIndex),
Protocol: v2pools.Protocol(port.Protocol),
LBMethod: lbmethod,
@ -705,11 +705,11 @@ func (lbaas *LbaasV2) EnsureLoadBalancer(clusterName string, apiService *v1.Serv
// Unknown error, retry later
return nil, fmt.Errorf("error creating pool for listener %s: %v", listener.ID, err)
}
waitLoadbalancerActiveProvisioningStatus(lbaas.network, loadbalancer.ID)
waitLoadbalancerActiveProvisioningStatus(lbaas.lb, loadbalancer.ID)
}
glog.V(4).Infof("Pool for listener %s: %s", listener.ID, pool.ID)
members, err := getMembersByPoolID(lbaas.network, pool.ID)
members, err := getMembersByPoolID(lbaas.lb, pool.ID)
if err != nil && !isNotFound(err) {
return nil, fmt.Errorf("error getting pool members %s: %v", pool.ID, err)
}
@ -727,7 +727,7 @@ func (lbaas *LbaasV2) EnsureLoadBalancer(clusterName string, apiService *v1.Serv
if !memberExists(members, addr, int(port.NodePort)) {
glog.V(4).Infof("Creating member for pool %s", pool.ID)
_, err := v2pools.CreateMember(lbaas.network, pool.ID, v2pools.CreateMemberOpts{
_, err := v2pools.CreateMember(lbaas.lb, pool.ID, v2pools.CreateMemberOpts{
ProtocolPort: int(port.NodePort),
Address: addr,
SubnetID: lbaas.opts.SubnetId,
@ -736,7 +736,7 @@ func (lbaas *LbaasV2) EnsureLoadBalancer(clusterName string, apiService *v1.Serv
return nil, fmt.Errorf("error creating LB pool member for node: %s, %v", node.Name, err)
}
waitLoadbalancerActiveProvisioningStatus(lbaas.network, loadbalancer.ID)
waitLoadbalancerActiveProvisioningStatus(lbaas.lb, loadbalancer.ID)
} else {
// After all members have been processed, remaining members are deleted as obsolete.
members = popMember(members, addr, int(port.NodePort))
@ -748,17 +748,17 @@ func (lbaas *LbaasV2) EnsureLoadBalancer(clusterName string, apiService *v1.Serv
// Delete obsolete members for this pool
for _, member := range members {
glog.V(4).Infof("Deleting obsolete member %s for pool %s address %s", member.ID, pool.ID, member.Address)
err := v2pools.DeleteMember(lbaas.network, pool.ID, member.ID).ExtractErr()
err := v2pools.DeleteMember(lbaas.lb, pool.ID, member.ID).ExtractErr()
if err != nil && !isNotFound(err) {
return nil, fmt.Errorf("error deleting obsolete member %s for pool %s address %s: %v", member.ID, pool.ID, member.Address, err)
}
waitLoadbalancerActiveProvisioningStatus(lbaas.network, loadbalancer.ID)
waitLoadbalancerActiveProvisioningStatus(lbaas.lb, loadbalancer.ID)
}
monitorID := pool.MonitorID
if monitorID == "" && lbaas.opts.CreateMonitor {
glog.V(4).Infof("Creating monitor for pool %s", pool.ID)
monitor, err := v2monitors.Create(lbaas.network, v2monitors.CreateOpts{
monitor, err := v2monitors.Create(lbaas.lb, v2monitors.CreateOpts{
PoolID: pool.ID,
Type: string(port.Protocol),
Delay: int(lbaas.opts.MonitorDelay.Duration.Seconds()),
@ -768,7 +768,7 @@ func (lbaas *LbaasV2) EnsureLoadBalancer(clusterName string, apiService *v1.Serv
if err != nil {
return nil, fmt.Errorf("error creating LB pool healthmonitor: %v", err)
}
waitLoadbalancerActiveProvisioningStatus(lbaas.network, loadbalancer.ID)
waitLoadbalancerActiveProvisioningStatus(lbaas.lb, loadbalancer.ID)
monitorID = monitor.ID
} else if lbaas.opts.CreateMonitor == false {
glog.V(4).Infof("Do not create monitor for pool %s when create-monitor is false", pool.ID)
@ -783,7 +783,7 @@ func (lbaas *LbaasV2) EnsureLoadBalancer(clusterName string, apiService *v1.Serv
for _, listener := range oldListeners {
glog.V(4).Infof("Deleting obsolete listener %s:", listener.ID)
// get pool for listener
pool, err := getPoolByListenerID(lbaas.network, loadbalancer.ID, listener.ID)
pool, err := getPoolByListenerID(lbaas.lb, loadbalancer.ID, listener.ID)
if err != nil && err != ErrNotFound {
return nil, fmt.Errorf("error getting pool for obsolete listener %s: %v", listener.ID, err)
}
@ -792,46 +792,46 @@ func (lbaas *LbaasV2) EnsureLoadBalancer(clusterName string, apiService *v1.Serv
monitorID := pool.MonitorID
if monitorID != "" {
glog.V(4).Infof("Deleting obsolete monitor %s for pool %s", monitorID, pool.ID)
err = v2monitors.Delete(lbaas.network, monitorID).ExtractErr()
err = v2monitors.Delete(lbaas.lb, monitorID).ExtractErr()
if err != nil && !isNotFound(err) {
return nil, fmt.Errorf("error deleting obsolete monitor %s for pool %s: %v", monitorID, pool.ID, err)
}
waitLoadbalancerActiveProvisioningStatus(lbaas.network, loadbalancer.ID)
waitLoadbalancerActiveProvisioningStatus(lbaas.lb, loadbalancer.ID)
}
// get and delete pool members
members, err := getMembersByPoolID(lbaas.network, pool.ID)
members, err := getMembersByPoolID(lbaas.lb, pool.ID)
if err != nil && !isNotFound(err) {
return nil, fmt.Errorf("error getting members for pool %s: %v", pool.ID, err)
}
if members != nil {
for _, member := range members {
glog.V(4).Infof("Deleting obsolete member %s for pool %s address %s", member.ID, pool.ID, member.Address)
err := v2pools.DeleteMember(lbaas.network, pool.ID, member.ID).ExtractErr()
err := v2pools.DeleteMember(lbaas.lb, pool.ID, member.ID).ExtractErr()
if err != nil && !isNotFound(err) {
return nil, fmt.Errorf("error deleting obsolete member %s for pool %s address %s: %v", member.ID, pool.ID, member.Address, err)
}
waitLoadbalancerActiveProvisioningStatus(lbaas.network, loadbalancer.ID)
waitLoadbalancerActiveProvisioningStatus(lbaas.lb, loadbalancer.ID)
}
}
glog.V(4).Infof("Deleting obsolete pool %s for listener %s", pool.ID, listener.ID)
// delete pool
err = v2pools.Delete(lbaas.network, pool.ID).ExtractErr()
err = v2pools.Delete(lbaas.lb, pool.ID).ExtractErr()
if err != nil && !isNotFound(err) {
return nil, fmt.Errorf("error deleting obsolete pool %s for listener %s: %v", pool.ID, listener.ID, err)
}
waitLoadbalancerActiveProvisioningStatus(lbaas.network, loadbalancer.ID)
waitLoadbalancerActiveProvisioningStatus(lbaas.lb, loadbalancer.ID)
}
// delete listener
err = listeners.Delete(lbaas.network, listener.ID).ExtractErr()
err = listeners.Delete(lbaas.lb, listener.ID).ExtractErr()
if err != nil && !isNotFound(err) {
return nil, fmt.Errorf("error deleteting obsolete listener: %v", err)
}
waitLoadbalancerActiveProvisioningStatus(lbaas.network, loadbalancer.ID)
waitLoadbalancerActiveProvisioningStatus(lbaas.lb, loadbalancer.ID)
glog.V(2).Infof("Deleted obsolete listener: %s", listener.ID)
}
portID := loadbalancer.VipPortID
floatIP, err := getFloatingIPByPortID(lbaas.network, portID)
floatIP, err := getFloatingIPByPortID(lbaas.lb, portID)
if err != nil && err != ErrNotFound {
return nil, fmt.Errorf("error getting floating ip for port %s: %v", portID, err)
}
@ -1068,7 +1068,7 @@ func (lbaas *LbaasV2) UpdateLoadBalancer(clusterName string, service *v1.Service
return fmt.Errorf("no ports provided to openstack load balancer")
}
loadbalancer, err := getLoadbalancerByName(lbaas.network, loadBalancerName)
loadbalancer, err := getLoadbalancerByName(lbaas.lb, loadBalancerName)
if err != nil {
return err
}
@ -1083,7 +1083,7 @@ func (lbaas *LbaasV2) UpdateLoadBalancer(clusterName string, service *v1.Service
}
var listenerIDs []string
lbListeners := make(map[portKey]listeners.Listener)
allListeners, err := getListenersByLoadBalancerID(lbaas.network, loadbalancer.ID)
allListeners, err := getListenersByLoadBalancerID(lbaas.lb, loadbalancer.ID)
if err != nil {
return fmt.Errorf("error getting listeners for LB %s: %v", loadBalancerName, err)
}
@ -1096,7 +1096,7 @@ func (lbaas *LbaasV2) UpdateLoadBalancer(clusterName string, service *v1.Service
// Get all pools for this loadbalancer, by listener ID.
lbPools := make(map[string]v2pools.Pool)
for _, listenerID := range listenerIDs {
pool, err := getPoolByListenerID(lbaas.network, loadbalancer.ID, listenerID)
pool, err := getPoolByListenerID(lbaas.lb, loadbalancer.ID, listenerID)
if err != nil {
return fmt.Errorf("error getting pool for listener %s: %v", listenerID, err)
}
@ -1131,7 +1131,7 @@ func (lbaas *LbaasV2) UpdateLoadBalancer(clusterName string, service *v1.Service
}
// Find existing pool members (by address) for this port
getMembers, err := getMembersByPoolID(lbaas.network, pool.ID)
getMembers, err := getMembersByPoolID(lbaas.lb, pool.ID)
if err != nil {
return fmt.Errorf("error getting pool members %s: %v", pool.ID, err)
}
@ -1146,7 +1146,7 @@ func (lbaas *LbaasV2) UpdateLoadBalancer(clusterName string, service *v1.Service
// Already exists, do not create member
continue
}
_, err := v2pools.CreateMember(lbaas.network, pool.ID, v2pools.CreateMemberOpts{
_, err := v2pools.CreateMember(lbaas.lb, pool.ID, v2pools.CreateMemberOpts{
Address: addr,
ProtocolPort: int(port.NodePort),
SubnetID: lbaas.opts.SubnetId,
@ -1154,7 +1154,7 @@ func (lbaas *LbaasV2) UpdateLoadBalancer(clusterName string, service *v1.Service
if err != nil {
return err
}
waitLoadbalancerActiveProvisioningStatus(lbaas.network, loadbalancer.ID)
waitLoadbalancerActiveProvisioningStatus(lbaas.lb, loadbalancer.ID)
}
// Remove any old members for this port
@ -1163,11 +1163,11 @@ func (lbaas *LbaasV2) UpdateLoadBalancer(clusterName string, service *v1.Service
// Still present, do not delete member
continue
}
err = v2pools.DeleteMember(lbaas.network, pool.ID, member.ID).ExtractErr()
err = v2pools.DeleteMember(lbaas.lb, pool.ID, member.ID).ExtractErr()
if err != nil && !isNotFound(err) {
return err
}
waitLoadbalancerActiveProvisioningStatus(lbaas.network, loadbalancer.ID)
waitLoadbalancerActiveProvisioningStatus(lbaas.lb, loadbalancer.ID)
}
}
@ -1265,7 +1265,7 @@ func (lbaas *LbaasV2) EnsureLoadBalancerDeleted(clusterName string, service *v1.
loadBalancerName := cloudprovider.GetLoadBalancerName(service)
glog.V(4).Infof("EnsureLoadBalancerDeleted(%v, %v)", clusterName, loadBalancerName)
loadbalancer, err := getLoadbalancerByName(lbaas.network, loadBalancerName)
loadbalancer, err := getLoadbalancerByName(lbaas.lb, loadBalancerName)
if err != nil && err != ErrNotFound {
return err
}
@ -1288,7 +1288,7 @@ func (lbaas *LbaasV2) EnsureLoadBalancerDeleted(clusterName string, service *v1.
}
// get all listeners associated with this loadbalancer
listenerList, err := getListenersByLoadBalancerID(lbaas.network, loadbalancer.ID)
listenerList, err := getListenersByLoadBalancerID(lbaas.lb, loadbalancer.ID)
if err != nil {
return fmt.Errorf("error getting LB %s listeners: %v", loadbalancer.ID, err)
}
@ -1297,7 +1297,7 @@ func (lbaas *LbaasV2) EnsureLoadBalancerDeleted(clusterName string, service *v1.
var poolIDs []string
var monitorIDs []string
for _, listener := range listenerList {
pool, err := getPoolByListenerID(lbaas.network, loadbalancer.ID, listener.ID)
pool, err := getPoolByListenerID(lbaas.lb, loadbalancer.ID, listener.ID)
if err != nil && err != ErrNotFound {
return fmt.Errorf("error getting pool for listener %s: %v", listener.ID, err)
}
@ -1313,7 +1313,7 @@ func (lbaas *LbaasV2) EnsureLoadBalancerDeleted(clusterName string, service *v1.
// get all members associated with each poolIDs
var memberIDs []string
for _, pool := range poolIDs {
membersList, err := getMembersByPoolID(lbaas.network, pool)
membersList, err := getMembersByPoolID(lbaas.lb, pool)
if err != nil && !isNotFound(err) {
return fmt.Errorf("error getting pool members %s: %v", pool, err)
}
@ -1324,47 +1324,47 @@ func (lbaas *LbaasV2) EnsureLoadBalancerDeleted(clusterName string, service *v1.
// delete all monitors
for _, monitorID := range monitorIDs {
err := v2monitors.Delete(lbaas.network, monitorID).ExtractErr()
err := v2monitors.Delete(lbaas.lb, monitorID).ExtractErr()
if err != nil && !isNotFound(err) {
return err
}
waitLoadbalancerActiveProvisioningStatus(lbaas.network, loadbalancer.ID)
waitLoadbalancerActiveProvisioningStatus(lbaas.lb, loadbalancer.ID)
}
// delete all members and pools
for _, poolID := range poolIDs {
// delete all members for this pool
for _, memberID := range memberIDs {
err := v2pools.DeleteMember(lbaas.network, poolID, memberID).ExtractErr()
err := v2pools.DeleteMember(lbaas.lb, poolID, memberID).ExtractErr()
if err != nil && !isNotFound(err) {
return err
}
waitLoadbalancerActiveProvisioningStatus(lbaas.network, loadbalancer.ID)
waitLoadbalancerActiveProvisioningStatus(lbaas.lb, loadbalancer.ID)
}
// delete pool
err := v2pools.Delete(lbaas.network, poolID).ExtractErr()
err := v2pools.Delete(lbaas.lb, poolID).ExtractErr()
if err != nil && !isNotFound(err) {
return err
}
waitLoadbalancerActiveProvisioningStatus(lbaas.network, loadbalancer.ID)
waitLoadbalancerActiveProvisioningStatus(lbaas.lb, loadbalancer.ID)
}
// delete all listeners
for _, listener := range listenerList {
err := listeners.Delete(lbaas.network, listener.ID).ExtractErr()
err := listeners.Delete(lbaas.lb, listener.ID).ExtractErr()
if err != nil && !isNotFound(err) {
return err
}
waitLoadbalancerActiveProvisioningStatus(lbaas.network, loadbalancer.ID)
waitLoadbalancerActiveProvisioningStatus(lbaas.lb, loadbalancer.ID)
}
// delete loadbalancer
err = loadbalancers.Delete(lbaas.network, loadbalancer.ID).ExtractErr()
err = loadbalancers.Delete(lbaas.lb, loadbalancer.ID).ExtractErr()
if err != nil && !isNotFound(err) {
return err
}
waitLoadbalancerDeleted(lbaas.network, loadbalancer.ID)
waitLoadbalancerDeleted(lbaas.lb, loadbalancer.ID)
// Delete the Security Group
if lbaas.opts.ManageSecurityGroups {