Skip to content

Commit 3d41b41

Browse files
committed
Add support of Boskos for AWS
wrote with the assistance of Gemini 2.5 Signed-off-by: Arnaud Meukam <[email protected]>
1 parent e0629cc commit 3d41b41

File tree

4 files changed

+138
-36
lines changed

4 files changed

+138
-36
lines changed
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
/*
2+
Copyright 2025 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package deployer
18+
19+
import (
20+
"encoding/json"
21+
"fmt"
22+
"os"
23+
24+
"k8s.io/klog/v2"
25+
"sigs.k8s.io/kubetest2/pkg/boskos"
26+
)
27+
28+
func (d *deployer) acquireBoskosAWSAccount() error {
29+
klog.V(1).Info("Acquiring AWS account from Boskos")
30+
31+
boskosClient, err := boskos.NewClient(d.BoskosLocation)
32+
if err != nil {
33+
return fmt.Errorf("failed to make boskos client: %s", err)
34+
}
35+
d.boskos = boskosClient
36+
37+
resource, err := boskos.Acquire(
38+
d.boskos,
39+
d.BoskosAWSResourceType,
40+
d.BoskosAcquireTimeout,
41+
d.BoskosHeartbeatInterval,
42+
d.boskosHeartbeatClose,
43+
)
44+
if err != nil {
45+
return fmt.Errorf("init failed to get aws account from boskos: %s", err)
46+
}
47+
d.boskosAWSAccount = resource.Name
48+
klog.V(1).Infof("Got aws account %s from boskos", d.boskosAWSAccount)
49+
50+
if resource.UserData == nil {
51+
return fmt.Errorf("boskos resource %s has nil UserData", resource.Name)
52+
}
53+
54+
jsonBytes, err := json.Marshal(resource.UserData)
55+
if err != nil {
56+
// Use %w to wrap the error for better debugging
57+
return fmt.Errorf("failed to marshal boskos user data: %w", err)
58+
}
59+
60+
var data struct {
61+
AccessKeyID string `json:"access_key_id"`
62+
SecretAccessKey string `json:"secret_access_key"`
63+
SessionToken string `json:"session_token"`
64+
}
65+
66+
// 2. Unmarshal the JSON bytes (from the map) into the 'data' struct
67+
if err := json.Unmarshal(jsonBytes, &data); err != nil {
68+
return fmt.Errorf("failed to unmarshal boskos user data: %w", err)
69+
}
70+
71+
os.Setenv("AWS_ACCESS_KEY_ID", data.AccessKeyID)
72+
os.Setenv("AWS_SECRET_ACCESS_KEY", data.SecretAccessKey)
73+
os.Setenv("AWS_SESSION_TOKEN", data.SessionToken)
74+
75+
return nil
76+
}
77+
78+
func (d *deployer) acquireBoskosGCPProject() error {
79+
klog.V(1).Info("No GCP project provided, acquiring from Boskos")
80+
81+
boskosClient, err := boskos.NewClient(d.BoskosLocation)
82+
if err != nil {
83+
return fmt.Errorf("failed to make boskos client: %s", err)
84+
}
85+
d.boskos = boskosClient
86+
87+
resource, err := boskos.Acquire(
88+
d.boskos,
89+
d.BoskosGCPResourceType,
90+
d.BoskosAcquireTimeout,
91+
d.BoskosHeartbeatInterval,
92+
d.boskosHeartbeatClose,
93+
)
94+
if err != nil {
95+
return fmt.Errorf("init failed to get project from boskos: %s", err)
96+
}
97+
d.GCPProject = resource.Name
98+
klog.V(1).Infof("Got project %s from boskos", d.GCPProject)
99+
return nil
100+
}
101+
102+
func (d *deployer) releaseBoskosResources() error {
103+
if d.boskos == nil {
104+
return nil
105+
}
106+
klog.V(2).Info("releasing boskos project")
107+
resources := []string{}
108+
if d.GCPProject != "" {
109+
resources = append(resources, d.GCPProject)
110+
}
111+
if d.boskosAWSAccount != "" {
112+
resources = append(resources, d.boskosAWSAccount)
113+
}
114+
err := boskos.Release(
115+
d.boskos,
116+
resources,
117+
d.boskosHeartbeatClose,
118+
)
119+
if err != nil {
120+
return fmt.Errorf("down failed to release boskos project: %s", err)
121+
}
122+
return nil
123+
}

tests/e2e/kubetest2-kops/deployer/common.go

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ import (
2929
"k8s.io/kops/tests/e2e/kubetest2-kops/gce"
3030
"k8s.io/kops/tests/e2e/pkg/target"
3131
"k8s.io/kops/tests/e2e/pkg/util"
32-
"sigs.k8s.io/kubetest2/pkg/boskos"
3332
)
3433

3534
func (d *deployer) init() error {
@@ -53,6 +52,11 @@ func (d *deployer) initialize() error {
5352

5453
switch d.CloudProvider {
5554
case "aws":
55+
if d.UseBoskosAWS {
56+
if err := d.acquireBoskosAWSAccount(); err != nil {
57+
return err
58+
}
59+
}
5660
client, err := aws.NewClient(context.Background())
5761
if err != nil {
5862
return fmt.Errorf("init failed to build AWS client: %w", err)
@@ -91,26 +95,9 @@ func (d *deployer) initialize() error {
9195
d.SSHUser = "root"
9296
case "gce":
9397
if d.GCPProject == "" {
94-
klog.V(1).Info("No GCP project provided, acquiring from Boskos")
95-
96-
boskosClient, err := boskos.NewClient(d.BoskosLocation)
97-
if err != nil {
98-
return fmt.Errorf("failed to make boskos client: %s", err)
99-
}
100-
d.boskos = boskosClient
101-
102-
resource, err := boskos.Acquire(
103-
d.boskos,
104-
d.BoskosResourceType,
105-
d.BoskosAcquireTimeout,
106-
d.BoskosHeartbeatInterval,
107-
d.boskosHeartbeatClose,
108-
)
109-
if err != nil {
110-
return fmt.Errorf("init failed to get project from boskos: %s", err)
98+
if err := d.acquireBoskosGCPProject(); err != nil {
99+
return err
111100
}
112-
d.GCPProject = resource.Name
113-
klog.V(1).Infof("Got project %s from boskos", d.GCPProject)
114101

115102
if d.SSHPrivateKeyPath == "" {
116103
d.SSHPrivateKeyPath = os.Getenv("GCE_SSH_PRIVATE_KEY_FILE")

tests/e2e/kubetest2-kops/deployer/deployer.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,14 @@ type deployer struct {
105105
// boskos struct field will be non-nil when the deployer is
106106
// using boskos to acquire a GCP project
107107
boskos *client.Client
108+
boskosAWSAccount string
108109
BoskosLocation string `flag:"boskos-location" desc:"If set, manually specifies the location of the Boskos server."`
109110
BoskosAcquireTimeout time.Duration `flag:"boskos-acquire-timeout" desc:"How long should boskos wait to acquire a resource before timing out"`
110111
BoskosHeartbeatInterval time.Duration `flag:"boskos-heartbeat-interval" desc:"How often should boskos send a heartbeat to Boskos to hold the acquired resource. 0 means no heartbeat."`
111-
BoskosResourceType string `flag:"boskos-resource-type" desc:"If set, manually specifies the resource type of GCP projects to acquire from Boskos."`
112+
BoskosGCPResourceType string `flag:"boskos-gcp-resource-type" desc:"If set, manually specifies the resource type of GCP projects to acquire from Boskos."`
113+
BoskosAWSResourceType string `flag:"boskos-aws-resource-type" desc:"If set, manually specifies the resource type of AWS accounts to acquire from Boskos."`
114+
UseBoskosAWS bool `flag:"use-boskos-aws" desc:"If set, use boskos to acquire AWS accounts."`
115+
112116
// this channel serves as a signal channel for the hearbeat goroutine
113117
// so that it can be explicitly closed
114118
boskosHeartbeatClose chan struct{}
@@ -139,7 +143,8 @@ func New(opts types.Options) (types.Deployer, *pflag.FlagSet) {
139143
ValidationCount: 10,
140144
ValidationInterval: 10 * time.Second,
141145
BoskosLocation: "http://boskos.test-pods.svc.cluster.local.",
142-
BoskosResourceType: "gce-project",
146+
BoskosGCPResourceType: "gce-project",
147+
BoskosAWSResourceType: "aws-account",
143148
BoskosAcquireTimeout: 5 * time.Minute,
144149
BoskosHeartbeatInterval: 5 * time.Minute,
145150
Tags: []string{

tests/e2e/kubetest2-kops/deployer/down.go

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,11 @@ package deployer
1818

1919
import (
2020
"context"
21-
"fmt"
2221
"strings"
2322

2423
"k8s.io/klog/v2"
2524
"k8s.io/kops/tests/e2e/kubetest2-kops/gce"
2625
"k8s.io/kops/tests/e2e/pkg/kops"
27-
"sigs.k8s.io/kubetest2/pkg/boskos"
2826
"sigs.k8s.io/kubetest2/pkg/exec"
2927
)
3028

@@ -86,16 +84,5 @@ func (d *deployer) Down() error {
8684
}
8785
}
8886

89-
if d.boskos != nil {
90-
klog.V(2).Info("releasing boskos project")
91-
err := boskos.Release(
92-
d.boskos,
93-
[]string{d.GCPProject},
94-
d.boskosHeartbeatClose,
95-
)
96-
if err != nil {
97-
return fmt.Errorf("down failed to release boskos project: %s", err)
98-
}
99-
}
100-
return nil
87+
return d.releaseBoskosResources()
10188
}

0 commit comments

Comments
 (0)