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

Smart availability zones #556

Merged
merged 14 commits into from
Mar 26, 2024
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
92 changes: 92 additions & 0 deletions .github/workflows/aws_azs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
name: Update helm/cluster-aws/files/azs-in-region.yaml with new availability zones
on:
#schedule:
# - cron: '0 0 * * *'
push:
branches:
- smart-availability-zones

jobs:
import_new_regions_and_zones:
runs-on: ubuntu-22.04
container: quay.io/giantswarm/golang:1.22.1
steps:
- name: Check out the code
uses: actions/checkout@v4
with:
clean: false
- name: Calculate md5sum of azs-in-region.yaml before the script runs
run: |
md5sum helm/cluster-aws/files/azs-in-region.yaml > /tmp/before
- name: Build azs-getter
run: |
cd azs-getter
go get
go build -o ../azs-getter-bin main.go
- name: Run azs-getter to update azs-in-region.yaml
env:
AWS_ACCESS_KEY_ID_CHINA: "${{ secrets.AWS_ACCESS_KEY_ID_CHINA }}"
AWS_SECRET_ACCESS_KEY_CHINA: "${{ secrets.AWS_SECRET_ACCESS_KEY_CHINA }}"
AWS_ACCESS_KEY_ID_EUROPE: "${{ secrets.AWS_ACCESS_KEY_ID_EUROPE }}"
AWS_SECRET_ACCESS_KEY_EUROPE: "${{ secrets.AWS_SECRET_ACCESS_KEY_EUROPE }}"
run: |
./azs-getter-bin --dest-file=./helm/cluster-aws/files/azs-in-region.yaml
rm ./azs-getter-bin
- name: Check for changes
id: check_changes
run: |
md5sum helm/cluster-aws/files/azs-in-region.yaml > /tmp/after

diff /tmp/before /tmp/after || echo ::set-output name=needs_pr::true
- name: Add Changelog entry
env:
msg: "Update Availability Zones in helm/cluster-aws/files/azs-in-region.yaml"
if: steps.check_changes.outputs.needs_pr == 'true'
run: |
# Line number containing unreleased tag
unreleased="$(grep -En '^## \[Unreleased\]' CHANGELOG.md | cut -f1 -d:)"

# Line number containing latest release
latest="$(grep -En '^## \[[0-9]+' CHANGELOG.md | head -n 1|cut -f1 -d:)"

# Current changes
current="$(cat CHANGELOG.md | head -n $(($latest - 1))|tail -n $(($latest - $unreleased - 1)))"

# look for "Changed" section
changed="$(echo "$current" | grep -En '^### Changed'|cut -f1 -d:)"

if [ "$changed" == "" ]
then
changed=2
awk "NR==$(($unreleased + 1)){print \"\n## Changed\n\"}7" CHANGELOG.md >changelog.tmp
mv changelog.tmp CHANGELOG.md
fi

# Add new changelog entry
awk "NR==$(($unreleased + $changed + 2)){print \"- ${msg}\n\"}7" CHANGELOG.md >changelog.tmp
mv changelog.tmp CHANGELOG.md

- name: Prepare branch for PR
env:
remote_repo: "https://${{ github.actor }}:${{ secrets.TAYLORBOT_GITHUB_ACTION }}@github.com/${{ github.repository }}.git"
destination_branch_name: "automated-azs"
GITHUB_TOKEN: "${{ secrets.TAYLORBOT_GITHUB_ACTION }}"
base: "${{ github.ref }}"
if: steps.check_changes.outputs.needs_pr == 'true'
run: |
git config --global --add safe.directory "`pwd`"
git config --local user.email "[email protected]"
git config --local user.name "taylorbot"
git add -A
git commit -m "Update Availability Zones in helm/cluster-aws/files/azs-in-region.yaml"
git push "${remote_repo}" HEAD:${destination_branch_name} --force

- name: Create PR
uses: thomaseizinger/[email protected]
if: steps.check_changes.outputs.needs_pr == 'true'
with:
GITHUB_TOKEN: ${{ secrets.TAYLORBOT_GITHUB_ACTION }}
head: "automated-azs"
base: ${{ github.ref }}
title: "Update Availability Zones in helm/cluster-aws/files/azs-in-region.yaml"

4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Update Chart.lock with current version of dependencies.

### Added

- Smart defaulting for AWS availability zones using actual AZs in the region of choice rather than hardcoded values.

