diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml new file mode 100644 index 0000000..3c77778 --- /dev/null +++ b/.github/workflows/test.yaml @@ -0,0 +1,15 @@ +name: test + +on: [push] + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version-file: ./go.mod + - run: go test -v ./... + - run: go build -v ./... diff --git a/go.mod b/go.mod index 07adb08..cca6f4d 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ toolchain go1.22.3 require ( github.com/goccy/go-yaml v1.11.3 github.com/spf13/cobra v1.8.0 + github.com/stretchr/testify v1.8.4 k8s.io/apimachinery v0.30.1 k8s.io/client-go v0.30.1 ) @@ -25,6 +26,7 @@ require ( github.com/mattn/go-isatty v0.0.20 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/spf13/pflag v1.0.5 // indirect golang.org/x/net v0.23.0 // indirect golang.org/x/oauth2 v0.10.0 // indirect @@ -37,6 +39,7 @@ require ( google.golang.org/protobuf v1.33.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/klog/v2 v2.120.1 // indirect k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect diff --git a/pkg/kubernetes/kubeconfig_test.go b/pkg/kubernetes/kubeconfig_test.go new file mode 100644 index 0000000..380cc7c --- /dev/null +++ b/pkg/kubernetes/kubeconfig_test.go @@ -0,0 +1,113 @@ +package kubernetes_test + +import ( + "fmt" + "os" + "testing" + + "github.com/stretchr/testify/assert" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/tools/clientcmd/api" + + "github.com/ryota-sakamoto/kubernetes-on-multipass/pkg/kubernetes" +) + +const baseKubeconfig = `apiVersion: v1 +kind: Config +clusters: +- cluster: + certificate-authority-data: aG9nZQ== + server: https://192.168.205.%[1]d:6443 + name: kubernetes%[1]d +contexts: +- context: + cluster: kubernetes%[1]d + user: admin%[1]d + name: kubernetes%[1]d +current-context: kubernetes%[1]d +users: +- name: admin%[1]d + user: + client-certificate-data: dGVzdAo= + client-key-data: YWJjCg== +` + +func TestMergeKubeconfig(t *testing.T) { + tempDir, err := os.MkdirTemp("", "kom") + if err != nil { + t.Fatal(err) + } + defer func() { + os.RemoveAll(tempDir) + }() + + makeTempKubeconfig(t, tempDir+"/kubeconfig1", fmt.Sprintf(baseKubeconfig, 1)) + makeTempKubeconfig(t, tempDir+"/kubeconfig2", fmt.Sprintf(baseKubeconfig, 2)) + + mergedConfig, err := kubernetes.MergeKubeconfig([]string{tempDir + "/kubeconfig1", tempDir + "/kubeconfig2"}) + if err != nil { + t.Fatal(err) + } + + assert.EqualValues(t, &api.Config{ + APIVersion: "", + Kind: "", + Preferences: api.Preferences{ + Colors: false, + Extensions: make(map[string]runtime.Object), + }, + Clusters: map[string]*api.Cluster{ + "kubernetes1": { + LocationOfOrigin: tempDir + "/kubeconfig1", + Server: "https://192.168.205.1:6443", + CertificateAuthorityData: []byte("hoge"), + Extensions: make(map[string]runtime.Object), + }, + "kubernetes2": { + LocationOfOrigin: tempDir + "/kubeconfig2", + Server: "https://192.168.205.2:6443", + CertificateAuthorityData: []byte("hoge"), + Extensions: make(map[string]runtime.Object), + }, + }, + Contexts: map[string]*api.Context{ + "kubernetes1": { + LocationOfOrigin: tempDir + "/kubeconfig1", + Cluster: "kubernetes1", + AuthInfo: "admin1", + Extensions: make(map[string]runtime.Object), + }, + "kubernetes2": { + LocationOfOrigin: tempDir + "/kubeconfig2", + Cluster: "kubernetes2", + AuthInfo: "admin2", + Extensions: make(map[string]runtime.Object), + }, + }, + CurrentContext: "kubernetes1", + AuthInfos: map[string]*api.AuthInfo{ + "admin1": { + LocationOfOrigin: tempDir + "/kubeconfig1", + ClientCertificateData: []byte("test\n"), + ClientKeyData: []byte("abc\n"), + Extensions: make(map[string]runtime.Object), + }, + "admin2": { + LocationOfOrigin: tempDir + "/kubeconfig2", + ClientCertificateData: []byte("test\n"), + ClientKeyData: []byte("abc\n"), + Extensions: make(map[string]runtime.Object), + }, + }, + Extensions: make(map[string]runtime.Object), + }, mergedConfig) +} + +func makeTempKubeconfig(t *testing.T, path, content string) { + t.Helper() + + err := os.WriteFile(path, []byte(content), 0644) + if err != nil { + t.Fatal(err) + } +}