github.com/caos/orbos@v1.5.14-0.20221103111702-e6cd0cea7ad4/internal/operator/orbiter/kinds/providers/static/desired.go (about) 1 package static 2 3 import ( 4 "errors" 5 "fmt" 6 "net" 7 "regexp" 8 9 "github.com/caos/orbos/mntr" 10 "github.com/caos/orbos/pkg/secret" 11 "github.com/caos/orbos/pkg/tree" 12 ) 13 14 type DesiredV0 struct { 15 Common *tree.Common `yaml:",inline"` 16 Spec Spec 17 Loadbalancing *tree.Tree 18 } 19 20 type Spec struct { 21 Verbose bool 22 Pools map[string][]*Machine 23 Keys *Keys 24 ExternalInterfaces []string 25 PrivateInterface string 26 LeaveOSRepositories bool 27 } 28 29 type Keys struct { 30 BootstrapKeyPrivate *secret.Secret `yaml:",omitempty"` 31 BootstrapKeyPublic *secret.Secret `yaml:",omitempty"` 32 MaintenanceKeyPrivate *secret.Secret `yaml:",omitempty"` 33 MaintenanceKeyPublic *secret.Secret `yaml:",omitempty"` 34 } 35 36 func (d DesiredV0) validateAdapt() (err error) { 37 defer func() { 38 err = mntr.ToUserError(err) 39 }() 40 41 for pool, machines := range d.Spec.Pools { 42 for _, machine := range machines { 43 if err := machine.validate(); err != nil { 44 return fmt.Errorf("validating machine %s in pool %s failed: %w", machine.ID, pool, err) 45 } 46 } 47 } 48 return nil 49 } 50 51 func (d DesiredV0) validateQuery() (err error) { 52 defer func() { 53 err = mntr.ToUserError(err) 54 }() 55 56 if d.Spec.Keys == nil || 57 d.Spec.Keys.BootstrapKeyPrivate == nil || 58 d.Spec.Keys.BootstrapKeyPrivate.Value == "" { 59 return errors.New("bootstrap private ssh key missing... please provide a private ssh bootstrap key using orbctl writesecret command") 60 } 61 62 if d.Spec.Keys.MaintenanceKeyPrivate == nil || 63 d.Spec.Keys.MaintenanceKeyPrivate.Value == "" || 64 d.Spec.Keys.MaintenanceKeyPublic == nil || 65 d.Spec.Keys.MaintenanceKeyPublic.Value == "" { 66 return errors.New("maintenance ssh key missing... please initialize your orb using orbctl configure command") 67 } 68 69 return nil 70 } 71 72 func parseDesiredV0(desiredTree *tree.Tree) (desiredKind *DesiredV0, err error) { 73 defer func() { 74 err = mntr.ToUserError(err) 75 }() 76 77 desiredKind = &DesiredV0{ 78 Common: desiredTree.Common, 79 Spec: Spec{}, 80 } 81 82 if err := desiredTree.Original.Decode(desiredKind); err != nil { 83 return nil, fmt.Errorf("parsing desired state failed: %w", err) 84 } 85 86 return desiredKind, nil 87 } 88 89 type Machine struct { 90 ID string 91 Hostname string 92 IP string 93 RebootRequired bool 94 ReplacementRequired bool 95 } 96 97 var internetHosts = regexp.MustCompile("^[a-z0-9]([-a-z0-9]*[a-z0-9])?$") 98 99 func validateName(name string) (err error) { 100 defer func() { 101 err = mntr.ToUserError(err) 102 }() 103 104 if len(name) > 63 || !internetHosts.MatchString(name) { 105 return fmt.Errorf("name must be compatible with https://tools.ietf.org/html/rfc1123#section-2, but %s is not", name) 106 } 107 return nil 108 } 109 110 func (c *Machine) validate() error { 111 112 if err := validateName(c.ID); err != nil { 113 return fmt.Errorf("validating id failed: %w", err) 114 } 115 116 if err := validateName(c.Hostname); err != nil { 117 return fmt.Errorf("validating hostname failed: %w", err) 118 } 119 120 if net.ParseIP(c.IP) == nil { 121 return fmt.Errorf("%s is not a valid ip address", c.IP) 122 } 123 return nil 124 }