## [0.66.0] - 2024-03-21

### Added
Expand Down
25 changes: 25 additions & 0 deletions azs-getter/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
module github.com/giantswarm/azs-getter

go 1.22.1

require (
github.com/aws/aws-sdk-go-v2 v1.26.0
github.com/aws/aws-sdk-go-v2/config v1.27.8
github.com/aws/aws-sdk-go-v2/credentials v1.17.8
github.com/aws/aws-sdk-go-v2/service/ec2 v1.152.0
gopkg.in/yaml.v3 v3.0.1
)

require (
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.4 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.4 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.4 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.6 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.20.3 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.3 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.28.5 // indirect
github.com/aws/smithy-go v1.20.1 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
)
43 changes: 43 additions & 0 deletions azs-getter/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
github.com/aws/aws-sdk-go-v2 v1.26.0 h1:/Ce4OCiM3EkpW7Y+xUnfAFpchU78K7/Ug01sZni9PgA=
github.com/aws/aws-sdk-go-v2 v1.26.0/go.mod h1:35hUlJVYd+M++iLI3ALmVwMOyRYMmRqUXpTtRGW+K9I=
github.com/aws/aws-sdk-go-v2/config v1.27.8 h1:0r8epOsiJ7YJz65MGcb8i91ehFp4kvvFe2qkq5oYeRI=
github.com/aws/aws-sdk-go-v2/config v1.27.8/go.mod h1:XsmYKxYNuIhLsFddpNds+j9H5XKzjWDdg/SZngiwFio=
github.com/aws/aws-sdk-go-v2/credentials v1.17.8 h1:WUdNLXbyNbU07V/WFrSOBXqZTDgmmMNMgUFzpYOKJhw=
github.com/aws/aws-sdk-go-v2/credentials v1.17.8/go.mod h1:iPZzLpaBIfhyvVS/XGD3JvR1GP3YdHTqpySKDlqkfs8=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.4 h1:S+L2QSKhUuShih3aq9P/mkzDBiOO5tTyVg+vXREfsfg=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.4/go.mod h1:nQ3how7DMnFMWiU1SpECohgC82fpn4cKZ875NDMmwtA=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.4 h1:0ScVK/4qZ8CIW0k8jOeFVsyS/sAiXpYxRBLolMkuLQM=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.4/go.mod h1:84KyjNZdHC6QZW08nfHI6yZgPd+qRgaWcYsyLUo3QY8=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.4 h1:sHmMWWX5E7guWEFQ9SVo6A3S4xpPrWnd77a6y4WM6PU=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.4/go.mod h1:WjpDrhWisWOIoS9n3nk67A3Ll1vfULJ9Kq6h29HTD48=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY=
github.com/aws/aws-sdk-go-v2/service/ec2 v1.152.0 h1:ltCQObuImVYmIrMX65ikB9W83MEun3Ry2Sk11ecZ8Xw=
github.com/aws/aws-sdk-go-v2/service/ec2 v1.152.0/go.mod h1:TeZ9dVQzGaLG+SBIgdLIDbJ6WmfFvksLeG3EHGnNfZM=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1 h1:EyBZibRTVAs6ECHZOw5/wlylS9OcTzwyjeQMudmREjE=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1/go.mod h1:JKpmtYhhPs7D97NL/ltqz7yCkERFW5dOlHyVl66ZYF8=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.6 h1:b+E7zIUHMmcB4Dckjpkapoy47W6C9QBv/zoUP+Hn8Kc=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.6/go.mod h1:S2fNV0rxrP78NhPbCZeQgY8H9jdDMeGtwcfZIRxzBqU=
github.com/aws/aws-sdk-go-v2/service/sso v1.20.3 h1:mnbuWHOcM70/OFUlZZ5rcdfA8PflGXXiefU/O+1S3+8=
github.com/aws/aws-sdk-go-v2/service/sso v1.20.3/go.mod h1:5HFu51Elk+4oRBZVxmHrSds5jFXmFj8C3w7DVF2gnrs=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.3 h1:uLq0BKatTmDzWa/Nu4WO0M1AaQDaPpwTKAeByEc6WFM=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.3/go.mod h1:b+qdhjnxj8GSR6t5YfphOffeoQSQ1KmpoVVuBn+PWxs=
github.com/aws/aws-sdk-go-v2/service/sts v1.28.5 h1:J/PpTf/hllOjx8Xu9DMflff3FajfLxqM5+tepvVXmxg=
github.com/aws/aws-sdk-go-v2/service/sts v1.28.5/go.mod h1:0ih0Z83YDH/QeQ6Ori2yGE2XvWYv/Xm+cZc01LC6oK0=
github.com/aws/smithy-go v1.20.1 h1:4SZlSlMr36UEqC7XOyRVb27XMeZubNcBNN+9IgEPIQw=
github.com/aws/smithy-go v1.20.1/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
64 changes: 64 additions & 0 deletions azs-getter/internal/awshelper/awshelper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package awshelper

