cmd/nodeadm/init/init.go (117 lines of code) (raw):
package init
import (
"context"
"fmt"
"os"
"github.com/integrii/flaggy"
"go.uber.org/zap"
"k8s.io/utils/strings/slices"
"github.com/aws/eks-hybrid/internal/cli"
"github.com/aws/eks-hybrid/internal/containerd"
"github.com/aws/eks-hybrid/internal/flows"
"github.com/aws/eks-hybrid/internal/logger"
"github.com/aws/eks-hybrid/internal/node"
"github.com/aws/eks-hybrid/internal/system"
"github.com/aws/eks-hybrid/internal/tracker"
)
const (
installValidation = "install-validation"
cniPortCheckValidation = "cni-validation"
calicoVxLanPort = "4789"
ciliumVxLanPort = "8472"
vxLanProtocol = "udp"
)
const initHelpText = `Examples:
# Initialize using configuration file
nodeadm init --config-source file://nodeConfig.yaml
Documentation:
https://docs.aws.amazon.com/eks/latest/userguide/hybrid-nodes-nodeadm.html#_init`
func NewInitCommand() cli.Command {
init := initCmd{}
init.cmd = flaggy.NewSubcommand("init")
init.cmd.String(&init.configSource, "c", "config-source", "Source of node configuration. The format is a URI with supported schemes: [file, imds].")
init.cmd.StringSlice(&init.daemons, "d", "daemon", "Specify one or more of `containerd` and `kubelet`. This is intended for testing and should not be used in a production environment.")
init.cmd.StringSlice(&init.skipPhases, "s", "skip", "Phases of the bootstrap to skip. Allowed values: [install-validation, cni-validation, node-ip-validation, kubelet-cert-validation, preprocess, config, run].")
init.cmd.Description = "Initialize this instance as a node in an EKS cluster"
init.cmd.AdditionalHelpAppend = initHelpText
return &init
}
type initCmd struct {
cmd *flaggy.Subcommand
configSource string
skipPhases []string
daemons []string
}
func (c *initCmd) Flaggy() *flaggy.Subcommand {
return c.cmd
}
func (c *initCmd) Run(log *zap.Logger, opts *cli.GlobalOptions) error {
ctx := context.Background()
ctx = logger.NewContext(ctx, log)
log.Info("Checking user is root..")
root, err := cli.IsRunningAsRoot()
if err != nil {
return err
} else if !root {
return cli.ErrMustRunAsRoot
}
if c.configSource == "" {
flaggy.ShowHelpAndExit("--config-source is a required flag. The format is a URI with supported schemes: [file, imds]." +
" For example on hybrid nodes --config-source file://nodeConfig.yaml")
}
if !slices.Contains(c.skipPhases, installValidation) {
log.Info("Loading installed components")
_, err = tracker.GetInstalledArtifacts()
if err != nil && os.IsNotExist(err) {
log.Info("Nodeadm components are not installed. Please run `nodeadm install` before running init")
return nil
} else if err != nil {
return err
}
if err := containerd.ValidateSystemdUnitFile(); err != nil {
return fmt.Errorf("a systemd unit file for containerd is required to init the node: %w", err)
}
}
// Check if either of cilium or calico vxlan port are open
if !slices.Contains(c.skipPhases, cniPortCheckValidation) {
log.Info("Validating firewall ports for cilium and calico")
if err := validateFirewallOpenPorts(); err != nil {
return fmt.Errorf("Cilium (%s/%s) or Calico (%s/%s) VxLan ports are not open on the host. If you are not using VxLan, this validation can by bypassed with --skip %s",
ciliumVxLanPort, vxLanProtocol, calicoVxLanPort, vxLanProtocol, cniPortCheckValidation)
}
}
nodeProvider, err := node.NewNodeProvider(c.configSource, c.skipPhases, log)
if err != nil {
return err
}
initer := &flows.Initer{
NodeProvider: nodeProvider,
SkipPhases: c.skipPhases,
Logger: log,
}
return initer.Run(ctx)
}
func validateFirewallOpenPorts() error {
firewallManager := system.NewFirewallManager()
enabled, err := firewallManager.IsEnabled()
if err != nil {
return err
}
if !enabled {
return nil
}
if err := firewallManager.FlushRules(); err != nil {
return err
}
ciliumVxlanPortOpen, err := firewallManager.IsPortOpen(ciliumVxLanPort, vxLanProtocol)
if err != nil {
return err
}
calicoVxlanPortOpen, err := firewallManager.IsPortOpen(calicoVxLanPort, vxLanProtocol)
if err != nil {
return err
}
if !ciliumVxlanPortOpen && !calicoVxlanPortOpen {
return fmt.Errorf("both cilium and calico vxlan ports are closed")
}
return nil
}