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  }