import (
"context"
"fmt"
"strings"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/ec2"
"github.com/aws/aws-sdk-go-v2/service/ec2/types"
)

type AwsHelper struct {
sdkConfig aws.Config
}

func New(awsConfig aws.Config) (*AwsHelper, error) {
return &AwsHelper{
sdkConfig: awsConfig,
}, nil
}

func (a *AwsHelper) ListRegions(ctx context.Context) ([]string, error) {
ec2Client := ec2.NewFromConfig(a.sdkConfig)
regionsOutput, err := ec2Client.DescribeRegions(ctx, &ec2.DescribeRegionsInput{
AllRegions: aws.Bool(false),
})

if err != nil {
fmt.Println("Couldn't get regions")
return nil, err
}

ret := make([]string, 0)
for _, region := range regionsOutput.Regions {
ret = append(ret, *region.RegionName)
}

return ret, nil
}

func (a *AwsHelper) GetAzsForRegion(ctx context.Context, region string) ([]string, error) {
config := a.sdkConfig
config.Region = region
ec2Client := ec2.NewFromConfig(config)

azsOutput, err := ec2Client.DescribeAvailabilityZones(ctx, &ec2.DescribeAvailabilityZonesInput{
AllAvailabilityZones: aws.Bool(true),
Filters: []types.Filter{{Name: aws.String("zone-type"), Values: []string{"availability-zone"}}},
})

if err != nil {
return nil, err
}

// We just want the zone letter (such as "a") rather than the full zone name (such as "us-west-2a")
zoneNames := make([]string, 0)
for _, az := range azsOutput.AvailabilityZones {
clean, _ := strings.CutPrefix(*az.ZoneName, region)
zoneNames = append(zoneNames, clean)
}

return zoneNames, nil
}
114 changes: 114 additions & 0 deletions azs-getter/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package main

import (
"context"
"flag"
"fmt"
"os"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
awscreds "github.com/aws/aws-sdk-go-v2/credentials"
"gopkg.in/yaml.v3"

"github.com/giantswarm/azs-getter/internal/awshelper"
)

type credentials struct {
accessKeyId string
secretAccessKey string
region string
}

func main() {
ctx := context.TODO()

var dest string

flag.StringVar(&dest, "dest-file", "./helm/cluster-aws/files/azs-in-region.yaml", "Path of the yaml file where to write the new AZs")
flag.Parse()

if dest == "" {
fmt.Println("No destination file provided, defaulting to stdout")
dest = "/dev/stdout"
}

creds := []credentials{
{
// EUROPE
accessKeyId: os.Getenv("AWS_ACCESS_KEY_ID_EUROPE"),
secretAccessKey: os.Getenv("AWS_SECRET_ACCESS_KEY_EUROPE"),
region: "eu-west-1",
},
{
// CHINA
accessKeyId: os.Getenv("AWS_ACCESS_KEY_ID_CHINA"),
secretAccessKey: os.Getenv("AWS_SECRET_ACCESS_KEY_CHINA"),
region: "cn-north-1",
},
}

data := map[string][]string{}

for _, c := range creds {
sdkConfig, err := config.LoadDefaultConfig(ctx, config.WithCredentialsProvider(awscreds.NewStaticCredentialsProvider(c.accessKeyId, c.secretAccessKey, "")), config.WithRegion(c.region))
if err != nil {
fmt.Println("Couldn't load default configuration. Have you set up your AWS account?")
fmt.Println(err)
os.Exit(1)
}

azsPerRegion, err := getAzsFromCredentials(ctx, sdkConfig)
if err != nil {
fmt.Println("Error getting azs")
fmt.Println(err)
os.Exit(2)
}

for r, azs := range azsPerRegion {
data[r] = azs
}
}

b, err := yaml.Marshal(data)
if err != nil {
fmt.Println("error marshaling azs to yaml")
fmt.Println(err)
os.Exit(3)
}

err = os.WriteFile(dest, b, 0644)
if err != nil {
fmt.Println("error writing azs to file")
fmt.Println(err)
os.Exit(4)
}
}

