From 7d90326e82412a34b8a9815688f031f84cb6539a Mon Sep 17 00:00:00 2001 From: Mojtaba Date: Mon, 15 Jul 2024 09:19:22 +0330 Subject: [PATCH 1/6] chore: rename TestScope field --- e2e/basic/suite_setup_test.go | 2 +- e2e/bittwister/suite_setup_test.go | 2 +- e2e/system/build_from_git_test.go | 2 +- e2e/tshark/tshark_test.go | 4 ++-- pkg/instance/helper.go | 2 +- pkg/knuu/errors.go | 4 ++-- pkg/knuu/knuu.go | 30 +++++++++++++----------------- pkg/knuu/knuu_old.go | 4 ++-- pkg/knuu/knuu_test.go | 26 +++++++++++++------------- pkg/preloader/preloader.go | 2 +- pkg/system/dependencies.go | 2 +- 11 files changed, 38 insertions(+), 42 deletions(-) diff --git a/e2e/basic/suite_setup_test.go b/e2e/basic/suite_setup_test.go index f2a0ec0..39ac31f 100644 --- a/e2e/basic/suite_setup_test.go +++ b/e2e/basic/suite_setup_test.go @@ -21,7 +21,7 @@ func (s *TestSuite) SetupSuite() { ctx = context.Background() ) s.Knuu, err = knuu.New(ctx, knuu.Options{ - TestScope: "e2e-basic", + Scope: "e2e-basic", }) s.Require().NoError(err) s.Knuu.HandleStopSignal(ctx) diff --git a/e2e/bittwister/suite_setup_test.go b/e2e/bittwister/suite_setup_test.go index 213fe88..1b2681a 100644 --- a/e2e/bittwister/suite_setup_test.go +++ b/e2e/bittwister/suite_setup_test.go @@ -23,7 +23,7 @@ func (s *Suite) SetupSuite() { ProxyEnabled: true, }) s.Require().NoError(err) - s.T().Logf("Scope: %s", s.Knuu.Scope()) + s.T().Logf("Scope: %s", s.Knuu.Scope) s.Knuu.HandleStopSignal(ctx) } diff --git a/e2e/system/build_from_git_test.go b/e2e/system/build_from_git_test.go index d458311..6e283e5 100644 --- a/e2e/system/build_from_git_test.go +++ b/e2e/system/build_from_git_test.go @@ -71,7 +71,7 @@ func TestBuildFromGitWithModifications(t *testing.T) { logger := logrus.New() - k8sClient, err := k8s.NewClient(ctx, knuu.DefaultTestScope(), logger) + k8sClient, err := k8s.NewClient(ctx, knuu.DefaultScope(), logger) require.NoError(t, err, "Error creating k8s client") // Since we are modifying the git repo, diff --git a/e2e/tshark/tshark_test.go b/e2e/tshark/tshark_test.go index 9d1865c..780d581 100644 --- a/e2e/tshark/tshark_test.go +++ b/e2e/tshark/tshark_test.go @@ -35,7 +35,7 @@ func TestTshark(t *testing.T) { ctx := context.Background() logger := logrus.New() - k8sClient, err := k8s.NewClient(ctx, knuu.DefaultTestScope(), logger) + k8sClient, err := k8s.NewClient(ctx, knuu.DefaultScope(), logger) require.NoError(t, err, "error creating k8s client") minioClient, err := minio.New(ctx, k8sClient, logger) @@ -50,7 +50,7 @@ func TestTshark(t *testing.T) { } }() - scope := kn.Scope() + scope := kn.Scope t.Logf("Test scope: %s", scope) target, err := kn.NewInstance("busybox") diff --git a/pkg/instance/helper.go b/pkg/instance/helper.go index d81efa0..5cb6630 100644 --- a/pkg/instance/helper.go +++ b/pkg/instance/helper.go @@ -78,7 +78,7 @@ func (i *Instance) getLabels() map[string]string { return map[string]string{ labelAppKey: i.k8sName, labelManagedByKey: labelKnuuValue, - labelScopeKey: i.TestScope, + labelScopeKey: i.Scope, labelTestStartedKey: i.StartTime, labelNameKey: i.name, labelK8sNameKey: i.k8sName, diff --git a/pkg/knuu/errors.go b/pkg/knuu/errors.go index dbc55c2..b620420 100644 --- a/pkg/knuu/errors.go +++ b/pkg/knuu/errors.go @@ -205,8 +205,8 @@ var ( ErrCannotGetTraefikEndpoint = errors.New("CannotGetTraefikEndpoint", "cannot get traefik endpoint") ErrGettingProxyURL = errors.New("GettingProxyURL", "error getting proxy URL for service '%s'") ErrTraefikAPINotAvailable = errors.New("TraefikAPINotAvailable", "traefik API is not available") - ErrTestScopeNotSet = errors.New("TestScopeNotSet", "test scope is not set") + ErrScopeNotSet = errors.New("ScopeNotSet", "test scope is not set") ErrK8sClientNotSet = errors.New("K8sClientNotSet", "k8s client is not set") - ErrTestScopeMistMatch = errors.New("TestScopeMistMatch", "test scope '%s' set in options does not match scope '%s' set by the k8sClient namespace") + ErrScopeMistMatch = errors.New("ScopeMistMatch", "scope '%s' set in options does not match scope '%s' set by the k8sClient namespace") ErrHandleTimeout = errors.New("HandleTimeout", "error starting handle timeout") ) diff --git a/pkg/knuu/knuu.go b/pkg/knuu/knuu.go index eda6970..7490109 100644 --- a/pkg/knuu/knuu.go +++ b/pkg/knuu/knuu.go @@ -41,7 +41,7 @@ type Options struct { K8sClient k8s.KubeManager MinioClient *minio.Minio ImageBuilder builder.Builder - TestScope string + Scope string ProxyEnabled bool Timeout time.Duration Logger *logrus.Logger @@ -58,7 +58,7 @@ func New(ctx context.Context, opts Options) (*Knuu, error) { MinioClient: opts.MinioClient, ImageBuilder: opts.ImageBuilder, Logger: opts.Logger, - TestScope: opts.TestScope, + Scope: opts.Scope, StartTime: time.Now().UTC().Format(TimeFormat), }, timeout: opts.Timeout, @@ -77,12 +77,8 @@ func New(ctx context.Context, opts Options) (*Knuu, error) { return k, nil } -func (k *Knuu) Scope() string { - return k.TestScope -} - func (k *Knuu) CleanUp(ctx context.Context) error { - return k.K8sClient.DeleteNamespace(ctx, k.TestScope) + return k.K8sClient.DeleteNamespace(ctx, k.Scope) } func (k *Knuu) HandleStopSignal(ctx context.Context) { @@ -121,7 +117,7 @@ func (k *Knuu) handleTimeout(ctx context.Context) error { // and then deletes them. This is useful for cleaning up specific test resources before proceeding to delete the namespace. commands = append(commands, fmt.Sprintf("kubectl get all,pvc,netpol,roles,serviceaccounts,rolebindings,configmaps -l knuu.sh/scope=%s -n %s -o json | jq -r '.items[] | select(.metadata.labels.\"knuu.sh/type\" != \"%s\") | \"\\(.kind)/\\(.metadata.name)\"' | xargs -r kubectl delete -n %s", - k.TestScope, k.K8sClient.Namespace(), instance.TimeoutHandlerInstance.String(), k.K8sClient.Namespace())) + k.Scope, k.K8sClient.Namespace(), instance.TimeoutHandlerInstance.String(), k.K8sClient.Namespace())) // Delete the namespace as it was created by knuu. k.Logger.Debugf("The namespace generated [%s] will be deleted", k.K8sClient.Namespace()) @@ -129,7 +125,7 @@ func (k *Knuu) handleTimeout(ctx context.Context) error { // Delete all labeled resources within the namespace. // Unlike the previous command that excludes certain types, this command ensures that everything remaining is deleted. - commands = append(commands, fmt.Sprintf("kubectl delete all,pvc,netpol,roles,serviceaccounts,rolebindings,configmaps -l knuu.sh/scope=%s -n %s", k.TestScope, k.K8sClient.Namespace())) + commands = append(commands, fmt.Sprintf("kubectl delete all,pvc,netpol,roles,serviceaccounts,rolebindings,configmaps -l knuu.sh/scope=%s -n %s", k.Scope, k.K8sClient.Namespace())) finalCmd := strings.Join(commands, " && ") @@ -155,7 +151,7 @@ func (k *Knuu) handleTimeout(ctx context.Context) error { return nil } -func DefaultTestScope() string { +func DefaultScope() string { t := time.Now() return fmt.Sprintf("%s-%03d", t.Format("20060102-150405"), t.Nanosecond()/1e6) } @@ -167,8 +163,8 @@ func validateOptions(opts Options) error { return ErrK8sClientNotSet } - if opts.TestScope != "" && opts.K8sClient != nil && opts.TestScope != opts.K8sClient.Namespace() { - return ErrTestScopeMistMatch.WithParams(opts.TestScope, opts.K8sClient.Namespace()) + if opts.Scope != "" && opts.K8sClient != nil && opts.Scope != opts.K8sClient.Namespace() { + return ErrScopeMistMatch.WithParams(opts.Scope, opts.K8sClient.Namespace()) } return nil } @@ -178,14 +174,14 @@ func setDefaults(ctx context.Context, k *Knuu) error { k.Logger = log.DefaultLogger() } - if k.TestScope == "" { + if k.Scope == "" { if k.K8sClient != nil { - k.TestScope = k.K8sClient.Namespace() + k.Scope = k.K8sClient.Namespace() } else { - k.TestScope = DefaultTestScope() + k.Scope = DefaultScope() } } - k.TestScope = k8s.SanitizeName(k.TestScope) + k.Scope = k8s.SanitizeName(k.Scope) if k.timeout == 0 { k.timeout = defaultTimeout @@ -193,7 +189,7 @@ func setDefaults(ctx context.Context, k *Knuu) error { if k.K8sClient == nil { var err error - k.K8sClient, err = k8s.NewClient(ctx, k.TestScope, k.Logger) + k.K8sClient, err = k8s.NewClient(ctx, k.Scope, k.Logger) if err != nil { return ErrCannotInitializeK8s.Wrap(err) } diff --git a/pkg/knuu/knuu_old.go b/pkg/knuu/knuu_old.go index 341f109..ca2439e 100644 --- a/pkg/knuu/knuu_old.go +++ b/pkg/knuu/knuu_old.go @@ -43,7 +43,7 @@ func Scope() string { if tmpKnuu == nil { return "" } - return tmpKnuu.Scope() + return tmpKnuu.Scope } // Deprecated: Use the new package knuu instead. @@ -87,7 +87,7 @@ func InitializeWithScope(testScope string) error { tmpKnuu, err = New(ctx, Options{ K8sClient: k8sClient, - TestScope: testScope, + Scope: testScope, Timeout: timeout, ProxyEnabled: true, MinioClient: minioClient, diff --git a/pkg/knuu/knuu_test.go b/pkg/knuu/knuu_test.go index 3e5b521..dbe84b5 100644 --- a/pkg/knuu/knuu_test.go +++ b/pkg/knuu/knuu_test.go @@ -73,7 +73,7 @@ func TestNew(t *testing.T) { assert.NotNil(t, k.Logger) assert.NotNil(t, k.K8sClient) assert.NotNil(t, k.ImageBuilder) - assert.NotEmpty(t, k.TestScope) + assert.NotEmpty(t, k.Scope) assert.Equal(t, defaultTimeout, k.timeout) }, }, @@ -98,8 +98,8 @@ func TestNew(t *testing.T) { { name: "With custom Logger", options: Options{ - TestScope: "test", - Logger: &logrus.Logger{}, + Scope: "test", + Logger: &logrus.Logger{}, }, expectedError: nil, validateFunc: func(t *testing.T, k *Knuu) { @@ -110,8 +110,8 @@ func TestNew(t *testing.T) { { name: "With custom Timeout", options: Options{ - TestScope: "test", - Timeout: 30 * time.Minute, + Scope: "test", + Timeout: 30 * time.Minute, }, expectedError: nil, validateFunc: func(t *testing.T, k *Knuu) { @@ -122,7 +122,7 @@ func TestNew(t *testing.T) { { name: "With custom Image Builder", options: Options{ - TestScope: "test", + Scope: "test", ImageBuilder: &kaniko.Kaniko{}, }, expectedError: nil, @@ -132,14 +132,14 @@ func TestNew(t *testing.T) { }, }, { - name: "With K8sClient but without TestScope", + name: "With K8sClient but without Scope", options: Options{ K8sClient: &mockK8s{}, }, expectedError: nil, validateFunc: func(t *testing.T, k *Knuu) { assert.NotNil(t, k) - assert.Equal(t, "test", k.TestScope) + assert.Equal(t, "test", k.Scope) }, }, } @@ -181,20 +181,20 @@ func TestValidateOptions(t *testing.T) { expectedErr: nil, }, { - name: "TestScope and K8sClient not set", + name: "Scope and K8sClient not set", options: Options{ - TestScope: "", + Scope: "", K8sClient: nil, }, expectedErr: nil, }, { - name: "TestScope does not match K8sClient namespace", + name: "Scope does not match K8sClient namespace", options: Options{ - TestScope: "another_scope", + Scope: "another_scope", K8sClient: &mockK8s{}, }, - expectedErr: ErrTestScopeMistMatch.WithParams("another_scope", "test"), + expectedErr: ErrScopeMistMatch.WithParams("another_scope", "test"), }, { name: "No options set", diff --git a/pkg/preloader/preloader.go b/pkg/preloader/preloader.go index a297e11..b60f782 100644 --- a/pkg/preloader/preloader.go +++ b/pkg/preloader/preloader.go @@ -113,7 +113,7 @@ func (p *Preloader) preloadImages(ctx context.Context) error { labels := map[string]string{ labelApp: p.K8sName, labelManagedBy: managedByLabel, - labelScope: p.TestScope, + labelScope: p.Scope, labelTestStarted: p.StartTime, } diff --git a/pkg/system/dependencies.go b/pkg/system/dependencies.go index aea1ae0..524ed52 100644 --- a/pkg/system/dependencies.go +++ b/pkg/system/dependencies.go @@ -15,6 +15,6 @@ type SystemDependencies struct { MinioClient *minio.Minio Logger *logrus.Logger Proxy *traefik.Traefik - TestScope string + Scope string StartTime string } From aff7ad58adaa2b156f67d4dff31ab23eb59b67e8 Mon Sep 17 00:00:00 2001 From: Mojtaba Date: Mon, 15 Jul 2024 10:45:57 +0330 Subject: [PATCH 2/6] chore: bump k8s version to fix the DOS Vulnerability --- go.mod | 11 +++++------ go.sum | 22 ++++++++++++---------- pkg/k8s/pvc.go | 2 +- pkg/minio/minio.go | 2 +- 4 files changed, 19 insertions(+), 18 deletions(-) diff --git a/go.mod b/go.mod index b6102b5..15667f8 100644 --- a/go.mod +++ b/go.mod @@ -6,14 +6,13 @@ 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/joho/godotenv v1.5.1 github.com/minio/minio-go/v7 v7.0.73 github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.9.0 gopkg.in/yaml.v3 v3.0.1 - k8s.io/api v0.28.2 - k8s.io/apimachinery v0.28.2 - k8s.io/client-go v0.28.2 + k8s.io/api v0.30.2 + k8s.io/apimachinery v0.30.2 + k8s.io/client-go v0.30.2 k8s.io/utils v0.0.0-20230726121419-3b25d923346b ) @@ -45,6 +44,7 @@ require ( github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 // indirect github.com/gorilla/handlers v1.5.2 // indirect github.com/gorilla/mux v1.8.1 // indirect + github.com/gorilla/websocket v1.5.0 // indirect 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 @@ -59,8 +59,7 @@ require ( 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/onsi/ginkgo/v2 v2.15.0 // indirect - github.com/onsi/gomega v1.30.0 // indirect + github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // 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 diff --git a/go.sum b/go.sum index eabe075..f799290 100644 --- a/go.sum +++ b/go.sum @@ -91,12 +91,12 @@ github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkM github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= 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/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= -github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= 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= @@ -137,10 +137,12 @@ 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/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.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8= -github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= +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= @@ -326,12 +328,12 @@ 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.28.2 h1:9mpl5mOb6vXZvqbQmankOfPIGiudghwCoLl1EYfUZbw= -k8s.io/api v0.28.2/go.mod h1:RVnJBsjU8tcMq7C3iaRSGMeaKt2TWEUXcpIt/90fjEg= -k8s.io/apimachinery v0.28.2 h1:KCOJLrc6gu+wV1BYgwik4AF4vXOlVJPdiqn0yAWWwXQ= -k8s.io/apimachinery v0.28.2/go.mod h1:RdzF87y/ngqk9H4z3EL2Rppv5jj95vGS/HaFXrLDApU= -k8s.io/client-go v0.28.2 h1:DNoYI1vGq0slMBN/SWKMZMw0Rq+0EQW6/AK4v9+3VeY= -k8s.io/client-go v0.28.2/go.mod h1:sMkApowspLuc7omj1FOSUxSoqjr+d5Q0Yc0LOFnYFJY= +k8s.io/api v0.30.2 h1:+ZhRj+28QT4UOH+BKznu4CBgPWgkXO7XAvMcMl0qKvI= +k8s.io/api v0.30.2/go.mod h1:ULg5g9JvOev2dG0u2hig4Z7tQ2hHIuS+m8MNZ+X6EmI= +k8s.io/apimachinery v0.30.2 h1:fEMcnBj6qkzzPGSVsAZtQThU62SmQ4ZymlXRC5yFSCg= +k8s.io/apimachinery v0.30.2/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc= +k8s.io/client-go v0.30.2 h1:sBIVJdojUNPDU/jObC+18tXWcTJVcwyqS9diGdWHk50= +k8s.io/client-go v0.30.2/go.mod h1:JglKSWULm9xlJLx4KCkfLLQ7XwtlbflV6uFFSHTMgVs= k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= diff --git a/pkg/k8s/pvc.go b/pkg/k8s/pvc.go index 3e27cbd..57e1653 100644 --- a/pkg/k8s/pvc.go +++ b/pkg/k8s/pvc.go @@ -26,7 +26,7 @@ func (c *Client) CreatePersistentVolumeClaim( AccessModes: []v1.PersistentVolumeAccessMode{ v1.ReadWriteOnce, }, - Resources: v1.ResourceRequirements{ + Resources: v1.VolumeResourceRequirements{ Requests: v1.ResourceList{ v1.ResourceStorage: size, }, diff --git a/pkg/minio/minio.go b/pkg/minio/minio.go index ad77c50..4df794f 100644 --- a/pkg/minio/minio.go +++ b/pkg/minio/minio.go @@ -451,7 +451,7 @@ func (m *Minio) createPVC(ctx context.Context, pvcName string, storageSize resou }, Spec: v1.PersistentVolumeClaimSpec{ AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce}, - Resources: v1.ResourceRequirements{ + Resources: v1.VolumeResourceRequirements{ Requests: v1.ResourceList{ v1.ResourceStorage: storageSize, }, From 57626644133649e4b06055121b83a567af640ad6 Mon Sep 17 00:00:00 2001 From: Mojtaba Date: Tue, 16 Jul 2024 08:38:24 +0330 Subject: [PATCH 3/6] chore: bumped go version to fix it --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 15667f8..3d6ccd6 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/celestiaorg/knuu -go 1.22.4 +go 1.22.5 require ( github.com/celestiaorg/bittwister v0.0.0-20231213180407-65cdbaf5b8c7 From 71f402f1df82e5b895ecd6ac9bf62b3ab5598597 Mon Sep 17 00:00:00 2001 From: Mojtaba Date: Tue, 16 Jul 2024 10:40:07 +0330 Subject: [PATCH 4/6] chore: deprecate Executor --- e2e/assert_cleanups.go | 2 +- e2e/basic/probe_test.go | 6 ++- e2e/executor.go | 53 ++++++++++++++++++ e2e/system/env_to_json_test.go | 6 ++- e2e/system/external_file_test.go | 6 ++- e2e/system/file_test.go | 5 +- e2e/system/file_test_image_cached_test.go | 3 +- e2e/system/files_to_volumes_cm_test.go | 11 ++-- e2e/system/folder_test.go | 5 +- e2e/system/folder_test_image_cached_test.go | 3 +- pkg/instance/executor.go | 59 --------------------- pkg/instance/instance.go | 6 +-- pkg/instance/type.go | 3 -- pkg/instance/type_test.go | 5 -- pkg/knuu/errors.go | 1 + pkg/knuu/instance.go | 6 --- pkg/knuu/instance_old.go | 15 +----- 17 files changed, 86 insertions(+), 109 deletions(-) create mode 100644 e2e/executor.go delete mode 100644 pkg/instance/executor.go diff --git a/e2e/assert_cleanups.go b/e2e/assert_cleanups.go index 179b8b2..b956eeb 100644 --- a/e2e/assert_cleanups.go +++ b/e2e/assert_cleanups.go @@ -20,7 +20,7 @@ func AssertCleanupInstance(t *testing.T, instance *knuu.Instance) error { } // AssertCleanupInstances is a helper function that cleans up a list of instances. -func AssertCleanupInstances(t *testing.T, executor *knuu.Executor, instances []*knuu.Instance) error { +func AssertCleanupInstances(t *testing.T, executor *knuu.Instance, instances []*knuu.Instance) error { if os.Getenv("KNUU_SKIP_CLEANUP") == "true" { t.Log("Skipping cleanup") return nil diff --git a/e2e/basic/probe_test.go b/e2e/basic/probe_test.go index 6f21415..308c853 100644 --- a/e2e/basic/probe_test.go +++ b/e2e/basic/probe_test.go @@ -1,6 +1,7 @@ package basic import ( + "context" "testing" "github.com/stretchr/testify/assert" @@ -8,6 +9,7 @@ import ( v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/util/intstr" + "github.com/celestiaorg/knuu/e2e" "github.com/celestiaorg/knuu/pkg/knuu" ) @@ -15,7 +17,7 @@ func TestProbe(t *testing.T) { t.Parallel() // Setup - executor, err := knuu.NewExecutor() + executor, err := e2e.NewExecutor(context.Background(), "prob-executor") if err != nil { t.Fatalf("Error creating executor: %v", err) } @@ -60,7 +62,7 @@ func TestProbe(t *testing.T) { } t.Cleanup(func() { - require.NoError(t, knuu.BatchDestroy(executor.Instance, web)) + require.NoError(t, knuu.BatchDestroy(executor, web)) }) // Test logic diff --git a/e2e/executor.go b/e2e/executor.go new file mode 100644 index 0000000..df24e6c --- /dev/null +++ b/e2e/executor.go @@ -0,0 +1,53 @@ +package e2e + +import ( + "context" + + "k8s.io/apimachinery/pkg/api/resource" + + "github.com/celestiaorg/knuu/pkg/knuu" +) + +const ( + executorDefaultImage = "docker.io/nicolaka/netshoot:latest" + sleepCommand = "sleep" + infinityArg = "infinity" +) + +var ( + executorMemoryLimit = resource.MustParse("100Mi") + executorCpuLimit = resource.MustParse("100m") +) + +func NewExecutor(ctx context.Context, executorName string) (*knuu.Instance, error) { + i, err := knuu.NewInstance(executorName) + if err != nil { + return nil, err + } + + if err := i.SetImage(executorDefaultImage); err != nil { + return nil, err + } + + if err := i.Commit(); err != nil { + return nil, err + } + + if err := i.SetArgs(sleepCommand, infinityArg); err != nil { + return nil, err + } + + if err := i.SetMemory(executorMemoryLimit.String(), executorMemoryLimit.String()); err != nil { + return nil, err + } + + if err := i.SetCPU(executorCpuLimit.String()); err != nil { + return nil, err + } + + if err := i.Start(); err != nil { + return nil, err + } + + return i, nil +} diff --git a/e2e/system/env_to_json_test.go b/e2e/system/env_to_json_test.go index 75f924f..cfcea33 100644 --- a/e2e/system/env_to_json_test.go +++ b/e2e/system/env_to_json_test.go @@ -1,6 +1,7 @@ package system import ( + "context" "encoding/json" "fmt" "os" @@ -10,6 +11,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/celestiaorg/knuu/e2e" "github.com/celestiaorg/knuu/pkg/knuu" ) @@ -17,7 +19,7 @@ func TestEnvToJSON(t *testing.T) { t.Parallel() // Setup - executor, err := knuu.NewExecutor() + executor, err := e2e.NewExecutor(context.Background(), "env-to-json-executor") if err != nil { t.Fatalf("Error creating executor: %v", err) } @@ -104,7 +106,7 @@ func TestEnvToJSON(t *testing.T) { } t.Cleanup(func() { - all := append(instances, executor.Instance) + all := append(instances, executor) require.NoError(t, knuu.BatchDestroy(all...)) }) diff --git a/e2e/system/external_file_test.go b/e2e/system/external_file_test.go index 9ace375..3b1e14a 100644 --- a/e2e/system/external_file_test.go +++ b/e2e/system/external_file_test.go @@ -1,10 +1,12 @@ package system import ( + "context" "io" "os" "testing" + "github.com/celestiaorg/knuu/e2e" "github.com/celestiaorg/knuu/pkg/knuu" "github.com/stretchr/testify/assert" @@ -15,7 +17,7 @@ func TestExternalFile(t *testing.T) { t.Parallel() // Setup - executor, err := knuu.NewExecutor() + executor, err := e2e.NewExecutor(context.Background(), "external-file-executor") if err != nil { t.Fatalf("Error creating executor: %v", err) } @@ -69,7 +71,7 @@ func TestExternalFile(t *testing.T) { } t.Cleanup(func() { - require.NoError(t, knuu.BatchDestroy(executor.Instance, server)) + require.NoError(t, knuu.BatchDestroy(executor, server)) }) // Test logic diff --git a/e2e/system/file_test.go b/e2e/system/file_test.go index 2d8b94a..67d93a1 100644 --- a/e2e/system/file_test.go +++ b/e2e/system/file_test.go @@ -9,6 +9,7 @@ import ( "testing" "time" + "github.com/celestiaorg/knuu/e2e" "github.com/celestiaorg/knuu/pkg/knuu" "github.com/google/uuid" @@ -21,7 +22,7 @@ func TestFile(t *testing.T) { t.Parallel() // Setup - executor, err := knuu.NewExecutor() + executor, err := e2e.NewExecutor(context.Background(), "file-executor") if err != nil { t.Fatalf("Error creating executor: %v", err) } @@ -53,7 +54,7 @@ func TestFile(t *testing.T) { } t.Cleanup(func() { - require.NoError(t, knuu.BatchDestroy(executor.Instance, serverfile)) + require.NoError(t, knuu.BatchDestroy(executor, serverfile)) }) // Test logic diff --git a/e2e/system/file_test_image_cached_test.go b/e2e/system/file_test_image_cached_test.go index cf23422..ba6c701 100644 --- a/e2e/system/file_test_image_cached_test.go +++ b/e2e/system/file_test_image_cached_test.go @@ -1,6 +1,7 @@ package system import ( + "context" "fmt" "sync" "testing" @@ -14,7 +15,7 @@ import ( func TestFileCached(t *testing.T) { t.Parallel() // Setup - executor, err := knuu.NewExecutor() + executor, err := e2e.NewExecutor(context.Background(), "file-cached-executor") if err != nil { t.Fatalf("Error creating executor: %v", err) } diff --git a/e2e/system/files_to_volumes_cm_test.go b/e2e/system/files_to_volumes_cm_test.go index 9fa7a11..fdec3ce 100644 --- a/e2e/system/files_to_volumes_cm_test.go +++ b/e2e/system/files_to_volumes_cm_test.go @@ -1,6 +1,7 @@ package system import ( + "context" "fmt" "strings" "sync" @@ -20,7 +21,7 @@ func TestNoVolumesNoFiles(t *testing.T) { t.Parallel() // Setup - executor, err := knuu.NewExecutor() + executor, err := e2e.NewExecutor(context.Background(), "no-volumes-no-files-executor") if err != nil { t.Fatalf("Error creating executor: %v", err) } @@ -82,7 +83,7 @@ func TestOneVolumeNoFiles(t *testing.T) { t.Parallel() // Setup - executor, err := knuu.NewExecutor() + executor, err := e2e.NewExecutor(context.Background(), "one-volume-no-files-executor") if err != nil { t.Fatalf("Error creating executor: %v", err) } @@ -147,7 +148,7 @@ func TestOneVolumeNoFiles(t *testing.T) { func TestNoVolumesOneFile(t *testing.T) { t.Parallel() // Setup - executor, err := knuu.NewExecutor() + executor, err := e2e.NewExecutor(context.Background(), "no-volumes-one-file-executor") if err != nil { t.Fatalf("Error creating executor: %v", err) } @@ -230,7 +231,7 @@ func TestOneVolumeOneFile(t *testing.T) { t.Parallel() // Setup - executor, err := knuu.NewExecutor() + executor, err := e2e.NewExecutor(context.Background(), "one-volume-one-file-executor") if err != nil { t.Fatalf("Error creating executor: %v", err) } @@ -311,7 +312,7 @@ func TestOneVolumeTwoFiles(t *testing.T) { t.Parallel() // Setup - executor, err := knuu.NewExecutor() + executor, err := e2e.NewExecutor(context.Background(), "one-volume-two-files-executor") if err != nil { t.Fatalf("Error creating executor: %v", err) } diff --git a/e2e/system/folder_test.go b/e2e/system/folder_test.go index 75833ff..0b6c24c 100644 --- a/e2e/system/folder_test.go +++ b/e2e/system/folder_test.go @@ -1,6 +1,7 @@ package system import ( + "context" "testing" "github.com/stretchr/testify/assert" @@ -14,7 +15,7 @@ func TestFolder(t *testing.T) { t.Parallel() // Setup - executor, err := knuu.NewExecutor() + executor, err := e2e.NewExecutor(context.Background(), "folder-executor") if err != nil { t.Fatalf("Error creating executor: %v", err) } @@ -32,7 +33,7 @@ func TestFolder(t *testing.T) { } t.Cleanup(func() { - require.NoError(t, knuu.BatchDestroy(executor.Instance, web)) + require.NoError(t, knuu.BatchDestroy(executor, web)) }) // Test logic diff --git a/e2e/system/folder_test_image_cached_test.go b/e2e/system/folder_test_image_cached_test.go index 0df91db..8ddb56e 100644 --- a/e2e/system/folder_test_image_cached_test.go +++ b/e2e/system/folder_test_image_cached_test.go @@ -1,6 +1,7 @@ package system import ( + "context" "fmt" "sync" "testing" @@ -15,7 +16,7 @@ func TestFolderCached(t *testing.T) { t.Parallel() // Setup - executor, err := knuu.NewExecutor() + executor, err := e2e.NewExecutor(context.Background(), "folder-cached-executor") if err != nil { t.Fatalf("Error creating executor: %v", err) } diff --git a/pkg/instance/executor.go b/pkg/instance/executor.go deleted file mode 100644 index a9def8b..0000000 --- a/pkg/instance/executor.go +++ /dev/null @@ -1,59 +0,0 @@ -package instance - -import ( - "context" - - "k8s.io/apimachinery/pkg/api/resource" - - "github.com/celestiaorg/knuu/pkg/system" -) - -const ( - executorDefaultImage = "docker.io/nicolaka/netshoot:latest" - executorName = "executor" - sleepCommand = "sleep" - infinityArg = "infinity" -) - -var ( - executorMemoryLimit = resource.MustParse("100Mi") - executorCpuLimit = resource.MustParse("100m") -) - -type Executor struct { - *Instance -} - -func NewExecutor(ctx context.Context, sysDeps system.SystemDependencies) (*Executor, error) { - i, err := New(executorName, sysDeps) - if err != nil { - return nil, ErrCreatingInstance.Wrap(err) - } - - if err := i.SetImage(ctx, executorDefaultImage); err != nil { - return nil, ErrSettingImage.Wrap(err) - } - - if err := i.Commit(); err != nil { - return nil, ErrCommittingInstance.Wrap(err) - } - - if err := i.SetArgs(sleepCommand, infinityArg); err != nil { - return nil, ErrSettingArgs.Wrap(err) - } - - if err := i.SetMemory(executorMemoryLimit, executorMemoryLimit); err != nil { - return nil, ErrSettingMemory.Wrap(err) - } - - if err := i.SetCPU(executorCpuLimit); err != nil { - return nil, ErrSettingCPU.Wrap(err) - } - i.instanceType = ExecutorInstance - - if err := i.Start(ctx); err != nil { - return nil, ErrStartingInstance.Wrap(err) - } - - return &Executor{Instance: i}, nil -} diff --git a/pkg/instance/instance.go b/pkg/instance/instance.go index a7ab69e..7311a98 100644 --- a/pkg/instance/instance.go +++ b/pkg/instance/instance.go @@ -1218,17 +1218,13 @@ func (i *Instance) WaitInstanceIsRunning(ctx context.Context) error { } // DisableNetwork disables the network of the instance -// This does not apply to executor instances // This function can only be called in the state 'Started' func (i *Instance) DisableNetwork(ctx context.Context) error { if !i.IsInState(StateStarted) { return ErrDisablingNetworkNotAllowed.WithParams(i.state.String()) } - executorSelectorMap := map[string]string{ - labelType: ExecutorInstance.String(), - } - err := i.K8sClient.CreateNetworkPolicy(ctx, i.k8sName, i.getLabels(), executorSelectorMap, executorSelectorMap) + err := i.K8sClient.CreateNetworkPolicy(ctx, i.k8sName, i.getLabels(), nil, nil) if err != nil { return ErrDisablingNetwork.WithParams(i.k8sName).Wrap(err) } diff --git a/pkg/instance/type.go b/pkg/instance/type.go index 1343883..1ebac35 100644 --- a/pkg/instance/type.go +++ b/pkg/instance/type.go @@ -7,7 +7,6 @@ type InstanceType int const ( UnknownInstance InstanceType = iota BasicInstance - ExecutorInstance TimeoutHandlerInstance ) @@ -16,8 +15,6 @@ func (s InstanceType) String() string { switch s { case BasicInstance: return "BasicInstance" - case ExecutorInstance: - return "ExecutorInstance" case TimeoutHandlerInstance: return "TimeoutHandlerInstance" case UnknownInstance: diff --git a/pkg/instance/type_test.go b/pkg/instance/type_test.go index 990f3c7..99dbc1f 100644 --- a/pkg/instance/type_test.go +++ b/pkg/instance/type_test.go @@ -16,11 +16,6 @@ func TestInstanceType(t *testing.T) { in: BasicInstance, // Input want: "BasicInstance", // Expected output }, - { - name: "ExecutorInstance", - in: ExecutorInstance, - want: "ExecutorInstance", - }, { name: "TimeoutHandlerInstance", in: TimeoutHandlerInstance, diff --git a/pkg/knuu/errors.go b/pkg/knuu/errors.go index b620420..aae1981 100644 --- a/pkg/knuu/errors.go +++ b/pkg/knuu/errors.go @@ -209,4 +209,5 @@ var ( ErrK8sClientNotSet = errors.New("K8sClientNotSet", "k8s client is not set") ErrScopeMistMatch = errors.New("ScopeMistMatch", "scope '%s' set in options does not match scope '%s' set by the k8sClient namespace") ErrHandleTimeout = errors.New("HandleTimeout", "error starting handle timeout") + ErrDeprecated = errors.New("Deprecated", "deprecated") ) diff --git a/pkg/knuu/instance.go b/pkg/knuu/instance.go index 7f8398a..c9e6e75 100644 --- a/pkg/knuu/instance.go +++ b/pkg/knuu/instance.go @@ -2,8 +2,6 @@ package knuu import ( - "context" - "github.com/celestiaorg/knuu/pkg/instance" "github.com/celestiaorg/knuu/pkg/preloader" ) @@ -12,10 +10,6 @@ func (k *Knuu) NewInstance(name string) (*instance.Instance, error) { return instance.New(name, k.SystemDependencies) } -func (k *Knuu) NewExecutor(ctx context.Context) (*instance.Executor, error) { - return instance.NewExecutor(ctx, k.SystemDependencies) -} - func (k *Knuu) NewPreloader() (*preloader.Preloader, error) { return preloader.New(k.SystemDependencies) } diff --git a/pkg/knuu/instance_old.go b/pkg/knuu/instance_old.go index 0667630..dcec331 100644 --- a/pkg/knuu/instance_old.go +++ b/pkg/knuu/instance_old.go @@ -353,19 +353,8 @@ func (i *Instance) CustomResourceDefinitionExists(gvr *schema.GroupVersionResour } // Deprecated: Use the new package knuu instead. -func NewExecutor() (*Executor, error) { - if tmpKnuu == nil { - return nil, errors.New("tmpKnuu is not initialized") - } - e, err := tmpKnuu.NewExecutor(context.Background()) - if err != nil { - return nil, err - } - return &Executor{ - Instance: &Instance{ - Instance: *e.Instance, - }, - }, nil +func __NewExecutor() (*Executor, error) { + return nil, ErrDeprecated } // Deprecated: Use the new package knuu instead. From 0b81b8159de98eb474936cace7130633a0a3421e Mon Sep 17 00:00:00 2001 From: Mojtaba Date: Tue, 16 Jul 2024 10:45:43 +0330 Subject: [PATCH 5/6] fix: rename the deprecated NewExecutor --- pkg/knuu/instance_old.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/knuu/instance_old.go b/pkg/knuu/instance_old.go index dcec331..e9f361c 100644 --- a/pkg/knuu/instance_old.go +++ b/pkg/knuu/instance_old.go @@ -353,7 +353,7 @@ func (i *Instance) CustomResourceDefinitionExists(gvr *schema.GroupVersionResour } // Deprecated: Use the new package knuu instead. -func __NewExecutor() (*Executor, error) { +func NewExecutor() (*Executor, error) { return nil, ErrDeprecated } From 1e6eef37db84f24c27f96111db6416e4057747f5 Mon Sep 17 00:00:00 2001 From: Moji Date: Wed, 24 Jul 2024 09:47:54 +0200 Subject: [PATCH 6/6] chore: refactor e2e system tests to new knuu obj (#520) * chore: refactor system e2e tests to new knuu obj * fix: added missing commit before start * fix: added missing commit before start * fix: added missing commit before start * chore: code cleanup * chore: some more cleanup --- e2e/assert_cleanups.go | 43 --- e2e/assert_create.go | 55 --- e2e/basic/probe_test.go | 22 +- e2e/executor.go | 17 +- e2e/system/build_from_git_test.go | 101 ++--- e2e/system/env_to_json_test.go | 162 +++----- e2e/system/external_file_test.go | 110 ++---- e2e/system/file_test.go | 197 +++++----- e2e/system/file_test_image_cached_test.go | 77 ++-- e2e/system/files_to_volumes_cm_test.go | 407 +++++++------------- e2e/system/folder_test.go | 73 ++-- e2e/system/folder_test_image_cached_test.go | 78 ++-- e2e/system/main_test.go | 20 - e2e/system/start_callback_test.go | 3 - e2e/system/suite_setup_test.go | 96 +++++ pkg/instance/errors.go | 2 +- pkg/instance/instance.go | 2 +- pkg/knuu/knuu_old.go | 4 + 18 files changed, 584 insertions(+), 885 deletions(-) delete mode 100644 e2e/assert_cleanups.go delete mode 100644 e2e/assert_create.go delete mode 100644 e2e/system/main_test.go create mode 100644 e2e/system/suite_setup_test.go diff --git a/e2e/assert_cleanups.go b/e2e/assert_cleanups.go deleted file mode 100644 index b956eeb..0000000 --- a/e2e/assert_cleanups.go +++ /dev/null @@ -1,43 +0,0 @@ -package e2e - -import ( - "os" - "testing" - - "github.com/celestiaorg/knuu/pkg/knuu" -) - -// AssertCleanupInstance is a helper function that cleans up a single instance. -func AssertCleanupInstance(t *testing.T, instance *knuu.Instance) error { - if instance == nil { - t.Fatal("Instance is nil") - } - - if err := instance.Destroy(); err != nil { - t.Fatalf("Error destroying instance: %v", err) - } - return nil -} - -// AssertCleanupInstances is a helper function that cleans up a list of instances. -func AssertCleanupInstances(t *testing.T, executor *knuu.Instance, instances []*knuu.Instance) error { - if os.Getenv("KNUU_SKIP_CLEANUP") == "true" { - t.Log("Skipping cleanup") - return nil - } - - if executor == nil { - t.Fatal("Executor is nil") - } - - if err := executor.Destroy(); err != nil { - t.Fatalf("Error destroying executor: %v", err) - } - - err := knuu.BatchDestroy(instances...) - if err != nil { - t.Fatalf("Error destroying instances: %v", err) - } - - return nil -} diff --git a/e2e/assert_create.go b/e2e/assert_create.go deleted file mode 100644 index 469ee2d..0000000 --- a/e2e/assert_create.go +++ /dev/null @@ -1,55 +0,0 @@ -package e2e - -import ( - "testing" - - "github.com/celestiaorg/knuu/pkg/knuu" -) - -const ( - // nginxImage is the image used to create the instances. - nginxImage = "docker.io/nginx:latest" - // nginxVolume is the volume used to create the instances. - nginxVolume = "1Gi" - // nginxVolumeOwner is the owner of the volume used to create the instances. - nginxVolumeOwner = 0 - // nginxPort is the port used to create the instances. - nginxPort = 80 - // nginxPath is the path used to create the instances. - nginxPath = "/usr/share/nginx/html" -) - -// AssertCreateInstanceNginxWithVolumeOwner creates and configures an instance with common settings used across tests but doesn't call commit. -func AssertCreateInstanceNginxWithVolumeOwnerWithoutCommit(t *testing.T, instanceName string) *knuu.Instance { - instance, err := knuu.NewInstance(instanceName) - if err != nil { - t.Fatalf("Error creating instance '%v': %v", instanceName, err) - } - err = instance.SetImage(nginxImage) - if err != nil { - t.Fatalf("Error setting image for '%v': %v", instanceName, err) - } - err = instance.AddPortTCP(nginxPort) - if err != nil { - t.Fatalf("Error adding port for '%v': %v", instanceName, err) - } - _, err = instance.ExecuteCommand("mkdir", "-p", nginxPath) - if err != nil { - t.Fatalf("Error executing command for '%v': %v", instanceName, err) - } - err = instance.AddVolumeWithOwner(nginxPath, nginxVolume, nginxVolumeOwner) - if err != nil { - t.Fatalf("Error adding volume: %v", err) - } - return instance -} - -// AssertCreateInstanceNginxWithVolumeOwner creates and configures an instance with common settings used across tests. -func AssertCreateInstanceNginxWithVolumeOwner(t *testing.T, instanceName string) *knuu.Instance { - instance := AssertCreateInstanceNginxWithVolumeOwnerWithoutCommit(t, instanceName) - err := instance.Commit() - if err != nil { - t.Fatalf("Error committing instance '%v': %v", instanceName, err) - } - return instance -} diff --git a/e2e/basic/probe_test.go b/e2e/basic/probe_test.go index 308c853..8800763 100644 --- a/e2e/basic/probe_test.go +++ b/e2e/basic/probe_test.go @@ -5,7 +5,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/util/intstr" @@ -17,7 +16,13 @@ func TestProbe(t *testing.T) { t.Parallel() // Setup - executor, err := e2e.NewExecutor(context.Background(), "prob-executor") + // Ideally this has to be defined in the test suit setup + exe := e2e.Executor{ + Kn: knuu.GetKnuuObj(), + } + + ctx := context.Background() + executor, err := exe.NewInstance(ctx, "prob-executor") if err != nil { t.Fatalf("Error creating executor: %v", err) } @@ -62,7 +67,16 @@ func TestProbe(t *testing.T) { } t.Cleanup(func() { - require.NoError(t, knuu.BatchDestroy(executor, web)) + // after refactor, we can use instance.BatchDestroy for simplicity + err := executor.Destroy(ctx) + if err != nil { + t.Logf("Error destroying instance: %v", err) + } + + err = web.Destroy() + if err != nil { + t.Logf("Error destroying instance: %v", err) + } }) // Test logic @@ -81,7 +95,7 @@ func TestProbe(t *testing.T) { t.Fatalf("Error waiting for instance to be running: %v", err) } - wget, err := executor.ExecuteCommand("wget", "-q", "-O", "-", webIP) + wget, err := executor.ExecuteCommand(ctx, "wget", "-q", "-O", "-", webIP) if err != nil { t.Fatalf("Error executing command '%v':", err) } diff --git a/e2e/executor.go b/e2e/executor.go index df24e6c..329cb70 100644 --- a/e2e/executor.go +++ b/e2e/executor.go @@ -5,6 +5,7 @@ import ( "k8s.io/apimachinery/pkg/api/resource" + "github.com/celestiaorg/knuu/pkg/instance" "github.com/celestiaorg/knuu/pkg/knuu" ) @@ -14,18 +15,22 @@ const ( infinityArg = "infinity" ) +type Executor struct { + Kn *knuu.Knuu +} + var ( executorMemoryLimit = resource.MustParse("100Mi") executorCpuLimit = resource.MustParse("100m") ) -func NewExecutor(ctx context.Context, executorName string) (*knuu.Instance, error) { - i, err := knuu.NewInstance(executorName) +func (e *Executor) NewInstance(ctx context.Context, name string) (*instance.Instance, error) { + i, err := e.Kn.NewInstance(name) if err != nil { return nil, err } - if err := i.SetImage(executorDefaultImage); err != nil { + if err := i.SetImage(ctx, executorDefaultImage); err != nil { return nil, err } @@ -37,15 +42,15 @@ func NewExecutor(ctx context.Context, executorName string) (*knuu.Instance, erro return nil, err } - if err := i.SetMemory(executorMemoryLimit.String(), executorMemoryLimit.String()); err != nil { + if err := i.SetMemory(executorMemoryLimit, executorMemoryLimit); err != nil { return nil, err } - if err := i.SetCPU(executorCpuLimit.String()); err != nil { + if err := i.SetCPU(executorCpuLimit); err != nil { return nil, err } - if err := i.Start(); err != nil { + if err := i.Start(ctx); err != nil { return nil, err } diff --git a/e2e/system/build_from_git_test.go b/e2e/system/build_from_git_test.go index 6e283e5..09fa5c5 100644 --- a/e2e/system/build_from_git_test.go +++ b/e2e/system/build_from_git_test.go @@ -3,32 +3,21 @@ package system import ( "context" "strings" - "testing" - - "github.com/sirupsen/logrus" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" "github.com/celestiaorg/knuu/pkg/builder" - "github.com/celestiaorg/knuu/pkg/k8s" - "github.com/celestiaorg/knuu/pkg/knuu" - "github.com/celestiaorg/knuu/pkg/minio" ) -func TestBuildFromGit(t *testing.T) { - t.Parallel() +func (s *Suite) TestBuildFromGit() { + const namePrefix = "build-from-git" + s.T().Parallel() // Setup ctx := context.Background() - // The default image builder is kaniko here - kn, err := knuu.New(ctx, knuu.Options{}) - require.NoError(t, err, "Error creating knuu") - - target, err := kn.NewInstance("git-builder") - require.NoError(t, err, "Error creating instance") + target, err := s.Knuu.NewInstance(namePrefix) + s.Require().NoError(err) - t.Log("Building the image") + s.T().Log("Building the image") // This is a blocking call which builds the image from git repo err = target.SetGitRepo(ctx, builder.GitContext{ @@ -37,84 +26,66 @@ func TestBuildFromGit(t *testing.T) { Username: "", Password: "", }) - require.NoError(t, err, "Error setting git repo") + s.Require().NoError(err) - t.Log("Image built") + s.T().Log("Image built") - t.Cleanup(func() { - if err := kn.CleanUp(ctx); err != nil { - t.Logf("Error cleaning up knuu: %v", err) + s.T().Cleanup(func() { + if err := target.Destroy(ctx); err != nil { + s.T().Logf("Error cleaning up knuu: %v", err) } }) - require.NoError(t, target.Commit()) - - t.Logf("Starting instance") + s.Require().NoError(target.Commit()) - assert.NoError(t, target.Start(ctx)) + s.T().Logf("Starting instance") + s.Require().NoError(target.Start(ctx)) - t.Logf("Instance started") + s.T().Logf("Instance started") // The file is created by the dockerfile in the repo, // so to make sure it is built correctly, we check the file data, err := target.GetFileBytes(ctx, "/test.txt") - require.NoError(t, err, "Error getting file bytes") + s.Require().NoError(err) data = []byte(strings.TrimSpace(string(data))) - assert.Equal(t, []byte("Hello, World!"), data, "File bytes do not match") + s.Assert().Equal([]byte("Hello, World!"), data, "File bytes do not match") } -func TestBuildFromGitWithModifications(t *testing.T) { - t.Parallel() +func (s *Suite) TestBuildFromGitWithModifications() { + const namePrefix = "build-from-git-with-modifications" + s.T().Parallel() // Setup - ctx := context.Background() - - logger := logrus.New() - - k8sClient, err := k8s.NewClient(ctx, knuu.DefaultScope(), logger) - require.NoError(t, err, "Error creating k8s client") - - // Since we are modifying the git repo, - // we need to setup minio to allow the builder to push the changes - minioClient, err := minio.New(ctx, k8sClient, logger) - require.NoError(t, err, "Error creating minio client") - - // The default image builder is kaniko here - kn, err := knuu.New(ctx, knuu.Options{ - K8sClient: k8sClient, - MinioClient: minioClient, - }) - require.NoError(t, err, "Error creating knuu") - - sampleInstance, err := kn.NewInstance("git-builder") - require.NoError(t, err, "Error creating instance") + target, err := s.Knuu.NewInstance(namePrefix) + s.Require().NoError(err) + ctx := context.Background() // This is a blocking call which builds the image from git repo - err = sampleInstance.SetGitRepo(ctx, builder.GitContext{ + err = target.SetGitRepo(ctx, builder.GitContext{ Repo: "https://github.com/celestiaorg/knuu.git", Branch: "test/build-from-git", // This branch has a Dockerfile and is protected as to not be deleted Username: "", Password: "", }) - require.NoError(t, err, "Error setting git repo") + s.Require().NoError(err) - require.NoError(t, sampleInstance.SetCommand("sleep", "infinity"), "Error setting command") + s.Require().NoError(target.SetCommand("sleep", "infinity")) - err = sampleInstance.AddFileBytes([]byte("Hello, world!"), "/home/hello.txt", "root:root") - require.NoError(t, err, "Error adding file") + err = target.AddFileBytes([]byte("Hello, world!"), "/home/hello.txt", "root:root") + s.Require().NoError(err, "Error adding file") - require.NoError(t, sampleInstance.Commit(), "Error committing instance") + s.Require().NoError(target.Commit()) - t.Cleanup(func() { - if err := kn.CleanUp(ctx); err != nil { - t.Logf("Error cleaning up knuu: %v", err) + s.T().Cleanup(func() { + if err := target.Destroy(ctx); err != nil { + s.T().Logf("Error cleaning up knuu: %v", err) } }) - require.NoError(t, sampleInstance.Start(ctx), "Error starting instance") + s.Require().NoError(target.Start(ctx)) - data, err := sampleInstance.GetFileBytes(ctx, "/home/hello.txt") - require.NoError(t, err, "Error getting file bytes") + data, err := target.GetFileBytes(ctx, "/home/hello.txt") + s.Require().NoError(err, "Error getting file bytes") - require.Equal(t, []byte("Hello, world!"), data, "File bytes do not match") + s.Assert().Equal([]byte("Hello, world!"), data, "File bytes do not match") } diff --git a/e2e/system/env_to_json_test.go b/e2e/system/env_to_json_test.go index cfcea33..41bfe13 100644 --- a/e2e/system/env_to_json_test.go +++ b/e2e/system/env_to_json_test.go @@ -4,137 +4,81 @@ import ( "context" "encoding/json" "fmt" - "os" - "testing" + "strings" - "github.com/sirupsen/logrus" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/celestiaorg/knuu/e2e" - "github.com/celestiaorg/knuu/pkg/knuu" + "github.com/celestiaorg/knuu/pkg/instance" ) -func TestEnvToJSON(t *testing.T) { - t.Parallel() +func (s *Suite) TestEnvToJSON() { + const ( + namePrefix = "env-to-json" + numberOfInstances = 2 + ) - // Setup - executor, err := e2e.NewExecutor(context.Background(), "env-to-json-executor") - if err != nil { - t.Fatalf("Error creating executor: %v", err) - } + s.T().Parallel() - const numberOfInstances = 2 - instances := make([]*knuu.Instance, numberOfInstances) + // Setup + ctx := context.Background() + executor, err := s.Executor.NewInstance(ctx, namePrefix+"-executor") + s.Require().NoError(err) // Define the env vars - testEnvVarKey1 := "TESTKEY1" - testEnvVarKey2 := "TESTKEY2" - testEnvVarKey3 := "TESTKEY3" - testEnvVarValue1 := "testvalue1" - testEnvVarValue2 := "testvalue2" - testEnvVarValue3 := "testvalue3" - - // Set the OS env vars - setEnv := func(key, value string) { - err = os.Setenv(key, value) - if err != nil { - t.Fatalf("Error setting env var '%v': %v", key, err) - } - } - setEnv(testEnvVarKey1, testEnvVarValue1) - setEnv(testEnvVarKey2, testEnvVarValue2) - setEnv(testEnvVarKey3, testEnvVarValue3) - - // Define helper function to get env vars - getEnv := func(key string) string { - value := os.Getenv(key) - if value == "" { - t.Fatalf("Error getting env var '%v'", key) - } - return value - } - jsonBytes, err := json.Marshal(map[string]string{ - testEnvVarKey1: getEnv(testEnvVarKey1), - testEnvVarKey2: getEnv(testEnvVarKey2), - testEnvVarKey3: getEnv(testEnvVarKey3), - }) - if err != nil { - t.Fatalf("Error converting env vars to JSON: %v", err) + envVars := map[string]string{ + "TESTKEY1": "testvalue1", + "TESTKEY2": "testvalue2", + "TESTKEY3": "testvalue3", } + + jsonBytes, err := json.Marshal(envVars) + s.Require().NoError(err) + jsonString := string(jsonBytes) - logrus.Debugf("JSON: %v", jsonString) + s.T().Logf("JSON: %v", jsonString) + instances := make([]*instance.Instance, numberOfInstances) for i := 0; i < numberOfInstances; i++ { - instanceName := fmt.Sprintf("web%d", i+1) - instance, err := knuu.NewInstance(instanceName) - if err != nil { - t.Fatalf("Error creating instance '%v': %v", instanceName, err) - } - err = instance.SetImage("docker.io/nginx:latest") - if err != nil { - t.Fatalf("Error setting image for '%v': %v", instanceName, err) - } - instance.AddPortTCP(80) - _, err = instance.ExecuteCommand("mkdir", "-p", "/usr/share/nginx/html") - if err != nil { - t.Fatalf("Error executing command for '%v': %v", instanceName, err) - } + name := fmt.Sprintf("%s-web%d", namePrefix, i+1) - logrus.Debugf("Writing JSON to instance '%v': %v", instanceName, jsonString) - _, err = instance.ExecuteCommand("mkdir", "-p", "/opt/env") - if err != nil { - t.Fatalf("Error writing JSON to instance '%v': %v", instanceName, err) - } - // write the json file to the instance - _, err = instance.ExecuteCommand("echo", fmt.Sprintf("'%s'", jsonString), ">", "/opt/env/env.json") - if err != nil { - t.Fatalf("Error writing JSON to instance '%v': %v", instanceName, err) - } - // for testing it, we also add it as index.html to the nginx server - _, err = instance.ExecuteCommand("echo", fmt.Sprintf("'%s'", jsonString), ">", "/usr/share/nginx/html/index.html") - if err != nil { - t.Fatalf("Error writing JSON to instance '%v': %v", instanceName, err) - } + ins := s.createNginxInstance(ctx, name) + s.Require().NoError(ins.Commit()) + s.Require().NoError(ins.Start(ctx)) - err = instance.Commit() - if err != nil { - t.Fatalf("Error committing instance '%v': %v", instanceName, err) - } + _, err = ins.ExecuteCommand(ctx, "mkdir", "-p", nginxHTMLPath) + s.Require().NoError(err) - instances[i] = instance - } + s.T().Logf("Writing JSON to instance '%v': %v", name, jsonString) + _, err = ins.ExecuteCommand(ctx, "mkdir", "-p", "/opt/env") + s.Require().NoError(err) - t.Cleanup(func() { - all := append(instances, executor) - require.NoError(t, knuu.BatchDestroy(all...)) - }) + // write the json file to the instance + _, err = ins.ExecuteCommand(ctx, "echo", fmt.Sprintf("'%s'", jsonString), ">", "/opt/env/env.json") + s.Require().NoError(err) - // Test logic - for _, instance := range instances { - err = instance.StartAsync() - if err != nil { - t.Fatalf("Error waiting for instance to be running: %v", err) - } + // for testing it, we also add it as index.html to the nginx server + _, err = ins.ExecuteCommand(ctx, "echo", fmt.Sprintf("'%s'", jsonString), ">", nginxHTMLPath+"/index.html") + s.Require().NoError(err, "writing JSON to instance '%v': %v", name, err) + + instances[i] = ins } - for _, instance := range instances { - webIP, err := instance.GetIP() + s.T().Cleanup(func() { + all := append(instances, executor) + err := instance.BatchDestroy(ctx, all...) if err != nil { - t.Fatalf("Error getting IP: %v", err) + s.T().Logf("error destroying instances: %v", err) } + }) - err = instance.WaitInstanceIsRunning() - if err != nil { - t.Fatalf("Error waiting for instance to be running: %v", err) - } + // Test logic + for _, i := range instances { + webIP, err := i.GetIP(ctx) + s.Require().NoError(err) - wget, err := executor.ExecuteCommand("wget", "-q", "-O", "-", webIP) - if err != nil { - t.Fatalf("Error executing command: %v", err) - } + wget, err := executor.ExecuteCommand(ctx, "wget", "-q", "-O", "-", webIP) + s.Require().NoError(err) - expected := fmt.Sprintf("{\"%s\":\"%s\",\"%s\":\"%s\",\"%s\":\"%s\"}\n", testEnvVarKey1, testEnvVarValue1, testEnvVarKey2, testEnvVarValue2, testEnvVarKey3, testEnvVarValue3) - assert.Equal(t, expected, wget) + expectedBytes, err := json.Marshal(envVars) + s.Require().NoError(err) + s.Assert().Equal(string(expectedBytes), strings.TrimSpace(wget)) } } diff --git a/e2e/system/external_file_test.go b/e2e/system/external_file_test.go index 3b1e14a..aa6231f 100644 --- a/e2e/system/external_file_test.go +++ b/e2e/system/external_file_test.go @@ -4,96 +4,60 @@ import ( "context" "io" "os" - "testing" + "path/filepath" - "github.com/celestiaorg/knuu/e2e" - "github.com/celestiaorg/knuu/pkg/knuu" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" + "github.com/celestiaorg/knuu/pkg/instance" ) -func TestExternalFile(t *testing.T) { - t.Parallel() +func (s *Suite) TestExternalFile() { + const namePrefix = "external-file" + s.T().Parallel() // Setup - executor, err := e2e.NewExecutor(context.Background(), "external-file-executor") - if err != nil { - t.Fatalf("Error creating executor: %v", err) - } - - server, err := knuu.NewInstance("server") - if err != nil { - t.Fatalf("Error creating instance '%v':", err) - } - err = server.SetImage("docker.io/nginx:latest") - if err != nil { - t.Fatalf("Error setting image '%v':", err) - } - server.AddPortTCP(80) - _, err = server.ExecuteCommand("mkdir", "-p", "/usr/share/nginx/html") - if err != nil { - t.Fatalf("Error executing command '%v':", err) - } + ctx := context.Background() + executor, err := s.Executor.NewInstance(ctx, namePrefix+"-executor") + s.Require().NoError(err) + + server := s.createNginxInstance(ctx, namePrefix+"-server") + // copy resources/html/index.html to /tmp/index.html - srcFile, err := os.Open("resources/html/index.html") - if err != nil { - t.Fatalf("Error opening source file '%v':", err) - } + srcFile, err := os.Open(resourcesHTML + "/index.html") + s.Require().NoError(err) defer srcFile.Close() // Create the destination file - dstFile, err := os.Create("/tmp/index.html") - if err != nil { - t.Fatalf("Error creating destination file '%v':", err) - } + htmlTmpPath := filepath.Join(os.TempDir(), "index.html") + dstFile, err := os.Create(htmlTmpPath) + s.Require().NoError(err) defer dstFile.Close() // Copy the contents of the source file into the destination file _, err = io.Copy(dstFile, srcFile) - if err != nil { - t.Fatalf("Error copying contents '%v':", err) - } + s.Require().NoError(err) // Ensure that the copy is successful by syncing the written data to the disk - err = dstFile.Sync() - if err != nil { - t.Fatalf("Error syncing data to disk '%v':", err) - } - - err = server.AddFile("/tmp/index.html", "/usr/share/nginx/html/index.html", "0:0") - if err != nil { - t.Fatalf("Error adding file '%v':", err) - } - err = server.Commit() - if err != nil { - t.Fatalf("Error committing instance: %v", err) - } - - t.Cleanup(func() { - require.NoError(t, knuu.BatchDestroy(executor, server)) + s.Require().NoError(dstFile.Sync()) + + err = server.AddFile(htmlTmpPath, nginxHTMLPath+"/index.html", "0:0") + s.Require().NoError(err) + + s.Require().NoError(server.Commit()) + + s.T().Cleanup(func() { + err := instance.BatchDestroy(ctx, executor, server) + if err != nil { + s.T().Logf("error destroying instance: %v", err) + } }) // Test logic + serverIP, err := server.GetIP(ctx) + s.Require().NoError(err) + + s.Require().NoError(server.Start(ctx)) + + wget, err := executor.ExecuteCommand(ctx, "wget", "-q", "-O", "-", serverIP) + s.Require().NoError(err) - serverIP, err := server.GetIP() - if err != nil { - t.Fatalf("Error getting IP '%v':", err) - } - - err = server.Start() - if err != nil { - t.Fatalf("Error starting instance: %v", err) - } - err = server.WaitInstanceIsRunning() - if err != nil { - t.Fatalf("Error waiting for instance to be running: %v", err) - } - - wget, err := executor.ExecuteCommand("wget", "-q", "-O", "-", serverIP) - if err != nil { - t.Fatalf("Error executing command '%v':", err) - } - - assert.Contains(t, wget, "Hello World!") + s.Assert().Contains(wget, "Hello World!") } diff --git a/e2e/system/file_test.go b/e2e/system/file_test.go index 67d93a1..854c8ee 100644 --- a/e2e/system/file_test.go +++ b/e2e/system/file_test.go @@ -2,165 +2,146 @@ package system import ( "context" - "fmt" "io" "net/http" "os" - "testing" "time" - "github.com/celestiaorg/knuu/e2e" - "github.com/celestiaorg/knuu/pkg/knuu" + "github.com/celestiaorg/knuu/pkg/instance" "github.com/google/uuid" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) -func TestFile(t *testing.T) { - t.Parallel() +func (s *Suite) TestFile() { + const namePrefix = "file" + s.T().Parallel() // Setup - executor, err := e2e.NewExecutor(context.Background(), "file-executor") - if err != nil { - t.Fatalf("Error creating executor: %v", err) - } - - serverfile, err := knuu.NewInstance("serverfile") - if err != nil { - t.Fatalf("Error creating instance '%v':", err) - } - err = serverfile.SetImage("docker.io/nginx:latest") - if err != nil { - t.Fatalf("Error setting image '%v':", err) - } - serverfile.AddPortTCP(80) - _, err = serverfile.ExecuteCommand("mkdir", "-p", "/usr/share/nginx/html") - if err != nil { - t.Fatalf("Error executing command '%v':", err) - } - err = serverfile.AddFile("resources/html/index.html", "/usr/share/nginx/html/index.html", "0:0") - if err != nil { - t.Fatalf("Error adding file '%v':", err) - } - err = serverfile.AddVolumeWithOwner("/usr/share/nginx/html", "1Gi", 0) - if err != nil { - t.Fatalf("Error adding volume: %v", err) - } - err = serverfile.Commit() - if err != nil { - t.Fatalf("Error committing instance: %v", err) - } - - t.Cleanup(func() { - require.NoError(t, knuu.BatchDestroy(executor, serverfile)) + ctx := context.Background() + executor, err := s.Executor.NewInstance(ctx, namePrefix+"-executor") + s.Require().NoError(err) + + serverfile := s.createNginxInstanceWithVolume(ctx, namePrefix+"-serverfile") + + err = serverfile.AddFile(resourcesHTML+"/index.html", nginxHTMLPath+"/index.html", "0:0") + s.Require().NoError(err) + + s.Require().NoError(serverfile.Commit()) + + s.T().Cleanup(func() { + err := instance.BatchDestroy(ctx, serverfile, executor) + if err != nil { + s.T().Logf("Error destroying instance: %v", err) + } }) // Test logic - serverfileIP, err := serverfile.GetIP() - if err != nil { - t.Fatalf("Error getting IP '%v':", err) - } - - err = serverfile.Start() - if err != nil { - t.Fatalf("Error starting instance: %v", err) - } - err = serverfile.WaitInstanceIsRunning() - if err != nil { - t.Fatalf("Error waiting for instance to be running: %v", err) - } - - wget, err := executor.ExecuteCommand("wget", "-q", "-O", "-", serverfileIP) - if err != nil { - t.Fatalf("Error executing command '%v':", err) - } - - assert.Contains(t, wget, "Hello World!") + serverfileIP, err := serverfile.GetIP(ctx) + s.Require().NoError(err) + + s.Require().NoError(serverfile.Start(ctx)) + + wget, err := executor.ExecuteCommand(ctx, "wget", "-q", "-O", "-", serverfileIP) + s.Require().NoError(err) + + s.Assert().Contains(wget, "Hello World!") } -func TestDownloadFileFromRunningInstance(t *testing.T) { - t.Parallel() +func (s *Suite) TestDownloadFileFromRunningInstance() { + const namePrefix = "download-file-running" + s.T().Parallel() // Setup - target, err := knuu.NewInstance("target") - require.NoError(t, err, "Error creating instance") + target, err := s.Knuu.NewInstance(namePrefix + "-target") + s.Require().NoError(err) - require.NoError(t, target.SetImage("alpine:latest"), "Error setting image") - require.NoError(t, target.SetArgs("tail", "-f", "/dev/null"), "Error setting args") // Keep the container running - require.NoError(t, target.Commit(), "Error committing instance") - require.NoError(t, target.Start(), "Error starting instance") + ctx := context.Background() + s.Require().NoError(target.SetImage(ctx, "alpine:latest")) + s.Require().NoError(target.SetArgs("tail", "-f", "/dev/null")) // Keep the container running + s.Require().NoError(target.Commit()) + s.Require().NoError(target.Start(ctx)) - t.Cleanup(func() { - require.NoError(t, knuu.BatchDestroy(target)) + s.T().Cleanup(func() { + if err := target.Destroy(ctx); err != nil { + s.T().Logf("error destroying instance: %v", err) + } }) // Test logic - fileContent := "Hello World!" - filePath := "/hello.txt" + const ( + fileContent = "Hello World!" + filePath = "/hello.txt" + ) // Create a file in the target instance - out, err := target.ExecuteCommand("echo", "-n", fileContent, ">", filePath) - require.NoError(t, err, fmt.Sprintf("Error executing command: %v", out)) + out, err := target.ExecuteCommand(ctx, "echo", "-n", fileContent, ">", filePath) + s.Require().NoError(err, "executing command output: %v", out) - gotContent, err := target.GetFileBytes(filePath) - require.NoError(t, err, "Error getting file bytes") + gotContent, err := target.GetFileBytes(ctx, filePath) + s.Require().NoError(err, "Error getting file bytes") - assert.Equal(t, fileContent, string(gotContent)) + s.Assert().Equal(fileContent, string(gotContent)) } -func TestMinio(t *testing.T) { - t.Parallel() +func (s *Suite) TestMinio() { + const ( + namePrefix = "minio" + minioBucketName = "knuu-e2e-test" + minioPushTimeout = 1 * time.Minute + ) + s.T().Parallel() // Setup - - target, err := knuu.NewInstance("target") - require.NoError(t, err, "Error creating instance") - - require.NoError(t, target.SetImage("alpine:latest"), "Error setting image") - require.NoError(t, target.SetArgs("tail", "-f", "/dev/null"), "Error setting args") // Keep the container running - require.NoError(t, target.Commit(), "Error committing instance") - require.NoError(t, target.Start(), "Error starting instance") - - t.Cleanup(func() { - require.NoError(t, knuu.BatchDestroy(target)) + target, err := s.Knuu.NewInstance(namePrefix + "-target") + s.Require().NoError(err) + + ctx := context.Background() + s.Require().NoError(target.SetImage(ctx, "alpine:latest")) + s.Require().NoError(target.SetArgs("tail", "-f", "/dev/null")) // Keep the container running + s.Require().NoError(target.Commit()) + s.Require().NoError(target.Start(ctx)) + + s.T().Cleanup(func() { + if err := target.Destroy(ctx); err != nil { + s.T().Logf("error destroying instance: %v", err) + } }) - fileContent := "Hello World!" - contentName := uuid.New().String() + var ( + fileContent = "Hello World!" + contentName = uuid.New().String() + ) + s.T().Logf("contentName: %v", contentName) tmpFile, err := os.CreateTemp("", "hello.txt") - require.NoError(t, err, "Error creating temporary file") + s.Require().NoError(err, "Error creating temporary file") defer os.Remove(tmpFile.Name()) - fmt.Printf("contentName: %v\n", contentName) - _, err = tmpFile.WriteString(fileContent) - require.NoError(t, err, "Error writing to temporary file") + s.Require().NoError(err, "writing to temporary file") tmpFile.Close() // Write to file did not work, so need to open it again tmpFile, err = os.Open(tmpFile.Name()) - require.NoError(t, err, "Error opening temporary file") + s.Require().NoError(err, "opening temporary file") defer tmpFile.Close() - fmt.Printf("tmpFile.Name(): %v\n", tmpFile.Name()) + s.T().Logf("tmpFile name: %v", tmpFile.Name()) - ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute) + mCtx, cancel := context.WithTimeout(ctx, minioPushTimeout) defer cancel() - err = knuu.PushFileToMinio(ctx, contentName, tmpFile) - require.NoError(t, err, "Error pushing file to Minio") + err = s.Knuu.MinioClient.Push(mCtx, tmpFile, contentName, minioBucketName) + s.Require().NoError(err) - url, err := knuu.GetMinioURL(ctx, contentName) - require.NoError(t, err, "Error getting Minio URL") + url, err := s.Knuu.MinioClient.GetURL(ctx, contentName, minioBucketName) + s.Require().NoError(err) resp, err := http.Get(url) - require.NoError(t, err, "Error downloading the file from URL") + s.Require().NoError(err) defer resp.Body.Close() gotContent, err := io.ReadAll(resp.Body) - require.NoError(t, err, "Error reading the response body") + s.Require().NoError(err) - assert.Equal(t, fileContent, string(gotContent)) + s.Assert().Equal(fileContent, string(gotContent)) } diff --git a/e2e/system/file_test_image_cached_test.go b/e2e/system/file_test_image_cached_test.go index ba6c701..077e7e9 100644 --- a/e2e/system/file_test_image_cached_test.go +++ b/e2e/system/file_test_image_cached_test.go @@ -4,77 +4,64 @@ import ( "context" "fmt" "sync" - "testing" - "github.com/stretchr/testify/assert" - - "github.com/celestiaorg/knuu/e2e" - "github.com/celestiaorg/knuu/pkg/knuu" + "github.com/celestiaorg/knuu/pkg/instance" ) -func TestFileCached(t *testing.T) { - t.Parallel() +func (s *Suite) TestFileCached() { + const namePrefix = "file-cached" + s.T().Parallel() // Setup - executor, err := e2e.NewExecutor(context.Background(), "file-cached-executor") - if err != nil { - t.Fatalf("Error creating executor: %v", err) - } + ctx := context.Background() + executor, err := s.Executor.NewInstance(ctx, namePrefix+"-executor") + s.Require().NoError(err) const numberOfInstances = 10 - instances := make([]*knuu.Instance, numberOfInstances) + instances := make([]*instance.Instance, numberOfInstances) + + instanceName := func(i int) string { + return fmt.Sprintf("%s-web%d", namePrefix, i+1) + } for i := 0; i < numberOfInstances; i++ { - instanceName := fmt.Sprintf("web%d", i+1) - instances[i] = e2e.AssertCreateInstanceNginxWithVolumeOwner(t, instanceName) + instances[i] = s.createNginxInstanceWithVolume(ctx, instanceName(i)) } var wgFolders sync.WaitGroup - for i, instance := range instances { + for i, ins := range instances { wgFolders.Add(1) - go func(i int, instance *knuu.Instance) { + go func(i int, instance *instance.Instance) { defer wgFolders.Done() - instanceName := fmt.Sprintf("web%d", i+1) // adding the folder after the Commit, it will help us to use a cached image. - err = instance.AddFile("resources/html/index.html", "/usr/share/nginx/html/index.html", "0:0") - if err != nil { - t.Errorf("Error adding file to '%v': %v", instanceName, err) - } - }(i, instance) + err = instance.AddFile(resourcesHTML+"/index.html", nginxHTMLPath+"/index.html", "0:0") + s.Require().NoError(err, "adding file to '%v'", instanceName(i)) + }(i, ins) } wgFolders.Wait() - t.Cleanup(func() { - // Cleanup - err := e2e.AssertCleanupInstances(t, executor, instances) + s.T().Cleanup(func() { + all := append(instances, executor) + err := instance.BatchDestroy(ctx, all...) if err != nil { - t.Fatalf("Error cleaning up: %v", err) + s.T().Logf("error destroying instance: %v", err) } }) // Test logic - for _, instance := range instances { - err = instance.StartAsync() - if err != nil { - t.Fatalf("Error waiting for instance to be running: %v", err) - } + for _, i := range instances { + s.Require().NoError(i.Commit()) + s.Require().NoError(i.StartAsync(ctx)) } - for _, instance := range instances { - webIP, err := instance.GetIP() - if err != nil { - t.Fatalf("Error getting IP: %v", err) - } + for _, i := range instances { + webIP, err := i.GetIP(ctx) + s.Require().NoError(err) - err = instance.WaitInstanceIsRunning() - if err != nil { - t.Fatalf("Error waiting for instance to be running: %v", err) - } + s.Require().NoError(i.WaitInstanceIsRunning(ctx)) - wget, err := executor.ExecuteCommand("wget", "-q", "-O", "-", webIP) - if err != nil { - t.Fatalf("Error executing command: %v", err) - } + wget, err := executor.ExecuteCommand(ctx, "wget", "-q", "-O", "-", webIP) + s.Require().NoError(err) - assert.Contains(t, wget, "Hello World!") + s.Assert().Contains(wget, "Hello World!") } } diff --git a/e2e/system/files_to_volumes_cm_test.go b/e2e/system/files_to_volumes_cm_test.go index fdec3ce..fbae178 100644 --- a/e2e/system/files_to_volumes_cm_test.go +++ b/e2e/system/files_to_volumes_cm_test.go @@ -5,394 +5,279 @@ import ( "fmt" "strings" "sync" - "testing" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" + "k8s.io/apimachinery/pkg/api/resource" - "github.com/celestiaorg/knuu/e2e" - "github.com/celestiaorg/knuu/pkg/knuu" + "github.com/celestiaorg/knuu/pkg/instance" ) // TestOneVolumeNoFiles tests the scenario where we have one volume and no files. // the initContainer command that it generates looks like: // no initContainer command, as there is no volumes, nor files. -func TestNoVolumesNoFiles(t *testing.T) { - t.Parallel() +func (s *Suite) TestNoVolumesNoFiles() { + const namePrefix = "no-volumes-no-files" + s.T().Parallel() // Setup - executor, err := e2e.NewExecutor(context.Background(), "no-volumes-no-files-executor") - if err != nil { - t.Fatalf("Error creating executor: %v", err) - } + ctx := context.Background() + executor, err := s.Executor.NewInstance(ctx, namePrefix+"-executor") + s.Require().NoError(err) - instanceName := "web-1" - instance, err := knuu.NewInstance(instanceName) - if err != nil { - t.Fatalf("Error creating instance '%v': %v", instanceName, err) - } - err = instance.SetImage("docker.io/nginx:latest") - if err != nil { - t.Fatalf("Error setting image for '%v': %v", instanceName, err) - } - err = instance.AddPortTCP(80) - if err != nil { - t.Fatalf("Error adding port for '%v': %v", instanceName, err) - } - err = instance.Commit() - if err != nil { - t.Fatalf("Error committing instance '%v': %v", instanceName, err) - } + target := s.createNginxInstance(ctx, namePrefix+"-target") + s.Require().NoError(target.Commit()) // Cleanup - t.Cleanup(func() { - err := e2e.AssertCleanupInstance(t, instance) + s.T().Cleanup(func() { + err := instance.BatchDestroy(ctx, executor, target) if err != nil { - t.Fatalf("Error cleaning up: %v", err) + s.T().Logf("error destroying instance: %v", err) } }) // Test logic - err = instance.StartAsync() - if err != nil { - t.Fatalf("Error waiting for instance to be running: %v", err) - } + s.Require().NoError(target.StartAsync(ctx)) - webIP, err := instance.GetIP() - if err != nil { - t.Fatalf("Error getting IP: %v", err) - } + webIP, err := target.GetIP(ctx) + s.Require().NoError(err) - err = instance.WaitInstanceIsRunning() - if err != nil { - t.Fatalf("Error waiting for instance to be running: %v", err) - } + s.Require().NoError(target.WaitInstanceIsRunning(ctx)) - wget, err := executor.ExecuteCommand("wget", "-q", "-O", "-", webIP) - if err != nil { - t.Fatalf("Error executing command: %v", err) - } + wget, err := executor.ExecuteCommand(ctx, "wget", "-q", "-O", "-", webIP) + s.Require().NoError(err) - assert.Contains(t, wget, "Welcome to nginx!") + s.Assert().Contains(wget, "Welcome to nginx!") } // TestOneVolumeNoFiles tests the scenario where we have one volume and no files. // the initContainer command that it generates looks like: // mkdir -p /knuu && if [ -d /opt/vol1 ] && [ \"$(ls -A /opt/vol1)\" ]; then cp -r /opt/vol1/* /knuu//opt/vol1 && chown -R 0:0 /knuu/* ;fi -func TestOneVolumeNoFiles(t *testing.T) { - t.Parallel() +func (s *Suite) TestOneVolumeNoFiles() { + const namePrefix = "one-volume-no-files" + s.T().Parallel() // Setup - executor, err := e2e.NewExecutor(context.Background(), "one-volume-no-files-executor") - if err != nil { - t.Fatalf("Error creating executor: %v", err) - } + ctx := context.Background() + executor, err := s.Executor.NewInstance(ctx, namePrefix+"-executor") + s.Require().NoError(err) - instanceName := "web-1" - instance, err := knuu.NewInstance(instanceName) - if err != nil { - t.Fatalf("Error creating instance '%v': %v", instanceName, err) - } - err = instance.SetImage("docker.io/nginx:latest") - if err != nil { - t.Fatalf("Error setting image for '%v': %v", instanceName, err) - } - err = instance.AddPortTCP(80) - if err != nil { - t.Fatalf("Error adding port for '%v': %v", instanceName, err) - } - err = instance.AddVolumeWithOwner("/opt/vol1", "1Gi", 0) - if err != nil { - t.Fatalf("Error adding volume: %v", err) - } - err = instance.Commit() - if err != nil { - t.Fatalf("Error committing instance '%v': %v", instanceName, err) - } + target := s.createNginxInstance(ctx, namePrefix+"-target") - // Cleanup - t.Cleanup(func() { - err := e2e.AssertCleanupInstance(t, instance) + err = target.AddVolumeWithOwner("/opt/vol1", resource.MustParse("1Gi"), 0) + s.Require().NoError(err) + + s.Require().NoError(target.Commit()) + + s.T().Cleanup(func() { + err := instance.BatchDestroy(ctx, executor, target) if err != nil { - t.Fatalf("Error cleaning up: %v", err) + s.T().Logf("error destroying instance: %v", err) } }) // Test logic - err = instance.StartAsync() - if err != nil { - t.Fatalf("Error waiting for instance to be running: %v", err) - } + s.Require().NoError(target.StartAsync(ctx)) - webIP, err := instance.GetIP() - if err != nil { - t.Fatalf("Error getting IP: %v", err) - } + webIP, err := target.GetIP(ctx) + s.Require().NoError(err) - err = instance.WaitInstanceIsRunning() - if err != nil { - t.Fatalf("Error waiting for instance to be running: %v", err) - } + s.Require().NoError(target.WaitInstanceIsRunning(ctx)) - wget, err := executor.ExecuteCommand("wget", "-q", "-O", "-", webIP) - if err != nil { - t.Fatalf("Error executing command: %v", err) - } + wget, err := executor.ExecuteCommand(ctx, "wget", "-q", "-O", "-", webIP) + s.Require().NoError(err) - assert.Contains(t, wget, "Welcome to nginx!") + s.Assert().Contains(wget, "Welcome to nginx!") } // TestNoVolumesOneFile tests the scenario where we have no volumes and one file. // the initContainer command that it generates looks like: // no initContainer command, as we do not have volumes. -func TestNoVolumesOneFile(t *testing.T) { - t.Parallel() - // Setup - executor, err := e2e.NewExecutor(context.Background(), "no-volumes-one-file-executor") - if err != nil { - t.Fatalf("Error creating executor: %v", err) - } +func (s *Suite) TestNoVolumesOneFile() { + const ( + namePrefix = "no-volumes-one-file" + numberOfInstances = 2 + ) - const numberOfInstances = 2 - instances := make([]*knuu.Instance, numberOfInstances) + s.T().Parallel() + // Setup + ctx := context.Background() + executor, err := s.Executor.NewInstance(ctx, namePrefix+"-executor") + s.Require().NoError(err) + instances := make([]*instance.Instance, numberOfInstances) for i := 0; i < numberOfInstances; i++ { - instanceName := fmt.Sprintf("web%d", i+1) - instances[i] = e2e.AssertCreateInstanceNginxWithVolumeOwner(t, instanceName) + name := fmt.Sprintf("%s-%d", namePrefix, i+1) + instances[i] = s.createNginxInstance(ctx, name) } - var wgFolders sync.WaitGroup - errorChannel := make(chan error, len(instances)) + var ( + wgFolders sync.WaitGroup + ) - for i, instance := range instances { + for _, i := range instances { wgFolders.Add(1) - go func(i int, instance *knuu.Instance) { + go func(i *instance.Instance) { defer wgFolders.Done() - instanceName := fmt.Sprintf("web%d", i+1) // adding the folder after the Commit, it will help us to use a cached image. - err = instance.AddFile("resources/file_cm_to_folder/test_1", "/usr/share/nginx/html/index.html", "0:0") - if err != nil { - errorChannel <- fmt.Errorf("Error adding file to '%v': %v", instanceName, err) - return - } - errorChannel <- nil - }(i, instance) + err = i.AddFile(resourcesFileCMToFolder+"/test_1", nginxHTMLPath+"/index.html", "0:0") + s.Require().NoError(err, "adding file to '%v'", i.Name()) + }(i) } wgFolders.Wait() - close(errorChannel) - for err := range errorChannel { + s.T().Cleanup(func() { + all := append(instances, executor) + err := instance.BatchDestroy(ctx, all...) if err != nil { - t.Fatalf("%v", err) - } - } - - // Cleanup - t.Cleanup(func() { - err := e2e.AssertCleanupInstances(t, executor, instances) - if err != nil { - t.Fatalf("Error cleaning up: %v", err) + s.T().Logf("error destroying instance: %v", err) } }) // Test logic - for _, instance := range instances { - err = instance.StartAsync() - if err != nil { - t.Fatalf("Error waiting for instance to be running: %v", err) - } + for _, i := range instances { + s.Require().NoError(i.Commit()) + s.Require().NoError(i.StartAsync(ctx)) } - for _, instance := range instances { - webIP, err := instance.GetIP() - if err != nil { - t.Fatalf("Error getting IP: %v", err) - } + for _, i := range instances { + webIP, err := i.GetIP(ctx) + s.Require().NoError(err) - err = instance.WaitInstanceIsRunning() - if err != nil { - t.Fatalf("Error waiting for instance to be running: %v", err) - } + err = i.WaitInstanceIsRunning(ctx) + s.Require().NoError(err) - wget, err := executor.ExecuteCommand("wget", "-q", "-O", "-", webIP) - if err != nil { - t.Fatalf("Error executing command: %v", err) - } + wget, err := executor.ExecuteCommand(ctx, "wget", "-q", "-O", "-", webIP) + s.Require().NoError(err) wget = strings.TrimSpace(wget) - assert.Equal(t, "hello from 1", wget) + s.Assert().Equal("hello from 1", wget) } } // TestOneVolumeOneFile tests the scenario where we have one volume and one file. // the initContainer command that it generates looks like: // mkdir -p /knuu && mkdir -p /knuu/usr/share/nginx/html && chmod -R 777 /knuu//usr/share/nginx/html && if [ -d /usr/share/nginx/html ] && [ \"$(ls -A /usr/share/nginx/html)\" ]; then cp -r /usr/share/nginx/html/* /knuu//usr/share/nginx/html && chown -R 0:0 /knuu/* ;fi -func TestOneVolumeOneFile(t *testing.T) { - t.Parallel() +func (s *Suite) TestOneVolumeOneFile() { + const ( + namePrefix = "one-volume-one-file" + numberOfInstances = 2 + ) + s.T().Parallel() // Setup - executor, err := e2e.NewExecutor(context.Background(), "one-volume-one-file-executor") - if err != nil { - t.Fatalf("Error creating executor: %v", err) - } - - const numberOfInstances = 2 - instances := make([]*knuu.Instance, numberOfInstances) + ctx := context.Background() + executor, err := s.Executor.NewInstance(ctx, namePrefix+"-executor") + s.Require().NoError(err) + instances := make([]*instance.Instance, numberOfInstances) for i := 0; i < numberOfInstances; i++ { - instanceName := fmt.Sprintf("web%d", i+1) - instances[i] = e2e.AssertCreateInstanceNginxWithVolumeOwner(t, instanceName) + name := fmt.Sprintf("%s-%d", namePrefix, i+1) + instances[i] = s.createNginxInstanceWithVolume(ctx, name) } var wgFolders sync.WaitGroup - errorChannel := make(chan error, len(instances)) - - for i, instance := range instances { + for _, i := range instances { wgFolders.Add(1) - go func(i int, instance *knuu.Instance) { + go func(ins *instance.Instance) { defer wgFolders.Done() - instanceName := fmt.Sprintf("web%d", i+1) // adding the folder after the Commit, it will help us to use a cached image. - err := instance.AddFile("resources/file_cm_to_folder/test_1", "/usr/share/nginx/html/index.html", "0:0") - if err != nil { - errorChannel <- fmt.Errorf("Error adding file to '%v': %v", instanceName, err) - return - } - errorChannel <- nil - }(i, instance) + err = ins.AddFile(resourcesFileCMToFolder+"/test_1", nginxHTMLPath+"/index.html", "0:0") + s.Require().NoError(err, "adding file to '%v': %v", i.Name()) + }(i) } wgFolders.Wait() - close(errorChannel) - - for err := range errorChannel { - require.NoError(t, err) - } - t.Cleanup(func() { - // Cleanup - err := e2e.AssertCleanupInstances(t, executor, instances) + s.T().Cleanup(func() { + all := append(instances, executor) + err := instance.BatchDestroy(ctx, all...) if err != nil { - t.Fatalf("Error cleaning up: %v", err) + s.T().Logf("error destroying instance: %v", err) } }) // Test logic - for _, instance := range instances { - err = instance.StartAsync() - if err != nil { - t.Fatalf("Error waiting for instance to be running: %v", err) - } + for _, i := range instances { + s.Require().NoError(i.Commit()) + s.Require().NoError(i.StartAsync(ctx)) } - for _, instance := range instances { - webIP, err := instance.GetIP() - if err != nil { - t.Fatalf("Error getting IP: %v", err) - } + for _, i := range instances { + webIP, err := i.GetIP(ctx) + s.Require().NoError(err) + s.Require().NoError(i.WaitInstanceIsRunning(ctx)) - err = instance.WaitInstanceIsRunning() - if err != nil { - t.Fatalf("Error waiting for instance to be running: %v", err) - } - - wget, err := executor.ExecuteCommand("wget", "-q", "-O", "-", webIP) - if err != nil { - t.Fatalf("Error executing command: %v", err) - } + wget, err := executor.ExecuteCommand(ctx, "wget", "-q", "-O", "-", webIP) + s.Require().NoError(err) wget = strings.TrimSpace(wget) - assert.Equal(t, "hello from 1", wget) + s.Assert().Equal("hello from 1", wget) } } // TestOneVolumeOneFile tests the scenario where we have one volume and one file. // the initContainer command that it generates looks like: // mkdir -p /knuu && mkdir -p /knuu/usr/share/nginx/html && chmod -R 777 /knuu//usr/share/nginx/html && if [ -d /usr/share/nginx/html ] && [ \"$(ls -A /usr/share/nginx/html)\" ]; then cp -r /usr/share/nginx/html/* /knuu//usr/share/nginx/html && chown -R 0:0 /knuu/* ;fi -func TestOneVolumeTwoFiles(t *testing.T) { - t.Parallel() +func (s *Suite) TestOneVolumeTwoFiles() { + const ( + namePrefix = "one-volume-two-files" + numberOfInstances = 2 + ) + s.T().Parallel() // Setup - executor, err := e2e.NewExecutor(context.Background(), "one-volume-two-files-executor") - if err != nil { - t.Fatalf("Error creating executor: %v", err) - } + ctx := context.Background() + executor, err := s.Executor.NewInstance(ctx, namePrefix+"-executor") + s.Require().NoError(err) - const numberOfInstances = 2 - instances := make([]*knuu.Instance, numberOfInstances) + instances := make([]*instance.Instance, numberOfInstances) for i := 0; i < numberOfInstances; i++ { - instanceName := fmt.Sprintf("web%d", i+1) - instances[i] = e2e.AssertCreateInstanceNginxWithVolumeOwner(t, instanceName) + name := fmt.Sprintf("%s-%d", namePrefix, i+1) + instances[i] = s.createNginxInstanceWithVolume(ctx, name) } var wgFolders sync.WaitGroup - errorChannel := make(chan error, len(instances)*2) // Allocate space for potential errors from each file addition in each instance - - for i, instance := range instances { + for _, i := range instances { wgFolders.Add(1) - go func(i int, instance *knuu.Instance) { + go func(i *instance.Instance) { defer wgFolders.Done() - instanceName := fmt.Sprintf("web%d", i+1) // adding the folder after the Commit, it will help us to use a cached image. - if err := instance.AddFile("resources/file_cm_to_folder/test_1", "/usr/share/nginx/html/index.html", "0:0"); err != nil { - errorChannel <- fmt.Errorf("Error adding file test_1 to '%v': %w", instanceName, err) - return - } - if err := instance.AddFile("resources/file_cm_to_folder/test_2", "/usr/share/nginx/html/index-2.html", "0:0"); err != nil { - errorChannel <- fmt.Errorf("Error adding file test_2 to '%v': %w", instanceName, err) - return - } - }(i, instance) - } - wgFolders.Wait() - close(errorChannel) + err := i.AddFile(resourcesFileCMToFolder+"/test_1", nginxHTMLPath+"/index.html", "0:0") + s.Require().NoError(err, "adding file to '%v'", i.Name()) - // Handle errors from the error channel - for err := range errorChannel { - require.NoError(t, err) + err = i.AddFile(resourcesFileCMToFolder+"/test_2", nginxHTMLPath+"/index-2.html", "0:0") + s.Require().NoError(err, "adding file to '%v'", i.Name()) + }(i) } + wgFolders.Wait() - t.Cleanup(func() { - // Cleanup - err := e2e.AssertCleanupInstances(t, executor, instances) + s.T().Cleanup(func() { + all := append(instances, executor) + err := instance.BatchDestroy(ctx, all...) if err != nil { - t.Fatalf("Error cleaning up: %v", err) + s.T().Logf("error destroying instance: %v", err) } }) // Test logic - for _, instance := range instances { - err = instance.StartAsync() - if err != nil { - t.Fatalf("Error waiting for instance to be running: %v", err) - } + for _, i := range instances { + s.Require().NoError(i.Commit()) + s.Require().NoError(i.StartAsync(ctx)) } - for _, instance := range instances { - webIP, err := instance.GetIP() - if err != nil { - t.Fatalf("Error getting IP: %v", err) - } + for _, i := range instances { + webIP, err := i.GetIP(ctx) + s.Require().NoError(err) + s.Require().NoError(i.WaitInstanceIsRunning(ctx)) - err = instance.WaitInstanceIsRunning() - if err != nil { - t.Fatalf("Error waiting for instance to be running: %v", err) - } - - wgetIndex, err := executor.ExecuteCommand("wget", "-q", "-O", "-", webIP) - if err != nil { - t.Fatalf("Error executing command: %v", err) - } + wgetIndex, err := executor.ExecuteCommand(ctx, "wget", "-q", "-O", "-", webIP) + s.Require().NoError(err) wgetIndex = strings.TrimSpace(wgetIndex) + s.Assert().Equal("hello from 1", wgetIndex) webIP2 := webIP + "/index-2.html" - wgetIndex2, err := executor.ExecuteCommand("wget", "-q", "-O", "-", webIP2) - if err != nil { - t.Fatalf("Error executing command: %v", err) - } + wgetIndex2, err := executor.ExecuteCommand(ctx, "wget", "-q", "-O", "-", webIP2) + s.Require().NoError(err) wgetIndex2 = strings.TrimSpace(wgetIndex2) - - assert.Equal(t, "hello from 1", wgetIndex) - assert.Equal(t, "hello from 2", wgetIndex2) + s.Assert().Equal("hello from 2", wgetIndex2) } } diff --git a/e2e/system/folder_test.go b/e2e/system/folder_test.go index 0b6c24c..6200756 100644 --- a/e2e/system/folder_test.go +++ b/e2e/system/folder_test.go @@ -2,59 +2,42 @@ package system import ( "context" - "testing" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/celestiaorg/knuu/e2e" - "github.com/celestiaorg/knuu/pkg/knuu" + "github.com/celestiaorg/knuu/pkg/instance" ) -func TestFolder(t *testing.T) { - t.Parallel() +func (s *Suite) TestFolder() { + const namePrefix = "folder" + s.T().Parallel() + // Setup + ctx := context.Background() + executor, err := s.Executor.NewInstance(ctx, namePrefix) + require.NoError(s.T(), err) + + web := s.createNginxInstanceWithVolume(ctx, namePrefix) + err = web.AddFolder(resourcesHTML, nginxHTMLPath, "0:0") + require.NoError(s.T(), err) + + require.NoError(s.T(), web.Commit()) - executor, err := e2e.NewExecutor(context.Background(), "folder-executor") - if err != nil { - t.Fatalf("Error creating executor: %v", err) - } - - // Create and commit the instance - instanceName := "web" - web := e2e.AssertCreateInstanceNginxWithVolumeOwnerWithoutCommit(t, instanceName) - err = web.AddFolder("resources/html", "/usr/share/nginx/html", "0:0") - if err != nil { - t.Fatalf("Error adding file to '%v': %v", instanceName, err) - } - err = web.Commit() - if err != nil { - t.Fatalf("Error committing instance '%v': %v", instanceName, err) - } - - t.Cleanup(func() { - require.NoError(t, knuu.BatchDestroy(executor, web)) + s.T().Cleanup(func() { + err := instance.BatchDestroy(ctx, web, executor) + if err != nil { + s.T().Logf("Error destroying instance: %v", err) + } }) // Test logic - webIP, err := web.GetIP() - if err != nil { - t.Fatalf("Error getting IP '%v':", err) - } - - err = web.Start() - if err != nil { - t.Fatalf("Error starting instance: %v", err) - } - err = web.WaitInstanceIsRunning() - if err != nil { - t.Fatalf("Error waiting for instance to be running: %v", err) - } - - wget, err := executor.ExecuteCommand("wget", "-q", "-O", "-", webIP) - if err != nil { - t.Fatalf("Error executing command '%v':", err) - } - - assert.Contains(t, wget, "Hello World!") + webIP, err := web.GetIP(ctx) + s.Require().NoError(err) + + s.Require().NoError(web.Start(ctx)) + + wget, err := executor.ExecuteCommand(ctx, "wget", "-q", "-O", "-", webIP) + s.Require().NoError(err) + + s.Assert().Contains(wget, "Hello World!") } diff --git a/e2e/system/folder_test_image_cached_test.go b/e2e/system/folder_test_image_cached_test.go index 8ddb56e..b778fb3 100644 --- a/e2e/system/folder_test_image_cached_test.go +++ b/e2e/system/folder_test_image_cached_test.go @@ -4,78 +4,64 @@ import ( "context" "fmt" "sync" - "testing" - "github.com/stretchr/testify/assert" - - "github.com/celestiaorg/knuu/e2e" - "github.com/celestiaorg/knuu/pkg/knuu" + "github.com/celestiaorg/knuu/pkg/instance" ) -func TestFolderCached(t *testing.T) { - t.Parallel() +func (s *Suite) TestFolderCached() { + const ( + namePrefix = "folder-cached" + numberOfInstances = 10 + ) + s.T().Parallel() // Setup - executor, err := e2e.NewExecutor(context.Background(), "folder-cached-executor") - if err != nil { - t.Fatalf("Error creating executor: %v", err) - } - - // Test logic - const numberOfInstances = 10 - instances := make([]*knuu.Instance, numberOfInstances) + ctx := context.Background() + executor, err := s.Executor.NewInstance(ctx, namePrefix+"-executor") + s.Require().NoError(err) + instances := make([]*instance.Instance, numberOfInstances) for i := 0; i < numberOfInstances; i++ { - instanceName := fmt.Sprintf("web%d", i+1) - instances[i] = e2e.AssertCreateInstanceNginxWithVolumeOwner(t, instanceName) + name := fmt.Sprintf("%s-%d", namePrefix, i+1) + instances[i] = s.createNginxInstanceWithVolume(ctx, name) } var wgFolders sync.WaitGroup - for _, instance := range instances { + for _, i := range instances { wgFolders.Add(1) - go func(instance *knuu.Instance) { + go func(i *instance.Instance) { defer wgFolders.Done() // adding the folder after the Commit, it will help us to use a cached image. - err := instance.AddFolder("resources/html", "/usr/share/nginx/html", "0:0") - if err != nil { - t.Errorf("Error adding file to '%v': %v", instance.Name(), err) - } - }(instance) + err := i.AddFolder(resourcesHTML, nginxHTMLPath, "0:0") + s.Require().NoError(err, "adding file to '%v'", i.Name()) + }(i) } wgFolders.Wait() // Cleanup - t.Cleanup(func() { - err := e2e.AssertCleanupInstances(t, executor, instances) + s.T().Cleanup(func() { + all := append(instances, executor) + err := instance.BatchDestroy(ctx, all...) if err != nil { - t.Fatalf("Error cleaning up: %v", err) + s.T().Logf("error destroying instance: %v", err) } }) // Test logic - for _, instance := range instances { - err = instance.StartAsync() - if err != nil { - t.Fatalf("Error waiting for instance to be running: %v", err) - } + for _, i := range instances { + s.Require().NoError(i.Commit()) + s.Require().NoError(i.StartAsync(ctx)) } - for _, instance := range instances { - webIP, err := instance.GetIP() - if err != nil { - t.Fatalf("Error getting IP: %v", err) - } + for _, i := range instances { + webIP, err := i.GetIP(ctx) + s.Require().NoError(err) - err = instance.WaitInstanceIsRunning() - if err != nil { - t.Fatalf("Error waiting for instance to be running: %v", err) - } + s.Require().NoError(i.WaitInstanceIsRunning(ctx)) - wget, err := executor.ExecuteCommand("wget", "-q", "-O", "-", webIP) - if err != nil { - t.Fatalf("Error executing command: %v", err) - } + wget, err := executor.ExecuteCommand(ctx, "wget", "-q", "-O", "-", webIP) + s.Require().NoError(err) - assert.Contains(t, wget, "Hello World!") + s.Assert().Contains(wget, "Hello World!") } } diff --git a/e2e/system/main_test.go b/e2e/system/main_test.go deleted file mode 100644 index b8f33f1..0000000 --- a/e2e/system/main_test.go +++ /dev/null @@ -1,20 +0,0 @@ -package system - -import ( - "os" - "testing" - - "github.com/sirupsen/logrus" - - "github.com/celestiaorg/knuu/pkg/knuu" -) - -func TestMain(m *testing.M) { - err := knuu.Initialize() - if err != nil { - logrus.Fatalf("error initializing knuu: %v", err) - } - logrus.Infof("Scope: %s", knuu.Scope()) - exitVal := m.Run() - os.Exit(exitVal) -} diff --git a/e2e/system/start_callback_test.go b/e2e/system/start_callback_test.go index 9fd420a..db1b1de 100644 --- a/e2e/system/start_callback_test.go +++ b/e2e/system/start_callback_test.go @@ -15,9 +15,6 @@ import ( const ( callbackName = "callback-test" - nginxImage = "nginx:latest" - nginxPort = 80 - nginxCommand = "nginx -g daemon off" sleepTimeBeforeReady = "1" // second ) diff --git a/e2e/system/suite_setup_test.go b/e2e/system/suite_setup_test.go new file mode 100644 index 0000000..058eb87 --- /dev/null +++ b/e2e/system/suite_setup_test.go @@ -0,0 +1,96 @@ +package system + +import ( + "context" + "testing" + + "github.com/sirupsen/logrus" + "github.com/stretchr/testify/suite" + "k8s.io/apimachinery/pkg/api/resource" + + "github.com/celestiaorg/knuu/e2e" + "github.com/celestiaorg/knuu/pkg/instance" + "github.com/celestiaorg/knuu/pkg/k8s" + "github.com/celestiaorg/knuu/pkg/knuu" + "github.com/celestiaorg/knuu/pkg/minio" +) + +const ( + nginxImage = "docker.io/nginx:latest" + nginxVolumeOwner = 0 + nginxPort = 80 + nginxHTMLPath = "/usr/share/nginx/html" + nginxCommand = "nginx -g daemon off" + + resourcesHTML = "resources/html" + resourcesFileCMToFolder = "resources/file_cm_to_folder" +) + +type Suite struct { + suite.Suite + Knuu *knuu.Knuu + Executor e2e.Executor +} + +var ( + nginxVolume = resource.MustParse("1Gi") +) + +func (s *Suite) SetupSuite() { + var ( + ctx = context.Background() + logger = logrus.New() + ) + + k8sClient, err := k8s.NewClient(ctx, knuu.DefaultScope(), logger) + s.Require().NoError(err, "Error creating k8s client") + + minioClient, err := minio.New(ctx, k8sClient, logger) + s.Require().NoError(err, "Error creating minio client") + + s.Knuu, err = knuu.New(ctx, knuu.Options{ + ProxyEnabled: true, + K8sClient: k8sClient, + MinioClient: minioClient, // needed for build from git tests + }) + s.Require().NoError(err) + + s.T().Logf("Scope: %s", s.Knuu.Scope) + s.Knuu.HandleStopSignal(ctx) + + s.Executor.Kn = s.Knuu +} + +func (s *Suite) TearDownSuite() { + s.T().Cleanup(func() { + logrus.Info("Tearing down test suite...") + err := s.Knuu.CleanUp(context.Background()) + if err != nil { + s.T().Logf("Error cleaning up test suite: %v", err) + } + }) +} + +func TestRunSuite(t *testing.T) { + suite.Run(t, new(Suite)) +} + +func (s *Suite) createNginxInstance(ctx context.Context, name string) *instance.Instance { + ins, err := s.Knuu.NewInstance(name) + s.Require().NoError(err) + + s.Require().NoError(ins.SetImage(ctx, nginxImage)) + s.Require().NoError(ins.AddPortTCP(nginxPort)) + + return ins +} + +func (s *Suite) createNginxInstanceWithVolume(ctx context.Context, name string) *instance.Instance { + ins := s.createNginxInstance(ctx, name) + + _, err := ins.ExecuteCommand(ctx, "mkdir", "-p", nginxHTMLPath) + s.Require().NoError(err) + + s.Require().NoError(ins.AddVolumeWithOwner(nginxHTMLPath, nginxVolume, nginxVolumeOwner)) + return ins +} diff --git a/pkg/instance/errors.go b/pkg/instance/errors.go index 7a1713a..34b9d63 100644 --- a/pkg/instance/errors.go +++ b/pkg/instance/errors.go @@ -136,7 +136,7 @@ var ( ErrSettingPrivilegedNotAllowed = errors.New("SettingPrivilegedNotAllowed", "setting privileged is only allowed in state 'Preparing' or 'Committed'. Current state is '%s") ErrAddingCapabilityNotAllowed = errors.New("AddingCapabilityNotAllowed", "adding capability is only allowed in state 'Preparing' or 'Committed'. Current state is '%s") ErrAddingCapabilitiesNotAllowed = errors.New("AddingCapabilitiesNotAllowed", "adding capabilities is only allowed in state 'Preparing' or 'Committed'. Current state is '%s") - ErrStartingNotAllowed = errors.New("StartingNotAllowed", "starting is only allowed in state 'Committed' or 'Stopped'. Current state of sidecar '%s' is '%s'") + ErrStartingNotAllowed = errors.New("StartingNotAllowed", "starting is only allowed in state 'Committed' or 'Stopped'. Current state of instance '%s' is '%s'") ErrStartingNotAllowedForSidecar = errors.New("StartingNotAllowedForSidecar", "starting is only allowed in state 'Committed' or 'Stopped'. Current state of sidecar '%s' is '%s") ErrStartingSidecarNotAllowed = errors.New("StartingSidecarNotAllowed", "starting a sidecar is not allowed") ErrAddingOtelCollectorSidecar = errors.New("AddingOtelCollectorSidecar", "error adding OpenTelemetry collector sidecar for instance '%s'") diff --git a/pkg/instance/instance.go b/pkg/instance/instance.go index 7311a98..1d78bd0 100644 --- a/pkg/instance/instance.go +++ b/pkg/instance/instance.go @@ -1112,7 +1112,7 @@ func (i *Instance) StartWithCallback(ctx context.Context, callback func()) error // This function can only be called in the state 'Committed' or 'Stopped' func (i *Instance) StartAsync(ctx context.Context) error { if !i.IsInState(StateCommitted, StateStopped) { - return ErrStartingNotAllowed.WithParams(i.state.String()) + return ErrStartingNotAllowed.WithParams(i.k8sName, i.state.String()) } err := applyFunctionToInstances(i.sidecars, func(sidecar *Instance) error { if !sidecar.IsInState(StateCommitted, StateStopped) { diff --git a/pkg/knuu/knuu_old.go b/pkg/knuu/knuu_old.go index ca2439e..db8eca3 100644 --- a/pkg/knuu/knuu_old.go +++ b/pkg/knuu/knuu_old.go @@ -160,3 +160,7 @@ func PushFileToMinio(ctx context.Context, contentName string, reader io.Reader) func GetMinioURL(ctx context.Context, contentName string) (string, error) { return tmpKnuu.MinioClient.GetURL(ctx, contentName, minioBucketName) } + +func GetKnuuObj() *Knuu { + return tmpKnuu +}