diff --git a/upup/pkg/fi/cloudup/openstack/BUILD.bazel b/upup/pkg/fi/cloudup/openstack/BUILD.bazel index 9d26568930db6..f88cd6fb033e7 100644 --- a/upup/pkg/fi/cloudup/openstack/BUILD.bazel +++ b/upup/pkg/fi/cloudup/openstack/BUILD.bazel @@ -12,6 +12,7 @@ go_library( "instance.go", "keypair.go", "loadbalancer.go", + "mock_cloud.go", "network.go", "port.go", "router.go", diff --git a/upup/pkg/fi/cloudup/openstack/availability_zone.go b/upup/pkg/fi/cloudup/openstack/availability_zone.go index 66ae60e104554..96a8878d46d3a 100644 --- a/upup/pkg/fi/cloudup/openstack/availability_zone.go +++ b/upup/pkg/fi/cloudup/openstack/availability_zone.go @@ -26,6 +26,10 @@ import ( ) func (c *openstackCloud) ListAvailabilityZones(serviceClient *gophercloud.ServiceClient) (azList []az.AvailabilityZone, err error) { + return listAvailabilityZones(c, serviceClient) +} + +func listAvailabilityZones(c OpenstackCloud, serviceClient *gophercloud.ServiceClient) (azList []az.AvailabilityZone, err error) { done, err := vfs.RetryWithBackoff(readBackoff, func() (bool, error) { azPage, err := az.List(serviceClient).AllPages() @@ -50,6 +54,10 @@ func (c *openstackCloud) ListAvailabilityZones(serviceClient *gophercloud.Servic } func (c *openstackCloud) GetStorageAZFromCompute(computeAZ string) (*az.AvailabilityZone, error) { + return getStorageAZFromCompute(c, computeAZ) +} + +func getStorageAZFromCompute(c OpenstackCloud, computeAZ string) (*az.AvailabilityZone, error) { // TODO: This is less than desirable, but openstack differs here // Check to see if the availability zone exists. azList, err := c.ListAvailabilityZones(c.BlockStorageClient()) diff --git a/upup/pkg/fi/cloudup/openstack/cloud.go b/upup/pkg/fi/cloudup/openstack/cloud.go index d59c8e42d7f60..31b9a89fab31f 100644 --- a/upup/pkg/fi/cloudup/openstack/cloud.go +++ b/upup/pkg/fi/cloudup/openstack/cloud.go @@ -96,6 +96,7 @@ type OpenstackCloud interface { NetworkingClient() *gophercloud.ServiceClient LoadBalancerClient() *gophercloud.ServiceClient DNSClient() *gophercloud.ServiceClient + ImageClient() *gophercloud.ServiceClient UseOctavia() bool UseZones([]string) @@ -320,9 +321,22 @@ type openstackCloud struct { var _ fi.Cloud = &openstackCloud{} +var openstackCloudInstances map[string]OpenstackCloud = make(map[string]OpenstackCloud) + func NewOpenstackCloud(tags map[string]string, spec *kops.ClusterSpec) (OpenstackCloud, error) { + config := vfs.OpenstackConfig{} + region, err := config.GetRegion() + if err != nil { + return nil, fmt.Errorf("error finding openstack region: %v", err) + } + + raw := openstackCloudInstances[region] + if raw != nil { + return raw, nil + } + authOption, err := config.GetCredential() if err != nil { return nil, err @@ -333,11 +347,6 @@ func NewOpenstackCloud(tags map[string]string, spec *kops.ClusterSpec) (Openstac return nil, fmt.Errorf("error building openstack provider client: %v", err) } - region, err := config.GetRegion() - if err != nil { - return nil, fmt.Errorf("error finding openstack region: %v", err) - } - if spec != nil && spec.CloudConfig != nil && spec.CloudConfig.Openstack != nil && spec.CloudConfig.Openstack.InsecureSkipVerify != nil { tlsconfig := &tls.Config{} tlsconfig.InsecureSkipVerify = fi.BoolValue(spec.CloudConfig.Openstack.InsecureSkipVerify) @@ -470,6 +479,8 @@ func NewOpenstackCloud(tags map[string]string, spec *kops.ClusterSpec) (Openstac } } c.lbClient = lbClient + openstackCloudInstances[region] = c + return c, nil } @@ -502,6 +513,10 @@ func (c *openstackCloud) DNSClient() *gophercloud.ServiceClient { return c.dnsClient } +func (c *openstackCloud) ImageClient() *gophercloud.ServiceClient { + return c.glanceClient +} + func (c *openstackCloud) Region() string { return c.region } @@ -520,10 +535,14 @@ func (c *openstackCloud) DNS() (dnsprovider.Interface, error) { // FindVPCInfo list subnets in network func (c *openstackCloud) FindVPCInfo(id string) (*fi.VPCInfo, error) { + return findVPCInfo(c, id, c.zones) +} + +func findVPCInfo(c OpenstackCloud, id string, zones []string) (*fi.VPCInfo, error) { vpcInfo := &fi.VPCInfo{} // Find subnets in the network { - if len(c.zones) == 0 { + if len(zones) == 0 { return nil, fmt.Errorf("could not initialize zones") } klog.V(2).Infof("Calling ListSubnets for subnets in Network %q", id) @@ -536,7 +555,7 @@ func (c *openstackCloud) FindVPCInfo(id string) (*fi.VPCInfo, error) { } for index, subnet := range subnets { - zone := c.zones[int(index)%len(c.zones)] + zone := zones[int(index)%len(zones)] subnetInfo := &fi.SubnetInfo{ ID: subnet.ID, CIDR: subnet.CIDR, @@ -550,6 +569,10 @@ func (c *openstackCloud) FindVPCInfo(id string) (*fi.VPCInfo, error) { // DeleteGroup in openstack will delete servergroup, instances and ports func (c *openstackCloud) DeleteGroup(g *cloudinstances.CloudInstanceGroup) error { + return deleteGroup(c, g) +} + +func deleteGroup(c OpenstackCloud, g *cloudinstances.CloudInstanceGroup) error { grp := g.Raw.(*servergroups.ServerGroup) for _, id := range grp.Members { @@ -582,6 +605,10 @@ func (c *openstackCloud) DeleteGroup(g *cloudinstances.CloudInstanceGroup) error } func (c *openstackCloud) GetCloudGroups(cluster *kops.Cluster, instancegroups []*kops.InstanceGroup, warnUnmatched bool, nodes []v1.Node) (map[string]*cloudinstances.CloudInstanceGroup, error) { + return getCloudGroups(c, cluster, instancegroups, warnUnmatched, nodes) +} + +func getCloudGroups(c OpenstackCloud, cluster *kops.Cluster, instancegroups []*kops.InstanceGroup, warnUnmatched bool, nodes []v1.Node) (map[string]*cloudinstances.CloudInstanceGroup, error) { nodeMap := cloudinstances.GetNodeMap(nodes, cluster) groups := make(map[string]*cloudinstances.CloudInstanceGroup) @@ -602,7 +629,7 @@ func (c *openstackCloud) GetCloudGroups(cluster *kops.Cluster, instancegroups [] } continue } - groups[instancegroup.ObjectMeta.Name], err = c.osBuildCloudInstanceGroup(cluster, instancegroup, &grp, nodeMap) + groups[instancegroup.ObjectMeta.Name], err = osBuildCloudInstanceGroup(c, cluster, instancegroup, &grp, nodeMap) if err != nil { return nil, fmt.Errorf("error getting cloud instance group %q: %v", instancegroup.ObjectMeta.Name, err) } @@ -620,6 +647,10 @@ type Address struct { } func (c *openstackCloud) GetApiIngressStatus(cluster *kops.Cluster) ([]kops.ApiIngressStatus, error) { + return getApiIngressStatus(c, cluster) +} + +func getApiIngressStatus(c OpenstackCloud, cluster *kops.Cluster) ([]kops.ApiIngressStatus, error) { var ingresses []kops.ApiIngressStatus if cluster.Spec.CloudConfig.Openstack.Loadbalancer != nil { if cluster.Spec.MasterPublicName != "" { diff --git a/upup/pkg/fi/cloudup/openstack/dns.go b/upup/pkg/fi/cloudup/openstack/dns.go index 5c774ddd07c15..3d973ecfe14e6 100644 --- a/upup/pkg/fi/cloudup/openstack/dns.go +++ b/upup/pkg/fi/cloudup/openstack/dns.go @@ -27,6 +27,10 @@ import ( // ListDNSZones will list available DNS zones func (c *openstackCloud) ListDNSZones(opt zones.ListOptsBuilder) ([]zones.Zone, error) { + return listDNSZones(c, opt) +} + +func listDNSZones(c OpenstackCloud, opt zones.ListOptsBuilder) ([]zones.Zone, error) { var zs []zones.Zone done, err := vfs.RetryWithBackoff(readBackoff, func() (bool, error) { @@ -52,6 +56,10 @@ func (c *openstackCloud) ListDNSZones(opt zones.ListOptsBuilder) ([]zones.Zone, // ListDNSRecordsets will list DNS recordsets func (c *openstackCloud) ListDNSRecordsets(zoneID string, opt recordsets.ListOptsBuilder) ([]recordsets.RecordSet, error) { + return listDNSRecordsets(c, zoneID, opt) +} + +func listDNSRecordsets(c OpenstackCloud, zoneID string, opt recordsets.ListOptsBuilder) ([]recordsets.RecordSet, error) { var rrs []recordsets.RecordSet done, err := vfs.RetryWithBackoff(readBackoff, func() (bool, error) { diff --git a/upup/pkg/fi/cloudup/openstack/floatingip.go b/upup/pkg/fi/cloudup/openstack/floatingip.go index bf5869ac871c3..a0947fd49ac6e 100644 --- a/upup/pkg/fi/cloudup/openstack/floatingip.go +++ b/upup/pkg/fi/cloudup/openstack/floatingip.go @@ -26,6 +26,10 @@ import ( ) func (c *openstackCloud) GetFloatingIP(id string) (fip *floatingips.FloatingIP, err error) { + return getFloatingIP(c, id) +} + +func getFloatingIP(c OpenstackCloud, id string) (fip *floatingips.FloatingIP, err error) { done, err := vfs.RetryWithBackoff(readBackoff, func() (bool, error) { fip, err = floatingips.Get(c.ComputeClient(), id).Extract() @@ -43,7 +47,33 @@ func (c *openstackCloud) GetFloatingIP(id string) (fip *floatingips.FloatingIP, return fip, nil } +func (c *openstackCloud) CreateFloatingIP(opts floatingips.CreateOpts) (fip *floatingips.FloatingIP, err error) { + return createFloatingIP(c, opts) +} + +func createFloatingIP(c OpenstackCloud, opts floatingips.CreateOpts) (fip *floatingips.FloatingIP, err error) { + done, err := vfs.RetryWithBackoff(writeBackoff, func() (bool, error) { + + fip, err = floatingips.Create(c.ComputeClient(), opts).Extract() + if err != nil { + return false, fmt.Errorf("CreateFloatingIP: create floating IP failed: %v", err) + } + return true, nil + }) + if !done { + if err == nil { + err = wait.ErrWaitTimeout + } + return fip, err + } + return fip, nil +} + func (c *openstackCloud) AssociateFloatingIPToInstance(serverID string, opts floatingips.AssociateOpts) (err error) { + return associateFloatingIPToInstance(c, serverID, opts) +} + +func associateFloatingIPToInstance(c OpenstackCloud, serverID string, opts floatingips.AssociateOpts) (err error) { done, err := vfs.RetryWithBackoff(writeBackoff, func() (bool, error) { err = floatingips.AssociateInstance(c.ComputeClient(), serverID, opts).ExtractErr() if err != nil { @@ -59,6 +89,10 @@ func (c *openstackCloud) AssociateFloatingIPToInstance(serverID string, opts flo } func (c *openstackCloud) CreateL3FloatingIP(opts l3floatingip.CreateOpts) (fip *l3floatingip.FloatingIP, err error) { + return createL3FloatingIP(c, opts) +} + +func createL3FloatingIP(c OpenstackCloud, opts l3floatingip.CreateOpts) (fip *l3floatingip.FloatingIP, err error) { done, err := vfs.RetryWithBackoff(writeBackoff, func() (bool, error) { fip, err = l3floatingip.Create(c.NetworkingClient(), opts).Extract() @@ -77,6 +111,10 @@ func (c *openstackCloud) CreateL3FloatingIP(opts l3floatingip.CreateOpts) (fip * } func (c *openstackCloud) ListFloatingIPs() (fips []floatingips.FloatingIP, err error) { + return listFloatingIPs(c) +} + +func listFloatingIPs(c OpenstackCloud) (fips []floatingips.FloatingIP, err error) { done, err := vfs.RetryWithBackoff(readBackoff, func() (bool, error) { pages, err := floatingips.List(c.ComputeClient()).AllPages() @@ -99,6 +137,10 @@ func (c *openstackCloud) ListFloatingIPs() (fips []floatingips.FloatingIP, err e } func (c *openstackCloud) ListL3FloatingIPs(opts l3floatingip.ListOpts) (fips []l3floatingip.FloatingIP, err error) { + return listL3FloatingIPs(c, opts) +} + +func listL3FloatingIPs(c OpenstackCloud, opts l3floatingip.ListOpts) (fips []l3floatingip.FloatingIP, err error) { done, err := vfs.RetryWithBackoff(readBackoff, func() (bool, error) { page, err := l3floatingip.List(c.NetworkingClient(), opts).AllPages() @@ -121,6 +163,10 @@ func (c *openstackCloud) ListL3FloatingIPs(opts l3floatingip.ListOpts) (fips []l } func (c *openstackCloud) DeleteFloatingIP(id string) (err error) { + return deleteFloatingIP(c, id) +} + +func deleteFloatingIP(c OpenstackCloud, id string) (err error) { done, err := vfs.RetryWithBackoff(writeBackoff, func() (bool, error) { err = l3floatingip.Delete(c.ComputeClient(), id).ExtractErr() @@ -136,6 +182,10 @@ func (c *openstackCloud) DeleteFloatingIP(id string) (err error) { } func (c *openstackCloud) DeleteL3FloatingIP(id string) (err error) { + return deleteL3FloatingIP(c, id) +} + +func deleteL3FloatingIP(c OpenstackCloud, id string) (err error) { done, err := vfs.RetryWithBackoff(writeBackoff, func() (bool, error) { err = l3floatingip.Delete(c.NetworkingClient(), id).ExtractErr() diff --git a/upup/pkg/fi/cloudup/openstack/image.go b/upup/pkg/fi/cloudup/openstack/image.go index 0edb194f3010b..35e18150b66c9 100644 --- a/upup/pkg/fi/cloudup/openstack/image.go +++ b/upup/pkg/fi/cloudup/openstack/image.go @@ -23,8 +23,12 @@ import ( ) func (c *openstackCloud) GetImage(name string) (*images.Image, error) { + return getImage(c, name) +} + +func getImage(c OpenstackCloud, name string) (*images.Image, error) { opts := images.ListOpts{Name: name} - pager := images.List(c.glanceClient, opts) + pager := images.List(c.ImageClient(), opts) page, err := pager.AllPages() if err != nil { return nil, fmt.Errorf("failed to list images: %v", err) diff --git a/upup/pkg/fi/cloudup/openstack/instance.go b/upup/pkg/fi/cloudup/openstack/instance.go index 52b2a574f67b0..72d70d722b30f 100644 --- a/upup/pkg/fi/cloudup/openstack/instance.go +++ b/upup/pkg/fi/cloudup/openstack/instance.go @@ -46,6 +46,10 @@ var floatingBackoff = wait.Backoff{ } func (c *openstackCloud) CreateInstance(opt servers.CreateOptsBuilder) (*servers.Server, error) { + return createInstance(c, opt) +} + +func createInstance(c OpenstackCloud, opt servers.CreateOptsBuilder) (*servers.Server, error) { var server *servers.Server done, err := vfs.RetryWithBackoff(writeBackoff, func() (bool, error) { @@ -66,6 +70,11 @@ func (c *openstackCloud) CreateInstance(opt servers.CreateOptsBuilder) (*servers } func (c *openstackCloud) ListServerFloatingIPs(instanceID string) ([]*string, error) { + return listServerFloatingIPs(c, instanceID, c.floatingEnabled) +} + +func listServerFloatingIPs(c OpenstackCloud, instanceID string, floatingEnabled bool) ([]*string, error) { + var result []*string _, err := vfs.RetryWithBackoff(floatingBackoff, func() (bool, error) { server, err := c.GetInstance(instanceID) @@ -81,7 +90,7 @@ func (c *openstackCloud) ListServerFloatingIPs(instanceID string) ([]*string, er for _, addrList := range addresses { for _, props := range addrList { - if c.floatingEnabled { + if floatingEnabled { if props.IPType == "floating" { result = append(result, fi.String(props.Addr)) } @@ -102,21 +111,37 @@ func (c *openstackCloud) ListServerFloatingIPs(instanceID string) ([]*string, er } func (c *openstackCloud) DeleteInstance(i *cloudinstances.CloudInstanceGroupMember) error { + return deleteInstance(c, i) +} + +func deleteInstance(c OpenstackCloud, i *cloudinstances.CloudInstanceGroupMember) error { klog.Warning("This does not work without running kops update cluster --yes in another terminal") - return c.DeleteInstanceWithID(i.ID) + return deleteInstanceWithID(c, i.ID) } func (c *openstackCloud) DeleteInstanceWithID(instanceID string) error { + return deleteInstanceWithID(c, instanceID) +} + +func deleteInstanceWithID(c OpenstackCloud, instanceID string) error { return servers.Delete(c.ComputeClient(), instanceID).ExtractErr() } // DetachInstance is not implemented yet. It needs to cause a cloud instance to no longer be counted against the group's size limits. func (c *openstackCloud) DetachInstance(i *cloudinstances.CloudInstanceGroupMember) error { + return detachInstance(c, i) +} + +func detachInstance(c OpenstackCloud, i *cloudinstances.CloudInstanceGroupMember) error { klog.V(8).Info("openstack cloud provider DetachInstance not implemented yet") return fmt.Errorf("openstack cloud provider does not support surging") } func (c *openstackCloud) GetInstance(id string) (*servers.Server, error) { + return getInstance(c, id) +} + +func getInstance(c OpenstackCloud, id string) (*servers.Server, error) { var server *servers.Server done, err := vfs.RetryWithBackoff(readBackoff, func() (bool, error) { @@ -137,6 +162,10 @@ func (c *openstackCloud) GetInstance(id string) (*servers.Server, error) { } func (c *openstackCloud) ListInstances(opt servers.ListOptsBuilder) ([]servers.Server, error) { + return listInstances(c, opt) +} + +func listInstances(c OpenstackCloud, opt servers.ListOptsBuilder) ([]servers.Server, error) { var instances []servers.Server done, err := vfs.RetryWithBackoff(readBackoff, func() (bool, error) { diff --git a/upup/pkg/fi/cloudup/openstack/keypair.go b/upup/pkg/fi/cloudup/openstack/keypair.go index 2711e078d6fc8..273e6188f5ab8 100644 --- a/upup/pkg/fi/cloudup/openstack/keypair.go +++ b/upup/pkg/fi/cloudup/openstack/keypair.go @@ -25,6 +25,10 @@ import ( ) func (c *openstackCloud) GetKeypair(name string) (*keypairs.KeyPair, error) { + return getKeypair(c, name) +} + +func getKeypair(c OpenstackCloud, name string) (*keypairs.KeyPair, error) { var k *keypairs.KeyPair done, err := vfs.RetryWithBackoff(readBackoff, func() (bool, error) { rs, err := keypairs.Get(c.ComputeClient(), name).Extract() @@ -47,6 +51,10 @@ func (c *openstackCloud) GetKeypair(name string) (*keypairs.KeyPair, error) { } func (c *openstackCloud) CreateKeypair(opt keypairs.CreateOptsBuilder) (*keypairs.KeyPair, error) { + return createKeypair(c, opt) +} + +func createKeypair(c OpenstackCloud, opt keypairs.CreateOptsBuilder) (*keypairs.KeyPair, error) { var k *keypairs.KeyPair done, err := vfs.RetryWithBackoff(writeBackoff, func() (bool, error) { @@ -67,6 +75,10 @@ func (c *openstackCloud) CreateKeypair(opt keypairs.CreateOptsBuilder) (*keypair } func (c *openstackCloud) DeleteKeyPair(name string) error { + return deleteKeyPair(c, name) +} + +func deleteKeyPair(c OpenstackCloud, name string) error { done, err := vfs.RetryWithBackoff(readBackoff, func() (bool, error) { err := keypairs.Delete(c.ComputeClient(), name).ExtractErr() if err != nil && !isNotFound(err) { @@ -85,6 +97,10 @@ func (c *openstackCloud) DeleteKeyPair(name string) error { } func (c *openstackCloud) ListKeypairs() ([]keypairs.KeyPair, error) { + return listKeypairs(c) +} + +func listKeypairs(c OpenstackCloud) ([]keypairs.KeyPair, error) { var k []keypairs.KeyPair done, err := vfs.RetryWithBackoff(readBackoff, func() (bool, error) { allPages, err := keypairs.List(c.ComputeClient()).AllPages() diff --git a/upup/pkg/fi/cloudup/openstack/loadbalancer.go b/upup/pkg/fi/cloudup/openstack/loadbalancer.go index 2e2e2c7bda06b..dc55f8923cb6b 100644 --- a/upup/pkg/fi/cloudup/openstack/loadbalancer.go +++ b/upup/pkg/fi/cloudup/openstack/loadbalancer.go @@ -29,6 +29,10 @@ import ( ) func (c *openstackCloud) ListMonitors(opts monitors.ListOpts) (monitorList []monitors.Monitor, err error) { + return listMonitors(c, opts) +} + +func listMonitors(c OpenstackCloud, opts monitors.ListOpts) (monitorList []monitors.Monitor, err error) { if c.LoadBalancerClient() == nil { return monitorList, fmt.Errorf("loadbalancer support not available in this deployment") } @@ -53,6 +57,10 @@ func (c *openstackCloud) ListMonitors(opts monitors.ListOpts) (monitorList []mon } func (c *openstackCloud) DeleteMonitor(monitorID string) error { + return deleteMonitor(c, monitorID) +} + +func deleteMonitor(c OpenstackCloud, monitorID string) error { if c.LoadBalancerClient() == nil { return fmt.Errorf("loadbalancer support not available in this deployment") } @@ -73,6 +81,10 @@ func (c *openstackCloud) DeleteMonitor(monitorID string) error { } func (c *openstackCloud) DeletePool(poolID string) error { + return deletePool(c, poolID) +} + +func deletePool(c OpenstackCloud, poolID string) error { if c.LoadBalancerClient() == nil { return fmt.Errorf("loadbalancer support not available in this deployment") } @@ -94,6 +106,10 @@ func (c *openstackCloud) DeletePool(poolID string) error { } func (c *openstackCloud) DeleteListener(listenerID string) error { + return deleteListener(c, listenerID) +} + +func deleteListener(c OpenstackCloud, listenerID string) error { if c.LoadBalancerClient() == nil { return fmt.Errorf("loadbalancer support not available in this deployment") } @@ -115,6 +131,10 @@ func (c *openstackCloud) DeleteListener(listenerID string) error { } func (c *openstackCloud) DeleteLB(lbID string, opts loadbalancers.DeleteOpts) error { + return deleteLB(c, lbID, opts) +} + +func deleteLB(c OpenstackCloud, lbID string, opts loadbalancers.DeleteOpts) error { if c.LoadBalancerClient() == nil { return fmt.Errorf("loadbalancer support not available in this deployment") } @@ -136,6 +156,10 @@ func (c *openstackCloud) DeleteLB(lbID string, opts loadbalancers.DeleteOpts) er } func (c *openstackCloud) CreateLB(opt loadbalancers.CreateOptsBuilder) (*loadbalancers.LoadBalancer, error) { + return createLB(c, opt) +} + +func createLB(c OpenstackCloud, opt loadbalancers.CreateOptsBuilder) (*loadbalancers.LoadBalancer, error) { if c.LoadBalancerClient() == nil { return nil, fmt.Errorf("loadbalancer support not available in this deployment") } @@ -159,6 +183,10 @@ func (c *openstackCloud) CreateLB(opt loadbalancers.CreateOptsBuilder) (*loadbal } func (c *openstackCloud) GetLB(loadbalancerID string) (lb *loadbalancers.LoadBalancer, err error) { + return getLB(c, loadbalancerID) +} + +func getLB(c OpenstackCloud, loadbalancerID string) (lb *loadbalancers.LoadBalancer, err error) { if c.LoadBalancerClient() == nil { return nil, fmt.Errorf("loadbalancer support not available in this deployment") } @@ -181,6 +209,10 @@ func (c *openstackCloud) GetLB(loadbalancerID string) (lb *loadbalancers.LoadBal // ListLBs will list load balancers func (c *openstackCloud) ListLBs(opt loadbalancers.ListOptsBuilder) (lbs []loadbalancers.LoadBalancer, err error) { + return listLBs(c, opt) +} + +func listLBs(c OpenstackCloud, opt loadbalancers.ListOptsBuilder) (lbs []loadbalancers.LoadBalancer, err error) { if c.LoadBalancerClient() == nil { // skip error because cluster delete will otherwise fail return lbs, nil @@ -207,6 +239,10 @@ func (c *openstackCloud) ListLBs(opt loadbalancers.ListOptsBuilder) (lbs []loadb } func (c *openstackCloud) GetPool(poolID string, memberID string) (member *v2pools.Member, err error) { + return getPool(c, poolID, memberID) +} + +func getPool(c OpenstackCloud, poolID string, memberID string) (member *v2pools.Member, err error) { if c.LoadBalancerClient() == nil { return nil, fmt.Errorf("loadbalancer support not available in this deployment") } @@ -228,6 +264,10 @@ func (c *openstackCloud) GetPool(poolID string, memberID string) (member *v2pool } func (c *openstackCloud) AssociateToPool(server *servers.Server, poolID string, opts v2pools.CreateMemberOpts) (association *v2pools.Member, err error) { + return associateToPool(c, server, poolID, opts) +} + +func associateToPool(c OpenstackCloud, server *servers.Server, poolID string, opts v2pools.CreateMemberOpts) (association *v2pools.Member, err error) { if c.LoadBalancerClient() == nil { return nil, fmt.Errorf("loadbalancer support not available in this deployment") } @@ -255,6 +295,10 @@ func (c *openstackCloud) AssociateToPool(server *servers.Server, poolID string, } func (c *openstackCloud) CreatePool(opts v2pools.CreateOpts) (pool *v2pools.Pool, err error) { + return createPool(c, opts) +} + +func createPool(c OpenstackCloud, opts v2pools.CreateOpts) (pool *v2pools.Pool, err error) { if c.LoadBalancerClient() == nil { return nil, fmt.Errorf("loadbalancer support not available in this deployment") } @@ -276,6 +320,10 @@ func (c *openstackCloud) CreatePool(opts v2pools.CreateOpts) (pool *v2pools.Pool } func (c *openstackCloud) ListPools(opts v2pools.ListOpts) (poolList []v2pools.Pool, err error) { + return listPools(c, opts) +} + +func listPools(c OpenstackCloud, opts v2pools.ListOpts) (poolList []v2pools.Pool, err error) { if c.LoadBalancerClient() == nil { return poolList, fmt.Errorf("loadbalancer support not available in this deployment") } @@ -301,6 +349,10 @@ func (c *openstackCloud) ListPools(opts v2pools.ListOpts) (poolList []v2pools.Po } func (c *openstackCloud) ListListeners(opts listeners.ListOpts) (listenerList []listeners.Listener, err error) { + return listListeners(c, opts) +} + +func listListeners(c OpenstackCloud, opts listeners.ListOpts) (listenerList []listeners.Listener, err error) { if c.LoadBalancerClient() == nil { return listenerList, fmt.Errorf("loadbalancer support not available in this deployment") } @@ -326,6 +378,10 @@ func (c *openstackCloud) ListListeners(opts listeners.ListOpts) (listenerList [] } func (c *openstackCloud) CreateListener(opts listeners.CreateOpts) (listener *listeners.Listener, err error) { + return createListener(c, opts) +} + +func createListener(c OpenstackCloud, opts listeners.CreateOpts) (listener *listeners.Listener, err error) { if c.LoadBalancerClient() == nil { return nil, fmt.Errorf("loadbalancer support not available in this deployment") } diff --git a/upup/pkg/fi/cloudup/openstack/mock_cloud.go b/upup/pkg/fi/cloudup/openstack/mock_cloud.go new file mode 100644 index 0000000000000..7d3155d22c65f --- /dev/null +++ b/upup/pkg/fi/cloudup/openstack/mock_cloud.go @@ -0,0 +1,442 @@ +/* +Copyright 2020 The Kubernetes Authors. + +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 openstack + +import ( + "fmt" + + "github.com/gophercloud/gophercloud" + cinder "github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes" + az "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/availabilityzones" + "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/floatingips" + "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs" + "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/servergroups" + "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/volumeattach" + "github.com/gophercloud/gophercloud/openstack/compute/v2/servers" + "github.com/gophercloud/gophercloud/openstack/dns/v2/recordsets" + "github.com/gophercloud/gophercloud/openstack/dns/v2/zones" + "github.com/gophercloud/gophercloud/openstack/imageservice/v2/images" + "github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/listeners" + "github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/loadbalancers" + "github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/monitors" + v2pools "github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/pools" + l3floatingip "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips" + "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers" + sg "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/groups" + sgr "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/rules" + "github.com/gophercloud/gophercloud/openstack/networking/v2/networks" + "github.com/gophercloud/gophercloud/openstack/networking/v2/ports" + "github.com/gophercloud/gophercloud/openstack/networking/v2/subnets" + v1 "k8s.io/api/core/v1" + "k8s.io/kops/dnsprovider/pkg/dnsprovider" + dnsproviderdesignate "k8s.io/kops/dnsprovider/pkg/dnsprovider/providers/openstack/designate" + "k8s.io/kops/pkg/apis/kops" + "k8s.io/kops/pkg/cloudinstances" + "k8s.io/kops/upup/pkg/fi" +) + +type MockCloud struct { + MockCinderClient *gophercloud.ServiceClient + MockNeutronClient *gophercloud.ServiceClient + MockNovaClient *gophercloud.ServiceClient + MockDNSClient *gophercloud.ServiceClient + MockLBClient *gophercloud.ServiceClient + MockGlanceClient *gophercloud.ServiceClient + region string + tags map[string]string + useOctavia bool + zones []string + extNetworkName *string + extSubnetName *string + floatingSubnet *string +} + +func InstallMockOpenstackCloud(region string) *MockCloud { + i := BuildMockOpenstackCloud(region) + openstackCloudInstances[region] = i + return i +} + +func BuildMockOpenstackCloud(region string) *MockCloud { + return &MockCloud{ + region: region, + } +} + +var _ fi.Cloud = (*MockCloud)(nil) + +func (c *MockCloud) ComputeClient() *gophercloud.ServiceClient { + return c.MockNovaClient +} + +func (c *MockCloud) BlockStorageClient() *gophercloud.ServiceClient { + return c.MockCinderClient +} + +func (c *MockCloud) NetworkingClient() *gophercloud.ServiceClient { + return c.MockNeutronClient +} + +func (c *MockCloud) LoadBalancerClient() *gophercloud.ServiceClient { + return c.MockLBClient +} + +func (c *MockCloud) DNSClient() *gophercloud.ServiceClient { + return c.MockDNSClient +} + +func (c *MockCloud) ImageClient() *gophercloud.ServiceClient { + return c.MockGlanceClient +} + +func (c *MockCloud) DeleteGroup(g *cloudinstances.CloudInstanceGroup) error { + return deleteGroup(c, g) +} + +func (c *MockCloud) DeleteInstance(i *cloudinstances.CloudInstanceGroupMember) error { + return deleteInstance(c, i) +} + +func (c *MockCloud) DetachInstance(i *cloudinstances.CloudInstanceGroupMember) error { + return detachInstance(c, i) +} + +func (c *MockCloud) GetCloudGroups(cluster *kops.Cluster, instancegroups []*kops.InstanceGroup, warnUnmatched bool, nodes []v1.Node) (map[string]*cloudinstances.CloudInstanceGroup, error) { + return getCloudGroups(c, cluster, instancegroups, warnUnmatched, nodes) +} + +func (c *MockCloud) ProviderID() kops.CloudProviderID { + return kops.CloudProviderOpenstack +} + +func (c *MockCloud) DNS() (dnsprovider.Interface, error) { + if c.MockDNSClient == nil { + return nil, fmt.Errorf("MockDNS not set") + } + return dnsproviderdesignate.New(c.MockDNSClient), nil +} + +func (c *MockCloud) FindVPCInfo(id string) (*fi.VPCInfo, error) { + return findVPCInfo(c, id, c.zones) +} + +func (c *MockCloud) Region() string { + return c.region +} + +func (c *MockCloud) AppendTag(resource string, id string, tag string) error { + return appendTag(c, resource, id, tag) +} + +func (c *MockCloud) AssociateFloatingIPToInstance(serverID string, opts floatingips.AssociateOpts) (err error) { + return associateFloatingIPToInstance(c, serverID, opts) +} + +func (c *MockCloud) AssociateToPool(server *servers.Server, poolID string, opts v2pools.CreateMemberOpts) (association *v2pools.Member, err error) { + return associateToPool(c, server, poolID, opts) +} + +func (c *MockCloud) AttachVolume(serverID string, opts volumeattach.CreateOpts) (attachment *volumeattach.VolumeAttachment, err error) { + return attachVolume(c, serverID, opts) +} + +func (c *MockCloud) CreateFloatingIP(opts floatingips.CreateOpts) (fip *floatingips.FloatingIP, err error) { + return createFloatingIP(c, opts) +} + +func (c *MockCloud) CreateInstance(opt servers.CreateOptsBuilder) (*servers.Server, error) { + return createInstance(c, opt) +} + +func (c *MockCloud) CreateKeypair(opt keypairs.CreateOptsBuilder) (*keypairs.KeyPair, error) { + return createKeypair(c, opt) +} +func (c *MockCloud) CreateL3FloatingIP(opts l3floatingip.CreateOpts) (fip *l3floatingip.FloatingIP, err error) { + return createL3FloatingIP(c, opts) +} +func (c *MockCloud) CreateLB(opt loadbalancers.CreateOptsBuilder) (*loadbalancers.LoadBalancer, error) { + return createLB(c, opt) +} + +func (c *MockCloud) CreateListener(opts listeners.CreateOpts) (listener *listeners.Listener, err error) { + return createListener(c, opts) +} + +func (c *MockCloud) CreateNetwork(opt networks.CreateOptsBuilder) (*networks.Network, error) { + return createNetwork(c, opt) +} + +func (c *MockCloud) CreatePool(opts v2pools.CreateOpts) (pool *v2pools.Pool, err error) { + return createPool(c, opts) +} + +func (c *MockCloud) CreatePort(opt ports.CreateOptsBuilder) (*ports.Port, error) { + return createPort(c, opt) +} + +func (c *MockCloud) CreateRouter(opt routers.CreateOptsBuilder) (*routers.Router, error) { + return createRouter(c, opt) +} + +func (c *MockCloud) CreateRouterInterface(routerID string, opt routers.AddInterfaceOptsBuilder) (*routers.InterfaceInfo, error) { + return createRouterInterface(c, routerID, opt) +} + +func (c *MockCloud) CreateSecurityGroup(opt sg.CreateOptsBuilder) (*sg.SecGroup, error) { + return createSecurityGroup(c, opt) +} + +func (c *MockCloud) CreateSecurityGroupRule(opt sgr.CreateOptsBuilder) (*sgr.SecGroupRule, error) { + return createSecurityGroupRule(c, opt) +} + +func (c *MockCloud) CreateServerGroup(opt servergroups.CreateOptsBuilder) (*servergroups.ServerGroup, error) { + return createServerGroup(c, opt) +} + +func (c *MockCloud) CreateSubnet(opt subnets.CreateOptsBuilder) (*subnets.Subnet, error) { + return createSubnet(c, opt) +} + +func (c *MockCloud) CreateVolume(opt cinder.CreateOptsBuilder) (*cinder.Volume, error) { + return createVolume(c, opt) +} + +func (c *MockCloud) DefaultInstanceType(cluster *kops.Cluster, ig *kops.InstanceGroup) (string, error) { + return defaultInstanceType(c, cluster, ig) +} + +func (c *MockCloud) DeleteFloatingIP(id string) (err error) { + return deleteFloatingIP(c, id) +} +func (c *MockCloud) DeleteInstanceWithID(instanceID string) error { + return deleteInstanceWithID(c, instanceID) +} +func (c *MockCloud) DeleteKeyPair(name string) error { + return deleteKeyPair(c, name) +} + +func (c *MockCloud) DeleteL3FloatingIP(id string) (err error) { + return deleteL3FloatingIP(c, id) +} + +func (c *MockCloud) DeleteLB(lbID string, opts loadbalancers.DeleteOpts) error { + return deleteLB(c, lbID, opts) +} + +func (c *MockCloud) DeleteListener(listenerID string) error { + return deleteListener(c, listenerID) +} + +func (c *MockCloud) DeleteMonitor(monitorID string) error { + return deleteMonitor(c, monitorID) +} +func (c *MockCloud) DeleteNetwork(networkID string) error { + return deleteNetwork(c, networkID) +} +func (c *MockCloud) DeletePool(poolID string) error { + return deletePool(c, poolID) +} + +func (c *MockCloud) DeletePort(portID string) error { + return deletePort(c, portID) +} + +func (c *MockCloud) DeleteRouter(routerID string) error { + return deleteRouter(c, routerID) +} + +func (c *MockCloud) DeleteSecurityGroup(sgID string) error { + return deleteSecurityGroup(c, sgID) +} +func (c *MockCloud) DeleteSecurityGroupRule(ruleID string) error { + return deleteSecurityGroupRule(c, ruleID) +} +func (c *MockCloud) DeleteRouterInterface(routerID string, opt routers.RemoveInterfaceOptsBuilder) error { + return deleteRouterInterface(c, routerID, opt) +} + +func (c *MockCloud) DeleteServerGroup(groupID string) error { + return deleteServerGroup(c, groupID) +} + +func (c *MockCloud) DeleteSubnet(subnetID string) error { + return deleteSubnet(c, subnetID) +} + +func (c *MockCloud) DeleteTag(resource string, id string, tag string) error { + return deleteTag(c, resource, id, tag) +} +func (c *MockCloud) DeleteVolume(volumeID string) error { + return deleteVolume(c, volumeID) +} + +func (c *MockCloud) FindClusterStatus(cluster *kops.Cluster) (*kops.ClusterStatus, error) { + return findClusterStatus(c, cluster) +} + +func (c *MockCloud) FindNetworkBySubnetID(subnetID string) (*networks.Network, error) { + return findNetworkBySubnetID(c, subnetID) +} +func (c *MockCloud) GetApiIngressStatus(cluster *kops.Cluster) ([]kops.ApiIngressStatus, error) { + return getApiIngressStatus(c, cluster) +} +func (c *MockCloud) GetCloudTags() map[string]string { + return c.tags +} +func (c *MockCloud) GetExternalNetwork() (net *networks.Network, err error) { + return getExternalNetwork(c, *c.extNetworkName) +} +func (c *MockCloud) GetExternalSubnet() (subnet *subnets.Subnet, err error) { + return getExternalSubnet(c, c.extSubnetName) +} + +func (c *MockCloud) GetFloatingIP(id string) (fip *floatingips.FloatingIP, err error) { + return getFloatingIP(c, id) +} + +func (c *MockCloud) GetImage(name string) (*images.Image, error) { + return getImage(c, name) +} + +func (c *MockCloud) GetInstance(id string) (*servers.Server, error) { + return getInstance(c, id) +} + +func (c *MockCloud) GetKeypair(name string) (*keypairs.KeyPair, error) { + return getKeypair(c, name) +} + +func (c *MockCloud) GetLB(loadbalancerID string) (lb *loadbalancers.LoadBalancer, err error) { + return getLB(c, loadbalancerID) +} +func (c *MockCloud) GetNetwork(id string) (*networks.Network, error) { + return getNetwork(c, id) +} + +func (c *MockCloud) GetLBFloatingSubnet() (subnet *subnets.Subnet, err error) { + return getLBFloatingSubnet(c, c.floatingSubnet) +} + +func (c *MockCloud) GetPool(poolID string, memberID string) (member *v2pools.Member, err error) { + return getPool(c, poolID, memberID) +} + +func (c *MockCloud) GetPort(id string) (*ports.Port, error) { + return getPort(c, id) +} + +func (c *MockCloud) GetStorageAZFromCompute(computeAZ string) (*az.AvailabilityZone, error) { + return getStorageAZFromCompute(c, computeAZ) +} + +func (c *MockCloud) GetSubnet(subnetID string) (*subnets.Subnet, error) { + return getSubnet(c, subnetID) +} + +func (c *MockCloud) ListAvailabilityZones(serviceClient *gophercloud.ServiceClient) (azList []az.AvailabilityZone, err error) { + return listAvailabilityZones(c, serviceClient) +} +func (c *MockCloud) ListDNSZones(opt zones.ListOptsBuilder) ([]zones.Zone, error) { + return listDNSZones(c, opt) +} +func (c *MockCloud) ListDNSRecordsets(zoneID string, opt recordsets.ListOptsBuilder) ([]recordsets.RecordSet, error) { + return listDNSRecordsets(c, zoneID, opt) +} +func (c *MockCloud) ListFloatingIPs() (fips []floatingips.FloatingIP, err error) { + return listFloatingIPs(c) +} + +func (c *MockCloud) ListInstances(opt servers.ListOptsBuilder) ([]servers.Server, error) { + return listInstances(c, opt) +} +func (c *MockCloud) ListKeypairs() ([]keypairs.KeyPair, error) { + return listKeypairs(c) +} +func (c *MockCloud) ListL3FloatingIPs(opts l3floatingip.ListOpts) (fips []l3floatingip.FloatingIP, err error) { + return listL3FloatingIPs(c, opts) +} + +func (c *MockCloud) ListLBs(opt loadbalancers.ListOptsBuilder) (lbs []loadbalancers.LoadBalancer, err error) { + return listLBs(c, opt) +} +func (c *MockCloud) ListListeners(opts listeners.ListOpts) (listenerList []listeners.Listener, err error) { + return listListeners(c, opts) +} +func (c *MockCloud) ListMonitors(opts monitors.ListOpts) (monitorList []monitors.Monitor, err error) { + return listMonitors(c, opts) +} + +func (c *MockCloud) ListNetworks(opt networks.ListOptsBuilder) ([]networks.Network, error) { + return listNetworks(c, opt) +} +func (c *MockCloud) ListPools(opts v2pools.ListOpts) (poolList []v2pools.Pool, err error) { + return listPools(c, opts) +} + +func (c *MockCloud) ListPorts(opt ports.ListOptsBuilder) ([]ports.Port, error) { + return listPorts(c, opt) +} + +func (c *MockCloud) ListRouters(opt routers.ListOpts) ([]routers.Router, error) { + return listRouters(c, opt) +} + +func (c *MockCloud) ListSecurityGroups(opt sg.ListOpts) ([]sg.SecGroup, error) { + return listSecurityGroups(c, opt) +} + +func (c *MockCloud) ListSecurityGroupRules(opt sgr.ListOpts) ([]sgr.SecGroupRule, error) { + return listSecurityGroupRules(c, opt) +} + +func (c *MockCloud) ListServerFloatingIPs(instanceID string) ([]*string, error) { + return listServerFloatingIPs(c, instanceID, true) +} +func (c *MockCloud) ListServerGroups() ([]servergroups.ServerGroup, error) { + return listServerGroups(c) +} +func (c *MockCloud) ListSubnets(opt subnets.ListOptsBuilder) ([]subnets.Subnet, error) { + return listSubnets(c, opt) +} + +func (c *MockCloud) ListVolumes(opt cinder.ListOptsBuilder) ([]cinder.Volume, error) { + return listVolumes(c, opt) +} + +func (c *MockCloud) SetExternalNetwork(name *string) { + c.extNetworkName = name +} + +func (c *MockCloud) SetExternalSubnet(name *string) { + c.extSubnetName = name +} + +func (c *MockCloud) SetLBFloatingSubnet(name *string) { + c.floatingSubnet = name +} +func (c *MockCloud) SetVolumeTags(id string, tags map[string]string) error { + return setVolumeTags(c, id, tags) +} + +func (c *MockCloud) UseOctavia() bool { + return c.useOctavia +} + +func (c *MockCloud) UseZones(zones []string) { + c.zones = zones +} diff --git a/upup/pkg/fi/cloudup/openstack/network.go b/upup/pkg/fi/cloudup/openstack/network.go index 24b3afac3d0bb..4f7eb83da2943 100644 --- a/upup/pkg/fi/cloudup/openstack/network.go +++ b/upup/pkg/fi/cloudup/openstack/network.go @@ -24,11 +24,14 @@ import ( "github.com/gophercloud/gophercloud/openstack/networking/v2/networks" "github.com/gophercloud/gophercloud/pagination" "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/kops/upup/pkg/fi" "k8s.io/kops/util/pkg/vfs" ) func (c *openstackCloud) AppendTag(resource string, id string, tag string) error { + return appendTag(c, resource, id, tag) +} + +func appendTag(c OpenstackCloud, resource string, id string, tag string) error { done, err := vfs.RetryWithBackoff(readBackoff, func() (bool, error) { err := attributestags.Add(c.NetworkingClient(), resource, id, tag).ExtractErr() if err != nil { @@ -46,6 +49,10 @@ func (c *openstackCloud) AppendTag(resource string, id string, tag string) error } func (c *openstackCloud) DeleteTag(resource string, id string, tag string) error { + return deleteTag(c, resource, id, tag) +} + +func deleteTag(c OpenstackCloud, resource string, id string, tag string) error { done, err := vfs.RetryWithBackoff(readBackoff, func() (bool, error) { err := attributestags.Delete(c.NetworkingClient(), resource, id, tag).ExtractErr() if err != nil { @@ -63,6 +70,10 @@ func (c *openstackCloud) DeleteTag(resource string, id string, tag string) error } func (c *openstackCloud) FindNetworkBySubnetID(subnetID string) (*networks.Network, error) { + return findNetworkBySubnetID(c, subnetID) +} + +func findNetworkBySubnetID(c OpenstackCloud, subnetID string) (*networks.Network, error) { var rslt *networks.Network done, err := vfs.RetryWithBackoff(readBackoff, func() (bool, error) { subnet, err := c.GetSubnet(subnetID) @@ -88,6 +99,10 @@ func (c *openstackCloud) FindNetworkBySubnetID(subnetID string) (*networks.Netwo } func (c *openstackCloud) GetNetwork(id string) (*networks.Network, error) { + return getNetwork(c, id) +} + +func getNetwork(c OpenstackCloud, id string) (*networks.Network, error) { var network *networks.Network done, err := vfs.RetryWithBackoff(readBackoff, func() (bool, error) { r, err := networks.Get(c.NetworkingClient(), id).Extract() @@ -107,6 +122,10 @@ func (c *openstackCloud) GetNetwork(id string) (*networks.Network, error) { } func (c *openstackCloud) ListNetworks(opt networks.ListOptsBuilder) ([]networks.Network, error) { + return listNetworks(c, opt) +} + +func listNetworks(c OpenstackCloud, opt networks.ListOptsBuilder) ([]networks.Network, error) { var ns []networks.Network done, err := vfs.RetryWithBackoff(readBackoff, func() (bool, error) { @@ -132,6 +151,10 @@ func (c *openstackCloud) ListNetworks(opt networks.ListOptsBuilder) ([]networks. } func (c *openstackCloud) GetExternalNetwork() (net *networks.Network, err error) { + return getExternalNetwork(c, *c.extNetworkName) +} + +func getExternalNetwork(c OpenstackCloud, networkName string) (net *networks.Network, err error) { type NetworkWithExternalExt struct { networks.Network external.NetworkExternalExt @@ -146,7 +169,7 @@ func (c *openstackCloud) GetExternalNetwork() (net *networks.Network, err error) return false, err } for _, externalNet := range externalNetwork { - if externalNet.External && externalNet.Name == fi.StringValue(c.extNetworkName) { + if externalNet.External && externalNet.Name == networkName { net = &externalNet.Network return true, nil } @@ -169,6 +192,10 @@ func (c *openstackCloud) GetExternalNetwork() (net *networks.Network, err error) } func (c *openstackCloud) CreateNetwork(opt networks.CreateOptsBuilder) (*networks.Network, error) { + return createNetwork(c, opt) +} + +func createNetwork(c OpenstackCloud, opt networks.CreateOptsBuilder) (*networks.Network, error) { var n *networks.Network done, err := vfs.RetryWithBackoff(writeBackoff, func() (bool, error) { @@ -189,6 +216,10 @@ func (c *openstackCloud) CreateNetwork(opt networks.CreateOptsBuilder) (*network } func (c *openstackCloud) DeleteNetwork(networkID string) error { + return deleteNetwork(c, networkID) +} + +func deleteNetwork(c OpenstackCloud, networkID string) error { done, err := vfs.RetryWithBackoff(writeBackoff, func() (bool, error) { err := networks.Delete(c.NetworkingClient(), networkID).ExtractErr() if err != nil && !isNotFound(err) { diff --git a/upup/pkg/fi/cloudup/openstack/port.go b/upup/pkg/fi/cloudup/openstack/port.go index 9deb597f75cec..3c78267e1707d 100644 --- a/upup/pkg/fi/cloudup/openstack/port.go +++ b/upup/pkg/fi/cloudup/openstack/port.go @@ -25,14 +25,18 @@ import ( ) func (c *openstackCloud) CreatePort(opt ports.CreateOptsBuilder) (*ports.Port, error) { + return createPort(c, opt) +} + +func createPort(c OpenstackCloud, opt ports.CreateOptsBuilder) (*ports.Port, error) { var p *ports.Port done, err := vfs.RetryWithBackoff(writeBackoff, func() (bool, error) { - v, err := ports.Create(c.NetworkingClient(), opt).Extract() + port, err := ports.Create(c.NetworkingClient(), opt).Extract() if err != nil { return false, fmt.Errorf("error creating port: %v", err) } - p = v + p = port return true, nil }) if err != nil { @@ -45,6 +49,10 @@ func (c *openstackCloud) CreatePort(opt ports.CreateOptsBuilder) (*ports.Port, e } func (c *openstackCloud) GetPort(id string) (*ports.Port, error) { + return getPort(c, id) +} + +func getPort(c OpenstackCloud, id string) (*ports.Port, error) { var p *ports.Port done, err := vfs.RetryWithBackoff(readBackoff, func() (bool, error) { @@ -65,6 +73,10 @@ func (c *openstackCloud) GetPort(id string) (*ports.Port, error) { } func (c *openstackCloud) ListPorts(opt ports.ListOptsBuilder) ([]ports.Port, error) { + return listPorts(c, opt) +} + +func listPorts(c OpenstackCloud, opt ports.ListOptsBuilder) ([]ports.Port, error) { var p []ports.Port done, err := vfs.RetryWithBackoff(readBackoff, func() (bool, error) { @@ -90,6 +102,10 @@ func (c *openstackCloud) ListPorts(opt ports.ListOptsBuilder) ([]ports.Port, err } func (c *openstackCloud) DeletePort(portID string) error { + return deletePort(c, portID) +} + +func deletePort(c OpenstackCloud, portID string) error { done, err := vfs.RetryWithBackoff(writeBackoff, func() (bool, error) { err := ports.Delete(c.NetworkingClient(), portID).ExtractErr() if err != nil && !isNotFound(err) { diff --git a/upup/pkg/fi/cloudup/openstack/router.go b/upup/pkg/fi/cloudup/openstack/router.go index 9e17673cf3da4..ee1d18421b6ac 100644 --- a/upup/pkg/fi/cloudup/openstack/router.go +++ b/upup/pkg/fi/cloudup/openstack/router.go @@ -25,6 +25,10 @@ import ( ) func (c *openstackCloud) ListRouters(opt routers.ListOpts) ([]routers.Router, error) { + return listRouters(c, opt) +} + +func listRouters(c OpenstackCloud, opt routers.ListOpts) ([]routers.Router, error) { var rs []routers.Router done, err := vfs.RetryWithBackoff(readBackoff, func() (bool, error) { @@ -50,6 +54,10 @@ func (c *openstackCloud) ListRouters(opt routers.ListOpts) ([]routers.Router, er } func (c *openstackCloud) CreateRouter(opt routers.CreateOptsBuilder) (*routers.Router, error) { + return createRouter(c, opt) +} + +func createRouter(c OpenstackCloud, opt routers.CreateOptsBuilder) (*routers.Router, error) { var r *routers.Router done, err := vfs.RetryWithBackoff(writeBackoff, func() (bool, error) { @@ -70,6 +78,10 @@ func (c *openstackCloud) CreateRouter(opt routers.CreateOptsBuilder) (*routers.R } func (c *openstackCloud) CreateRouterInterface(routerID string, opt routers.AddInterfaceOptsBuilder) (*routers.InterfaceInfo, error) { + return createRouterInterface(c, routerID, opt) +} + +func createRouterInterface(c OpenstackCloud, routerID string, opt routers.AddInterfaceOptsBuilder) (*routers.InterfaceInfo, error) { var i *routers.InterfaceInfo done, err := vfs.RetryWithBackoff(writeBackoff, func() (bool, error) { @@ -90,6 +102,10 @@ func (c *openstackCloud) CreateRouterInterface(routerID string, opt routers.AddI } func (c *openstackCloud) DeleteRouterInterface(routerID string, opt routers.RemoveInterfaceOptsBuilder) error { + return deleteRouterInterface(c, routerID, opt) +} + +func deleteRouterInterface(c OpenstackCloud, routerID string, opt routers.RemoveInterfaceOptsBuilder) error { done, err := vfs.RetryWithBackoff(writeBackoff, func() (bool, error) { _, err := routers.RemoveInterface(c.NetworkingClient(), routerID, opt).Extract() if err != nil && !isNotFound(err) { @@ -107,6 +123,10 @@ func (c *openstackCloud) DeleteRouterInterface(routerID string, opt routers.Remo } func (c *openstackCloud) DeleteRouter(routerID string) error { + return deleteRouter(c, routerID) +} + +func deleteRouter(c OpenstackCloud, routerID string) error { done, err := vfs.RetryWithBackoff(writeBackoff, func() (bool, error) { err := routers.Delete(c.NetworkingClient(), routerID).ExtractErr() if err != nil && !isNotFound(err) { diff --git a/upup/pkg/fi/cloudup/openstack/security_group.go b/upup/pkg/fi/cloudup/openstack/security_group.go index 99fd384360814..28c65633bba5d 100644 --- a/upup/pkg/fi/cloudup/openstack/security_group.go +++ b/upup/pkg/fi/cloudup/openstack/security_group.go @@ -26,6 +26,10 @@ import ( ) func (c *openstackCloud) ListSecurityGroups(opt sg.ListOpts) ([]sg.SecGroup, error) { + return listSecurityGroups(c, opt) +} + +func listSecurityGroups(c OpenstackCloud, opt sg.ListOpts) ([]sg.SecGroup, error) { var groups []sg.SecGroup done, err := vfs.RetryWithBackoff(readBackoff, func() (bool, error) { @@ -51,6 +55,10 @@ func (c *openstackCloud) ListSecurityGroups(opt sg.ListOpts) ([]sg.SecGroup, err } func (c *openstackCloud) CreateSecurityGroup(opt sg.CreateOptsBuilder) (*sg.SecGroup, error) { + return createSecurityGroup(c, opt) +} + +func createSecurityGroup(c OpenstackCloud, opt sg.CreateOptsBuilder) (*sg.SecGroup, error) { var group *sg.SecGroup done, err := vfs.RetryWithBackoff(writeBackoff, func() (bool, error) { @@ -71,6 +79,10 @@ func (c *openstackCloud) CreateSecurityGroup(opt sg.CreateOptsBuilder) (*sg.SecG } func (c *openstackCloud) ListSecurityGroupRules(opt sgr.ListOpts) ([]sgr.SecGroupRule, error) { + return listSecurityGroupRules(c, opt) +} + +func listSecurityGroupRules(c OpenstackCloud, opt sgr.ListOpts) ([]sgr.SecGroupRule, error) { var rules []sgr.SecGroupRule done, err := vfs.RetryWithBackoff(readBackoff, func() (bool, error) { @@ -96,6 +108,10 @@ func (c *openstackCloud) ListSecurityGroupRules(opt sgr.ListOpts) ([]sgr.SecGrou } func (c *openstackCloud) CreateSecurityGroupRule(opt sgr.CreateOptsBuilder) (*sgr.SecGroupRule, error) { + return createSecurityGroupRule(c, opt) +} + +func createSecurityGroupRule(c OpenstackCloud, opt sgr.CreateOptsBuilder) (*sgr.SecGroupRule, error) { var rule *sgr.SecGroupRule done, err := vfs.RetryWithBackoff(writeBackoff, func() (bool, error) { @@ -116,6 +132,10 @@ func (c *openstackCloud) CreateSecurityGroupRule(opt sgr.CreateOptsBuilder) (*sg } func (c *openstackCloud) DeleteSecurityGroup(sgID string) error { + return deleteSecurityGroup(c, sgID) +} + +func deleteSecurityGroup(c OpenstackCloud, sgID string) error { done, err := vfs.RetryWithBackoff(writeBackoff, func() (bool, error) { err := sg.Delete(c.NetworkingClient(), sgID).ExtractErr() if err != nil && !isNotFound(err) { @@ -133,6 +153,10 @@ func (c *openstackCloud) DeleteSecurityGroup(sgID string) error { } func (c *openstackCloud) DeleteSecurityGroupRule(ruleID string) error { + return deleteSecurityGroupRule(c, ruleID) +} + +func deleteSecurityGroupRule(c OpenstackCloud, ruleID string) error { done, err := vfs.RetryWithBackoff(writeBackoff, func() (bool, error) { err := sgr.Delete(c.NetworkingClient(), ruleID).ExtractErr() if err != nil && !isNotFound(err) { diff --git a/upup/pkg/fi/cloudup/openstack/server_group.go b/upup/pkg/fi/cloudup/openstack/server_group.go index d22160231b3d7..36caf35ac77e5 100644 --- a/upup/pkg/fi/cloudup/openstack/server_group.go +++ b/upup/pkg/fi/cloudup/openstack/server_group.go @@ -32,6 +32,10 @@ import ( ) func (c *openstackCloud) CreateServerGroup(opt servergroups.CreateOptsBuilder) (*servergroups.ServerGroup, error) { + return createServerGroup(c, opt) +} + +func createServerGroup(c OpenstackCloud, opt servergroups.CreateOptsBuilder) (*servergroups.ServerGroup, error) { var i *servergroups.ServerGroup done, err := vfs.RetryWithBackoff(writeBackoff, func() (bool, error) { @@ -52,6 +56,9 @@ func (c *openstackCloud) CreateServerGroup(opt servergroups.CreateOptsBuilder) ( } func (c *openstackCloud) ListServerGroups() ([]servergroups.ServerGroup, error) { + return listServerGroups(c) +} +func listServerGroups(c OpenstackCloud) ([]servergroups.ServerGroup, error) { var sgs []servergroups.ServerGroup done, err := vfs.RetryWithBackoff(readBackoff, func() (bool, error) { @@ -101,7 +108,7 @@ func matchInstanceGroup(name string, clusterName string, instancegroups []*kops. return instancegroup, nil } -func (c *openstackCloud) osBuildCloudInstanceGroup(cluster *kops.Cluster, ig *kops.InstanceGroup, g *servergroups.ServerGroup, nodeMap map[string]*v1.Node) (*cloudinstances.CloudInstanceGroup, error) { +func osBuildCloudInstanceGroup(c OpenstackCloud, cluster *kops.Cluster, ig *kops.InstanceGroup, g *servergroups.ServerGroup, nodeMap map[string]*v1.Node) (*cloudinstances.CloudInstanceGroup, error) { newLaunchConfigName := g.Name cg := &cloudinstances.CloudInstanceGroup{ HumanName: newLaunchConfigName, @@ -135,6 +142,10 @@ func (c *openstackCloud) osBuildCloudInstanceGroup(cluster *kops.Cluster, ig *ko } func (c *openstackCloud) DeleteServerGroup(groupID string) error { + return deleteServerGroup(c, groupID) +} + +func deleteServerGroup(c OpenstackCloud, groupID string) error { done, err := vfs.RetryWithBackoff(writeBackoff, func() (bool, error) { err := servergroups.Delete(c.ComputeClient(), groupID).ExtractErr() if err != nil && !isNotFound(err) { diff --git a/upup/pkg/fi/cloudup/openstack/status.go b/upup/pkg/fi/cloudup/openstack/status.go index ff07e6a261b87..b99a22a08a697 100644 --- a/upup/pkg/fi/cloudup/openstack/status.go +++ b/upup/pkg/fi/cloudup/openstack/status.go @@ -42,6 +42,10 @@ import ( // FindClusterStatus discovers the status of the cluster, by looking for the tagged etcd volumes func (c *openstackCloud) FindClusterStatus(cluster *kops.Cluster) (*kops.ClusterStatus, error) { + return findClusterStatus(c, cluster) +} + +func findClusterStatus(c OpenstackCloud, cluster *kops.Cluster) (*kops.ClusterStatus, error) { etcdStatus, err := findEtcdStatus(c, cluster) if err != nil { return nil, err @@ -54,11 +58,11 @@ func (c *openstackCloud) FindClusterStatus(cluster *kops.Cluster) (*kops.Cluster } // findEtcdStatus discovers the status of etcd, by looking for the tagged etcd volumes -func findEtcdStatus(c *openstackCloud, cluster *kops.Cluster) ([]kops.EtcdClusterStatus, error) { +func findEtcdStatus(c OpenstackCloud, cluster *kops.Cluster) ([]kops.EtcdClusterStatus, error) { statusMap := make(map[string]*kops.EtcdClusterStatus) klog.V(2).Infof("Querying Openstack for etcd volumes") opt := cinderv3.ListOpts{ - Metadata: c.tags, + Metadata: c.GetCloudTags(), } volumes, err := c.ListVolumes(opt) if err != nil { diff --git a/upup/pkg/fi/cloudup/openstack/subnet.go b/upup/pkg/fi/cloudup/openstack/subnet.go index 2fa24ef38093d..ebf11c47a81c0 100644 --- a/upup/pkg/fi/cloudup/openstack/subnet.go +++ b/upup/pkg/fi/cloudup/openstack/subnet.go @@ -26,6 +26,10 @@ import ( ) func (c *openstackCloud) ListSubnets(opt subnets.ListOptsBuilder) ([]subnets.Subnet, error) { + return listSubnets(c, opt) +} + +func listSubnets(c OpenstackCloud, opt subnets.ListOptsBuilder) ([]subnets.Subnet, error) { var s []subnets.Subnet done, err := vfs.RetryWithBackoff(readBackoff, func() (bool, error) { @@ -51,6 +55,10 @@ func (c *openstackCloud) ListSubnets(opt subnets.ListOptsBuilder) ([]subnets.Sub } func (c *openstackCloud) GetSubnet(subnetID string) (*subnets.Subnet, error) { + return getSubnet(c, subnetID) +} + +func getSubnet(c OpenstackCloud, subnetID string) (*subnets.Subnet, error) { var subnet *subnets.Subnet done, err := vfs.RetryWithBackoff(readBackoff, func() (bool, error) { sub, err := subnets.Get(c.NetworkingClient(), subnetID).Extract() @@ -70,6 +78,10 @@ func (c *openstackCloud) GetSubnet(subnetID string) (*subnets.Subnet, error) { } func (c *openstackCloud) CreateSubnet(opt subnets.CreateOptsBuilder) (*subnets.Subnet, error) { + return createSubnet(c, opt) +} + +func createSubnet(c OpenstackCloud, opt subnets.CreateOptsBuilder) (*subnets.Subnet, error) { var s *subnets.Subnet done, err := vfs.RetryWithBackoff(writeBackoff, func() (bool, error) { @@ -90,6 +102,10 @@ func (c *openstackCloud) CreateSubnet(opt subnets.CreateOptsBuilder) (*subnets.S } func (c *openstackCloud) DeleteSubnet(subnetID string) error { + return deleteSubnet(c, subnetID) +} + +func deleteSubnet(c OpenstackCloud, subnetID string) error { done, err := vfs.RetryWithBackoff(writeBackoff, func() (bool, error) { err := subnets.Delete(c.NetworkingClient(), subnetID).ExtractErr() if err != nil && !isNotFound(err) { @@ -107,12 +123,16 @@ func (c *openstackCloud) DeleteSubnet(subnetID string) error { } func (c *openstackCloud) GetExternalSubnet() (subnet *subnets.Subnet, err error) { - if c.extSubnetName == nil { + return getExternalSubnet(c, c.extSubnetName) +} + +func getExternalSubnet(c OpenstackCloud, subnetName *string) (subnet *subnets.Subnet, err error) { + if subnetName == nil { return nil, nil } subnets, err := c.ListSubnets(subnets.ListOpts{ - Name: fi.StringValue(c.extSubnetName), + Name: fi.StringValue(subnetName), }) if err != nil { return nil, err @@ -125,12 +145,16 @@ func (c *openstackCloud) GetExternalSubnet() (subnet *subnets.Subnet, err error) } func (c *openstackCloud) GetLBFloatingSubnet() (subnet *subnets.Subnet, err error) { - if c.floatingSubnet == nil { + return getLBFloatingSubnet(c, c.floatingSubnet) +} + +func getLBFloatingSubnet(c OpenstackCloud, floatingSubnet *string) (subnet *subnets.Subnet, err error) { + if floatingSubnet == nil { return nil, nil } subnets, err := c.ListSubnets(subnets.ListOpts{ - Name: fi.StringValue(c.floatingSubnet), + Name: fi.StringValue(floatingSubnet), }) if err != nil { return nil, err diff --git a/upup/pkg/fi/cloudup/openstack/utils.go b/upup/pkg/fi/cloudup/openstack/utils.go index 4fbc1d35ec34d..87c770acc9562 100644 --- a/upup/pkg/fi/cloudup/openstack/utils.go +++ b/upup/pkg/fi/cloudup/openstack/utils.go @@ -52,6 +52,10 @@ func (s flavorList) Less(i, j int) bool { } func (c *openstackCloud) DefaultInstanceType(cluster *kops.Cluster, ig *kops.InstanceGroup) (string, error) { + return defaultInstanceType(c, cluster, ig) +} + +func defaultInstanceType(c OpenstackCloud, cluster *kops.Cluster, ig *kops.InstanceGroup) (string, error) { flavorPage, err := flavors.ListDetail(c.ComputeClient(), flavors.ListOpts{ MinRAM: 1024, }).AllPages() diff --git a/upup/pkg/fi/cloudup/openstack/volume.go b/upup/pkg/fi/cloudup/openstack/volume.go index d1a9e5606bb9e..600017c45adab 100644 --- a/upup/pkg/fi/cloudup/openstack/volume.go +++ b/upup/pkg/fi/cloudup/openstack/volume.go @@ -27,6 +27,10 @@ import ( ) func (c *openstackCloud) ListVolumes(opt cinder.ListOptsBuilder) ([]cinder.Volume, error) { + return listVolumes(c, opt) +} + +func listVolumes(c OpenstackCloud, opt cinder.ListOptsBuilder) ([]cinder.Volume, error) { var volumes []cinder.Volume done, err := vfs.RetryWithBackoff(readBackoff, func() (bool, error) { @@ -52,6 +56,10 @@ func (c *openstackCloud) ListVolumes(opt cinder.ListOptsBuilder) ([]cinder.Volum } func (c *openstackCloud) CreateVolume(opt cinder.CreateOptsBuilder) (*cinder.Volume, error) { + return createVolume(c, opt) +} + +func createVolume(c OpenstackCloud, opt cinder.CreateOptsBuilder) (*cinder.Volume, error) { var volume *cinder.Volume done, err := vfs.RetryWithBackoff(writeBackoff, func() (bool, error) { @@ -72,6 +80,10 @@ func (c *openstackCloud) CreateVolume(opt cinder.CreateOptsBuilder) (*cinder.Vol } func (c *openstackCloud) AttachVolume(serverID string, opts volumeattach.CreateOpts) (attachment *volumeattach.VolumeAttachment, err error) { + return attachVolume(c, serverID, opts) +} + +func attachVolume(c OpenstackCloud, serverID string, opts volumeattach.CreateOpts) (attachment *volumeattach.VolumeAttachment, err error) { done, err := vfs.RetryWithBackoff(writeBackoff, func() (bool, error) { volumeAttachment, err := volumeattach.Create(c.ComputeClient(), serverID, opts).Extract() if err != nil { @@ -90,6 +102,10 @@ func (c *openstackCloud) AttachVolume(serverID string, opts volumeattach.CreateO } func (c *openstackCloud) SetVolumeTags(id string, tags map[string]string) error { + return setVolumeTags(c, id, tags) +} + +func setVolumeTags(c OpenstackCloud, id string, tags map[string]string) error { if len(tags) == 0 { return nil } @@ -116,6 +132,10 @@ func (c *openstackCloud) SetVolumeTags(id string, tags map[string]string) error } func (c *openstackCloud) DeleteVolume(volumeID string) error { + return deleteVolume(c, volumeID) +} + +func deleteVolume(c OpenstackCloud, volumeID string) error { done, err := vfs.RetryWithBackoff(writeBackoff, func() (bool, error) { err := cinder.Delete(c.BlockStorageClient(), volumeID, cinder.DeleteOpts{}).ExtractErr() if err != nil && !isNotFound(err) {