Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tests: use DockerHub token in tests' kind clusters #679

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,8 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
KONG_TEST_KONNECT_ACCESS_TOKEN: ${{ secrets.KONG_TEST_KONNECT_ACCESS_TOKEN }}
KONG_TEST_KONNECT_SERVER_URL: us.api.konghq.tech
DOCKERHUB_PULL_TOKEN: ${{ secrets.DOCKERHUB_PULL_TOKEN }}
DOCKERHUB_PULL_USERNAME: ${{ vars.DOCKERHUB_PULL_USERNAME }}

- name: upload diagnostics
if: always()
Expand Down Expand Up @@ -343,6 +345,8 @@ jobs:
KONG_CONTROLLER_OUT: stdout
GOTESTSUM_JUNITFILE: integration-tests-bluegreen-webhook-enabled-${{ matrix.webhook-enabled }}.xml
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
DOCKERHUB_PULL_TOKEN: ${{ secrets.DOCKERHUB_PULL_TOKEN }}
DOCKERHUB_PULL_USERNAME: ${{ vars.DOCKERHUB_PULL_USERNAME }}

- name: upload diagnostics
if: always()
Expand Down Expand Up @@ -393,6 +397,8 @@ jobs:
KONG_PLUGIN_IMAGE_REGISTRY_CREDENTIALS: ${{ secrets.KONG_PLUGIN_IMAGE_REGISTRY_CREDENTIALS }}
GOTESTSUM_JUNITFILE: integration-tests-provision-dataplane-fail.xml
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
DOCKERHUB_PULL_TOKEN: ${{ secrets.DOCKERHUB_PULL_TOKEN }}
DOCKERHUB_PULL_USERNAME: ${{ vars.DOCKERHUB_PULL_USERNAME }}

- name: upload diagnostics
if: always()
Expand Down Expand Up @@ -445,6 +451,8 @@ jobs:
KONG_TEST_GATEWAY_OPERATOR_IMAGE_LOAD: gateway-operator:e2e-${{ github.sha }}
GOTESTSUM_JUNITFILE: "e2e-tests.xml"
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
DOCKERHUB_PULL_TOKEN: ${{ secrets.DOCKERHUB_PULL_TOKEN }}
DOCKERHUB_PULL_USERNAME: ${{ vars.DOCKERHUB_PULL_USERNAME }}

- name: upload diagnostics
if: always()
Expand Down
7 changes: 7 additions & 0 deletions pkg/utils/test/setup_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (

"github.com/kong/gateway-operator/modules/manager"
operatorclient "github.com/kong/gateway-operator/pkg/clientset"
"github.com/kong/gateway-operator/test/helpers"
)

