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

refactor pkg/kind #482

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
72 changes: 4 additions & 68 deletions pkg/kind/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,11 @@ package kind

import (
"context"
"embed"
"errors"
"fmt"
"github.com/cnoe-io/idpbuilder/pkg/util"
"github.com/cnoe-io/idpbuilder/pkg/util/files"
"io"
"io/fs"
"os"
"strconv"
"strings"

"github.com/cnoe-io/idpbuilder/api/v1alpha1"
"github.com/go-logr/logr"
Expand Down Expand Up @@ -43,11 +38,6 @@ type Cluster struct {
cfg v1alpha1.BuildCustomizationSpec
}

type PortMapping struct {
HostPort string
ContainerPort string
}

type IProvider interface {
List() ([]string, error)
ListNodes(string) ([]nodes.Node, error)
Expand All @@ -57,67 +47,13 @@ type IProvider interface {
ExportKubeConfig(string, string, bool) error
}

type TemplateConfig struct {
v1alpha1.BuildCustomizationSpec
KubernetesVersion string
ExtraPortsMapping []PortMapping
RegistryConfig string
}

//go:embed resources/*
var configFS embed.FS

func (c *Cluster) getConfig() ([]byte, error) {
httpClient := util.GetHttpClient()
rawConfigTempl, err := loadConfig(c.kindConfigPath, httpClient)

var rawConfigTempl []byte
var err error
portMappingPairs := parsePortMappings(c.extraPortsMapping)

if c.kindConfigPath != "" {
if strings.HasPrefix(c.kindConfigPath, "https://") || strings.HasPrefix(c.kindConfigPath, "http://") {
httpClient := util.GetHttpClient()
resp, err := httpClient.Get(c.kindConfigPath)
if err != nil {
return nil, fmt.Errorf("fetching remote kind config: %w", err)
}
defer resp.Body.Close()
rawConfigTempl, err = io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("reading remote kind config body: %w", err)
}
} else {
rawConfigTempl, err = os.ReadFile(c.kindConfigPath)
}
} else {
rawConfigTempl, err = fs.ReadFile(configFS, "resources/kind.yaml.tmpl")
}

if err != nil {
return nil, fmt.Errorf("reading kind config: %w", err)
}

var portMappingPairs []PortMapping
if len(c.extraPortsMapping) > 0 {
// Split pairs of ports "11=1111","22=2222",etc
pairs := strings.Split(c.extraPortsMapping, ",")
// Create a slice to store PortMapping pairs.
portMappingPairs = make([]PortMapping, len(pairs))
// Parse each pair into PortPair objects.
for i, pair := range pairs {
parts := strings.Split(pair, ":")
if len(parts) == 2 {
portMappingPairs[i] = PortMapping{parts[0], parts[1]}
}
}
}

registryConfig := ""
for _, s := range c.registryConfig {
path := os.ExpandEnv(s)
if _, err := os.Stat(path); err == nil {
registryConfig = path
break
}
}
registryConfig := findRegistryConfig(c.registryConfig)

if len(c.registryConfig) > 0 && registryConfig == "" {
return nil, errors.New("--registry-config flag used but no registry config was found")
Expand Down
73 changes: 0 additions & 73 deletions pkg/kind/cluster_test.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,12 @@
package kind

import (
"context"
"io"
"os"
"testing"

"github.com/cnoe-io/idpbuilder/api/v1alpha1"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
"github.com/go-logr/logr"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"sigs.k8s.io/kind/pkg/cluster/nodes"
"sigs.k8s.io/kind/pkg/exec"
)

func TestGetConfig(t *testing.T) {
Expand Down Expand Up @@ -202,69 +195,3 @@ func TestGetConfigCustom(t *testing.T) {
assert.YAMLEq(t, string(expected), string(b))
}
}

// Mock provider for testing
type mockProvider struct {
mock.Mock
IProvider
}

func (m *mockProvider) ListNodes(name string) ([]nodes.Node, error) {
args := m.Called(name)
return args.Get(0).([]nodes.Node), args.Error(1)
}

type mockRuntime struct {
mock.Mock
}

func (m *mockRuntime) ContainerWithPort(ctx context.Context, name string, port string) (bool, error) {
args := m.Called(ctx, name, port)
return args.Get(0).(bool), args.Error(1)
}

// Mock Docker client for testing
type DockerClientMock struct {
client.APIClient
mock.Mock
}

func (m *DockerClientMock) ContainerList(ctx context.Context, listOptions types.ContainerListOptions) ([]types.Container, error) {
mockArgs := m.Called(ctx, listOptions)
return mockArgs.Get(0).([]types.Container), mockArgs.Error(1)
}

type NodeMock struct {
mock.Mock
}

func (n *NodeMock) Command(command string, args ...string) exec.Cmd {
argsMock := append([]string{command}, args...)
mockArgs := n.Called(argsMock)
return mockArgs.Get(0).(exec.Cmd)
}

func (n *NodeMock) String() string {
args := n.Called()
return args.String(0)
}

func (n *NodeMock) Role() (string, error) {
args := n.Called()
return args.String(0), args.Error(1)
}

func (n *NodeMock) IP() (ipv4 string, ipv6 string, err error) {
args := n.Called()
return args.String(0), args.String(1), args.Error(2)
}

func (n *NodeMock) SerialLogs(writer io.Writer) error {
args := n.Called(writer)
return args.Error(0)
}

func (n *NodeMock) CommandContext(ctx context.Context, cmd string, args ...string) exec.Cmd {
mockArgs := n.Called(nil)
return mockArgs.Get(0).(exec.Cmd)
}
90 changes: 90 additions & 0 deletions pkg/kind/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package kind

import (
"embed"
"fmt"
"io"
"io/fs"
"net/http"
"os"
"strings"

"github.com/cnoe-io/idpbuilder/api/v1alpha1"
)

type PortMapping struct {
HostPort string
ContainerPort string
}

type TemplateConfig struct {
v1alpha1.BuildCustomizationSpec
KubernetesVersion string
ExtraPortsMapping []PortMapping
RegistryConfig string
}

//go:embed resources/* testdata/custom-kind.yaml.tmpl
var configFS embed.FS

type HttpClient interface {
Get(url string) (resp *http.Response, err error)
}

func loadConfig(path string, httpClient HttpClient) ([]byte, error) {
var rawConfigTempl []byte
var err error
if path != "" {
if strings.HasPrefix(path, "https://") || strings.HasPrefix(path, "http://") {
resp, err := httpClient.Get(path)
if err != nil {
return nil, fmt.Errorf("fetching remote kind config: %w", err)
}
defer resp.Body.Close()
if !(resp.StatusCode < 300 && resp.StatusCode >= 200) {
return nil, fmt.Errorf("got %d status code when fetching kind config", resp.StatusCode)
}
rawConfigTempl, err = io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("reading remote kind config body: %w", err)
}
} else {
rawConfigTempl, err = os.ReadFile(path)
}
} else {
rawConfigTempl, err = fs.ReadFile(configFS, "resources/kind.yaml.tmpl")
}

if err != nil {
return nil, fmt.Errorf("reading kind config: %w", err)
}
return rawConfigTempl, nil
}

func parsePortMappings(extraPortsMapping string) []PortMapping {
var portMappingPairs []PortMapping
if len(extraPortsMapping) > 0 {
// Split pairs of ports "11=1111","22=2222",etc
pairs := strings.Split(extraPortsMapping, ",")
// Create a slice to store PortMapping pairs.
portMappingPairs = make([]PortMapping, len(pairs))
// Parse each pair into PortPair objects.
for i, pair := range pairs {
parts := strings.Split(pair, ":")
if len(parts) == 2 {
portMappingPairs[i] = PortMapping{parts[0], parts[1]}
}
}
}
return portMappingPairs
}

func findRegistryConfig(registryConfigPaths []string) string {
for _, s := range registryConfigPaths {
path := os.ExpandEnv(s)
if _, err := os.Stat(path); err == nil {
return path
}
}
return ""
}
Loading
Loading