github.com/caos/orbos@v1.5.14-0.20221103111702-e6cd0cea7ad4/internal/operator/orbiter/kinds/providers/static/computesservice.go (about) 1 package static 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "path/filepath" 8 "strings" 9 10 "github.com/caos/orbos/internal/helpers" 11 12 secret2 "github.com/caos/orbos/pkg/secret" 13 14 "github.com/caos/orbos/internal/operator/orbiter/kinds/clusters/core/infra" 15 "github.com/caos/orbos/internal/operator/orbiter/kinds/providers/core" 16 "github.com/caos/orbos/mntr" 17 ) 18 19 var _ core.MachinesService = (*machinesService)(nil) 20 21 type machinesService struct { 22 monitor mntr.Monitor 23 desired *DesiredV0 24 statusFile string 25 onCreate func(machine infra.Machine, pool string) error 26 cache map[string]cachedMachines 27 } 28 29 func NewMachinesService( 30 monitor mntr.Monitor, 31 desired *DesiredV0, 32 id string) *machinesService { 33 return &machinesService{ 34 monitor, 35 desired, 36 filepath.Join("/var/orbiter", id), 37 nil, 38 nil, 39 } 40 } 41 42 func (c *machinesService) updateKeys() error { 43 44 pools, err := c.ListPools() 45 if err != nil { 46 panic(err) 47 } 48 49 keys := privateKeys(c.desired.Spec) 50 51 for _, pool := range pools { 52 machines, err := c.cachedPool(pool) 53 if err != nil { 54 return err 55 } 56 for _, machine := range machines { 57 if err := machine.UseKey(keys...); err != nil { 58 return err 59 } 60 } 61 } 62 return nil 63 } 64 65 func (c *machinesService) ListPools() ([]string, error) { 66 67 pools := make([]string, 0) 68 69 for key := range c.desired.Spec.Pools { 70 pools = append(pools, key) 71 } 72 73 return pools, nil 74 } 75 76 func (c *machinesService) List(poolName string) (infra.Machines, error) { 77 pool, err := c.cachedPool(poolName) 78 if err != nil { 79 return nil, err 80 } 81 82 return pool.Machines(), nil 83 } 84 85 func (c *machinesService) DesiredMachines(poolName string, instances int) int { 86 _, err := c.cachedPool(poolName) 87 if err != nil { 88 return 0 89 } 90 91 return instances 92 } 93 94 func (c *machinesService) Create(poolName string, _ int) (infra.Machines, error) { 95 pool, err := c.cachedPool(poolName) 96 if err != nil { 97 return nil, err 98 } 99 100 for _, machine := range pool { 101 if !machine.X_active { 102 machine.X_active = true 103 if err := machine.WriteFile(fmt.Sprintf("/home/orbiter/.ssh/authorized_keys"), bytes.NewReader([]byte(c.desired.Spec.Keys.MaintenanceKeyPublic.Value)), 600); err != nil { 104 return nil, err 105 } 106 107 if err := machine.WriteFile(c.statusFile, strings.NewReader("active"), 600); err != nil { 108 return nil, err 109 } 110 111 if err := c.onCreate(machine, poolName); err != nil { 112 return nil, err 113 } 114 115 return []infra.Machine{machine}, nil 116 } 117 } 118 119 return nil, mntr.ToUserError(errors.New("no machines left")) 120 } 121 122 func (c *machinesService) cachedPool(poolName string) (cachedMachines, error) { 123 124 specifiedMachines, ok := c.desired.Spec.Pools[poolName] 125 if !ok { 126 return nil, fmt.Errorf("pool %s does not exist", poolName) 127 } 128 129 cache, ok := c.cache[poolName] 130 if ok { 131 return cache, nil 132 } 133 134 keys := privateKeys(c.desired.Spec) 135 136 newCache := make([]*machine, 0) 137 138 initializeMachineFunc := func(spec *Machine) func() error { 139 return func() error { 140 newM := newMachine(c.monitor, c.statusFile, "orbiter", &spec.ID, string(spec.IP), 141 spec.RebootRequired, 142 func() { 143 spec.RebootRequired = true 144 }, func() { 145 spec.RebootRequired = false 146 }, 147 spec.ReplacementRequired, 148 func() { 149 spec.ReplacementRequired = true 150 }, func() { 151 spec.ReplacementRequired = false 152 }) 153 154 if err := newM.UseKey(keys...); err != nil { 155 return err 156 } 157 158 buf := new(bytes.Buffer) 159 defer buf.Reset() 160 if err := newM.ReadFile(c.statusFile, buf); err != nil { 161 // if error, treat as active 162 } 163 newM.X_active = strings.Contains(buf.String(), "active") 164 newCache = append(newCache, newM) 165 return nil 166 } 167 } 168 169 var fanout []func() error 170 for _, spec := range specifiedMachines { 171 fanout = append(fanout, initializeMachineFunc(spec)) 172 } 173 174 if err := helpers.Fanout(fanout)(); err != nil { 175 return nil, err 176 } 177 178 if c.cache == nil { 179 c.cache = make(map[string]cachedMachines) 180 } else if ok { // TODO: Never true 181 c.cache[poolName] = nil 182 delete(c.cache, poolName) 183 } 184 c.cache[poolName] = newCache 185 return newCache, nil 186 } 187 188 type cachedMachines []*machine 189 190 func (c cachedMachines) Machines() infra.Machines { 191 machines := make([]infra.Machine, 0) 192 for _, machine := range c { 193 if machine.X_active { 194 machines = append(machines, machine) 195 } 196 } 197 return machines 198 } 199 200 func privateKeys(spec Spec) [][]byte { 201 var privateKeys [][]byte 202 toBytes := func(key *secret2.Secret) { 203 if key != nil { 204 privateKeys = append(privateKeys, []byte(key.Value)) 205 } 206 } 207 toBytes(spec.Keys.BootstrapKeyPrivate) 208 toBytes(spec.Keys.MaintenanceKeyPrivate) 209 return privateKeys 210 }