Skip to content

Commit c8aa9b3

Browse files
committed
Re-implement the setup-envtest functionality in a package
There are two main points of re-implementing vs just moving the code: 1. Error handling in the old code base was based on panicking and recovering, where the recover basically just read out a field from the panic value and determined the correct exit code. In a package, we want more nuanced error handling, especially in order to allow test suites to catch the errors and surface them through their own reporting mechanisms. 2. There was a lot of global state in the old code base, "hidden" in the env.Env type that was used as a receiver for all the methods. This re-implementation tries to make the state more explicit, keeping only dependencies (like the remote client and local store) in the environment, while retaining the same behavior as the previous implementation. Tests have been ported over to their respective workflow sub-packages, and a few new ones have been added to cover cases the old test suite for one reason or another did not. Thus, we can be fairly confident that the new implementation does not break old functionality, even if it is a significant rewrite.
1 parent 1f5b39f commit c8aa9b3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+2389
-1985
lines changed

examples/scratch-env/go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ require (
2626
github.com/google/gnostic-models v0.6.8 // indirect
2727
github.com/google/go-cmp v0.6.0 // indirect
2828
github.com/google/gofuzz v1.2.0 // indirect
29-
github.com/google/uuid v1.3.1 // indirect
29+
github.com/google/uuid v1.3.0 // indirect
3030
github.com/imdario/mergo v0.3.6 // indirect
3131
github.com/josharian/intern v1.0.0 // indirect
3232
github.com/json-iterator/go v1.1.12 // indirect
@@ -46,7 +46,7 @@ require (
4646
golang.org/x/sys v0.19.0 // indirect
4747
golang.org/x/term v0.18.0 // indirect
4848
golang.org/x/text v0.14.0 // indirect
49-
golang.org/x/time v0.3.0 // indirect
49+
golang.org/x/time v0.5.0 // indirect
5050
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
5151
google.golang.org/appengine v1.6.7 // indirect
5252
google.golang.org/protobuf v1.33.0 // indirect

examples/scratch-env/go.sum

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
4343
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
4444
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec=
4545
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
46-
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
47-
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
46+
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
47+
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
4848
github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28=
4949
github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
5050
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
@@ -137,8 +137,8 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
137137
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
138138
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
139139
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
140-
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
141-
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
140+
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
141+
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
142142
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
143143
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
144144
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=

go.mod

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ require (
3030
sigs.k8s.io/yaml v1.3.0
3131
)
3232

33-
require golang.org/x/mod v0.15.0
33+
require (
34+
github.com/spf13/afero v1.11.0
35+
golang.org/x/mod v0.15.0
36+
)
3437

3538
require (
3639
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
@@ -53,7 +56,7 @@ require (
5356
github.com/google/cel-go v0.20.1 // indirect
5457
github.com/google/gnostic-models v0.6.8 // indirect
5558
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect
56-
github.com/google/uuid v1.3.1 // indirect
59+
github.com/google/uuid v1.4.0 // indirect
5760
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect
5861
github.com/imdario/mergo v0.3.6 // indirect
5962
github.com/josharian/intern v1.0.0 // indirect
@@ -81,11 +84,11 @@ require (
8184
golang.org/x/sync v0.6.0 // indirect
8285
golang.org/x/term v0.18.0 // indirect
8386
golang.org/x/text v0.14.0 // indirect
84-
golang.org/x/time v0.3.0 // indirect
87+
golang.org/x/time v0.5.0 // indirect
8588
golang.org/x/tools v0.18.0 // indirect
8689
google.golang.org/appengine v1.6.7 // indirect
87-
google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d // indirect
88-
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect
90+
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 // indirect
91+
google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f // indirect
8992
google.golang.org/grpc v1.59.0 // indirect
9093
google.golang.org/protobuf v1.33.0 // indirect
9194
gopkg.in/inf.v0 v0.9.1 // indirect

go.sum

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
6363
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
6464
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec=
6565
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
66-
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
67-
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
66+
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
67+
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
6868
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms=
6969
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg=
7070
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
@@ -110,6 +110,8 @@ github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k
110110
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
111111
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
112112
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
113+
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
114+
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
113115
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
114116
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
115117
github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU=
@@ -185,8 +187,8 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
185187
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
186188
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
187189
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
188-
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
189-
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
190+
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
191+
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
190192
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
191193
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
192194
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
@@ -201,12 +203,12 @@ gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw
201203
gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
202204
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
203205
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
204-
google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d h1:VBu5YqKPv6XiJ199exd8Br+Aetz+o08F+PLMnwJQHAY=
205-
google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4=
206-
google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d h1:DoPTO70H+bcDXcd39vOqb2viZxgqeBeSGtZ55yZU4/Q=
207-
google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk=
208-
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4=
209-
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M=
206+
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 h1:wpZ8pe2x1Q3f2KyT5f8oP/fa9rHAKgFPr/HZdNuS+PQ=
207+
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:J7XzRzVy1+IPwWHZUzoD0IccYZIrXILAQpc+Qy9CMhY=
208+
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 h1:JpwMPBpFN3uKhdaekDpiNlImDdkUAyiJ6ez/uxGaUSo=
209+
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4=
210+
google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f h1:ultW7fxlIvee4HYrtnaRPon9HpEgFk5zYpmfMgtKB5I=
211+
google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f/go.mod h1:L9KNLi232K1/xB6f7AlSX692koaRnKaWSR0stBki0Yc=
210212
google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk=
211213
google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
212214
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=

pkg/envtest/setup/cleanup/cleanup.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package cleanup
2+
3+
import (
4+
"context"
5+
"errors"
6+
7+
"sigs.k8s.io/controller-runtime/pkg/envtest/setup/env"
8+
"sigs.k8s.io/controller-runtime/pkg/envtest/setup/store"
9+
"sigs.k8s.io/controller-runtime/pkg/envtest/setup/versions"
10+
)
11+
12+
// Result is a list of version-platform pairs that were removed from the store.
13+
type Result []store.Item
14+
15+
// Cleanup removes binary packages from disk for all version-platform pairs that match the parameters
16+
//
17+
// Note that both the item collection and the error might be non-nil, if some packages were successfully
18+
// removed (they will be listed in the first return value) and some failed (the errors will be collected
19+
// in the second).
20+
func Cleanup(ctx context.Context, spec versions.Spec, options ...Option) (Result, error) {
21+
cfg := configure(options...)
22+
23+
env, err := env.New(cfg.envOpts...)
24+
if err != nil {
25+
return nil, err
26+
}
27+
28+
if err := env.Store.Initialize(ctx); err != nil {
29+
return nil, err
30+
}
31+
32+
items, err := env.Store.Remove(ctx, store.Filter{Version: spec, Platform: cfg.platform})
33+
if errors.Is(err, store.ErrUnableToList) {
34+
return nil, err
35+
}
36+
37+
// store.Remove returns an error if _any_ item failed to be removed,
38+
// but it also reports any items that were removed without errors.
39+
// Therefore, both items and err might be non-nil at the same time.
40+
return items, err
41+
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
package cleanup_test
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
. "github.com/onsi/ginkgo/v2"
8+
. "github.com/onsi/gomega"
9+
"github.com/spf13/afero"
10+
11+
"github.com/go-logr/logr"
12+
"sigs.k8s.io/controller-runtime/pkg/envtest/setup/cleanup"
13+
"sigs.k8s.io/controller-runtime/pkg/envtest/setup/env"
14+
"sigs.k8s.io/controller-runtime/pkg/envtest/setup/store"
15+
"sigs.k8s.io/controller-runtime/pkg/envtest/setup/testhelpers"
16+
"sigs.k8s.io/controller-runtime/pkg/envtest/setup/versions"
17+
)
18+
19+
var (
20+
testLog logr.Logger
21+
ctx context.Context
22+
)
23+
24+
func TestCleanup(t *testing.T) {
25+
testLog = testhelpers.GetLogger()
26+
ctx = logr.NewContext(context.Background(), testLog)
27+
28+
RegisterFailHandler(Fail)
29+
RunSpecs(t, "Cleanup Suite")
30+
}
31+
32+
var _ = Describe("Cleanup", func() {
33+
var (
34+
defaultEnvOpts []env.Option
35+
s *store.Store
36+
)
37+
38+
BeforeEach(func() {
39+
s = testhelpers.NewMockStore()
40+
})
41+
42+
JustBeforeEach(func() {
43+
defaultEnvOpts = []env.Option{
44+
env.WithClient(nil), // ensures we fail if we try to connect
45+
env.WithStore(s),
46+
env.WithFS(afero.NewIOFS(s.Root)),
47+
}
48+
})
49+
50+
Context("when cleanup is run", func() {
51+
version := versions.Spec{
52+
Selector: versions.Concrete{
53+
Major: 1,
54+
Minor: 16,
55+
Patch: 1,
56+
},
57+
}
58+
59+
var (
60+
matching, nonMatching []store.Item
61+
)
62+
63+
BeforeEach(func() {
64+
// ensure there are some versions matching what we're about to delete
65+
var err error
66+
matching, err = s.List(ctx, store.Filter{Version: version, Platform: versions.Platform{OS: "linux", Arch: "amd64"}})
67+
Expect(err).NotTo(HaveOccurred())
68+
Expect(matching).NotTo(BeEmpty(), "found no matching versions before cleanup")
69+
70+
// ensure there are some versions _not_ matching what we're about to delete
71+
nonMatching, err = s.List(ctx, store.Filter{Version: versions.Spec{Selector: versions.PatchSelector{Major: 1, Minor: 17, Patch: versions.AnyPoint}}, Platform: versions.Platform{OS: "linux", Arch: "amd64"}})
72+
Expect(err).NotTo(HaveOccurred())
73+
Expect(nonMatching).NotTo(BeEmpty(), "found no non-matching versions before cleanup")
74+
})
75+
76+
JustBeforeEach(func() {
77+
Expect(cleanup.Cleanup(
78+
ctx,
79+
version,
80+
cleanup.WithPlatform("linux", "amd64"),
81+
cleanup.WithEnvOptions(defaultEnvOpts...),
82+
)).To(Succeed())
83+
})
84+
85+
It("should remove matching versions", func() {
86+
items, err := s.List(ctx, store.Filter{Version: version, Platform: versions.Platform{OS: "linux", Arch: "amd64"}})
87+
Expect(err).NotTo(HaveOccurred())
88+
Expect(items).To(BeEmpty(), "found matching versions after cleanup")
89+
})
90+
91+
It("should not remove non-matching versions", func() {
92+
items, err := s.List(ctx, store.Filter{Version: versions.AnyVersion, Platform: versions.Platform{OS: "*", Arch: "*"}})
93+
Expect(err).NotTo(HaveOccurred())
94+
Expect(items).To(ContainElements(nonMatching), "non-matching items were affected")
95+
})
96+
})
97+
})

pkg/envtest/setup/cleanup/config.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package cleanup
2+
3+
import (
4+
"runtime"
5+
6+
"sigs.k8s.io/controller-runtime/pkg/envtest/setup/env"
7+
"sigs.k8s.io/controller-runtime/pkg/envtest/setup/versions"
8+
)
9+
10+
type config struct {
11+
envOpts []env.Option
12+
platform versions.Platform
13+
}
14+
15+
// Option is a functional option for configuring the cleanup process.
16+
type Option func(*config)
17+
18+
// WithEnvOptions adds options to the environment setup.
19+
func WithEnvOptions(opts ...env.Option) Option {
20+
return func(cfg *config) {
21+
cfg.envOpts = append(cfg.envOpts, opts...)
22+
}
23+
}
24+
25+
// WithPlatform sets the platform to use for cleanup.
26+
func WithPlatform(os string, arch string) Option {
27+
return func(cfg *config) {
28+
cfg.platform = versions.Platform{OS: os, Arch: arch}
29+
}
30+
}
31+
32+
func configure(options ...Option) *config {
33+
cfg := &config{
34+
platform: versions.Platform{
35+
Arch: runtime.GOARCH,
36+
OS: runtime.GOOS,
37+
},
38+
}
39+
40+
for _, opt := range options {
41+
opt(cfg)
42+
}
43+
44+
return cfg
45+
}

pkg/envtest/setup/env/assets.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package env
2+
3+
import (
4+
"context"
5+
"errors"
6+
"fmt"
7+
"io/fs"
8+
"path/filepath"
9+
10+
"sigs.k8s.io/controller-runtime/pkg/envtest/setup/versions"
11+
"sigs.k8s.io/controller-runtime/pkg/log"
12+
)
13+
14+
var expectedExecutables = []string{
15+
"kube-apiserver",
16+
"etcd",
17+
"kubectl",
18+
}
19+
20+
// TryUseAssetsFromPath attempts to use the assets from the provided path if they match the spec.
21+
// If they do not, or if some executable is missing, it returns an empty string.
22+
func (e *Env) TryUseAssetsFromPath(ctx context.Context, spec versions.Spec, path string) (versions.Spec, bool) {
23+
v, err := versions.FromPath(path)
24+
if err != nil {
25+
ok, checkErr := e.hasAllExecutables(path)
26+
log.FromContext(ctx).Info("has all executables", "ok", ok, "err", checkErr)
27+
if checkErr != nil {
28+
log.FromContext(ctx).Error(errors.Join(err, checkErr), "Failed checking if assets path has all binaries, ignoring", "path", path)
29+
return versions.Spec{}, false
30+
} else if ok {
31+
// If the path has all executables, we can use it even if we can't parse the version.
32+
// The user explicitly asked for this path, so set the version to a wildcard so that
33+
// it passes checks downstream.
34+
return versions.AnyVersion, true
35+
}
36+
37+
log.FromContext(ctx).Error(errors.Join(err, errors.New("some required binaries missing")), "Unable to use assets from path, ignoring", "path", path)
38+
return versions.Spec{}, false
39+
}
40+
41+
if !spec.Matches(*v) {
42+
log.FromContext(ctx).Error(nil, "Assets path does not match spec, ignoring", "path", path, "spec", spec)
43+
return versions.Spec{}, false
44+
}
45+
46+
if ok, err := e.hasAllExecutables(path); err != nil {
47+
log.FromContext(ctx).Error(err, "Failed checking if assets path has all binaries, ignoring", "path", path)
48+
return versions.Spec{}, false
49+
} else if !ok {
50+
log.FromContext(ctx).Error(nil, "Assets path is missing some executables, ignoring", "path", path)
51+
return versions.Spec{}, false
52+
}
53+
54+
return versions.Spec{Selector: v}, true
55+
}
56+
57+
func (e *Env) hasAllExecutables(path string) (bool, error) {
58+
for _, expected := range expectedExecutables {
59+
_, err := e.FS.Open(filepath.Join(path, expected))
60+
if err != nil {
61+
if errors.Is(err, fs.ErrNotExist) {
62+
return false, nil
63+
}
64+
return false, fmt.Errorf("check for existence of %s binary in %s: %w", expected, path, err)
65+
}
66+
}
67+
68+
return true, nil
69+
}

0 commit comments

Comments
 (0)