|
| 1 | +package qingcloud |
| 2 | + |
| 3 | +import ( |
| 4 | + "fmt" |
| 5 | + |
| 6 | + "github.com/davecgh/go-spew/spew" |
| 7 | + "k8s.io/klog/v2" |
| 8 | + |
| 9 | + "github.com/yunify/qingcloud-cloud-controller-manager/pkg/apis" |
| 10 | +) |
| 11 | + |
| 12 | +func (qc *QingCloud) prepareEip(eipSource *string) (eip *apis.EIP, err error) { |
| 13 | + |
| 14 | + switch *eipSource { |
| 15 | + case AllocateOnly: |
| 16 | + eip, err = qc.Client.AllocateEIP(nil) |
| 17 | + case UseAvailableOnly: |
| 18 | + eips, err := qc.Client.GetAvaliableEIPs() |
| 19 | + if err != nil { |
| 20 | + return nil, err |
| 21 | + } |
| 22 | + |
| 23 | + if len(eips) <= 0 { |
| 24 | + return nil, fmt.Errorf("no avaliable eips") |
| 25 | + } |
| 26 | + |
| 27 | + eip = eips[0] |
| 28 | + case UseAvailableOrAllocateOne: |
| 29 | + eips, err := qc.Client.GetAvaliableEIPs() |
| 30 | + if err != nil { |
| 31 | + return nil, err |
| 32 | + } |
| 33 | + |
| 34 | + if len(eips) <= 0 { |
| 35 | + eip, err = qc.Client.AllocateEIP(nil) |
| 36 | + if err != nil { |
| 37 | + return nil, err |
| 38 | + } |
| 39 | + } else { |
| 40 | + eip = eips[0] |
| 41 | + } |
| 42 | + } |
| 43 | + |
| 44 | + if err != nil { |
| 45 | + return nil, err |
| 46 | + } else if eip == nil { |
| 47 | + return nil, fmt.Errorf("has no eip") |
| 48 | + } |
| 49 | + return eip, nil |
| 50 | +} |
| 51 | + |
| 52 | +func (qc *QingCloud) diffLBEip(config *LoadBalancerConfig, lb *apis.LoadBalancer) (eipsToAdd, eipsToDel []*string, err error) { |
| 53 | + |
| 54 | + // lb eip |
| 55 | + lbEipMap := make(map[string]bool) |
| 56 | + if lb.Spec.EIPs != nil { |
| 57 | + for _, lbEipID := range lb.Spec.EIPs { |
| 58 | + lbEipMap[*lbEipID] = true |
| 59 | + } |
| 60 | + } |
| 61 | + |
| 62 | + // eip/internal --> eip; |
| 63 | + if config.EipIDs != nil { |
| 64 | + // config eip |
| 65 | + configEipMap := make(map[string]bool) |
| 66 | + for _, configEipID := range config.EipIDs { |
| 67 | + configEipMap[*configEipID] = true |
| 68 | + if !lbEipMap[*configEipID] { |
| 69 | + eipsToAdd = append(eipsToAdd, configEipID) |
| 70 | + } |
| 71 | + } |
| 72 | + |
| 73 | + for lbEipID := range lbEipMap { |
| 74 | + if !configEipMap[lbEipID] { |
| 75 | + eipsToDel = append(eipsToDel, &lbEipID) |
| 76 | + } |
| 77 | + } |
| 78 | + } else if config.EipSource != nil { |
| 79 | + switch *config.EipSource { |
| 80 | + case AllocateOnly, UseAvailableOnly, UseAvailableOrAllocateOne: |
| 81 | + if len(lb.Spec.EIPs) > 0 { |
| 82 | + // lb already has eip, do nothing |
| 83 | + klog.Infof("lb %s already has eip %s, do nothing", *lb.Status.LoadBalancerID, spew.Sdump(lb.Spec.EIPs)) |
| 84 | + } else { |
| 85 | + // get or create an available eip from qingcloud and associate this eip to lb |
| 86 | + eip, err := qc.prepareEip(config.EipSource) |
| 87 | + if err != nil { |
| 88 | + return nil, nil, fmt.Errorf("prepare eip for lb %s error: %v", *lb.Status.LoadBalancerID, err) |
| 89 | + } |
| 90 | + eipsToAdd = append(eipsToAdd, eip.Status.EIPID) |
| 91 | + } |
| 92 | + default: // annotation value not correct, do nothing |
| 93 | + return nil, nil, fmt.Errorf("the value of annotation '%s' is mistake", ServiceAnnotationLoadBalancerEipSource) |
| 94 | + } |
| 95 | + } else if config.NetworkType == NetworkModeInternal { // eip/internal --> intertal |
| 96 | + // delete all eip from this lb |
| 97 | + if lb.Spec.EIPs != nil { |
| 98 | + eipsToDel = append(eipsToDel, lb.Spec.EIPs...) |
| 99 | + } |
| 100 | + } |
| 101 | + return |
| 102 | +} |
| 103 | + |
| 104 | +func (qc *QingCloud) updateLBEip(config *LoadBalancerConfig, lb *apis.LoadBalancer) (err error) { |
| 105 | + var updated bool |
| 106 | + var eipsToAdd, eipsToDel []*string |
| 107 | + // if reuse lb, do nothing |
| 108 | + if config.ReuseLBID != "" { |
| 109 | + return nil |
| 110 | + } |
| 111 | + |
| 112 | + eipsToAdd, eipsToDel, err = qc.diffLBEip(config, lb) |
| 113 | + if err != nil { |
| 114 | + return err |
| 115 | + } |
| 116 | + |
| 117 | + // update lb eip |
| 118 | + if len(eipsToAdd) > 0 { |
| 119 | + klog.Infof("associating eips %s to lb %s", spew.Sdump(eipsToAdd), *lb.Status.LoadBalancerID) |
| 120 | + err = qc.Client.AssociateEIPsToLB(lb.Status.LoadBalancerID, eipsToAdd) |
| 121 | + if err != nil { |
| 122 | + return err |
| 123 | + } |
| 124 | + updated = true |
| 125 | + } |
| 126 | + if len(eipsToDel) > 0 { |
| 127 | + klog.Infof("dissociating eips %s from lb %s", spew.Sdump(eipsToDel), *lb.Status.LoadBalancerID) |
| 128 | + err = qc.Client.DissociateEIPsFromLB(lb.Status.LoadBalancerID, eipsToDel) |
| 129 | + if err != nil { |
| 130 | + return err |
| 131 | + } |
| 132 | + updated = true |
| 133 | + } |
| 134 | + |
| 135 | + // update lb status |
| 136 | + if updated { |
| 137 | + lbNew, err := qc.Client.GetLoadBalancerByName(config.LoadBalancerName) |
| 138 | + if err != nil { |
| 139 | + return fmt.Errorf("get loadbalancer by name error: %v", err) |
| 140 | + } |
| 141 | + lb.Status = lbNew.Status |
| 142 | + } |
| 143 | + |
| 144 | + return nil |
| 145 | +} |
0 commit comments