-
Notifications
You must be signed in to change notification settings - Fork 66
/
aws.go
157 lines (140 loc) · 5.37 KB
/
aws.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
package aws
import (
"context"
"encoding/json"
"fmt"
"os"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ec2"
config "github.com/openshift/api/config/v1"
mapi "github.com/openshift/api/machine/v1beta1"
core "k8s.io/api/core/v1"
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
client "k8s.io/client-go/kubernetes"
"github.com/openshift/windows-machine-config-operator/test/e2e/clusterinfo"
"github.com/openshift/windows-machine-config-operator/test/e2e/providers/machineset"
"github.com/openshift/windows-machine-config-operator/test/e2e/windows"
)
type Provider struct {
oc *clusterinfo.OpenShift
*config.InfrastructureStatus
}
// New returns a new Provider
func New(oc *clusterinfo.OpenShift, infraStatus *config.InfrastructureStatus) (*Provider, error) {
return &Provider{
oc: oc,
InfrastructureStatus: infraStatus,
}, nil
}
// newEC2Client returns an EC2 client for the given region
func newEC2Client(region string) (*ec2.EC2, error) {
credentialPath := os.Getenv("AWS_SHARED_CREDENTIALS_FILE")
if len(credentialPath) == 0 {
return nil, fmt.Errorf("AWS_SHARED_CREDENTIALS_FILE env var is empty")
}
if _, err := os.Stat(credentialPath); os.IsNotExist(err) {
return nil, fmt.Errorf("failed to find AWS credentials from path '%v'", credentialPath)
}
awsSession, err := session.NewSession(&aws.Config{
Credentials: credentials.NewSharedCredentials(credentialPath, "default"),
Region: aws.String(region),
})
if err != nil {
return nil, fmt.Errorf("error initializing aws session: %w", err)
}
return ec2.New(awsSession, aws.NewConfig()), nil
}
// getWindowsAMIFilter returns an EC2 AMI filter for the Windows Server version. The Windows Server AMIs typically have
// pattern Windows_Server-$version-variant-YYYY.MM.DD and the filter will grab all AMIs that match the filter.
func getWindowsAMIFilter(windowsServerVersion windows.ServerVersion) string {
switch windowsServerVersion {
case windows.Server2019:
return "Windows_Server-2019-English-Core-Base-????.??.??"
case windows.Server2022:
default:
}
return "Windows_Server-2022-English-Core-Base-????.??.??"
}
// getLatestWindowsAMI returns the ID of the latest released "Windows Server with Containers" AMI
func getLatestWindowsAMI(region string, windowsServerVersion windows.ServerVersion) (string, error) {
ec2Client, err := newEC2Client(region)
if err != nil {
return "", err
}
windowsAMIFilterValue := getWindowsAMIFilter(windowsServerVersion)
searchFilter := ec2.Filter{Name: aws.String("name"), Values: []*string{&windowsAMIFilterValue}}
describedImages, err := ec2Client.DescribeImages(&ec2.DescribeImagesInput{
Filters: []*ec2.Filter{&searchFilter},
Owners: []*string{aws.String("amazon")},
})
if err != nil {
return "", err
}
if len(describedImages.Images) < 1 {
return "", fmt.Errorf("found zero images matching given filter: %v", searchFilter)
}
// Find the last created image
latestImage := describedImages.Images[0]
latestTime, err := time.Parse(time.RFC3339, *latestImage.CreationDate)
if err != nil {
return "", err
}
for _, image := range describedImages.Images[1:] {
newTime, err := time.Parse(time.RFC3339, *image.CreationDate)
if err != nil {
return "", err
}
if newTime.After(latestTime) {
latestImage = image
latestTime = newTime
}
}
return *latestImage.ImageId, nil
}
// GenerateMachineSet generates a Windows MachineSet which is AWS provider specific
func (a *Provider) GenerateMachineSet(withIgnoreLabel bool, replicas int32, windowsServerVersion windows.ServerVersion) (*mapi.MachineSet, error) {
listOptions := meta.ListOptions{LabelSelector: "machine.openshift.io/cluster-api-machine-role=worker"}
machines, err := a.oc.Machine.Machines(clusterinfo.MachineAPINamespace).List(context.TODO(), listOptions)
if err != nil {
return nil, err
}
if len(machines.Items) == 0 {
return nil, fmt.Errorf("found 0 worker role machines")
}
linuxWorkerSpec := &mapi.AWSMachineProviderConfig{}
err = json.Unmarshal(machines.Items[0].Spec.ProviderSpec.Value.Raw, linuxWorkerSpec)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal raw machine provider spec: %v", err)
}
ami, err := getLatestWindowsAMI(a.PlatformStatus.AWS.Region, windowsServerVersion)
if err != nil {
return nil, fmt.Errorf("error choosing AMI: %w", err)
}
providerSpec := &mapi.AWSMachineProviderConfig{
AMI: mapi.AWSResourceReference{ID: &ami},
InstanceType: linuxWorkerSpec.InstanceType,
IAMInstanceProfile: linuxWorkerSpec.IAMInstanceProfile,
CredentialsSecret: linuxWorkerSpec.CredentialsSecret,
SecurityGroups: linuxWorkerSpec.SecurityGroups,
Subnet: linuxWorkerSpec.Subnet,
Placement: linuxWorkerSpec.Placement,
UserDataSecret: &core.LocalObjectReference{Name: clusterinfo.UserDataSecretName},
}
rawBytes, err := json.Marshal(providerSpec)
if err != nil {
return nil, err
}
return machineset.New(rawBytes, a.InfrastructureName, replicas, withIgnoreLabel, a.InfrastructureName+"-"), nil
}
func (a *Provider) GetType() config.PlatformType {
return config.AWSPlatformType
}
func (a *Provider) StorageSupport() bool {
return false
}
func (a *Provider) CreatePVC(_ client.Interface, _ string, _ *core.PersistentVolume) (*core.PersistentVolumeClaim, error) {
return nil, fmt.Errorf("storage not supported on AWS")
}