func getAzsFromCredentials(ctx context.Context, sdkConfig aws.Config) (map[string][]string, error) {
helper, err := awshelper.New(sdkConfig)
if err != nil {
fmt.Println("Error initializing aws helper")
return nil, err
}

regions, err := helper.ListRegions(ctx)
if err != nil {
fmt.Println("Error listing regions")
return nil, err
}

ret := make(map[string][]string)

for _, region := range regions {
azs, err := helper.GetAzsForRegion(ctx, region)
if err != nil {
fmt.Printf("Couldn't get azs for region %s", region)
return nil, err
}

ret[region] = azs
}

return ret, nil
}
2 changes: 1 addition & 1 deletion helm/cluster-aws/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ Properties within the `.global.connectivity` object
| `global.connectivity.proxy.httpProxy` | **HTTP proxy** - To be passed to the HTTP_PROXY environment variable in all hosts.|**Type:** `string`<br/>|
| `global.connectivity.proxy.httpsProxy` | **HTTPS proxy** - To be passed to the HTTPS_PROXY environment variable in all hosts.|**Type:** `string`<br/>|
| `global.connectivity.proxy.noProxy` | **No proxy** - To be passed to the NO_PROXY environment variable in all hosts.|**Type:** `string`<br/>|
| `global.connectivity.subnets` | **Subnets** - Subnets are created and tagged based on this definition.|**Type:** `array`<br/>**Default:** `[{"cidrBlocks":[{"availabilityZone":"a","cidr":"10.0.0.0/20"},{"availabilityZone":"b","cidr":"10.0.16.0/20"},{"availabilityZone":"c","cidr":"10.0.32.0/20"}],"isPublic":true},{"cidrBlocks":[{"availabilityZone":"a","cidr":"10.0.64.0/18"},{"availabilityZone":"b","cidr":"10.0.128.0/18"},{"availabilityZone":"c","cidr":"10.0.192.0/18"}],"isPublic":false}]`|
| `global.connectivity.subnets` | **Subnets** - Subnets are created and tagged based on this definition.|**Type:** `array`<br/>**Default:** `[{"cidrBlocks":[{"cidr":"10.0.0.0/20"},{"cidr":"10.0.16.0/20"},{"cidr":"10.0.32.0/20"}],"isPublic":true},{"cidrBlocks":[{"cidr":"10.0.64.0/18"},{"cidr":"10.0.128.0/18"},{"cidr":"10.0.192.0/18"}],"isPublic":false}]`|
| `global.connectivity.subnets[*]` | **Subnet**|**Type:** `object`<br/>|
| `global.connectivity.subnets[*].cidrBlocks` | **Network**|**Type:** `array`<br/>|
| `global.connectivity.subnets[*].cidrBlocks[*]` |**None**|**Type:** `object`<br/>|
Expand Down
1 change: 1 addition & 0 deletions helm/cluster-aws/ci/ci-values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ global:
- r6i.xlarge
- m5.xlarge
providerSpecific:
region: "eu-west-1"
awsAccountId: "1234567890"
components:
containerd:
Expand Down
2 changes: 2 additions & 0 deletions helm/cluster-aws/ci/test-mc-proxy-values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ global:
enabled: true
httpProxy: http://proxy.mcproxy.example.com:4000
httpsProxy: http://proxy.mcproxy.example.com:4000
providerSpecific:
region: "eu-west-1"
2 changes: 2 additions & 0 deletions helm/cluster-aws/ci/test-network-topology-values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ global:
vpcMode: private
controlPlane:
apiMode: private
providerSpecific:
region: "eu-west-1"
2 changes: 2 additions & 0 deletions helm/cluster-aws/ci/test-spot-instances.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ global:
spotInstances:
enabled: true
maxPrice: 1.2
providerSpecific:
region: "eu-west-1"
2 changes: 2 additions & 0 deletions helm/cluster-aws/ci/test-wc-minimal-values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ global:
servicePriority: lowest
connectivity:
baseDomain: example.com
providerSpecific:
region: "eu-west-1"
Loading
Loading