Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: check node state before udating #6

Merged
merged 3 commits into from
Sep 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
*.swp
.idea

.vscode
dist/
15 changes: 7 additions & 8 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,27 +28,27 @@ archives:
{{- if .Arm }}v{{ .Arm }}{{ end }}
# use zip for windows archives
format_overrides:
- goos: windows
format: zip
- goos: windows
format: zip
checksum:
name_template: 'checksums.txt'
name_template: "checksums.txt"
snapshot:
name_template: "{{ incpatch .Version }}-next"
changelog:
sort: asc
filters:
exclude:
- '^docs:'
- '^test:'
- "^docs:"
- "^test:"
dockers:
## standard AMIs e.g. eks m5.2xlarae types
## standard AMIs e.g. eks m5.2xlarae types
- image_templates:
- "ghcr.io/armory-io/eks-auto-updater:{{ .Version }}-linux-amd64"
use: buildx
goos: linux
build_flag_templates:
- "--platform=linux/amd64"
## This is graviton2 in AWS like mg5g.2xlarge types
## This is graviton2 in AWS like mg5g.2xlarge types
- image_templates:
- "ghcr.io/armory-io/eks-auto-updater:{{ .Version }}-linux-arm64v8"
use: buildx
Expand All @@ -62,7 +62,6 @@ docker_manifests:
image_templates:
- "ghcr.io/armory-io/eks-auto-updater:{{ .Version }}-linux-amd64"
- "ghcr.io/armory-io/eks-auto-updater:{{ .Version }}-linux-arm64v8"

# The lines beneath this are called `modelines`. See `:help modeline`
# Feel free to remove those if you don't want/use them.
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
Expand Down
43 changes: 35 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,41 @@
# eks-auto-updater

Auto updater docker image designed to take a target cluster and update both managed node pools and addon versions to latest releases

# What?
## What?

Currently EKS updates are... painful. This is a tool to auto update a given clusters dependencies like:
* Addons - find the current default version for a set of addons and update the addon version
* Managed node AMI - TF doesn't see version changes. This triggers an update of managed node pool
* CAUTION: IF YOU DO NOT have pod disruption budgets or other protections in place, this WILL cause downtime on services.

- Addons - find the current default version for a set of addons and update the addon version.
- Managed node AMI - TF doesn't see version changes. This triggers an update of managed node pool
- CAUTION: IF YOU DO NOT have pod disruption budgets or other protections in place, this WILL cause downtime on services.

## How?

To update your nodegroups, run the following command:

```bash
eks-auto-updater nodegroups \
--cluster-name <cluster-name> \
--region <region> \
--role-arn <role-arn> \
--nodegroup-wait-time <nodegroup-wait-time> \
--nodegroup-name <nodegroup-name>
```

To update your addons, run the following command:

```bash
eks-auto-updater addons \
--cluster-name <cluster-name> \
--region <region> \
--role-arn <role-arn> \
--addons <comma-separated-list-of-addons>
```

## Long term goals
* Possibly update the EKS cluster version?
* Auto update multiple node pools vs. a single one and set of addons
* Lookup addons vs. requiring to be passed
* Lookup addon configuration/identifiy differences vs. just overwriting

- Possibly update the EKS cluster version?
- Auto update multiple node pools vs. a single one and set of addons
- Lookup addons vs. requiring to be passed
- Lookup addon configuration/identifiy differences vs. just overwriting
73 changes: 73 additions & 0 deletions cmd/addons.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package cmd

import (
"errors"
"strings"
"sync"

"github.com/armory-io/eks-auto-updater/internal/updater"
"github.com/armory-io/eks-auto-updater/pkg/aws"
"github.com/armory-io/eks-auto-updater/pkg/aws/options"

"github.com/spf13/cobra"
)

