github.com/caos/orbos@v1.5.14-0.20221103111702-e6cd0cea7ad4/internal/operator/orbiter/kinds/providers/gce/ensure.go (about) 1 package gce 2 3 import ( 4 "fmt" 5 "strconv" 6 "strings" 7 8 "github.com/caos/orbos/mntr" 9 10 "github.com/caos/orbos/internal/operator/orbiter/kinds/providers/core" 11 12 "github.com/caos/orbos/internal/helpers" 13 14 "github.com/caos/orbos/internal/operator/orbiter/kinds/loadbalancers/dynamic" 15 "github.com/caos/orbos/internal/operator/orbiter/kinds/loadbalancers/dynamic/wrap" 16 17 "github.com/caos/orbos/internal/operator/common" 18 "github.com/caos/orbos/internal/operator/orbiter/kinds/clusters/core/infra" 19 dynamiclbmodel "github.com/caos/orbos/internal/operator/orbiter/kinds/loadbalancers/dynamic" 20 21 "github.com/caos/orbos/internal/operator/orbiter" 22 // externallbmodel "github.com/caos/orbos/internal/operator/orbiter/kinds/loadbalancers/external" 23 ) 24 25 func query( 26 desired *Spec, 27 current *Current, 28 lb interface{}, 29 svc *machinesService, 30 nodeAgentsCurrent *common.CurrentNodeAgents, 31 nodeAgentsDesired *common.DesiredNodeAgents, 32 naFuncs core.IterateNodeAgentFuncs, 33 orbiterCommit string, 34 ) (ensureFunc orbiter.EnsureFunc, err error) { 35 36 lbCurrent, ok := lb.(*dynamiclbmodel.Current) 37 if !ok { 38 panic(fmt.Errorf("unknown or unsupported load balancing of type %T", lb)) 39 } 40 vips, _, err := lbCurrent.Current.Spec(svc) 41 if err != nil { 42 return nil, err 43 } 44 normalized, firewalls := normalize(svc.context, vips) 45 46 var ( 47 ensureLB func() error 48 createFWs, deleteFWs []func() error 49 ) 50 if err := helpers.Fanout([]func() error{ 51 func() error { 52 var err error 53 ensureLB, err = queryLB(svc.context, normalized) 54 return err 55 }, 56 func() error { 57 var err error 58 createFWs, deleteFWs, err = queryFirewall(svc.context, firewalls) 59 return err 60 }, 61 })(); err != nil { 62 return nil, err 63 } 64 65 current.Current.Ingresses = make(map[string]*infra.Address) 66 for _, lb := range normalized { 67 current.Current.Ingresses[lb.transport] = &infra.Address{ 68 Location: lb.address.gce.Address, 69 BackendPort: internalPort(lb), 70 FrontendPort: externalPort(lb), 71 } 72 } 73 74 queryNA, installNA := naFuncs(nodeAgentsCurrent) 75 76 desireNodeAgent := func(pool string, machine infra.Machine) error { 77 78 machineID := machine.ID() 79 machineMonitor := svc.context.monitor.WithField("machine", machineID) 80 na, _ := nodeAgentsDesired.Get(machineID) 81 if na.Software.Health.Config == nil { 82 na.Software.Health.Config = make(map[string]string) 83 } 84 85 for _, lb := range normalized { 86 for _, destPool := range lb.targetPool.destPools { 87 if pool == destPool { 88 key := fmt.Sprintf( 89 "%s:%d%s", 90 "0.0.0.0", 91 lb.healthcheck.gce.Port, 92 lb.healthcheck.gce.RequestPath) 93 94 value := fmt.Sprintf( 95 "--protocol %s --ip %s --port %d --path %s --status %d --proxy=%t", 96 lb.healthcheck.desired.Protocol, 97 machine.IP(), 98 internalPort(lb), 99 lb.healthcheck.desired.Path, 100 lb.healthcheck.desired.Code, 101 lb.healthcheck.proxyProtocol, 102 ) 103 104 if v := na.Software.Health.Config[key]; v != value { 105 na.Software.Health.Config[key] = value 106 machineMonitor.WithFields(map[string]interface{}{ 107 "listen": key, 108 "checks": value, 109 }).Debug("Healthcheck desired") 110 } 111 fw := common.ToFirewall("external", map[string]*common.Allowed{ 112 lb.healthcheck.gce.Description: { 113 Port: fmt.Sprintf("%d", lb.healthcheck.gce.Port), 114 Protocol: "tcp", 115 }, 116 }) 117 if !na.Firewall.Contains(fw) { 118 machineMonitor.WithField("ports", fw.ToCurrent()).Debug("Firewall desired") 119 } 120 na.Firewall.Merge(fw) 121 } 122 } 123 } 124 running, err := queryNA(machine, orbiterCommit) 125 if err != nil { 126 return err 127 } 128 if !running { 129 return installNA(machine) 130 } 131 132 return nil 133 } 134 135 svc.onCreate = desireNodeAgent 136 wrappedMachines := wrap.MachinesService(svc, *lbCurrent, nil, func(vip *dynamic.VIP) string { 137 for _, transport := range vip.Transport { 138 address, ok := current.Current.Ingresses[transport.Name] 139 if ok { 140 return address.Location 141 } 142 } 143 panic(fmt.Errorf("external address for %v is not ensured", vip)) 144 }) 145 return func(pdf func(mntr.Monitor) error) *orbiter.EnsureResult { 146 147 var done bool 148 return orbiter.ToEnsureResult(done, helpers.Fanout([]func() error{ 149 func() error { return ensureIdentityAwareProxyAPIEnabled(svc.context) }, 150 func() error { return ensureNetwork(svc.context, createFWs, deleteFWs) }, 151 svc.restartPreemptibleMachines, 152 ensureLB, 153 func() error { 154 pools, err := svc.ListPools() 155 if err != nil { 156 return err 157 } 158 159 var desireNodeAgents []func() error 160 for _, pool := range pools { 161 machines, listErr := svc.List(pool) 162 if listErr != nil { 163 err = helpers.Concat(err, listErr) 164 } 165 for _, machine := range machines { 166 desireNodeAgents = append(desireNodeAgents, func(p string, m infra.Machine) func() error { 167 return func() error { 168 return desireNodeAgent(p, m) 169 } 170 }(pool, machine)) 171 } 172 } 173 return helpers.Fanout(desireNodeAgents)() 174 }, 175 func() error { 176 var err error 177 lbDone, err := wrappedMachines.InitializeDesiredNodeAgents() 178 if err != nil { 179 return err 180 } 181 182 fwDone, err := core.DesireInternalOSFirewall(svc.context.monitor, nodeAgentsDesired, nodeAgentsCurrent, svc, false, []string{"eth0"}) 183 if err != nil { 184 return err 185 } 186 done = lbDone && fwDone 187 188 return err 189 }, 190 })()) 191 }, initPools(current, desired, svc, normalized, wrappedMachines) 192 } 193 194 func internalPort(lb *normalizedLoadbalancer) uint16 { 195 return lb.backendPort 196 } 197 198 func externalPort(lb *normalizedLoadbalancer) uint16 { 199 port, err := strconv.ParseInt(strings.Split(lb.forwardingRule.gce.PortRange, "-")[0], 10, 16) 200 if err != nil { 201 panic(err) 202 } 203 return uint16(port) 204 }