Skip to content

Commit

Permalink
Merge pull request #93 from cybozu-go/kubectl-moco
Browse files Browse the repository at this point in the history
kubectl-moco plugin
  • Loading branch information
kfyharukz authored Nov 2, 2020
2 parents d0e729b + 0a6a038 commit 29d07d8
Show file tree
Hide file tree
Showing 612 changed files with 80,611 additions and 566 deletions.
13 changes: 11 additions & 2 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ jobs:
with:
go-version: ${{ env.go-version }}
- run: CGO_ENABLED=0 GOOS=linux GOARCH=amd64 make build/entrypoint
- run: CGO_ENABLED=0 GOOS=linux GOARCH=amd64 make build/kubectl-moco
- name: Create Release
id: create_release
uses: actions/create-release@v1
Expand All @@ -38,8 +39,7 @@ jobs:
See [CHANGELOG.md](./CHANGELOG.md) for details.
draft: false
prerelease: ${{ contains(github.ref, '-') }}
- name: Upload Release Assets
id: upload_release_asset
- name: Upload Agent
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand All @@ -48,3 +48,12 @@ jobs:
asset_path: ./build/entrypoint
asset_name: agent
asset_content_type: application/octet-stream
- name: Upload kubectl-moco
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./build/kubectl-moco
asset_name: kubectl-moco
asset_content_type: application/octet-stream
10 changes: 6 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,8 @@ validate: setup

# Run tests
.PHONY: test
test: $(KUBEBUILDER) init-test
test: $(KUBEBUILDER)
go test -race -v -coverprofile cover.out ./...

.PHONY: init-test
init-test:
docker build -t mysql-with-go:latest ./initialize/
docker run -v $(PWD):/go/src/github.com/cybozu-go/moco --rm mysql-with-go:latest sh -c "CGO_ENABLED=0 go test -mod=vendor -v ./initialize"

Expand Down Expand Up @@ -95,6 +92,11 @@ build/entrypoint:
mkdir -p build
GO111MODULE=on go build -o $@ ./cmd/entrypoint

# Build kubectl-moco binary
build/kubectl-moco:
mkdir -p build
GO111MODULE=on go build -o $@ ./cmd/kubectl-moco