// addonsCmd represents the addons command
var addonsCmd = &cobra.Command{
Use: "addons",
Short: "Upgrades EKS addons to the latest version",
Long: "",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
region := cmd.Flag("region").Value.String()
roleArn := cmd.Flag("role-arn").Value.String()
clusterName := cmd.Flag("cluster-name").Value.String()
addons := cmd.Flag("addons").Value.String()
addonsList := strings.Split(addons, ",")

awsClient, err := aws.NewClient(ctx,
options.WithRegion(region),
options.WithRoleArn(roleArn),
)
if err != nil {
return err
}

var wg sync.WaitGroup
errChan := make(chan error)
defer close(errChan)

updater := updater.NewEKSUpdater(awsClient.EKS())
for _, addon := range addonsList {
wg.Add(1)

go func(addon string) {
errChan <- updater.UpdateAddon(ctx, &clusterName, &addon, &wg)
}(addon)
}

var errResult error
go func() {
for err := range errChan {
if err != nil {
errResult = errors.Join(errResult, err)
}
}
}()

wg.Wait()

// Return all of the errors that were sent to the errChan channel
if errResult != nil {
return errResult
}

return nil
},
}

func init() {
rootCmd.AddCommand(addonsCmd)

addonsCmd.Flags().StringP("addons", "a", "kube-proxy,vpc-cni,coredns,aws-ebs-csi-driver", "Comma separated list of addons to update. For example: kube-proxy,vpc-cni,coredns,aws-ebs-csi-driver. Defaults to all addons")
}
51 changes: 51 additions & 0 deletions cmd/nodegroups.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package cmd

import (
"github.com/armory-io/eks-auto-updater/internal/updater"
"github.com/armory-io/eks-auto-updater/pkg/aws"
"github.com/armory-io/eks-auto-updater/pkg/aws/options"

"github.com/spf13/cobra"
)

// nodegroupCmd represents the nodegroup command
var nodegroupsCmd = &cobra.Command{
Use: "nodegroups",
Short: "Upgrades EKS nodegroups to the latest version",
Long: "",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
region := cmd.Flag("region").Value.String()
roleArn := cmd.Flag("role-arn").Value.String()
clusterName := cmd.Flag("cluster-name").Value.String()
nodegroupName := cmd.Flag("nodegroup-name").Value.String()
waitForNodeUpdates, _ := cmd.Flags().GetInt("nodegroup-wait-time")

awsClient, err := aws.NewClient(ctx,
options.WithRegion(region),
options.WithRoleArn(roleArn),
)
if err != nil {
return err
}

updater := updater.NewEKSUpdater(awsClient.EKS())
err = updater.UpdateClusterNodeGroup(ctx, &clusterName, &nodegroupName, waitForNodeUpdates)
if err != nil {
return err
}

return nil
},
}

func init() {
rootCmd.AddCommand(nodegroupsCmd)

// Nodegroup Name
nodegroupsCmd.Flags().String("nodegroup-name", "", "Name of the EKS nodegroup to update")
nodegroupsCmd.MarkFlagRequired("nodegroup-name")

// Nodegroup Wait Time
nodegroupsCmd.Flags().Int("nodegroup-wait-time", 120, "Time in minutes to wait for node group update to complete. Defaults to 120 minutes")
}
42 changes: 42 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package cmd

import (
"os"

"github.com/spf13/cobra"
)

// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "eks-auto-updater",
Short: "Updates EKS cluster components to the latest version",
Long: `eks-auto-updater is a CLI tool that updates following components of an EKS cluster to the latest version:
- Nodegroups
- Addons
`,
// Run: func(cmd *cobra.Command, args []string) { },
}

// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
err := rootCmd.Execute()
if err != nil {
os.Exit(1)
}
}

func init() {
rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")

// region
rootCmd.PersistentFlags().String("region", "us-west-2", "AWS Region to use")
rootCmd.MarkPersistentFlagRequired("region")

// cluster name
rootCmd.PersistentFlags().String("cluster-name", "", "Name of the EKS cluster to update")
rootCmd.MarkPersistentFlagRequired("cluster-name")

// role arn
rootCmd.PersistentFlags().String("role-arn", "", "ARN of the role to assume")
}
Loading