diff --git a/e2e/basic/probe_test.go b/e2e/basic/probe_test.go index 3caa567..95c5670 100644 --- a/e2e/basic/probe_test.go +++ b/e2e/basic/probe_test.go @@ -4,8 +4,8 @@ import ( "context" "strings" - v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/util/intstr" + corev1 "k8s.io/client-go/applyconfigurations/core/v1" "github.com/celestiaorg/knuu/e2e" ) @@ -23,16 +23,16 @@ func (s *Suite) TestProbe() { err = web.Storage().AddFile(resourcesHTML+"/index.html", e2e.NginxHTMLPath+"/index.html", "0:0") s.Require().NoError(err) - livenessProbe := v1.Probe{ - ProbeHandler: v1.ProbeHandler{ - HTTPGet: &v1.HTTPGetAction{ - Path: "/", - Port: intstr.IntOrString{Type: intstr.Int, IntVal: e2e.NginxPort}, - }, - }, - InitialDelaySeconds: 10, - } - s.Require().NoError(web.Monitoring().SetLivenessProbe(&livenessProbe)) + err = web.Monitoring().SetLivenessProbe( + corev1.Probe(). + WithHTTPGet(corev1.HTTPGetAction(). + WithPath("/"). + WithPort(intstr.FromInt(e2e.NginxPort)), + ). + WithInitialDelaySeconds(10), + ) + s.Require().NoError(err) + s.Require().NoError(web.Build().Commit(ctx)) s.Require().NoError(web.Execution().Start(ctx)) diff --git a/e2e/longrunning/image_upgrade_test.go b/e2e/longrunning/image_upgrade_test.go new file mode 100644 index 0000000..be6496f --- /dev/null +++ b/e2e/longrunning/image_upgrade_test.go @@ -0,0 +1,67 @@ +package longrunning + +import ( + "context" + "testing" + "time" + + "github.com/stretchr/testify/require" + "k8s.io/apimachinery/pkg/api/resource" +) + +func TestImageUpgrade(t *testing.T) { + const ( + instanceName = "image-upgrade" + firstImage = "alpine:3.20.3" + secondImage = "nginx:latest" + volumeSize = "1Gi" + volumePath = "/tmp/test-id" + fileContent = "hello world" + filePath = volumePath + "/test-id.txt" + ) + + ctx := context.Background() + + ins1, err := createInstance(ctx, instanceName, "", firstImage) + require.NoError(t, err) + + err = ins1.Storage().AddVolume(volumePath, resource.MustParse(volumeSize)) + require.NoError(t, err) + + require.NoError(t, ins1.Execution().Start(ctx)) + + testScope := ins1.Scope + t.Logf("Scope: %s", testScope) + + _, err = ins1.Execution().ExecuteCommand(ctx, "echo", fileContent, ">", filePath) + require.NoError(t, err) + + t.Logf("Waiting for 5 seconds to simulate a long running process") + time.Sleep(5 * time.Second) + + ins2, err := createInstance(ctx, instanceName, testScope, firstImage) + require.NoError(t, err) + + err = ins2.Storage().AddVolume(volumePath, resource.MustParse(volumeSize)) + require.NoError(t, err) + + require.NoError(t, ins2.Execution().Start(ctx)) + + // To upgrade the image, first the instance must be stopped + require.NoError(t, ins2.Execution().Stop(ctx)) + + // Now we can upgrade the image + require.NoError(t, ins2.Build().SetImage(ctx, secondImage)) + require.NoError(t, ins2.Build().Commit(ctx)) + require.NoError(t, ins2.Execution().Start(ctx)) + + // Test if the alpine image is replaced with the nginx image successfully + out, err := ins2.Execution().ExecuteCommand(ctx, "cat", "/etc/nginx/nginx.conf") + require.NoError(t, err) + require.NotEmpty(t, out) + + // Test if the volume is persisted across the image upgrade + out, err = ins2.Execution().ExecuteCommand(ctx, "cat", filePath) + require.NoError(t, err) + require.Contains(t, out, fileContent) +} diff --git a/e2e/longrunning/simple_test.go b/e2e/longrunning/simple_test.go new file mode 100644 index 0000000..2ef85c1 --- /dev/null +++ b/e2e/longrunning/simple_test.go @@ -0,0 +1,41 @@ +package longrunning + +import ( + "context" + "testing" + "time" + + "github.com/stretchr/testify/require" +) + +const ( + alpineImage = "alpine:3.20.3" +) + +func TestSimple(t *testing.T) { + const ( + instanceName = "simple-id" + fileContent = "identifier:12345" + ) + + ctx := context.Background() + + ins1, err := createInstanceAndStart(ctx, instanceName, "", alpineImage) + require.NoError(t, err) + testScope := ins1.Scope + + t.Logf("Scope: %s", testScope) + + _, err = ins1.Execution().ExecuteCommand(ctx, "echo", fileContent, ">", "/tmp/test-id") + require.NoError(t, err) + + t.Logf("Waiting for 5 seconds to simulate a long running process") + time.Sleep(5 * time.Second) + + ins2, err := createInstanceAndStart(ctx, instanceName, testScope, alpineImage) + require.NoError(t, err) + + out, err := ins2.Execution().ExecuteCommand(ctx, "cat", "/tmp/test-id") + require.NoError(t, err) + require.Contains(t, out, fileContent) +} diff --git a/e2e/longrunning/utils_test.go b/e2e/longrunning/utils_test.go new file mode 100644 index 0000000..2699d20 --- /dev/null +++ b/e2e/longrunning/utils_test.go @@ -0,0 +1,59 @@ +package longrunning + +import ( + "context" + "time" + + "github.com/celestiaorg/knuu/pkg/instance" + "github.com/celestiaorg/knuu/pkg/knuu" +) + +const ( + testTimeout = time.Minute * 5 +) + +func createInstance(ctx context.Context, name, testScope string, image string) (*instance.Instance, error) { + knOpts := knuu.Options{Timeout: testTimeout, SkipCleanup: true} + if testScope != "" { + knOpts.Scope = testScope + } + + kn, err := knuu.New(ctx, knOpts) + if err != nil { + return nil, err + } + + kn.HandleStopSignal(ctx) + + ins, err := kn.NewInstance(name) + if err != nil { + return nil, err + } + + if err := ins.Build().SetImage(ctx, image); err != nil { + return nil, err + } + + if err := ins.Build().Commit(ctx); err != nil { + return nil, err + } + + if err := ins.Build().SetStartCommand("sleep", "infinity"); err != nil { + return nil, err + } + + return ins, nil +} + +func createInstanceAndStart(ctx context.Context, name, testScope string, image string) (*instance.Instance, error) { + ins, err := createInstance(ctx, name, testScope, image) + if err != nil { + return nil, err + } + + if err := ins.Execution().Start(ctx); err != nil { + return nil, err + } + + return ins, nil +} diff --git a/e2e/system/start_callback_test.go b/e2e/system/start_callback_test.go index d260094..2f9d695 100644 --- a/e2e/system/start_callback_test.go +++ b/e2e/system/start_callback_test.go @@ -4,8 +4,8 @@ import ( "context" "sync" - corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/util/intstr" + corev1 "k8s.io/client-go/applyconfigurations/core/v1" "github.com/celestiaorg/knuu/e2e" ) @@ -23,14 +23,13 @@ func (s *Suite) TestStartWithCallback() { // This probe is used to make sure the instance will not be ready for a second so the // second execute command must fail and the first one with callback must succeed - err := target.Monitoring().SetReadinessProbe(&corev1.Probe{ - ProbeHandler: corev1.ProbeHandler{ - HTTPGet: &corev1.HTTPGetAction{ - Path: "/", - Port: intstr.FromInt(e2e.NginxPort), - }, - }, - }) + err := target.Monitoring().SetReadinessProbe( + corev1.Probe(). + WithHTTPGet(corev1.HTTPGetAction(). + WithPath("/"). + WithPort(intstr.FromInt(e2e.NginxPort)), + ), + ) s.Require().NoError(err) err = target.Build().SetStartCommand([]string{"sleep", sleepTimeBeforeReady, "&&", e2e.NginxCommand}...) diff --git a/go.mod b/go.mod index 5324d71..dd3bb30 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,6 @@ go 1.22.5 require ( github.com/celestiaorg/bittwister v0.0.0-20231213180407-65cdbaf5b8c7 - github.com/docker/docker v26.1.4+incompatible github.com/google/uuid v1.6.0 github.com/minio/minio-go/v7 v7.0.74 github.com/sirupsen/logrus v1.9.3 @@ -17,15 +16,8 @@ require ( ) require ( - github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect - github.com/Microsoft/go-winio v0.6.1 // indirect - github.com/acroca/go-symbols v0.1.1 // indirect github.com/cilium/ebpf v0.12.3 // indirect - github.com/containerd/log v0.1.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/distribution/reference v0.5.0 // indirect - github.com/docker/go-connections v0.4.1-0.20210727194412-58542c764a11 // indirect - github.com/docker/go-units v0.5.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/evanphx/json-patch v5.6.0+incompatible // indirect @@ -33,7 +25,6 @@ require ( github.com/frankban/quicktest v1.14.6 // indirect github.com/go-ini/ini v1.67.0 // indirect github.com/go-logr/logr v1.4.1 // indirect - github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.22.3 // indirect @@ -49,56 +40,35 @@ require ( github.com/imdario/mergo v0.3.16 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/karrick/godirwalk v1.17.0 // indirect github.com/klauspost/compress v1.17.9 // indirect github.com/klauspost/cpuid/v2 v2.2.8 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/minio/md5-simd v1.1.2 // indirect - github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/spdystream v0.2.0 // indirect - github.com/moby/term v0.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/morikuni/aec v1.0.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect - github.com/nsf/gocode v0.0.0-20230322162601-b672b49f3818 // indirect - github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/ramya-rao-a/go-outline v0.0.0-20210608161538-9736a4bde949 // indirect github.com/rs/xid v1.5.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/stretchr/objx v0.5.2 // indirect - github.com/uudashr/gopkgs v1.3.2 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect - go.opentelemetry.io/otel v1.26.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.26.0 // indirect - go.opentelemetry.io/otel/metric v1.26.0 // indirect - go.opentelemetry.io/otel/sdk v1.26.0 // indirect - go.opentelemetry.io/otel/trace v1.26.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect golang.org/x/crypto v0.29.0 // indirect golang.org/x/exp v0.0.0-20240213143201-ec583247a57a // indirect - golang.org/x/mod v0.22.0 // indirect golang.org/x/net v0.31.0 // indirect golang.org/x/oauth2 v0.17.0 // indirect - golang.org/x/sync v0.9.0 // indirect golang.org/x/sys v0.27.0 // indirect golang.org/x/term v0.26.0 // indirect golang.org/x/text v0.20.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.27.0 // indirect - golang.org/x/tools/cmd/guru v0.1.1-deprecated // indirect google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - gotest.tools/v3 v3.5.1 // indirect k8s.io/klog/v2 v2.120.1 // indirect k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect diff --git a/go.sum b/go.sum index aa90d21..1a3d5e5 100644 --- a/go.sum +++ b/go.sum @@ -1,38 +1,19 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= -github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= -github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= -github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= -github.com/acroca/go-symbols v0.1.1 h1:q3IzaMNYocw/Bnc2a8jkXf0hM3+POfLoq30x8HYuaPE= -github.com/acroca/go-symbols v0.1.1/go.mod h1:RKAIDWtcELAw6/wjNJGWRYZ7QEinSWoJeJ2H5cfK6AM= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/celestiaorg/bittwister v0.0.0-20231213180407-65cdbaf5b8c7 h1:nxplQi8wrLMjhu260RuigXylC3pWoDu4OVumPHeojnk= github.com/celestiaorg/bittwister v0.0.0-20231213180407-65cdbaf5b8c7/go.mod h1:1EF5MfOxVf0WC51Gb7pJ6bcZxnXKNAf9pqWtjgPBAYc= -github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= -github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cilium/ebpf v0.12.3 h1:8ht6F9MquybnY97at+VDZb3eQQr8ev79RueWeVaEcG4= github.com/cilium/ebpf v0.12.3/go.mod h1:TctK1ivibvI3znr66ljgi4hqOT8EYQjz1KWBfb1UVgM= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= -github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= -github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= -github.com/docker/docker v26.1.4+incompatible h1:vuTpXDuoga+Z38m1OZHzl7NKisKWaWlhjQk7IDPSLsU= -github.com/docker/docker v26.1.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/go-connections v0.4.1-0.20210727194412-58542c764a11 h1:IPrmumsT9t5BS7XcPhgsCTlkWbYg80SEXUzDpReaU6Y= -github.com/docker/go-connections v0.4.1-0.20210727194412-58542c764a11/go.mod h1:a6bNUGTbQBsY6VRHTr4h/rkOXjl244DyRD0tx3fgq4Q= -github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= -github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= @@ -49,11 +30,8 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A= github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= -github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= -github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= @@ -95,16 +73,12 @@ github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWS github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 h1:/c3QmbOGMGTOumP2iT/rCwB7b0QDGLKzqOmktBjT+Is= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1/go.mod h1:5SN9VR2LTsRFsrEC6FHgRbTWrTHu6tqPeKxEQv15giM= github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/karrick/godirwalk v1.17.0 h1:b4kY7nqDdioR/6qnbHQyDvmA17u5G1cZ6J+CZXwSWoI= -github.com/karrick/godirwalk v1.17.0/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= @@ -112,7 +86,6 @@ github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ib github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -126,43 +99,28 @@ github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= github.com/minio/minio-go/v7 v7.0.74 h1:fTo/XlPBTSpo3BAMshlwKL5RspXRv9us5UeHEGYCFe0= github.com/minio/minio-go/v7 v7.0.74/go.mod h1:qydcVzV8Hqtj1VtEocfxbmVFa2siu6HGa+LDEPogjD8= -github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= -github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= -github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= -github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= -github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/nsf/gocode v0.0.0-20230322162601-b672b49f3818 h1:btvxUuer0DCdhu/N5fvMxW759ASqzIsm6cF8D23TNYs= -github.com/nsf/gocode v0.0.0-20230322162601-b672b49f3818/go.mod h1:6Q8/OMaaKAgTX7/jt2bOXVDrm1eJhoNd+iwzghR7jvs= github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY= github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM= github.com/onsi/gomega v1.31.0 h1:54UJxxj6cPInHS3a35wm6BK/F9nHYueZ1NVujHDrnXE= github.com/onsi/gomega v1.31.0/go.mod h1:DW9aCi7U6Yi40wNVAvT6kzFnEVEI5n3DloYBiKiT6zk= -github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= -github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b h1:YWuSjZCQAPM8UUBLkYUk1e+rZcvWHJmFb6i6rM44Xs8= -github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/ramya-rao-a/go-outline v0.0.0-20210608161538-9736a4bde949 h1:iaD+iVf9xGfajsJp+zYrg9Lrk6gMJ6/hZHO4cYq5D5o= -github.com/ramya-rao-a/go-outline v0.0.0-20210608161538-9736a4bde949/go.mod h1:9V3eNbj9Z53yO7cKB6cSX9f0O7rYdIiuGBhjA1YsQuw= github.com/regen-network/protobuf v1.3.3-alpha.regen.1 h1:OHEc+q5iIAXpqiqFKeLpu5NwTIkVXUs48vFMwzqpqY4= github.com/regen-network/protobuf v1.3.3-alpha.regen.1/go.mod h1:2DjTFR1HhMQhiWC5sZ4OhQ3+NtdbZ6oBDKQwq5Ou+FI= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= @@ -170,18 +128,15 @@ github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjR github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -189,28 +144,9 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/uudashr/gopkgs v1.3.2 h1:ACme7LZyeSNIRIl9HtAA0RsT0eePUsrkHDVb2+aswhg= -github.com/uudashr/gopkgs v1.3.2/go.mod h1:MtCdKVJkxW7hNKWXPNWfpaeEp8+Ml3Q8myb4yWhn2Hg= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= -go.opentelemetry.io/otel v1.26.0 h1:LQwgL5s/1W7YiiRwxf03QGnWLb2HW4pLiAhaA5cZXBs= -go.opentelemetry.io/otel v1.26.0/go.mod h1:UmLkJHUAidDval2EICqBMbnAd0/m2vmpf/dAM+fvFs4= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.26.0 h1:1u/AyyOqAWzy+SkPxDpahCNZParHV8Vid1RnI2clyDE= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.26.0/go.mod h1:z46paqbJ9l7c9fIPCXTqTGwhQZ5XoTIsfeFYWboizjs= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.26.0 h1:1wp/gyxsuYtuE/JFxsQRtcCDtMrO2qMvlfXALU5wkzI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.26.0/go.mod h1:gbTHmghkGgqxMomVQQMur1Nba4M0MQ8AYThXDUjsJ38= -go.opentelemetry.io/otel/metric v1.26.0 h1:7S39CLuY5Jgg9CrnA9HHiEjGMF/X2VHvoXGgSllRz30= -go.opentelemetry.io/otel/metric v1.26.0/go.mod h1:SY+rHOI4cEawI9a7N1A4nIg/nTQXe1ccCNWYOJUrpX4= -go.opentelemetry.io/otel/sdk v1.26.0 h1:Y7bumHf5tAiDlRYFmGqetNcLaVUZmh4iYfmGxtmz7F8= -go.opentelemetry.io/otel/sdk v1.26.0/go.mod h1:0p8MXpqLeJ0pzcszQQN4F0S5FVjBLgypeGSngLsmirs= -go.opentelemetry.io/otel/trace v1.26.0 h1:1ieeAUb4y0TE26jUFrCIXKpTuVK7uJGN9/Z/2LP5sQA= -go.opentelemetry.io/otel/trace v1.26.0/go.mod h1:4iDxvGDQuUkHve82hJJ8UqrwswHYsZuWCBllGV2U2y0= -go.opentelemetry.io/proto/otlp v1.2.0 h1:pVeZGk7nXDC9O2hncA6nHldxEjm6LByfA2aN8IOkz94= -go.opentelemetry.io/proto/otlp v1.2.0/go.mod h1:gGpR8txAl5M03pDhMC79G6SdqNV26naRm/KDsgaHD8A= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= @@ -221,10 +157,6 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= -golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= -golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= -golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -235,14 +167,7 @@ golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvx golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= -golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= -golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= -golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= -golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -253,12 +178,7 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= -golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= -golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -269,40 +189,22 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= -golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= -golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= -golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= -golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= -golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU= golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -310,10 +212,6 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= -golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= @@ -326,16 +224,9 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= -golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= -golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE= -golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= golang.org/x/tools v0.27.0 h1:qEKojBykQkQ4EynWy4S8Weg69NumxKdn40Fce3uc/8o= golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q= -golang.org/x/tools/cmd/guru v0.1.1-deprecated h1:WiL3pQGXG71u4N45C0eRkE2IcEMAiQdDZ2H5lGspNjM= -golang.org/x/tools/cmd/guru v0.1.1-deprecated/go.mod h1:yFb7vixnH8+ByFZ63niwlvUUxyTE/6ULZ6AiEHZwlTk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -347,17 +238,11 @@ google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJ google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200324203455-a04cca1dde73/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de h1:jFNzHPIeuzhdRwVhbZdiym9q0ory/xY3sA+v2wPg8I0= -google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:5iCWqnniDlqZHrd3neWVTOwvh/v6s3232omMecelax8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda h1:LI5DOvAxUPMv/50agcLLoo+AdWc1irS9Rzz4vPuD1V4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= -google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= @@ -373,8 +258,6 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= -gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= k8s.io/api v0.30.2 h1:+ZhRj+28QT4UOH+BKznu4CBgPWgkXO7XAvMcMl0qKvI= diff --git a/pkg/instance/build.go b/pkg/instance/build.go index 16714a5..b0f54f6 100644 --- a/pkg/instance/build.go +++ b/pkg/instance/build.go @@ -18,7 +18,7 @@ import ( type build struct { instance *Instance imageName string - imagePullPolicy v1.PullPolicy + imagePullPolicy *v1.PullPolicy builderFactory *container.BuilderFactory command []string args []string @@ -36,12 +36,12 @@ func (b *build) ImageName() string { return b.imageName } -func (b *build) ImagePullPolicy() v1.PullPolicy { +func (b *build) ImagePullPolicy() *v1.PullPolicy { return b.imagePullPolicy } func (b *build) SetImagePullPolicy(pullPolicy v1.PullPolicy) { - b.imagePullPolicy = pullPolicy + b.imagePullPolicy = &pullPolicy } // SetImage sets the image of the instance. @@ -254,7 +254,8 @@ func (b *build) getBuildDir() (string, error) { if err != nil { return "", err } - return filepath.Join(tmpDir, b.instance.name), nil + b.buildDir = filepath.Join(tmpDir, b.instance.name) + return b.buildDir, nil } // addFileToBuilder adds a file to the builder diff --git a/pkg/instance/execution.go b/pkg/instance/execution.go index 622c5fb..220ccf5 100644 --- a/pkg/instance/execution.go +++ b/pkg/instance/execution.go @@ -2,6 +2,7 @@ package instance import ( "context" + "errors" "os" "strings" "time" @@ -310,16 +311,19 @@ func (e *execution) deployPod(ctx context.Context) error { labels := e.Labels() // create a service account for the pod - if err := e.instance.K8sClient.CreateServiceAccount(ctx, e.instance.name, labels); err != nil { + err := e.instance.K8sClient.CreateServiceAccount(ctx, e.instance.name, labels) + if err != nil && !errors.Is(err, k8s.ErrServiceAccountAlreadyExists) { return ErrFailedToCreateServiceAccount.Wrap(err) } // create a role and role binding for the pod if there are policy rules if len(e.instance.security.policyRules) > 0 { - if err := e.instance.K8sClient.CreateRole(ctx, e.instance.name, labels, e.instance.security.policyRules); err != nil { + err := e.instance.K8sClient.CreateRole(ctx, e.instance.name, labels, e.instance.security.policyRules) + if err != nil && !errors.Is(err, k8s.ErrRoleAlreadyExists) { return ErrFailedToCreateRole.Wrap(err) } - if err := e.instance.K8sClient.CreateRoleBinding(ctx, e.instance.name, labels, e.instance.name, e.instance.name); err != nil { + err = e.instance.K8sClient.CreateRoleBinding(ctx, e.instance.name, labels, e.instance.name, e.instance.name) + if err != nil && !errors.Is(err, k8s.ErrRoleBindingAlreadyExists) { return ErrFailedToCreateRoleBinding.Wrap(err) } } diff --git a/pkg/instance/instance.go b/pkg/instance/instance.go index d9aa769..48caec0 100644 --- a/pkg/instance/instance.go +++ b/pkg/instance/instance.go @@ -8,6 +8,7 @@ import ( v1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" "k8s.io/apimachinery/pkg/api/resource" + "k8s.io/utils/ptr" "github.com/celestiaorg/knuu/pkg/k8s" "github.com/celestiaorg/knuu/pkg/system" @@ -60,7 +61,7 @@ func New(name string, sysDeps *system.SystemDependencies) (*Instance, error) { args: make([]string, 0), env: make(map[string]string), imageCache: &sync.Map{}, - imagePullPolicy: v1.PullAlways, + imagePullPolicy: ptr.To[v1.PullPolicy](v1.PullAlways), } i.execution = &execution{instance: i} diff --git a/pkg/instance/monitoring.go b/pkg/instance/monitoring.go index b2361a7..47e8ccb 100644 --- a/pkg/instance/monitoring.go +++ b/pkg/instance/monitoring.go @@ -5,14 +5,16 @@ import ( "io" "github.com/sirupsen/logrus" - v1 "k8s.io/api/core/v1" + corev1 "k8s.io/client-go/applyconfigurations/core/v1" + + "github.com/celestiaorg/knuu/pkg/k8s" ) type monitoring struct { instance *Instance - livenessProbe *v1.Probe - readinessProbe *v1.Probe - startupProbe *v1.Probe + livenessProbe *corev1.ProbeApplyConfiguration + readinessProbe *corev1.ProbeApplyConfiguration + startupProbe *corev1.ProbeApplyConfiguration } func (i *Instance) Monitoring() *monitoring { @@ -30,7 +32,7 @@ func (m *monitoring) Logs(ctx context.Context) (io.ReadCloser, error) { // A live probe is a probe that is used to determine if the instance is still alive, and should be restarted if not // See usage documentation: https://pkg.go.dev/i.K8sCli.io/api/core/v1@v0.27.3#Probe // This function can only be called in the states 'Preparing' and 'Committed' -func (m *monitoring) SetLivenessProbe(livenessProbe *v1.Probe) error { +func (m *monitoring) SetLivenessProbe(livenessProbe *corev1.ProbeApplyConfiguration) error { if err := m.checkStateForProbe(); err != nil { return err } @@ -46,7 +48,7 @@ func (m *monitoring) SetLivenessProbe(livenessProbe *v1.Probe) error { // A readiness probe is a probe that is used to determine if the instance is ready to receive traffic // See usage documentation: https://pkg.go.dev/i.K8sCli.io/api/core/v1@v0.27.3#Probe // This function can only be called in the states 'Preparing' and 'Committed' -func (m *monitoring) SetReadinessProbe(readinessProbe *v1.Probe) error { +func (m *monitoring) SetReadinessProbe(readinessProbe *corev1.ProbeApplyConfiguration) error { if err := m.checkStateForProbe(); err != nil { return err } @@ -62,7 +64,7 @@ func (m *monitoring) SetReadinessProbe(readinessProbe *v1.Probe) error { // A startup probe is a probe that is used to determine if the instance is ready to receive traffic after a startup // See usage documentation: https://pkg.go.dev/i.K8sCli.io/api/core/v1@v0.27.3#Probe // This function can only be called in the states 'Preparing' and 'Committed' -func (m *monitoring) SetStartupProbe(startupProbe *v1.Probe) error { +func (m *monitoring) SetStartupProbe(startupProbe *corev1.ProbeApplyConfiguration) error { if err := m.checkStateForProbe(); err != nil { return err } @@ -87,19 +89,19 @@ func (m *monitoring) clone() *monitoring { return nil } - var livenessProbeCopy *v1.Probe + var livenessProbeCopy *corev1.ProbeApplyConfiguration if m.livenessProbe != nil { - livenessProbeCopy = m.livenessProbe.DeepCopy() + livenessProbeCopy = k8s.DeepCopyProbe(m.livenessProbe) } - var readinessProbeCopy *v1.Probe + var readinessProbeCopy *corev1.ProbeApplyConfiguration if m.readinessProbe != nil { - readinessProbeCopy = m.readinessProbe.DeepCopy() + readinessProbeCopy = k8s.DeepCopyProbe(m.readinessProbe) } - var startupProbeCopy *v1.Probe + var startupProbeCopy *corev1.ProbeApplyConfiguration if m.startupProbe != nil { - startupProbeCopy = m.startupProbe.DeepCopy() + startupProbeCopy = k8s.DeepCopyProbe(m.startupProbe) } return &monitoring{ diff --git a/pkg/instance/security.go b/pkg/instance/security.go index e451ffc..a9738e3 100644 --- a/pkg/instance/security.go +++ b/pkg/instance/security.go @@ -6,6 +6,7 @@ import ( "github.com/sirupsen/logrus" v1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" + corev1 "k8s.io/client-go/applyconfigurations/core/v1" ) // represents the security settings for a container @@ -80,8 +81,8 @@ func (s *security) AddKubernetesCapabilities(capabilities []string) error { } // prepareSecurityContext creates a v1.SecurityContext from the security configs -func (s *security) prepareSecurityContext() *v1.SecurityContext { - sc := &v1.SecurityContext{} +func (s *security) prepareSecurityContext() *corev1.SecurityContextApplyConfiguration { + sc := &corev1.SecurityContextApplyConfiguration{} if s.privileged { sc.Privileged = &s.privileged @@ -91,7 +92,7 @@ func (s *security) prepareSecurityContext() *v1.SecurityContext { for i, cap := range s.capabilitiesAdd { capabilities[i] = v1.Capability(cap) } - sc.Capabilities = &v1.Capabilities{ + sc.Capabilities = &corev1.CapabilitiesApplyConfiguration{ Add: capabilities, } diff --git a/pkg/instance/storage.go b/pkg/instance/storage.go index b2343ec..0125afe 100644 --- a/pkg/instance/storage.go +++ b/pkg/instance/storage.go @@ -343,6 +343,11 @@ func (s *storage) addFileToInstance(srcPath, dest, chown string) error { file := s.instance.K8sClient.NewFile(srcPath, dest, chown, permission) s.files = append(s.files, file) + s.instance.Logger.WithFields(logrus.Fields{ + "file": file, + "instance": s.instance.name, + }).Debug("added file to instance") + return nil } diff --git a/pkg/k8s/errors.go b/pkg/k8s/errors.go index d79833a..76abc55 100644 --- a/pkg/k8s/errors.go +++ b/pkg/k8s/errors.go @@ -147,4 +147,7 @@ var ( ErrNoPortsFoundForService = errors.New("NoPortsFoundForService", "no ports found for service %s") ErrNoValidNodeIPFound = errors.New("NoValidNodeIPFound", "no valid node IP found for service %s") ErrInvalidClusterDomain = errors.New("InvalidClusterDomain", "invalid cluster domain `%s`") + ErrServiceAccountAlreadyExists = errors.New("ServiceAccountAlreadyExists", "service account %s already exists") + ErrRoleAlreadyExists = errors.New("RoleAlreadyExists", "role %s already exists") + ErrRoleBindingAlreadyExists = errors.New("RoleBindingAlreadyExists", "role binding %s already exists") ) diff --git a/pkg/k8s/k8s.go b/pkg/k8s/k8s.go index ca944a7..d81f337 100644 --- a/pkg/k8s/k8s.go +++ b/pkg/k8s/k8s.go @@ -35,6 +35,9 @@ const ( // defaultClusterDomain is the default cluster domain defaultClusterDomain = "cluster.local" + + // FieldManager is the field manager to use for the Kubernetes client + FieldManager = "knuu" ) type Client struct { diff --git a/pkg/k8s/pod.go b/pkg/k8s/pod.go index 035923a..6eabe29 100644 --- a/pkg/k8s/pod.go +++ b/pkg/k8s/pod.go @@ -14,6 +14,7 @@ import ( apierrs "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + corev1 "k8s.io/client-go/applyconfigurations/core/v1" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/tools/portforward" "k8s.io/client-go/tools/remotecommand" @@ -34,23 +35,23 @@ const ( ) type ContainerConfig struct { - Name string // Name to assign to the Container - Image string // Name of the container image to use for the container - ImagePullPolicy v1.PullPolicy // Image pull policy for the container - Command []string // Command to run in the container - Args []string // Arguments to pass to the command in the container - Env map[string]string // Environment variables to set in the container - Volumes []*Volume // Volumes to mount in the Pod - MemoryRequest resource.Quantity // Memory request for the container - MemoryLimit resource.Quantity // Memory limit for the container - CPURequest resource.Quantity // CPU request for the container - LivenessProbe *v1.Probe // Liveness probe for the container - ReadinessProbe *v1.Probe // Readiness probe for the container - StartupProbe *v1.Probe // Startup probe for the container - Files []*File // Files to add to the Pod - SecurityContext *v1.SecurityContext // Security context for the container - TCPPorts []int // TCP ports to expose on the Pod - UDPPorts []int // UDP ports to expose on the Pod + Name string // Name to assign to the Container + Image string // Name of the container image to use for the container + ImagePullPolicy *v1.PullPolicy // Image pull policy for the container + Command []string // Command to run in the container + Args []string // Arguments to pass to the command in the container + Env map[string]string // Environment variables to set in the container + Volumes []*Volume // Volumes to mount in the Pod + MemoryRequest resource.Quantity // Memory request for the container + MemoryLimit resource.Quantity // Memory limit for the container + CPURequest resource.Quantity // CPU request for the container + LivenessProbe *corev1.ProbeApplyConfiguration // Liveness probe for the container + ReadinessProbe *corev1.ProbeApplyConfiguration // Readiness probe for the container + StartupProbe *corev1.ProbeApplyConfiguration // Startup probe for the container + Files []*File // Files to add to the Pod + SecurityContext *corev1.SecurityContextApplyConfiguration // Security context for the container + TCPPorts []int // TCP ports to expose on the Pod + UDPPorts []int // UDP ports to expose on the Pod } type PodConfig struct { @@ -88,14 +89,11 @@ func (c *Client) DeployPod(ctx context.Context, podConfig PodConfig, init bool) } pod := c.preparePod(podConfig, init) - createdPod, err := c.clientset.CoreV1().Pods(c.namespace).Create(ctx, pod, metav1.CreateOptions{}) - if err != nil { - return nil, ErrCreatingPod.Wrap(err) - } - - return createdPod, nil + return c.clientset.CoreV1().Pods(c.namespace). + Apply(ctx, pod, metav1.ApplyOptions{ + FieldManager: FieldManager, + }) } - func (c *Client) NewVolume(path string, size resource.Quantity, owner int64) *Volume { return &Volume{ Path: path, @@ -359,10 +357,10 @@ func (c *Client) getPod(ctx context.Context, name string) (*v1.Pod, error) { } // buildEnv builds an environment variable configuration for a Pod based on the given map of key-value pairs. -func buildEnv(envMap map[string]string) []v1.EnvVar { - envVars := make([]v1.EnvVar, 0, len(envMap)) +func buildEnv(envMap map[string]string) []corev1.EnvVarApplyConfiguration { + envVars := make([]corev1.EnvVarApplyConfiguration, 0, len(envMap)) for key, val := range envMap { - envVar := v1.EnvVar{Name: key, Value: val} + envVar := corev1.EnvVarApplyConfiguration{Name: ptr.To[string](key), Value: ptr.To[string](val)} envVars = append(envVars, envVar) } return envVars @@ -370,15 +368,15 @@ func buildEnv(envMap map[string]string) []v1.EnvVar { // buildPodVolumes generates a volume configuration for a pod based on the given name. // If the volumes amount is zero, returns an empty slice. -func buildPodVolumes(name string, volumesAmount, filesAmount int) []v1.Volume { - var podVolumes []v1.Volume +func buildPodVolumes(name string, volumesAmount, filesAmount int) []corev1.VolumeApplyConfiguration { + var podVolumes []corev1.VolumeApplyConfiguration if volumesAmount != 0 { - podVolume := v1.Volume{ - Name: name, - VolumeSource: v1.VolumeSource{ - PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{ - ClaimName: name, + podVolume := corev1.VolumeApplyConfiguration{ + Name: ptr.To[string](name), + VolumeSourceApplyConfiguration: corev1.VolumeSourceApplyConfiguration{ + PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSourceApplyConfiguration{ + ClaimName: ptr.To[string](name), }, }, } @@ -387,22 +385,22 @@ func buildPodVolumes(name string, volumesAmount, filesAmount int) []v1.Volume { } if volumesAmount == 0 && filesAmount != 0 { - podVolume := v1.Volume{ - Name: name, - VolumeSource: v1.VolumeSource{ - EmptyDir: &v1.EmptyDirVolumeSource{}, + podVolume := corev1.VolumeApplyConfiguration{ + Name: ptr.To[string](name), + VolumeSourceApplyConfiguration: corev1.VolumeSourceApplyConfiguration{ + EmptyDir: &corev1.EmptyDirVolumeSourceApplyConfiguration{}, }, } podVolumes = append(podVolumes, podVolume) } if filesAmount != 0 { - podFiles := v1.Volume{ - Name: name + podFilesConfigmapNameSuffix, - VolumeSource: v1.VolumeSource{ - ConfigMap: &v1.ConfigMapVolumeSource{ - LocalObjectReference: v1.LocalObjectReference{ - Name: name, + podFiles := corev1.VolumeApplyConfiguration{ + Name: ptr.To[string](name + podFilesConfigmapNameSuffix), + VolumeSourceApplyConfiguration: corev1.VolumeSourceApplyConfiguration{ + ConfigMap: &corev1.ConfigMapVolumeSourceApplyConfiguration{ + LocalObjectReferenceApplyConfiguration: corev1.LocalObjectReferenceApplyConfiguration{ + Name: ptr.To[string](name), }, DefaultMode: ptr.To[int32](0600), }, @@ -416,15 +414,15 @@ func buildPodVolumes(name string, volumesAmount, filesAmount int) []v1.Volume { } // buildContainerVolumes generates a volume mount configuration for a container based on the given name and volumes. -func buildContainerVolumes(name string, volumes []*Volume, files []*File) []v1.VolumeMount { - var containerVolumes []v1.VolumeMount +func buildContainerVolumes(name string, volumes []*Volume, files []*File) []corev1.VolumeMountApplyConfiguration { + var containerVolumes []corev1.VolumeMountApplyConfiguration for _, volume := range volumes { containerVolumes = append( containerVolumes, - v1.VolumeMount{ - Name: name, - MountPath: volume.Path, - SubPath: strings.TrimLeft(volume.Path, "/"), + corev1.VolumeMountApplyConfiguration{ + Name: ptr.To[string](name), + MountPath: ptr.To[string](volume.Path), + SubPath: ptr.To[string](strings.TrimLeft(volume.Path, "/")), }, ) } @@ -435,31 +433,31 @@ func buildContainerVolumes(name string, volumes []*Volume, files []*File) []v1.V uniquePaths[filepath.Dir(file.Dest)] = true } for path := range uniquePaths { - containerVolumes = append(containerVolumes, v1.VolumeMount{ - Name: name, - MountPath: path, - SubPath: strings.TrimPrefix(path, "/"), + containerVolumes = append(containerVolumes, corev1.VolumeMountApplyConfiguration{ + Name: ptr.To[string](name), + MountPath: ptr.To[string](path), + SubPath: ptr.To[string](strings.TrimPrefix(path, "/")), }) } } - var containerFiles []v1.VolumeMount + var containerFiles []corev1.VolumeMountApplyConfiguration return append(containerVolumes, containerFiles...) } // buildInitContainerVolumes generates a volume mount configuration for an init container based on the given name and volumes. -func buildInitContainerVolumes(name string, volumes []*Volume, files []*File) []v1.VolumeMount { +func buildInitContainerVolumes(name string, volumes []*Volume, files []*File) []corev1.VolumeMountApplyConfiguration { if len(volumes) == 0 && len(files) == 0 { - return []v1.VolumeMount{} // return empty slice if no volumes are specified + return []corev1.VolumeMountApplyConfiguration{} // return empty slice if no volumes are specified } - var containerVolumes []v1.VolumeMount + var containerVolumes []corev1.VolumeMountApplyConfiguration // if the user want do add volumes, we need to mount the knuu path if len(volumes) != 0 { - containerVolumes = append(containerVolumes, v1.VolumeMount{ - Name: name, - MountPath: knuuPath, + containerVolumes = append(containerVolumes, corev1.VolumeMountApplyConfiguration{ + Name: ptr.To[string](name), + MountPath: ptr.To[string](knuuPath), }) } // if the user don't want to add volumes, but want to add files, we need to mount the knuu path for the init container @@ -469,20 +467,20 @@ func buildInitContainerVolumes(name string, volumes []*Volume, files []*File) [] uniquePaths[filepath.Dir(file.Dest)] = true } for path := range uniquePaths { - containerVolumes = append(containerVolumes, v1.VolumeMount{ - Name: name, - MountPath: knuuPath + path, - SubPath: strings.TrimPrefix(path, "/"), + containerVolumes = append(containerVolumes, corev1.VolumeMountApplyConfiguration{ + Name: ptr.To[string](name), + MountPath: ptr.To[string](knuuPath + path), + SubPath: ptr.To[string](strings.TrimPrefix(path, "/")), }) } } - var containerFiles []v1.VolumeMount + var containerFiles []corev1.VolumeMountApplyConfiguration for n, file := range files { - containerFiles = append(containerFiles, v1.VolumeMount{ - Name: name + podFilesConfigmapNameSuffix, - MountPath: file.Dest, - SubPath: fmt.Sprintf("%d", n), + containerFiles = append(containerFiles, corev1.VolumeMountApplyConfiguration{ + Name: ptr.To[string](name + podFilesConfigmapNameSuffix), + MountPath: ptr.To[string](file.Dest), + SubPath: ptr.To[string](fmt.Sprintf("%d", n)), }) } @@ -544,42 +542,42 @@ func (c *Client) buildInitContainerCommand(volumes []*Volume, files []*File) []s } // buildResources generates a resource configuration for a container based on the given CPU and memory requests and limits. -func buildResources(memoryRequest, memoryLimit, cpuRequest resource.Quantity) v1.ResourceRequirements { - return v1.ResourceRequirements{ - Requests: v1.ResourceList{ +func buildResources(memoryRequest, memoryLimit, cpuRequest resource.Quantity) *corev1.ResourceRequirementsApplyConfiguration { + return &corev1.ResourceRequirementsApplyConfiguration{ + Requests: &v1.ResourceList{ v1.ResourceMemory: memoryRequest, v1.ResourceCPU: cpuRequest, }, - Limits: v1.ResourceList{ + Limits: &v1.ResourceList{ v1.ResourceMemory: memoryLimit, }, } } -func buildPodPorts(tcpPorts, udpPorts []int) []v1.ContainerPort { - ports := make([]v1.ContainerPort, 0, len(tcpPorts)+len(udpPorts)) +func buildPodPorts(tcpPorts, udpPorts []int) []corev1.ContainerPortApplyConfiguration { + ports := make([]corev1.ContainerPortApplyConfiguration, 0, len(tcpPorts)+len(udpPorts)) for _, port := range tcpPorts { - ports = append(ports, v1.ContainerPort{ - Name: fmt.Sprintf("tcp-%d", port), - Protocol: v1.ProtocolTCP, - ContainerPort: int32(port), + ports = append(ports, corev1.ContainerPortApplyConfiguration{ + Name: ptr.To[string](fmt.Sprintf("tcp-%d", port)), + Protocol: ptr.To[v1.Protocol](v1.ProtocolTCP), + ContainerPort: ptr.To[int32](int32(port)), }) } for _, port := range udpPorts { - ports = append(ports, v1.ContainerPort{ - Name: fmt.Sprintf("udp-%d", port), - Protocol: v1.ProtocolUDP, - ContainerPort: int32(port), + ports = append(ports, corev1.ContainerPortApplyConfiguration{ + Name: ptr.To[string](fmt.Sprintf("udp-%d", port)), + Protocol: ptr.To[v1.Protocol](v1.ProtocolUDP), + ContainerPort: ptr.To[int32](int32(port)), }) } return ports } // prepareContainer creates a v1.Container from a given ContainerConfig. -func prepareContainer(config ContainerConfig) v1.Container { - return v1.Container{ - Name: config.Name, - Image: config.Image, +func prepareContainer(config ContainerConfig) corev1.ContainerApplyConfiguration { + return corev1.ContainerApplyConfiguration{ + Name: ptr.To[string](config.Name), + Image: ptr.To[string](config.Image), ImagePullPolicy: config.ImagePullPolicy, Command: config.Command, Args: config.Args, @@ -595,16 +593,16 @@ func prepareContainer(config ContainerConfig) v1.Container { } // prepareInitContainers creates a slice of v1.Container as init containers. -func (c *Client) prepareInitContainers(config ContainerConfig, init bool) []v1.Container { +func (c *Client) prepareInitContainers(config ContainerConfig, init bool) []corev1.ContainerApplyConfiguration { if !init || (len(config.Volumes) == 0 && len(config.Files) == 0) { return nil } - return []v1.Container{ + return []corev1.ContainerApplyConfiguration{ { - Name: config.Name + initContainerNameSuffix, - Image: initContainerImage, - SecurityContext: &v1.SecurityContext{ + Name: ptr.To[string](config.Name + initContainerNameSuffix), + Image: ptr.To[string](initContainerImage), + SecurityContext: &corev1.SecurityContextApplyConfiguration{ RunAsUser: ptr.To[int64](defaultContainerUser), }, Command: c.buildInitContainerCommand(config.Volumes, config.Files), @@ -614,15 +612,15 @@ func (c *Client) prepareInitContainers(config ContainerConfig, init bool) []v1.C } // preparePodVolumes prepares pod volumes -func preparePodVolumes(config ContainerConfig) []v1.Volume { +func preparePodVolumes(config ContainerConfig) []corev1.VolumeApplyConfiguration { return buildPodVolumes(config.Name, len(config.Volumes), len(config.Files)) } -func (c *Client) preparePodSpec(spec PodConfig, init bool) v1.PodSpec { - podSpec := v1.PodSpec{ - ServiceAccountName: spec.ServiceAccountName, +func (c *Client) preparePodSpec(spec PodConfig, init bool) *corev1.PodSpecApplyConfiguration { + podSpec := &corev1.PodSpecApplyConfiguration{ + ServiceAccountName: ptr.To[string](spec.ServiceAccountName), InitContainers: c.prepareInitContainers(spec.ContainerConfig, init), - Containers: []v1.Container{prepareContainer(spec.ContainerConfig)}, + Containers: []corev1.ContainerApplyConfiguration{prepareContainer(spec.ContainerConfig)}, Volumes: preparePodVolumes(spec.ContainerConfig), NodeSelector: spec.NodeSelector, } @@ -641,16 +639,13 @@ func (c *Client) preparePodSpec(spec PodConfig, init bool) v1.PodSpec { return podSpec } -func (c *Client) preparePod(spec PodConfig, init bool) *v1.Pod { - pod := &v1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: spec.Namespace, - Name: spec.Name, - Labels: spec.Labels, - Annotations: spec.Annotations, - }, - Spec: c.preparePodSpec(spec, init), - } +func (c *Client) preparePod(spec PodConfig, init bool) *corev1.PodApplyConfiguration { + pod := corev1.Pod(spec.Name, spec.Namespace). + WithLabels(spec.Labels). + WithAnnotations(spec.Annotations). + WithSpec(c.preparePodSpec(spec, init)). + WithAPIVersion("v1"). + WithKind("Pod") c.logger.WithFields(logrus.Fields{ "name": spec.Name, diff --git a/pkg/k8s/pod_test.go b/pkg/k8s/pod_test.go index 5957297..7ff435b 100644 --- a/pkg/k8s/pod_test.go +++ b/pkg/k8s/pod_test.go @@ -2,6 +2,7 @@ package k8s_test import ( "context" + "fmt" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -28,7 +29,22 @@ func (s *TestSuite) TestDeployPod() { Labels: map[string]string{"app": "test"}, ContainerConfig: testContainerConfig, }, - setupMock: func() {}, + setupMock: func() { + s.client.Clientset().(*fake.Clientset). + PrependReactor("patch", "pods", + func(action k8stesting.Action) (handled bool, ret runtime.Object, err error) { + patchAction, ok := action.(k8stesting.PatchAction) + if !ok { + return false, nil, fmt.Errorf("expected PatchAction, got %T", action) + } + return true, &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: patchAction.GetName(), + Namespace: patchAction.GetNamespace(), + }, + }, nil + }) + }, init: false, expectedErr: nil, }, @@ -43,12 +59,12 @@ func (s *TestSuite) TestDeployPod() { init: false, setupMock: func() { s.client.Clientset().(*fake.Clientset). - PrependReactor("create", "pods", + PrependReactor("patch", "pods", func(action k8stesting.Action) (handled bool, ret runtime.Object, err error) { return true, nil, errInternalServerError }) }, - expectedErr: k8s.ErrCreatingPod.Wrap(errInternalServerError), + expectedErr: errInternalServerError, }, } @@ -86,9 +102,18 @@ func (s *TestSuite) TestReplacePod() { }, setupMock: func() { s.client.Clientset().(*fake.Clientset). - PrependReactor("delete", "pods", + PrependReactor("patch", "pods", func(action k8stesting.Action) (handled bool, ret runtime.Object, err error) { - return true, nil, nil + patchAction, ok := action.(k8stesting.PatchAction) + if !ok { + return false, nil, fmt.Errorf("expected PatchAction, got %T", action) + } + return true, &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: patchAction.GetName(), + Namespace: patchAction.GetNamespace(), + }, + }, nil }) }, expectedErr: nil, diff --git a/pkg/k8s/prob.go b/pkg/k8s/prob.go new file mode 100644 index 0000000..499bbda --- /dev/null +++ b/pkg/k8s/prob.go @@ -0,0 +1,48 @@ +package k8s + +import corev1 "k8s.io/client-go/applyconfigurations/core/v1" + +func DeepCopyProbe(probe *corev1.ProbeApplyConfiguration) *corev1.ProbeApplyConfiguration { + if probe == nil { + return nil + } + + copy := &corev1.ProbeApplyConfiguration{ + InitialDelaySeconds: probe.InitialDelaySeconds, + TimeoutSeconds: probe.TimeoutSeconds, + PeriodSeconds: probe.PeriodSeconds, + SuccessThreshold: probe.SuccessThreshold, + FailureThreshold: probe.FailureThreshold, + TerminationGracePeriodSeconds: probe.TerminationGracePeriodSeconds, + } + + if probe.Exec != nil { + copy.Exec = &corev1.ExecActionApplyConfiguration{ + Command: append([]string{}, probe.Exec.Command...), + } + } + + if probe.HTTPGet != nil { + copy.HTTPGet = &corev1.HTTPGetActionApplyConfiguration{ + Path: probe.HTTPGet.Path, + Port: probe.HTTPGet.Port, + Host: probe.HTTPGet.Host, + Scheme: probe.HTTPGet.Scheme, + } + } + + if probe.TCPSocket != nil { + copy.TCPSocket = &corev1.TCPSocketActionApplyConfiguration{ + Port: probe.TCPSocket.Port, + } + } + + if probe.GRPC != nil { + copy.GRPC = &corev1.GRPCActionApplyConfiguration{ + Port: probe.GRPC.Port, + Service: probe.GRPC.Service, + } + } + + return copy +} diff --git a/pkg/k8s/pvc.go b/pkg/k8s/pvc.go index a6a8f5f..235ab49 100644 --- a/pkg/k8s/pvc.go +++ b/pkg/k8s/pvc.go @@ -7,6 +7,7 @@ import ( "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + corev1 "k8s.io/client-go/applyconfigurations/core/v1" ) // CreatePersistentVolumeClaim deploys a PersistentVolumeClaim if it does not exist. @@ -29,29 +30,25 @@ func (c *Client) CreatePersistentVolumeClaim( return err } - pvc := &v1.PersistentVolumeClaim{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: c.namespace, - Name: name, - Labels: labels, - }, - Spec: v1.PersistentVolumeClaimSpec{ - AccessModes: []v1.PersistentVolumeAccessMode{ - v1.ReadWriteOnce, - }, - Resources: v1.VolumeResourceRequirements{ - Requests: v1.ResourceList{ + pvc := corev1.PersistentVolumeClaim(name, c.namespace). + WithLabels(labels). + WithSpec(corev1.PersistentVolumeClaimSpec(). + WithAccessModes(v1.ReadWriteOnce). + WithResources(corev1.VolumeResourceRequirements(). + WithRequests(v1.ResourceList{ v1.ResourceStorage: size, - }, - }, - }, - } + }), + ), + ) - if _, err := c.clientset.CoreV1().PersistentVolumeClaims(c.namespace).Create(ctx, pvc, metav1.CreateOptions{}); err != nil { + _, err := c.clientset.CoreV1().PersistentVolumeClaims(c.namespace).Apply(ctx, pvc, metav1.ApplyOptions{ + FieldManager: FieldManager, + }) + if err != nil { return ErrCreatingPersistentVolumeClaim.WithParams(name).Wrap(err) } - c.logger.WithField("name", name).Debug("PersistentVolumeClaim created") + c.logger.WithField("name", name).Debug("PersistentVolumeClaim applied") return nil } diff --git a/pkg/k8s/pvc_test.go b/pkg/k8s/pvc_test.go index bc7b8a3..fdbcba4 100644 --- a/pkg/k8s/pvc_test.go +++ b/pkg/k8s/pvc_test.go @@ -23,11 +23,17 @@ func (s *TestSuite) TestCreatePersistentVolumeClaim() { expectedErr error }{ { - name: "successful creation", - pvcName: "test-pvc", - labels: map[string]string{"app": "test"}, - size: resource.MustParse("1Gi"), - setupMock: func() {}, + name: "successful creation", + pvcName: "test-pvc", + labels: map[string]string{"app": "test"}, + size: resource.MustParse("1Gi"), + setupMock: func() { + s.client.Clientset().(*fake.Clientset). + PrependReactor("patch", "persistentvolumeclaims", + func(action k8stesting.Action) (handled bool, ret runtime.Object, err error) { + return true, nil, nil + }) + }, expectedErr: nil, }, { @@ -37,7 +43,7 @@ func (s *TestSuite) TestCreatePersistentVolumeClaim() { size: resource.MustParse("1Gi"), setupMock: func() { s.client.Clientset().(*fake.Clientset). - PrependReactor("create", "persistentvolumeclaims", + PrependReactor("patch", "persistentvolumeclaims", func(action k8stesting.Action) (handled bool, ret runtime.Object, err error) { return true, nil, errInternalServerError }) diff --git a/pkg/k8s/replicaset.go b/pkg/k8s/replicaset.go index 243d56b..6f0ccf4 100644 --- a/pkg/k8s/replicaset.go +++ b/pkg/k8s/replicaset.go @@ -9,6 +9,9 @@ import ( v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + applyv1 "k8s.io/client-go/applyconfigurations/apps/v1" + corev1 "k8s.io/client-go/applyconfigurations/core/v1" + applymetav1 "k8s.io/client-go/applyconfigurations/meta/v1" "k8s.io/utils/ptr" ) @@ -29,14 +32,20 @@ func (c *Client) CreateReplicaSet(ctx context.Context, rsConfig ReplicaSetConfig return nil, err } rsConfig.Namespace = c.namespace - rs := c.prepareReplicaSet(rsConfig, init) + newRs := c.prepareReplicaSet(rsConfig, init) - createdRs, err := c.clientset.AppsV1().ReplicaSets(c.namespace).Create(ctx, rs, metav1.CreateOptions{}) - if err != nil { - return nil, ErrCreatingReplicaSet.Wrap(err) + existingRS, err := c.clientset.AppsV1().ReplicaSets(c.namespace).Get(ctx, rsConfig.Name, metav1.GetOptions{}) + if err == nil { + newRs.Spec.Selector = applymetav1.LabelSelector().WithMatchLabels(existingRS.Spec.Selector.MatchLabels) + newRs.Spec.Template.Labels = existingRS.Spec.Template.Labels + newRs.Spec.Template.Annotations = existingRS.Spec.Template.Annotations + + } else if !errors.IsNotFound(err) { + return nil, err } - return createdRs, nil + return c.clientset.AppsV1().ReplicaSets(c.namespace). + Apply(ctx, newRs, metav1.ApplyOptions{FieldManager: FieldManager}) } func (c *Client) ReplaceReplicaSetWithGracePeriod(ctx context.Context, ReplicaSetConfig ReplicaSetConfig, gracePeriod *int64) (*appv1.ReplicaSet, error) { @@ -159,27 +168,23 @@ func (c *Client) waitForReplicaSetDeletion(ctx context.Context, name string) err } // preparePod prepares a pod configuration. -func (c *Client) prepareReplicaSet(rsConf ReplicaSetConfig, init bool) *appv1.ReplicaSet { - rs := &appv1.ReplicaSet{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: rsConf.Namespace, - Name: rsConf.Name, - Labels: rsConf.Labels, - }, - Spec: appv1.ReplicaSetSpec{ - Replicas: &rsConf.Replicas, - Selector: &metav1.LabelSelector{MatchLabels: rsConf.Labels}, - Template: v1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: rsConf.Namespace, - Name: rsConf.Name, - Labels: rsConf.Labels, - Annotations: rsConf.PodConfig.Annotations, - }, - Spec: c.preparePodSpec(rsConf.PodConfig, init), - }, - }, - } +func (c *Client) prepareReplicaSet(rsConf ReplicaSetConfig, init bool) *applyv1.ReplicaSetApplyConfiguration { + rs := applyv1.ReplicaSet(rsConf.Name, rsConf.Namespace). + WithLabels(rsConf.Labels). + WithAPIVersion("apps/v1"). + WithKind("ReplicaSet"). + WithSpec(applyv1.ReplicaSetSpec(). + WithReplicas(rsConf.Replicas). + WithSelector(applymetav1.LabelSelector(). + WithMatchLabels(rsConf.Labels), + ). + WithTemplate( + corev1.PodTemplateSpec(). + WithLabels(rsConf.Labels). + WithAnnotations(rsConf.PodConfig.Annotations). + WithSpec(c.preparePodSpec(rsConf.PodConfig, init)), + ), + ) c.logger.WithFields(logrus.Fields{ "name": rsConf.Name, diff --git a/pkg/k8s/replicaset_test.go b/pkg/k8s/replicaset_test.go index 03e89df..f98c388 100644 --- a/pkg/k8s/replicaset_test.go +++ b/pkg/k8s/replicaset_test.go @@ -2,6 +2,7 @@ package k8s_test import ( "context" + "fmt" appv1 "k8s.io/api/apps/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -35,8 +36,23 @@ func (s *TestSuite) TestCreateReplicaSet() { ContainerConfig: testContainerConfig, }, }, - init: false, - setupMock: func() {}, + init: false, + setupMock: func() { + s.client.Clientset().(*fake.Clientset). + PrependReactor("patch", "replicasets", + func(action k8stesting.Action) (handled bool, ret runtime.Object, err error) { + patchAction, ok := action.(k8stesting.PatchAction) + if !ok { + return false, nil, fmt.Errorf("expected PatchAction, got %T", action) + } + return true, &appv1.ReplicaSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: patchAction.GetName(), + Namespace: patchAction.GetNamespace(), + }, + }, nil + }) + }, expectedErr: nil, }, { @@ -56,12 +72,14 @@ func (s *TestSuite) TestCreateReplicaSet() { init: false, setupMock: func() { s.client.Clientset().(*fake.Clientset). - PrependReactor("create", "replicasets", + // we need to `patch` the replica set because the `apply` does not exist + // and `apply` calls `patch` under the hood + PrependReactor("patch", "replicasets", func(action k8stesting.Action) (handled bool, ret runtime.Object, err error) { return true, nil, errInternalServerError }) }, - expectedErr: k8s.ErrCreatingReplicaSet.Wrap(errInternalServerError), + expectedErr: errInternalServerError, }, } @@ -109,6 +127,21 @@ func (s *TestSuite) TestReplaceReplicaSetWithGracePeriod() { setupMock: func() { err := s.createReplicaSet("test-rs") s.Require().NoError(err) + + s.client.Clientset().(*fake.Clientset). + PrependReactor("patch", "replicasets", + func(action k8stesting.Action) (handled bool, ret runtime.Object, err error) { + patchAction, ok := action.(k8stesting.PatchAction) + if !ok { + return false, nil, fmt.Errorf("expected PatchAction, got %T", action) + } + return true, &appv1.ReplicaSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: patchAction.GetName(), + Namespace: patchAction.GetNamespace(), + }, + }, nil + }) }, expectedErr: nil, }, @@ -184,6 +217,21 @@ func (s *TestSuite) TestReplaceReplicaSet() { setupMock: func() { err := s.createReplicaSet("test-rs") s.Require().NoError(err) + + s.client.Clientset().(*fake.Clientset). + PrependReactor("patch", "replicasets", + func(action k8stesting.Action) (handled bool, ret runtime.Object, err error) { + patchAction, ok := action.(k8stesting.PatchAction) + if !ok { + return false, nil, fmt.Errorf("expected PatchAction, got %T", action) + } + return true, &appv1.ReplicaSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: patchAction.GetName(), + Namespace: patchAction.GetNamespace(), + }, + }, nil + }) }, expectedErr: nil, }, diff --git a/pkg/k8s/role.go b/pkg/k8s/role.go index ba5a805..b7420e2 100644 --- a/pkg/k8s/role.go +++ b/pkg/k8s/role.go @@ -4,7 +4,7 @@ import ( "context" rbacv1 "k8s.io/api/rbac/v1" - "k8s.io/apimachinery/pkg/api/errors" + apierrs "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -37,6 +37,9 @@ func (c *Client) CreateRole( } _, err := c.clientset.RbacV1().Roles(c.namespace).Create(ctx, role, metav1.CreateOptions{}) + if apierrs.IsAlreadyExists(err) { + return ErrRoleAlreadyExists.WithParams(name).Wrap(err) + } return err } @@ -63,11 +66,6 @@ func (c *Client) CreateClusterRole( return err } - _, err := c.clientset.RbacV1().ClusterRoles().Get(ctx, name, metav1.GetOptions{}) - if err == nil || !errors.IsNotFound(err) { - return ErrClusterRoleAlreadyExists.WithParams(name).Wrap(err) - } - role := &rbacv1.ClusterRole{ ObjectMeta: metav1.ObjectMeta{ Name: name, @@ -75,7 +73,10 @@ func (c *Client) CreateClusterRole( }, Rules: policyRules, } - _, err = c.clientset.RbacV1().ClusterRoles().Create(ctx, role, metav1.CreateOptions{}) + _, err := c.clientset.RbacV1().ClusterRoles().Create(ctx, role, metav1.CreateOptions{}) + if apierrs.IsAlreadyExists(err) { + return ErrClusterRoleAlreadyExists.WithParams(name).Wrap(err) + } return err } diff --git a/pkg/k8s/role_test.go b/pkg/k8s/role_test.go index 233ed60..f87e98c 100644 --- a/pkg/k8s/role_test.go +++ b/pkg/k8s/role_test.go @@ -7,8 +7,6 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/kubernetes/fake" k8stesting "k8s.io/client-go/testing" - - "github.com/celestiaorg/knuu/pkg/k8s" ) func (s *TestSuite) TestCreateRole() { @@ -156,18 +154,13 @@ func (s *TestSuite) TestCreateClusterRole() { }, }, setupMock: func() { - s.client.Clientset().(*fake.Clientset). - PrependReactor("get", "clusterroles", - func(action k8stesting.Action) (handled bool, ret runtime.Object, err error) { - return true, nil, nil - }) s.client.Clientset().(*fake.Clientset). PrependReactor("create", "clusterroles", func(action k8stesting.Action) (handled bool, ret runtime.Object, err error) { return true, nil, errInternalServerError }) }, - expectedErr: k8s.ErrClusterRoleAlreadyExists.WithParams("error-cluster-role").Wrap(errInternalServerError), + expectedErr: errInternalServerError, }, } diff --git a/pkg/k8s/rolebinding.go b/pkg/k8s/rolebinding.go index 760821f..ba83682 100644 --- a/pkg/k8s/rolebinding.go +++ b/pkg/k8s/rolebinding.go @@ -4,7 +4,7 @@ import ( "context" rbacv1 "k8s.io/api/rbac/v1" - "k8s.io/apimachinery/pkg/api/errors" + apierrs "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -50,6 +50,9 @@ func (c *Client) CreateRoleBinding( } _, err := c.clientset.RbacV1().RoleBindings(c.namespace).Create(ctx, rb, metav1.CreateOptions{}) + if apierrs.IsAlreadyExists(err) { + return ErrRoleBindingAlreadyExists.WithParams(name).Wrap(err) + } return err } @@ -79,11 +82,6 @@ func (c *Client) CreateClusterRoleBinding( return err } - _, err := c.clientset.RbacV1().ClusterRoleBindings().Get(ctx, name, metav1.GetOptions{}) - if err == nil || !errors.IsNotFound(err) { - return ErrClusterRoleBindingAlreadyExists.WithParams(name).Wrap(err) - } - role := &rbacv1.ClusterRoleBinding{ ObjectMeta: metav1.ObjectMeta{ Name: name, @@ -103,7 +101,10 @@ func (c *Client) CreateClusterRoleBinding( }, } - _, err = c.clientset.RbacV1().ClusterRoleBindings().Create(ctx, role, metav1.CreateOptions{}) + _, err := c.clientset.RbacV1().ClusterRoleBindings().Create(ctx, role, metav1.CreateOptions{}) + if apierrs.IsAlreadyExists(err) { + return ErrClusterRoleBindingAlreadyExists.WithParams(name).Wrap(err) + } return err } diff --git a/pkg/k8s/rolebinding_test.go b/pkg/k8s/rolebinding_test.go index 5e328bb..f532afc 100644 --- a/pkg/k8s/rolebinding_test.go +++ b/pkg/k8s/rolebinding_test.go @@ -3,7 +3,6 @@ package k8s_test import ( "context" - rbacv1 "k8s.io/api/rbac/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/kubernetes/fake" k8stesting "k8s.io/client-go/testing" @@ -138,11 +137,7 @@ func (s *TestSuite) TestCreateClusterRoleBinding() { clusterRole: "existing-clusterrole", serviceAccount: "existing-sa", setupMock: func() { - s.client.Clientset().(*fake.Clientset). - PrependReactor("get", "clusterrolebindings", - func(action k8stesting.Action) (handled bool, ret runtime.Object, err error) { - return true, &rbacv1.ClusterRoleBinding{}, nil - }) + s.createClusterRoleBinding("existing-clusterrolebinding", map[string]string{"app": "existing"}, "existing-clusterrole", "existing-sa") }, expectedErr: k8s.ErrClusterRoleBindingAlreadyExists.WithParams("existing-clusterrolebinding"), }, @@ -154,12 +149,12 @@ func (s *TestSuite) TestCreateClusterRoleBinding() { serviceAccount: "error-sa", setupMock: func() { s.client.Clientset().(*fake.Clientset). - PrependReactor("get", "clusterrolebindings", + PrependReactor("create", "clusterrolebindings", func(action k8stesting.Action) (handled bool, ret runtime.Object, err error) { return true, nil, errInternalServerError }) }, - expectedErr: k8s.ErrClusterRoleBindingAlreadyExists.WithParams("error-clusterrolebinding").Wrap(errInternalServerError), + expectedErr: errInternalServerError, }, } diff --git a/pkg/k8s/serviceaccount.go b/pkg/k8s/serviceaccount.go index 00f5ff9..1f6f365 100644 --- a/pkg/k8s/serviceaccount.go +++ b/pkg/k8s/serviceaccount.go @@ -4,6 +4,7 @@ import ( "context" v1 "k8s.io/api/core/v1" + apierrs "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -27,6 +28,9 @@ func (c *Client) CreateServiceAccount(ctx context.Context, name string, labels m } _, err := c.clientset.CoreV1().ServiceAccounts(c.namespace).Create(ctx, sa, metav1.CreateOptions{}) + if apierrs.IsAlreadyExists(err) { + return ErrServiceAccountAlreadyExists.WithParams(name).Wrap(err) + } return err } diff --git a/pkg/k8s/test_suite_test.go b/pkg/k8s/test_suite_test.go index c03a4f9..1273c8c 100644 --- a/pkg/k8s/test_suite_test.go +++ b/pkg/k8s/test_suite_test.go @@ -10,6 +10,7 @@ import ( appv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" netv1 "k8s.io/api/networking/v1" + rbacv1 "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" discfake "k8s.io/client-go/discovery/fake" @@ -95,3 +96,22 @@ func (s *TestSuite) createNetworkPolicy(name string) error { }, metav1.CreateOptions{}) return err } + +func (s *TestSuite) createClusterRoleBinding(name string, labels map[string]string, clusterRole string, serviceAccount string) error { + _, err := s.client.Clientset().RbacV1().ClusterRoleBindings(). + Create(context.Background(), &rbacv1.ClusterRoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Labels: labels, + }, + RoleRef: rbacv1.RoleRef{ + Kind: "ClusterRole", + Name: clusterRole, + APIGroup: rbacv1.GroupName, + }, + Subjects: []rbacv1.Subject{ + {Kind: "ServiceAccount", Name: serviceAccount}, + }, + }, metav1.CreateOptions{}) + return err +} diff --git a/pkg/knuu/errors.go b/pkg/knuu/errors.go index 99e4032..b3ede23 100644 --- a/pkg/knuu/errors.go +++ b/pkg/knuu/errors.go @@ -20,9 +20,6 @@ var ( ErrDeployingService = errors.New("DeployingService", "error deploying service '%s'") ErrGettingService = errors.New("GettingService", "error getting service '%s'") ErrPatchingService = errors.New("PatchingService", "error patching service '%s'") - ErrFailedToCreateServiceAccount = errors.New("FailedToCreateServiceAccount", "failed to create service account") - ErrFailedToCreateRole = errors.New("FailedToCreateRole", "failed to create role") - ErrFailedToCreateRoleBinding = errors.New("FailedToCreateRoleBinding", "failed to create role binding") ErrFailedToDeployPod = errors.New("FailedToDeployPod", "failed to deploy pod") ErrFailedToDeletePod = errors.New("FailedToDeletePod", "failed to delete pod") ErrFailedToDeleteServiceAccount = errors.New("FailedToDeleteServiceAccount", "failed to delete service account") diff --git a/pkg/knuu/knuu.go b/pkg/knuu/knuu.go index 4c4ac0c..a7fde53 100644 --- a/pkg/knuu/knuu.go +++ b/pkg/knuu/knuu.go @@ -41,6 +41,7 @@ type Knuu struct { *system.SystemDependencies stopMu sync.Mutex clusterDomain string + skipCleanup bool } type Options struct { @@ -52,6 +53,7 @@ type Options struct { Timeout time.Duration Logger *logrus.Logger ClusterDomain string // optional, if not set, "cluster.local" will be used + SkipCleanup bool } func New(ctx context.Context, opts Options) (*Knuu, error) { @@ -69,6 +71,7 @@ func New(ctx context.Context, opts Options) (*Knuu, error) { StartTime: time.Now().UTC().Format(TimeFormat), }, clusterDomain: opts.ClusterDomain, + skipCleanup: opts.SkipCleanup, } if err := setDefaults(ctx, k); err != nil { @@ -92,6 +95,10 @@ func New(ctx context.Context, opts Options) (*Knuu, error) { } func (k *Knuu) CleanUp(ctx context.Context) error { + if k.skipCleanup { + k.Logger.Info("skipping cleanup") + return nil + } return k.K8sClient.DeleteNamespace(ctx, k.Scope) } diff --git a/pkg/traefik/traefik.go b/pkg/traefik/traefik.go index e273bdc..0232f72 100644 --- a/pkg/traefik/traefik.go +++ b/pkg/traefik/traefik.go @@ -2,6 +2,7 @@ package traefik import ( "context" + "errors" "fmt" "time" @@ -52,7 +53,9 @@ func (t *Traefik) Deploy(ctx context.Context) error { } if err := t.K8sClient.CreateServiceAccount(ctx, serviceAccountName, nil); err != nil { - return ErrFailedToCreateServiceAccount.Wrap(err) + if !errors.Is(err, k8s.ErrServiceAccountAlreadyExists) { + return ErrFailedToCreateServiceAccount.Wrap(err) + } } clusterRoleName := k8s.SanitizeName(t.K8sClient.Namespace() + "-" + roleName)