# Generate manifests e.g. CRD, RBAC etc.
.PHONY: manifests
manifests: $(CONTROLLER_GEN)
Expand Down
23 changes: 12 additions & 11 deletions agent/clone_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/cybozu-go/moco"
"github.com/cybozu-go/moco/accessor"
"github.com/cybozu-go/moco/metrics"
"github.com/cybozu-go/moco/test_utils"
"github.com/google/go-cmp/cmp"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
Expand All @@ -26,25 +27,25 @@ func testClone() {
var registry *prometheus.Registry

BeforeEach(func() {
err := moco.StartMySQLD(donorHost, donorPort, donorServerID)
err := test_utils.StartMySQLD(donorHost, donorPort, donorServerID)
Expect(err).ShouldNot(HaveOccurred())
err = moco.StartMySQLD(replicaHost, replicaPort, replicaServerID)
err = test_utils.StartMySQLD(replicaHost, replicaPort, replicaServerID)
Expect(err).ShouldNot(HaveOccurred())

err = moco.InitializeMySQL(donorPort)
err = test_utils.InitializeMySQL(donorPort)
Expect(err).ShouldNot(HaveOccurred())
err = moco.InitializeMySQL(replicaPort)
err = test_utils.InitializeMySQL(replicaPort)
Expect(err).ShouldNot(HaveOccurred())

err = moco.PrepareTestData(donorPort)
err = test_utils.PrepareTestData(donorPort)
Expect(err).ShouldNot(HaveOccurred())

err = moco.SetValidDonorList(replicaPort, donorHost, donorPort)
err = test_utils.SetValidDonorList(replicaPort, donorHost, donorPort)
Expect(err).ShouldNot(HaveOccurred())

err = moco.ResetMaster(donorPort)
err = test_utils.ResetMaster(donorPort)
Expect(err).ShouldNot(HaveOccurred())
err = moco.ResetMaster(replicaPort)
err = test_utils.ResetMaster(replicaPort)
Expect(err).ShouldNot(HaveOccurred())

agent = New(host, token, password, password, replicationSourceSecretPath, "", replicaPort,
Expand All @@ -60,8 +61,8 @@ func testClone() {
})

AfterEach(func() {
moco.StopAndRemoveMySQLD(donorHost)
moco.StopAndRemoveMySQLD(replicaHost)
test_utils.StopAndRemoveMySQLD(donorHost)
test_utils.StopAndRemoveMySQLD(replicaHost)
})

It("should return 400 with bad requests", func() {
Expand Down Expand Up @@ -212,7 +213,7 @@ func testClone() {

It("should not clone if recipient has some data", func() {
By("write data to recipient")
err := moco.PrepareTestData(replicaPort)
err := test_utils.PrepareTestData(replicaPort)
Expect(err).ShouldNot(HaveOccurred())

By("cloning from donor")
Expand Down
27 changes: 14 additions & 13 deletions agent/health_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/cybozu-go/moco"
"github.com/cybozu-go/moco/accessor"
"github.com/cybozu-go/moco/metrics"
"github.com/cybozu-go/moco/test_utils"
"github.com/google/go-cmp/cmp"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
Expand All @@ -24,25 +25,25 @@ func testHealth() {
var registry *prometheus.Registry

BeforeEach(func() {
err := moco.StartMySQLD(donorHost, donorPort, donorServerID)
err := test_utils.StartMySQLD(donorHost, donorPort, donorServerID)
Expect(err).ShouldNot(HaveOccurred())
err = moco.StartMySQLD(replicaHost, replicaPort, replicaServerID)
err = test_utils.StartMySQLD(replicaHost, replicaPort, replicaServerID)
Expect(err).ShouldNot(HaveOccurred())

err = moco.InitializeMySQL(donorPort)
err = test_utils.InitializeMySQL(donorPort)
Expect(err).ShouldNot(HaveOccurred())
err = moco.InitializeMySQL(replicaPort)
err = test_utils.InitializeMySQL(replicaPort)
Expect(err).ShouldNot(HaveOccurred())

err = moco.PrepareTestData(donorPort)
err = test_utils.PrepareTestData(donorPort)
Expect(err).ShouldNot(HaveOccurred())

err = moco.SetValidDonorList(replicaPort, donorHost, donorPort)
err = test_utils.SetValidDonorList(replicaPort, donorHost, donorPort)
Expect(err).ShouldNot(HaveOccurred())

err = moco.ResetMaster(donorPort)
err = test_utils.ResetMaster(donorPort)
Expect(err).ShouldNot(HaveOccurred())
err = moco.ResetMaster(replicaPort)
err = test_utils.ResetMaster(replicaPort)
Expect(err).ShouldNot(HaveOccurred())

registry = prometheus.NewRegistry()
Expand All @@ -58,8 +59,8 @@ func testHealth() {
})

AfterEach(func() {
moco.StopAndRemoveMySQLD(donorHost)
moco.StopAndRemoveMySQLD(replicaHost)
test_utils.StopAndRemoveMySQLD(donorHost)
test_utils.StopAndRemoveMySQLD(replicaHost)
})

It("should return 200 if no errors or cloning is not in progress", func() {
Expand All @@ -70,9 +71,9 @@ func testHealth() {

It("should return 500 if cloning process is in progress", func() {
By("executing cloning")
err := moco.ResetMaster(replicaPort)
err := test_utils.ResetMaster(replicaPort)
Expect(err).ShouldNot(HaveOccurred())
err = moco.SetValidDonorList(replicaPort, donorHost, donorPort)
err = test_utils.SetValidDonorList(replicaPort, donorHost, donorPort)
Expect(err).ShouldNot(HaveOccurred())

req := httptest.NewRequest("GET", "http://"+replicaHost+"/clone", nil)
Expand Down Expand Up @@ -118,7 +119,7 @@ func testHealth() {

It("should return 500 if replica status has IO error", func() {
By("executing START SLAVE with invalid parameters")
err := moco.StartSlaveWithInvalidSettings(replicaPort)
err := test_utils.StartSlaveWithInvalidSettings(replicaPort)
Expect(err).ShouldNot(HaveOccurred())

By("getting health")
Expand Down
13 changes: 7 additions & 6 deletions agent/rotate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/cybozu-go/moco"
"github.com/cybozu-go/moco/accessor"
"github.com/cybozu-go/moco/metrics"
"github.com/cybozu-go/moco/test_utils"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/prometheus/client_golang/prometheus"
Expand Down Expand Up @@ -56,19 +57,19 @@ func testRotate() {
})

It("should rotate log files", func() {
err := moco.StartMySQLD(donorHost, donorPort, donorServerID)
err := test_utils.StartMySQLD(donorHost, donorPort, donorServerID)
Expect(err).ShouldNot(HaveOccurred())
err = moco.StartMySQLD(replicaHost, replicaPort, replicaServerID)
err = test_utils.StartMySQLD(replicaHost, replicaPort, replicaServerID)
Expect(err).ShouldNot(HaveOccurred())

err = moco.InitializeMySQL(donorPort)
err = test_utils.InitializeMySQL(donorPort)
Expect(err).ShouldNot(HaveOccurred())
err = moco.InitializeMySQL(replicaPort)
err = test_utils.InitializeMySQL(replicaPort)
Expect(err).ShouldNot(HaveOccurred())

defer func() {
moco.StopAndRemoveMySQLD(donorHost)
moco.StopAndRemoveMySQLD(replicaHost)
test_utils.StopAndRemoveMySQLD(donorHost)
test_utils.StopAndRemoveMySQLD(replicaHost)
}()

By("preparing log files for testing")
Expand Down
16 changes: 8 additions & 8 deletions agent/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"testing"
"time"

"github.com/cybozu-go/moco"
"github.com/cybozu-go/moco/test_utils"
"github.com/go-sql-driver/mysql"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
Expand Down Expand Up @@ -48,21 +48,21 @@ var _ = BeforeSuite(func(done Done) {
Expect(err).ShouldNot(HaveOccurred())
replicationSourceSecretPath = path.Join(pwd, "test_data")

moco.StopAndRemoveMySQLD(donorHost)
moco.StopAndRemoveMySQLD(replicaHost)
moco.RemoveNetwork()
test_utils.StopAndRemoveMySQLD(donorHost)
test_utils.StopAndRemoveMySQLD(replicaHost)
test_utils.RemoveNetwork()

Eventually(func() error {
return moco.CreateNetwork()
return test_utils.CreateNetwork()
}, 10*time.Second).Should(Succeed())

close(done)
}, 60)

var _ = AfterSuite(func() {
moco.StopAndRemoveMySQLD(donorHost)
moco.StopAndRemoveMySQLD(replicaHost)
moco.RemoveNetwork()
test_utils.StopAndRemoveMySQLD(donorHost)
test_utils.StopAndRemoveMySQLD(replicaHost)
test_utils.RemoveNetwork()
})

var _ = Describe("Test Agent", func() {
Expand Down
37 changes: 37 additions & 0 deletions cmd/kubectl-moco/cmd/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package cmd

import (
"context"
"errors"

"github.com/cybozu-go/moco"
mocov1alpha1 "github.com/cybozu-go/moco/api/v1alpha1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
)

func getPassword(ctx context.Context, cluster *mocov1alpha1.MySQLCluster, user string) (string, error) {
secret := &corev1.Secret{}
err := kubeClient.Get(ctx, types.NamespacedName{
Namespace: namespace,
Name: "root-password-" + moco.UniqueName(cluster),
}, secret)
if err != nil {
return "", err
}

userPassKeys := map[string]string{
"root": moco.RootPasswordEnvName,
moco.WritableUser: moco.WritablePasswordEnvName,
moco.ReadOnlyUser: moco.ReadOnlyPasswordEnvName,
}
key, ok := userPassKeys[user]
if !ok {
return "", errors.New("unknown user: " + user)
}
password, ok := secret.Data[key]
if !ok {
return "", errors.New("unknown user: " + user)
}
return string(password), nil
}
62 changes: 62 additions & 0 deletions cmd/kubectl-moco/cmd/credential.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package cmd

import (
"context"
"errors"
"fmt"

mocov1alpha1 "github.com/cybozu-go/moco/api/v1alpha1"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
)

var credentialConfig struct {
user string
format string
}

// credentialCmd represents the credential command
var credentialCmd = &cobra.Command{
Use: "credential",
Short: "Fetch the credential of a specified user",
Long: "Fetch the credential of a specified user.",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
return fetchCredential(cmd.Context(), args[0])
},
}

func fetchCredential(ctx context.Context, clusterName string) error {
cluster := &mocov1alpha1.MySQLCluster{}
err := kubeClient.Get(ctx, types.NamespacedName{
Namespace: namespace,
Name: clusterName,
}, cluster)
if err != nil {
return err
}
password, err := getPassword(ctx, cluster, credentialConfig.user)
if err != nil {
return err
}
switch credentialConfig.format {
case "plain":
fmt.Println(password)
case "myconf":
fmt.Printf(`[client]
user=%s
password="%s"
`, credentialConfig.user, password)
default:
return errors.New("unknown format: " + credentialConfig.format)
}
return nil
}

func init() {
fs := credentialCmd.Flags()
fs.StringVarP(&credentialConfig.user, "user", "u", "readonly", "User for login to mysql [`root`, `moco-writable` or `moco-readonly`]")
fs.StringVar(&credentialConfig.format, "format", "plain", "The format of output [`plain` or `myconf`]")

rootCmd.AddCommand(credentialCmd)
}
Loading

0 comments on commit 29d07d8

Please sign in to comment.