migrated LB regionalized API to zoned API

This commit is contained in:
Leïla MARABESE 2023-01-17 17:43:53 +01:00
parent ea2f7123e1
commit 3dece51a3a
5 changed files with 91 additions and 123 deletions

View File

@ -52,6 +52,10 @@ func (b *APILoadBalancerModelBuilder) Build(c *fi.CloudupModelBuilderContext) er
return fmt.Errorf("unhandled load-balancer type %q", lbSpec.Type) return fmt.Errorf("unhandled load-balancer type %q", lbSpec.Type)
} }
zone, err := scaleway.ParseZoneFromClusterSpec(b.Cluster.Spec)
if err != nil {
return fmt.Errorf("building load-balancer task: %w", err)
}
lbTags := []string(nil) lbTags := []string(nil)
for k, v := range b.CloudTags(b.ClusterName(), false) { for k, v := range b.CloudTags(b.ClusterName(), false) {
lbTags = append(lbTags, fmt.Sprintf("%s=%s", k, v)) lbTags = append(lbTags, fmt.Sprintf("%s=%s", k, v))
@ -60,10 +64,12 @@ func (b *APILoadBalancerModelBuilder) Build(c *fi.CloudupModelBuilderContext) er
loadBalancerName := "api." + b.ClusterName() loadBalancerName := "api." + b.ClusterName()
loadBalancer := &scalewaytasks.LoadBalancer{ loadBalancer := &scalewaytasks.LoadBalancer{
Name: fi.PtrTo(loadBalancerName), Name: fi.PtrTo(loadBalancerName),
Region: fi.PtrTo(b.Region), Zone: fi.PtrTo(string(zone)),
Lifecycle: b.Lifecycle, Lifecycle: b.Lifecycle,
Tags: lbTags, Tags: lbTags,
Description: "Load-balancer for kops cluster " + b.ClusterName(),
SslCompatibilityLevel: string(lb.SSLCompatibilityLevelSslCompatibilityLevelUnknown),
} }
c.AddTask(loadBalancer) c.AddTask(loadBalancer)

View File

@ -688,7 +688,7 @@ func (c *ApplyClusterCmd) Run(ctx context.Context) error {
KopsModelContext: modelContext, KopsModelContext: modelContext,
} }
l.Builders = append(l.Builders, l.Builders = append(l.Builders,
&scalewaymodel.APILoadBalancerModelBuilder{ScwModelContext: scwModelContext, Lifecycle: clusterLifecycle}, &scalewaymodel.APILoadBalancerModelBuilder{ScwModelContext: scwModelContext, Lifecycle: networkLifecycle},
&scalewaymodel.InstanceModelBuilder{ScwModelContext: scwModelContext, BootstrapScriptBuilder: bootstrapScriptBuilder, Lifecycle: clusterLifecycle}, &scalewaymodel.InstanceModelBuilder{ScwModelContext: scwModelContext, BootstrapScriptBuilder: bootstrapScriptBuilder, Lifecycle: clusterLifecycle},
&scalewaymodel.SSHKeyModelBuilder{ScwModelContext: scwModelContext, Lifecycle: securityLifecycle}, &scalewaymodel.SSHKeyModelBuilder{ScwModelContext: scwModelContext, Lifecycle: securityLifecycle},
) )

View File

@ -57,7 +57,7 @@ type ScwCloud interface {
IamService() *iam.API IamService() *iam.API
InstanceService() *instance.API InstanceService() *instance.API
LBService() *lb.API LBService() *lb.ZonedAPI
DeleteGroup(group *cloudinstances.CloudInstanceGroup) error DeleteGroup(group *cloudinstances.CloudInstanceGroup) error
DeleteInstance(i *cloudinstances.CloudInstance) error DeleteInstance(i *cloudinstances.CloudInstance) error
@ -91,7 +91,7 @@ type scwCloudImplementation struct {
iamAPI *iam.API iamAPI *iam.API
instanceAPI *instance.API instanceAPI *instance.API
lbAPI *lb.API lbAPI *lb.ZonedAPI
} }
// NewScwCloud returns a Cloud with a Scaleway Client using the env vars SCW_ACCESS_KEY, SCW_SECRET_KEY and SCW_DEFAULT_PROJECT_ID // NewScwCloud returns a Cloud with a Scaleway Client using the env vars SCW_ACCESS_KEY, SCW_SECRET_KEY and SCW_DEFAULT_PROJECT_ID
@ -140,7 +140,7 @@ func NewScwCloud(tags map[string]string) (ScwCloud, error) {
tags: tags, tags: tags,
iamAPI: iam.NewAPI(scwClient), iamAPI: iam.NewAPI(scwClient),
instanceAPI: instance.NewAPI(scwClient), instanceAPI: instance.NewAPI(scwClient),
lbAPI: lb.NewAPI(scwClient), lbAPI: lb.NewZonedAPI(scwClient),
}, nil }, nil
} }
@ -178,7 +178,7 @@ func (s *scwCloudImplementation) InstanceService() *instance.API {
return s.instanceAPI return s.instanceAPI
} }
func (s *scwCloudImplementation) LBService() *lb.API { func (s *scwCloudImplementation) LBService() *lb.ZonedAPI {
return s.lbAPI return s.lbAPI
} }
@ -229,9 +229,9 @@ func (s *scwCloudImplementation) DeregisterInstance(i *cloudinstances.CloudInsta
return fmt.Errorf("deregistering cloud instance %s of group %q: %w", i.ID, i.CloudInstanceGroup.HumanName, err) return fmt.Errorf("deregistering cloud instance %s of group %q: %w", i.ID, i.CloudInstanceGroup.HumanName, err)
} }
for _, loadBalancer := range lbs { for _, loadBalancer := range lbs {
backEnds, err := s.lbAPI.ListBackends(&lb.ListBackendsRequest{ backEnds, err := s.lbAPI.ListBackends(&lb.ZonedAPIListBackendsRequest{
Region: s.region, Zone: s.zone,
LBID: loadBalancer.ID, LBID: loadBalancer.ID,
}, scw.WithAllPages()) }, scw.WithAllPages())
if err != nil { if err != nil {
return fmt.Errorf("deregistering cloud instance %s of group %q: listing load-balancer's back-ends for instance creation: %w", i.ID, i.CloudInstanceGroup.HumanName, err) return fmt.Errorf("deregistering cloud instance %s of group %q: listing load-balancer's back-ends for instance creation: %w", i.ID, i.CloudInstanceGroup.HumanName, err)
@ -239,8 +239,8 @@ func (s *scwCloudImplementation) DeregisterInstance(i *cloudinstances.CloudInsta
for _, backEnd := range backEnds.Backends { for _, backEnd := range backEnds.Backends {
for _, serverIP := range backEnd.Pool { for _, serverIP := range backEnd.Pool {
if serverIP == fi.ValueOf(server.Server.PrivateIP) { if serverIP == fi.ValueOf(server.Server.PrivateIP) {
_, err := s.lbAPI.RemoveBackendServers(&lb.RemoveBackendServersRequest{ _, err := s.lbAPI.RemoveBackendServers(&lb.ZonedAPIRemoveBackendServersRequest{
Region: s.region, Zone: s.zone,
BackendID: backEnd.ID, BackendID: backEnd.ID,
ServerIP: []string{serverIP}, ServerIP: []string{serverIP},
}) })
@ -276,9 +276,9 @@ func (s *scwCloudImplementation) GetApiIngressStatus(cluster *kops.Cluster) ([]f
var ingresses []fi.ApiIngressStatus var ingresses []fi.ApiIngressStatus
name := "api." + cluster.Name name := "api." + cluster.Name
responseLoadBalancers, err := s.lbAPI.ListLBs(&lb.ListLBsRequest{ responseLoadBalancers, err := s.lbAPI.ListLBs(&lb.ZonedAPIListLBsRequest{
Region: scw.Region(s.Region()), Zone: s.zone,
Name: &name, Name: &name,
}, scw.WithAllPages()) }, scw.WithAllPages())
if err != nil { if err != nil {
return nil, fmt.Errorf("finding load-balancers: %w", err) return nil, fmt.Errorf("finding load-balancers: %w", err)
@ -382,9 +382,9 @@ func buildCloudGroup(ig *kops.InstanceGroup, sg []*instance.Server, nodeMap map[
func (s *scwCloudImplementation) GetClusterLoadBalancers(clusterName string) ([]*lb.LB, error) { func (s *scwCloudImplementation) GetClusterLoadBalancers(clusterName string) ([]*lb.LB, error) {
loadBalancerName := "api." + clusterName loadBalancerName := "api." + clusterName
lbs, err := s.lbAPI.ListLBs(&lb.ListLBsRequest{ lbs, err := s.lbAPI.ListLBs(&lb.ZonedAPIListLBsRequest{
Region: s.region, Zone: s.zone,
Name: &loadBalancerName, Name: &loadBalancerName,
}, scw.WithAllPages()) }, scw.WithAllPages())
if err != nil { if err != nil {
return nil, fmt.Errorf("listing cluster load-balancers: %w", err) return nil, fmt.Errorf("listing cluster load-balancers: %w", err)
@ -437,33 +437,33 @@ func (s *scwCloudImplementation) DeleteLoadBalancer(loadBalancer *lb.LB) error {
ipsToRelease := loadBalancer.IP ipsToRelease := loadBalancer.IP
// We delete the load-balancer once it's in a stable state // We delete the load-balancer once it's in a stable state
_, err := s.lbAPI.WaitForLb(&lb.WaitForLBRequest{ _, err := s.lbAPI.WaitForLb(&lb.ZonedAPIWaitForLBRequest{
LBID: loadBalancer.ID, LBID: loadBalancer.ID,
Region: s.region, Zone: s.zone,
}) })
if err != nil { if err != nil {
return fmt.Errorf("waiting for load-balancer: %w", err) return fmt.Errorf("waiting for load-balancer: %w", err)
} }
err = s.lbAPI.DeleteLB(&lb.DeleteLBRequest{ err = s.lbAPI.DeleteLB(&lb.ZonedAPIDeleteLBRequest{
Region: s.region, Zone: s.zone,
LBID: loadBalancer.ID, LBID: loadBalancer.ID,
}) })
if err != nil { if err != nil {
return fmt.Errorf("deleting load-balancer %s: %w", loadBalancer.ID, err) return fmt.Errorf("deleting load-balancer %s: %w", loadBalancer.ID, err)
} }
// We wait for the load-balancer to be deleted, then we detach its IPs // We wait for the load-balancer to be deleted, then we detach its IPs
_, err = s.lbAPI.WaitForLb(&lb.WaitForLBRequest{ _, err = s.lbAPI.WaitForLb(&lb.ZonedAPIWaitForLBRequest{
LBID: loadBalancer.ID, LBID: loadBalancer.ID,
Region: s.region, Zone: s.zone,
}) })
if !is404Error(err) { if !is404Error(err) {
return fmt.Errorf("waiting for load-balancer %s after deletion: %w", loadBalancer.ID, err) return fmt.Errorf("waiting for load-balancer %s after deletion: %w", loadBalancer.ID, err)
} }
for _, ip := range ipsToRelease { for _, ip := range ipsToRelease {
err := s.lbAPI.ReleaseIP(&lb.ReleaseIPRequest{ err := s.lbAPI.ReleaseIP(&lb.ZonedAPIReleaseIPRequest{
Region: s.region, Zone: s.zone,
IPID: ip.ID, IPID: ip.ID,
}) })
if err != nil { if err != nil {
return fmt.Errorf("deleting load-balancer IP: %w", err) return fmt.Errorf("deleting load-balancer IP: %w", err)

View File

@ -208,7 +208,7 @@ func (_ *Instance) RenderScw(c *fi.CloudupContext, actual, expected, changes *In
// If IG is control-plane, we add the new servers' IPs to the load-balancer's back-end // If IG is control-plane, we add the new servers' IPs to the load-balancer's back-end
if len(controlPlanePrivateIPs) > 0 { if len(controlPlanePrivateIPs) > 0 {
lbService := cloud.LBService() lbService := cloud.LBService()
region := scw.Region(cloud.Region()) zone := scw.Zone(cloud.Zone())
lbs, err := cloud.GetClusterLoadBalancers(cloud.ClusterName(expected.Tags)) lbs, err := cloud.GetClusterLoadBalancers(cloud.ClusterName(expected.Tags))
if err != nil { if err != nil {
@ -216,9 +216,9 @@ func (_ *Instance) RenderScw(c *fi.CloudupContext, actual, expected, changes *In
} }
for _, loadBalancer := range lbs { for _, loadBalancer := range lbs {
backEnds, err := lbService.ListBackends(&lb.ListBackendsRequest{ backEnds, err := lbService.ListBackends(&lb.ZonedAPIListBackendsRequest{
Region: region, Zone: zone,
LBID: loadBalancer.ID, LBID: loadBalancer.ID,
}) })
if err != nil { if err != nil {
return fmt.Errorf("listing load-balancer's back-ends for instance creation: %w", err) return fmt.Errorf("listing load-balancer's back-ends for instance creation: %w", err)
@ -228,8 +228,8 @@ func (_ *Instance) RenderScw(c *fi.CloudupContext, actual, expected, changes *In
} }
backEnd := backEnds.Backends[0] backEnd := backEnds.Backends[0]
_, err = lbService.AddBackendServers(&lb.AddBackendServersRequest{ _, err = lbService.AddBackendServers(&lb.ZonedAPIAddBackendServersRequest{
Region: region, Zone: zone,
BackendID: backEnd.ID, BackendID: backEnd.ID,
ServerIP: controlPlanePrivateIPs, ServerIP: controlPlanePrivateIPs,
}) })
@ -237,9 +237,9 @@ func (_ *Instance) RenderScw(c *fi.CloudupContext, actual, expected, changes *In
return fmt.Errorf("adding servers' IPs to load-balancer's back-end: %w", err) return fmt.Errorf("adding servers' IPs to load-balancer's back-end: %w", err)
} }
_, err = lbService.WaitForLb(&lb.WaitForLBRequest{ _, err = lbService.WaitForLb(&lb.ZonedAPIWaitForLBRequest{
LBID: loadBalancer.ID, LBID: loadBalancer.ID,
Region: region, Zone: zone,
}) })
if err != nil { if err != nil {
return fmt.Errorf("waiting for load-balancer %s: %w", loadBalancer.ID, err) return fmt.Errorf("waiting for load-balancer %s: %w", loadBalancer.ID, err)

View File

@ -32,11 +32,13 @@ type LoadBalancer struct {
Name *string Name *string
Lifecycle fi.Lifecycle Lifecycle fi.Lifecycle
Region *string Zone *string
LBID *string LBID *string
LBAddresses []string LBAddresses []string
Tags []string Tags []string
ForAPIServer bool Description string
SslCompatibilityLevel string
ForAPIServer bool
} }
var _ fi.CompareWithID = &LoadBalancer{} var _ fi.CompareWithID = &LoadBalancer{}
@ -51,20 +53,20 @@ func (l *LoadBalancer) IsForAPIServer() bool {
} }
func (l *LoadBalancer) Find(context *fi.CloudupContext) (*LoadBalancer, error) { func (l *LoadBalancer) Find(context *fi.CloudupContext) (*LoadBalancer, error) {
if fi.ValueOf(l.LBID) == "" {
return nil, nil
}
cloud := context.T.Cloud.(scaleway.ScwCloud) cloud := context.T.Cloud.(scaleway.ScwCloud)
lbService := cloud.LBService() lbService := cloud.LBService()
loadBalancer, err := lbService.GetLB(&lb.GetLBRequest{ lbResponse, err := lbService.ListLBs(&lb.ZonedAPIListLBsRequest{
Region: scw.Region(cloud.Region()), Zone: scw.Zone(cloud.Zone()),
LBID: fi.ValueOf(l.LBID), Name: l.Name,
}) }, scw.WithAllPages())
if err != nil { if err != nil {
return nil, fmt.Errorf("getting load-balancer %s: %s", fi.ValueOf(l.LBID), err) return nil, fmt.Errorf("getting load-balancer %s: %w", fi.ValueOf(l.LBID), err)
} }
if lbResponse.TotalCount != 1 {
return nil, nil
}
loadBalancer := lbResponse.LBs[0]
lbIPs := []string(nil) lbIPs := []string(nil)
for _, IP := range loadBalancer.IP { for _, IP := range loadBalancer.IP {
@ -72,8 +74,9 @@ func (l *LoadBalancer) Find(context *fi.CloudupContext) (*LoadBalancer, error) {
} }
return &LoadBalancer{ return &LoadBalancer{
Name: &loadBalancer.Name, Name: fi.PtrTo(loadBalancer.Name),
LBID: &loadBalancer.ID, LBID: fi.PtrTo(loadBalancer.ID),
Zone: fi.PtrTo(string(loadBalancer.Zone)),
LBAddresses: lbIPs, LBAddresses: lbIPs,
Tags: loadBalancer.Tags, Tags: loadBalancer.Tags,
Lifecycle: l.Lifecycle, Lifecycle: l.Lifecycle,
@ -89,9 +92,9 @@ func (l *LoadBalancer) FindAddresses(context *fi.CloudupContext) ([]string, erro
return nil, nil return nil, nil
} }
loadBalancer, err := lbService.GetLB(&lb.GetLBRequest{ loadBalancer, err := lbService.GetLB(&lb.ZonedAPIGetLBRequest{
Region: scw.Region(cloud.Region()), Zone: scw.Zone(cloud.Zone()),
LBID: fi.ValueOf(l.LBID), LBID: fi.ValueOf(l.LBID),
}) })
if err != nil { if err != nil {
return nil, err return nil, err
@ -117,15 +120,15 @@ func (_ *LoadBalancer) CheckChanges(actual, expected, changes *LoadBalancer) err
if changes.LBID != nil { if changes.LBID != nil {
return fi.CannotChangeField("ID") return fi.CannotChangeField("ID")
} }
if changes.Region != nil { if changes.Zone != nil {
return fi.CannotChangeField("Region") return fi.CannotChangeField("Zone")
} }
} else { } else {
if expected.Name == nil { if expected.Name == nil {
return fi.RequiredField("Name") return fi.RequiredField("Name")
} }
if expected.Region == nil { if expected.Zone == nil {
return fi.RequiredField("Region") return fi.RequiredField("Zone")
} }
} }
return nil return nil
@ -133,30 +136,20 @@ func (_ *LoadBalancer) CheckChanges(actual, expected, changes *LoadBalancer) err
func (l *LoadBalancer) RenderScw(t *scaleway.ScwAPITarget, actual, expected, changes *LoadBalancer) error { func (l *LoadBalancer) RenderScw(t *scaleway.ScwAPITarget, actual, expected, changes *LoadBalancer) error {
lbService := t.Cloud.LBService() lbService := t.Cloud.LBService()
region := scw.Region(fi.ValueOf(expected.Region)) zone := scw.Zone(fi.ValueOf(expected.Zone))
var loadBalancer *lb.LB
backEndToCreate := true
frontEndToCreate := true
if actual != nil { if actual != nil {
klog.Infof("Updating existing load-balancer with name %q", expected.Name)
lbToUpdate, err := lbService.GetLB(&lb.GetLBRequest{ klog.Infof("Updating existing load-balancer with name %q", expected.Name)
Region: region,
LBID: fi.ValueOf(actual.LBID),
})
if err != nil {
return fmt.Errorf("getting load-balancer %q (%s): %w", fi.ValueOf(actual.Name), fi.ValueOf(actual.LBID), err)
}
// We update the tags // We update the tags
if changes != nil || len(actual.Tags) != len(expected.Tags) { if changes != nil || len(actual.Tags) != len(expected.Tags) {
_, err = lbService.UpdateLB(&lb.UpdateLBRequest{ _, err := lbService.UpdateLB(&lb.ZonedAPIUpdateLBRequest{
Region: region, Zone: zone,
LBID: lbToUpdate.ID, LBID: fi.ValueOf(expected.LBID),
Name: lbToUpdate.Name, Name: fi.ValueOf(expected.Name),
Description: lbToUpdate.Description, Description: expected.Description,
SslCompatibilityLevel: lbToUpdate.SslCompatibilityLevel, SslCompatibilityLevel: lb.SSLCompatibilityLevel(expected.SslCompatibilityLevel),
Tags: expected.Tags, Tags: expected.Tags,
}) })
if err != nil { if err != nil {
@ -164,56 +157,25 @@ func (l *LoadBalancer) RenderScw(t *scaleway.ScwAPITarget, actual, expected, cha
} }
} }
// We check that the back-end exists expected.LBID = actual.LBID
backEnds, err := lbService.ListBackends(&lb.ListBackendsRequest{ expected.LBAddresses = actual.LBAddresses
Region: region,
LBID: lbToUpdate.ID,
Name: scw.StringPtr("lb-backend"),
})
if err != nil {
return fmt.Errorf("listing back-ends for load-balancer %q: %w", fi.ValueOf(expected.Name), err)
}
if backEnds.TotalCount > 0 {
backEndToCreate = false
}
// We check that the front-end exists
frontEnds, err := lbService.ListFrontends(&lb.ListFrontendsRequest{
Region: region,
LBID: lbToUpdate.ID,
Name: scw.StringPtr("lb-frontend"),
})
if err != nil {
return fmt.Errorf("listing front-ends for load-balancer %q: %w", fi.ValueOf(expected.Name), err)
}
if frontEnds.TotalCount > 0 {
frontEndToCreate = false
}
lbIPs := []string(nil)
for _, ip := range lbToUpdate.IP {
lbIPs = append(lbIPs, ip.IPAddress)
}
expected.LBID = &lbToUpdate.ID
expected.LBAddresses = lbIPs
loadBalancer = lbToUpdate
} else { } else {
klog.Infof("Creating new load-balancer with name %q", expected.Name) klog.Infof("Creating new load-balancer with name %q", expected.Name)
lbCreated, err := lbService.CreateLB(&lb.CreateLBRequest{ lbCreated, err := lbService.CreateLB(&lb.ZonedAPICreateLBRequest{
Region: region, Zone: zone,
Name: fi.ValueOf(expected.Name), Name: fi.ValueOf(expected.Name),
Tags: expected.Tags, Tags: expected.Tags,
}) })
if err != nil { if err != nil {
return fmt.Errorf("creating load-balancer: %w", err) return fmt.Errorf("creating load-balancer: %w", err)
} }
_, err = lbService.WaitForLb(&lb.WaitForLBRequest{ _, err = lbService.WaitForLb(&lb.ZonedAPIWaitForLBRequest{
LBID: lbCreated.ID, LBID: lbCreated.ID,
Region: region, Zone: zone,
}) })
if err != nil { if err != nil {
return fmt.Errorf("waiting for load-balancer %s: %w", lbCreated.ID, err) return fmt.Errorf("waiting for load-balancer %s: %w", lbCreated.ID, err)