From 623c5adc66e44f3a972d3a61a894c31c74a55900 Mon Sep 17 00:00:00 2001 From: ICHINOSE Shogo Date: Thu, 26 Oct 2023 00:43:26 +0900 Subject: [PATCH] implement rdsmysql command v2 --- .goreleaser.yaml | 1 + v2/.goreleaser.yaml | 1 + v2/cmd/rdsmysql/main.go | 100 +++++++++++++++++++++++++++++++++++ v2/cmd/rdsmysqldump/main.go | 100 +++++++++++++++++++++++++++++++++++ v2/go.mod | 14 ++++- v2/go.sum | 20 +++++++ v2/internal/config/config.go | 2 +- 7 files changed, 236 insertions(+), 2 deletions(-) create mode 100644 v2/cmd/rdsmysql/main.go create mode 100644 v2/cmd/rdsmysqldump/main.go diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 50e2e5b..872ba9d 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -20,6 +20,7 @@ builds: - linux - windows - darwin + main: ./cmd/rdsmysql archives: - format: tar.gz diff --git a/v2/.goreleaser.yaml b/v2/.goreleaser.yaml index 50e2e5b..872ba9d 100644 --- a/v2/.goreleaser.yaml +++ b/v2/.goreleaser.yaml @@ -20,6 +20,7 @@ builds: - linux - windows - darwin + main: ./cmd/rdsmysql archives: - format: tar.gz diff --git a/v2/cmd/rdsmysql/main.go b/v2/cmd/rdsmysql/main.go new file mode 100644 index 0000000..7ca6b5b --- /dev/null +++ b/v2/cmd/rdsmysql/main.go @@ -0,0 +1,100 @@ +package main + +import ( + "context" + "fmt" + "log" + "os" + "os/exec" + "os/signal" + "path/filepath" + "sync" + "syscall" + "time" + + awsConfig "github.com/aws/aws-sdk-go-v2/config" + "github.com/shogo82148/rdsmysql/v2/internal/config" +) + +func main() { + conf, err := config.Parse(os.Args[1:]) + if err != nil { + log.Fatal(err) + } + os.Exit(run(conf)) +} + +func run(c *config.Config) int { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + dir, err := os.MkdirTemp("", "rdsmysql-") + if err != nil { + log.Fatal(err) + } + defer os.RemoveAll(dir) + + cfg, err := awsConfig.LoadDefaultConfig(ctx) + if err != nil { + log.Fatal(err) + } + + err = config.Generate(ctx, cfg, dir, c) + if err != nil { + log.Fatal(err) + } + + mysql, err := exec.LookPath("mysql") + if err != nil { + log.Fatal(err) + } + + args := append([]string{fmt.Sprintf("--defaults-extra-file=%s", filepath.Join(dir, "my.conf"))}, c.Args...) + cmd := exec.Command(mysql, args...) + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Start(); err != nil { + log.Fatal(err) + } + + var wg sync.WaitGroup + done := make(chan struct{}) + + // transfer signals. + wg.Add(1) + go func() { + defer wg.Done() + sig := make(chan os.Signal, 1) + signal.Notify(sig, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) + for { + select { + case s := <-sig: + cmd.Process.Signal(s) + case <-done: + return + } + } + }() + + // password rotation + wg.Add(1) + go func() { + defer wg.Done() + ticker := time.NewTicker(5 * time.Minute) + defer ticker.Stop() + for { + select { + case <-ticker.C: + config.Generate(ctx, cfg, dir, c) + case <-done: + return + } + } + }() + + _ = cmd.Wait() + close(done) + wg.Wait() + return cmd.ProcessState.ExitCode() +} diff --git a/v2/cmd/rdsmysqldump/main.go b/v2/cmd/rdsmysqldump/main.go new file mode 100644 index 0000000..e600805 --- /dev/null +++ b/v2/cmd/rdsmysqldump/main.go @@ -0,0 +1,100 @@ +package main + +import ( + "context" + "fmt" + "log" + "os" + "os/exec" + "os/signal" + "path/filepath" + "sync" + "syscall" + "time" + + awsConfig "github.com/aws/aws-sdk-go-v2/config" + "github.com/shogo82148/rdsmysql/v2/internal/config" +) + +func main() { + conf, err := config.Parse(os.Args[1:]) + if err != nil { + log.Fatal(err) + } + os.Exit(run(conf)) +} + +func run(c *config.Config) int { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + dir, err := os.MkdirTemp("", "rdsmysql-") + if err != nil { + log.Fatal(err) + } + defer os.RemoveAll(dir) + + cfg, err := awsConfig.LoadDefaultConfig(ctx) + if err != nil { + log.Fatal(err) + } + + err = config.Generate(ctx, cfg, dir, c) + if err != nil { + log.Fatal(err) + } + + mysql, err := exec.LookPath("mysqldump") + if err != nil { + log.Fatal(err) + } + + args := append([]string{fmt.Sprintf("--defaults-extra-file=%s", filepath.Join(dir, "my.conf"))}, c.Args...) + cmd := exec.Command(mysql, args...) + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Start(); err != nil { + log.Fatal(err) + } + + var wg sync.WaitGroup + done := make(chan struct{}) + + // transfer signals. + wg.Add(1) + go func() { + defer wg.Done() + sig := make(chan os.Signal, 1) + signal.Notify(sig, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) + for { + select { + case s := <-sig: + cmd.Process.Signal(s) + case <-done: + return + } + } + }() + + // password rotation + wg.Add(1) + go func() { + defer wg.Done() + ticker := time.NewTicker(5 * time.Minute) + defer ticker.Stop() + for { + select { + case <-ticker.C: + config.Generate(ctx, cfg, dir, c) + case <-done: + return + } + } + }() + + _ = cmd.Wait() + close(done) + wg.Wait() + return cmd.ProcessState.ExitCode() +} diff --git a/v2/go.mod b/v2/go.mod index caa25b8..3edc694 100644 --- a/v2/go.mod +++ b/v2/go.mod @@ -4,9 +4,21 @@ go 1.20 require ( github.com/aws/aws-sdk-go-v2 v1.21.2 + github.com/aws/aws-sdk-go-v2/config v1.19.1 github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.2.21 github.com/go-sql-driver/mysql v1.7.1 golang.org/x/time v0.3.0 ) -require github.com/aws/smithy-go v1.15.0 // indirect +require ( + github.com/aws/aws-sdk-go-v2/credentials v1.13.43 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.13 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.43 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.37 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.3.45 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.37 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.15.2 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.17.3 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.23.2 // indirect + github.com/aws/smithy-go v1.15.0 // indirect +) diff --git a/v2/go.sum b/v2/go.sum index d69c7f4..b0146e4 100644 --- a/v2/go.sum +++ b/v2/go.sum @@ -1,7 +1,27 @@ github.com/aws/aws-sdk-go-v2 v1.21.2 h1:+LXZ0sgo8quN9UOKXXzAWRT3FWd4NxeXWOZom9pE7GA= github.com/aws/aws-sdk-go-v2 v1.21.2/go.mod h1:ErQhvNuEMhJjweavOYhxVkn2RUx7kQXVATHrjKtxIpM= +github.com/aws/aws-sdk-go-v2/config v1.19.1 h1:oe3vqcGftyk40icfLymhhhNysAwk0NfiwkDi2GTPMXs= +github.com/aws/aws-sdk-go-v2/config v1.19.1/go.mod h1:ZwDUgFnQgsazQTnWfeLWk5GjeqTQTL8lMkoE1UXzxdE= +github.com/aws/aws-sdk-go-v2/credentials v1.13.43 h1:LU8vo40zBlo3R7bAvBVy/ku4nxGEyZe9N8MqAeFTzF8= +github.com/aws/aws-sdk-go-v2/credentials v1.13.43/go.mod h1:zWJBz1Yf1ZtX5NGax9ZdNjhhI4rgjfgsyk6vTY1yfVg= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.13 h1:PIktER+hwIG286DqXyvVENjgLTAwGgoeriLDD5C+YlQ= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.13/go.mod h1:f/Ib/qYjhV2/qdsf79H3QP/eRE4AkVyEf6sk7XfZ1tg= github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.2.21 h1:m/oetLggG4HFTcU0CkY1uR18uKRNTm+V1XocGd3Wcxk= github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.2.21/go.mod h1:XoCNC17AXoRDfkX2bsFsGsn036fch7ATgchnAy+PsOQ= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.43 h1:nFBQlGtkbPzp/NjZLuFxRqmT91rLJkgvsEQs68h962Y= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.43/go.mod h1:auo+PiyLl0n1l8A0e8RIeR8tOzYPfZZH/JNlrJ8igTQ= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.37 h1:JRVhO25+r3ar2mKGP7E0LDl8K9/G36gjlqca5iQbaqc= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.37/go.mod h1:Qe+2KtKml+FEsQF/DHmDV+xjtche/hwoF75EG4UlHW8= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.45 h1:hze8YsjSh8Wl1rYa1CJpRmXP21BvOBuc76YhW0HsuQ4= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.45/go.mod h1:lD5M20o09/LCuQ2mE62Mb/iSdSlCNuj6H5ci7tW7OsE= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.37 h1:WWZA/I2K4ptBS1kg0kV1JbBtG/umed0vwHRrmcr9z7k= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.37/go.mod h1:vBmDnwWXWxNPFRMmG2m/3MKOe+xEcMDo1tanpaWCcck= +github.com/aws/aws-sdk-go-v2/service/sso v1.15.2 h1:JuPGc7IkOP4AaqcZSIcyqLpFSqBWK32rM9+a1g6u73k= +github.com/aws/aws-sdk-go-v2/service/sso v1.15.2/go.mod h1:gsL4keucRCgW+xA85ALBpRFfdSLH4kHOVSnLMSuBECo= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.17.3 h1:HFiiRkf1SdaAmV3/BHOFZ9DjFynPHj8G/UIO1lQS+fk= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.17.3/go.mod h1:a7bHA82fyUXOm+ZSWKU6PIoBxrjSprdLoM8xPYvzYVg= +github.com/aws/aws-sdk-go-v2/service/sts v1.23.2 h1:0BkLfgeDjfZnZ+MhB3ONb01u9pwFYTCZVhlsSSBvlbU= +github.com/aws/aws-sdk-go-v2/service/sts v1.23.2/go.mod h1:Eows6e1uQEsc4ZaHANmsPRzAKcVDrcmjjWiih2+HUUQ= github.com/aws/smithy-go v1.15.0 h1:PS/durmlzvAFpQHDs4wi4sNNP9ExsqZh6IlfdHXgKK8= github.com/aws/smithy-go v1.15.0/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/v2/internal/config/config.go b/v2/internal/config/config.go index de1cecc..b5ef0d9 100644 --- a/v2/internal/config/config.go +++ b/v2/internal/config/config.go @@ -15,7 +15,7 @@ import ( ) // Generate generates the configuration file for mysql. -func Generate(ctx context.Context, awsConfig *aws.Config, dir string, config *Config) error { +func Generate(ctx context.Context, awsConfig aws.Config, dir string, config *Config) error { cred := awsConfig.Credentials region := awsConfig.Region if region == "" {