-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
init.go
172 lines (150 loc) · 4.98 KB
/
init.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
package init
import (
"context"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/feature/ec2/imds"
"github.com/aws/aws-sdk-go-v2/service/ec2"
"github.com/integrii/flaggy"
"go.uber.org/zap"
"k8s.io/utils/strings/slices"
"github.com/awslabs/amazon-eks-ami/nodeadm/internal/api"
"github.com/awslabs/amazon-eks-ami/nodeadm/internal/aws/ecr"
"github.com/awslabs/amazon-eks-ami/nodeadm/internal/cli"
"github.com/awslabs/amazon-eks-ami/nodeadm/internal/configprovider"
"github.com/awslabs/amazon-eks-ami/nodeadm/internal/containerd"
"github.com/awslabs/amazon-eks-ami/nodeadm/internal/daemon"
"github.com/awslabs/amazon-eks-ami/nodeadm/internal/kubelet"
"github.com/awslabs/amazon-eks-ami/nodeadm/internal/system"
)
const (
configPhase = "config"
runPhase = "run"
)
func NewInitCommand() cli.Command {
init := initCmd{}
init.cmd = flaggy.NewSubcommand("init")
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 you want to skip")
init.cmd.Description = "Initialize this instance as a node in an EKS cluster"
return &init
}
type initCmd struct {
cmd *flaggy.Subcommand
skipPhases []string
daemons []string
}
func (c *initCmd) Flaggy() *flaggy.Subcommand {
return c.cmd
}
func (c *initCmd) Run(log *zap.Logger, opts *cli.GlobalOptions) error {
log.Info("Checking user is root..")
root, err := cli.IsRunningAsRoot()
if err != nil {
return err
} else if !root {
return cli.ErrMustRunAsRoot
}
log.Info("Loading configuration..", zap.String("configSource", opts.ConfigSource))
provider, err := configprovider.BuildConfigProvider(opts.ConfigSource)
if err != nil {
return err
}
nodeConfig, err := provider.Provide()
if err != nil {
return err
}
log.Info("Loaded configuration", zap.Reflect("config", nodeConfig))
log.Info("Enriching configuration..")
if err := enrichConfig(log, nodeConfig); err != nil {
return err
}
zap.L().Info("Validating configuration..")
if err := api.ValidateNodeConfig(nodeConfig); err != nil {
return err
}
log.Info("Creating daemon manager..")
daemonManager, err := daemon.NewDaemonManager()
if err != nil {
return err
}
defer daemonManager.Close()
aspects := []system.SystemAspect{
system.NewLocalDiskAspect(),
system.NewNetworkingAspect(),
}
daemons := []daemon.Daemon{
containerd.NewContainerdDaemon(daemonManager),
kubelet.NewKubeletDaemon(daemonManager),
}
if !slices.Contains(c.skipPhases, configPhase) {
log.Info("Configuring daemons...")
for _, daemon := range daemons {
if len(c.daemons) > 0 && !slices.Contains(c.daemons, daemon.Name()) {
continue
}
nameField := zap.String("name", daemon.Name())
log.Info("Configuring daemon...", nameField)
if err := daemon.Configure(nodeConfig); err != nil {
return err
}
log.Info("Configured daemon", nameField)
}
}
if !slices.Contains(c.skipPhases, runPhase) {
log.Info("Setting up system aspects...")
for _, aspect := range aspects {
nameField := zap.String("name", aspect.Name())
log.Info("Setting up system aspect..", nameField)
if err := aspect.Setup(nodeConfig); err != nil {
return err
}
log.Info("Set up system aspect", nameField)
}
for _, daemon := range daemons {
if len(c.daemons) > 0 && !slices.Contains(c.daemons, daemon.Name()) {
continue
}
nameField := zap.String("name", daemon.Name())
log.Info("Ensuring daemon is running..", nameField)
if err := daemon.EnsureRunning(); err != nil {
return err
}
log.Info("Daemon is running", nameField)
log.Info("Running post-launch tasks..", nameField)
if err := daemon.PostLaunch(nodeConfig); err != nil {
return err
}
log.Info("Finished post-launch tasks", nameField)
}
}
return nil
}
// Various initializations and verifications of the NodeConfig and
// perform in-place updates when allowed by the user
func enrichConfig(log *zap.Logger, cfg *api.NodeConfig) error {
log.Info("Fetching instance details..")
imdsClient := imds.New(imds.Options{})
awsConfig, err := config.LoadDefaultConfig(context.TODO(), config.WithClientLogMode(aws.LogRetries), config.WithEC2IMDSRegion(func(o *config.UseEC2IMDSRegion) {
o.Client = imdsClient
}))
if err != nil {
return err
}
instanceDetails, err := api.GetInstanceDetails(context.TODO(), cfg.Spec.FeatureGates, imdsClient, ec2.NewFromConfig(awsConfig))
if err != nil {
return err
}
cfg.Status.Instance = *instanceDetails
log.Info("Instance details populated", zap.Reflect("details", instanceDetails))
log.Info("Fetching default options...")
eksRegistry, err := ecr.GetEKSRegistry(instanceDetails.Region)
if err != nil {
return err
}
cfg.Status.Defaults = api.DefaultOptions{
SandboxImage: eksRegistry.GetSandboxImage(),
}
log.Info("Default options populated", zap.Reflect("defaults", cfg.Status.Defaults))
return nil
}