const (
Expand Down Expand Up @@ -102,6 +103,12 @@ func BuildEnvironment(ctx context.Context, existingCluster string, builderOpts .
func buildEnvironmentOnNewKindCluster(ctx context.Context, builderOpts ...BuilderOpt) (environments.Environment, error) {
builder := environments.NewBuilder()

kindBuilder := kind.NewBuilder()
if configFile, err := helpers.CreateKindConfigWithDockerCredentialsBasedOnEnvVars(ctx); err == nil {
kindBuilder.WithConfig(configFile)
builder.WithClusterBuilder(kindBuilder)
}

for _, o := range builderOpts {
o(builder, kind.KindClusterType)
}
Expand Down
7 changes: 7 additions & 0 deletions test/e2e/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,13 @@ func CreateEnvironment(t *testing.T, ctx context.Context, opts ...TestEnvOption)
if !test.IsMetalLBDisabled() {
builder.WithAddons(metallb.New())
}

kindBuilder := kind.NewBuilder()
if configFile, err := helpers.CreateKindConfigWithDockerCredentialsBasedOnEnvVars(ctx); err == nil {
kindBuilder.WithConfig(configFile)
builder.WithClusterBuilder(kindBuilder)
t.Logf("using kind config file (%s)", configFile)
}
}
if imageLoad != "" {
imageLoader, err := loadimage.NewBuilder().WithImage(imageLoad)
Expand Down
119 changes: 119 additions & 0 deletions test/helpers/dockerconfig.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package helpers

import (
"context"
"encoding/base64"
"encoding/json"
"fmt"
"os"
"path/filepath"
)

type dockerRegistryConfig struct {
Auths map[string]DockerRegistryAuth `json:"auths"`
}

// DockerRegistryAuth represents the auth field in the docker registry config.
type DockerRegistryAuth struct {
Auth string `json:"auth"`
}

// DockerRegistryConfigManager is a helper to manage the docker registry config
// for a k8s secret of type kubernetes.io/dockerconfigjson.
type DockerRegistryConfigManager struct {
config dockerRegistryConfig
}

// NewDockerRegistryConfigManager creates a new DockerRegistryConfigManager.
func NewDockerRegistryConfigManager() *DockerRegistryConfigManager {
return &DockerRegistryConfigManager{
config: dockerRegistryConfig{
Auths: map[string]DockerRegistryAuth{},
},
}
}

// Add adds new registry credentials to the config.
func (c *DockerRegistryConfigManager) Add(
registry string,
username string,
token string,
) error {
auth := fmt.Sprintf("%s:%s", username, token)
authEncoded := base64.StdEncoding.EncodeToString([]byte(auth))
c.config.Auths[registry] = DockerRegistryAuth{
Auth: authEncoded,
}
return nil
}

// EncodeForRegcred encodes the config for a k8s secret of type kubernetes.io/dockerconfigjson.
func (c *DockerRegistryConfigManager) EncodeForRegcred() ([]byte, error) {
b, err := json.Marshal(c.config)
if err != nil {
return nil, err
}
// out := make([]byte, base64.StdEncoding.EncodedLen(len(b)))
// base64.StdEncoding.Encode(out, b)
return b, nil
}

// MissingDockerHubEnvVarError is an error type for missing required env vars for DockerHub pull secret.
type MissingDockerHubEnvVarError struct{}

// Error returns the error message.
func (e MissingDockerHubEnvVarError) Error() string {
return "missing required env vars for DockerHub pull secret"
}

// CreateKindConfigWithDockerCredentialsBasedOnEnvVars creates a kind config with docker credentials.
func CreateKindConfigWithDockerCredentialsBasedOnEnvVars(
ctx context.Context,
) (string, error) {
const (
kindConfigTemplate = `kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
extraMounts:
- containerPath: /var/lib/kubelet/config.json
hostPath: %s`
)

dockerHubUser := os.Getenv("DOCKERHUB_PULL_USERNAME")
dockerHubToken := os.Getenv("DOCKERHUB_PULL_TOKEN")
if dockerHubUser == "" || dockerHubToken == "" {
return "", MissingDockerHubEnvVarError{}
}

regCfgMgr := NewDockerRegistryConfigManager()
if err := regCfgMgr.Add("https://index.docker.io/v1/", dockerHubUser, dockerHubToken); err != nil {
return "", err
}

cfgEncoded, err := regCfgMgr.EncodeForRegcred()
if err != nil {
return "", err
}

dockerConfigDir, err := os.MkdirTemp("", "dockerconfig")
if err != nil {
return "", err
}
dockerConfigFileName := filepath.Join(dockerConfigDir, "config.json")
if err := os.WriteFile(dockerConfigFileName, cfgEncoded, 0o777); err != nil { //nolint:gosec
return "", err
}

kindConfigDir, err := os.MkdirTemp("", "kindconfig")
if err != nil {
return "", err
}

kindConfigFileName := filepath.Join(kindConfigDir, "config.yaml")
if err := os.WriteFile(kindConfigFileName, []byte(fmt.Sprintf(kindConfigTemplate, dockerConfigFileName)), 0o777); err != nil { //nolint:gosec
return "", err
}

return kindConfigFileName, err
}
51 changes: 51 additions & 0 deletions test/helpers/dockerconfig_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package helpers

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestDockerRegistryConfigManager(t *testing.T) {
tests := []struct {
name string
update func(*testing.T, *DockerRegistryConfigManager)
expectedJSON string
expectedError error
}{
{
name: "Empty",
expectedJSON: `{"auths":{}}`,
},
{
name: "Valid configuration",
update: func(t *testing.T, c *DockerRegistryConfigManager) {
require.NoError(t,
c.Add(
"registry1",
"username1",
"token1",
),
)
},
expectedJSON: `{"auths":{"registry1":{"auth":"dXNlcm5hbWUxOnRva2VuMQ=="}}}`,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
mgr := NewDockerRegistryConfigManager()
if tt.update != nil {
tt.update(t, mgr)
}

jsonData, err := mgr.EncodeForRegcred()
if tt.expectedError != nil {
require.Error(t, err)
return
}
require.NoError(t, err)
require.Equal(t, tt.expectedJSON, string(jsonData))
})
}
}
Loading