diff --git a/README.md b/README.md index 9e5a6e1..5a77777 100644 --- a/README.md +++ b/README.md @@ -41,10 +41,11 @@ interval time. - **CI/CD Friendly:** Well-suited to be part of a CI/CD pipeline step - **Cross Platform:** One single pre-built binary for Linux, Mac OSX, and Windows - **Importable:** Beside the CLI tool, Wait4X can be imported as a pkg in your Go app +- **Command execution:** Execute your desired command after a successful wait ## Installation -There are many different ways to install **Wait4X** +There are many ways to install **Wait4X** ### with Docker @@ -235,3 +236,38 @@ wait4x rabbitmq 'amqp://127.0.0.1:5672' # Checking RabbitMQ connection with credentials and vhost wait4x rabbitmq 'amqp://guest:guest@127.0.0.1:5672/vhost' ``` + +### Command Execution + +We need to wait for something in order to execute something else. This feature is also supported by using `--` after a feature parameter. + +Let's have some scenarios: + +* As soon as the MySQL server becomes ready, run a Django migration: + +```shell +wait4x mysql username:password@unix(/tmp/mysql.sock)/myDatabase -- django migrate +``` + +* As soon as the new version of the website becomes ready, send an email to the support team: + +```shell +wait4x http https://www.kernel.org/ --expect-body-xpath "//*[@id="website-logo"]" -- mail -s "The new version of the website has just been released" support@company < /dev/null +``` + +* Chain type: when PostgreSQL becomes ready, then wait for RabbitMQ, when it becomes ready, then run the integration tests: + +```shell +wait4x postgresql 'postgres://bob:secret@/mydb?host=/var/run/postgresql' -t 1m -- wait4x rabbitmq 'amqp://guest:guest@127.0.0.1:5672/vhost' -t 30s -- ./integration-tests.sh +``` + +* Using an environment variable in the command: + +```shell +EMAIL="support@company" wait4x http https://www.kernel.org/ --expect-body-xpath "//*[@id="website-logo"]" -- mail -s "New version of the website has just released" $EMAIL < /dev/null + +# Or + +export EMAIL="support@company" +wait4x http https://www.kernel.org/ --expect-body-xpath "//*[@id="website-logo"]" -- mail -s "New version of the website has just released" $EMAIL < /dev/null +``` diff --git a/internal/app/wait4x/cmd/http.go b/internal/app/wait4x/cmd/http.go index b1d8daa..730eef5 100644 --- a/internal/app/wait4x/cmd/http.go +++ b/internal/app/wait4x/cmd/http.go @@ -28,7 +28,7 @@ import ( // NewHTTPCommand creates the http sub-command func NewHTTPCommand() *cobra.Command { httpCommand := &cobra.Command{ - Use: "http ADDRESS", + Use: "http ADDRESS [flags] [-- command [args...]]", Short: "Check HTTP connection.", Long: "", Args: func(cmd *cobra.Command, args []string) error { diff --git a/internal/app/wait4x/cmd/influxdb.go b/internal/app/wait4x/cmd/influxdb.go index e2d4a19..8b9bdcc 100644 --- a/internal/app/wait4x/cmd/influxdb.go +++ b/internal/app/wait4x/cmd/influxdb.go @@ -24,7 +24,7 @@ import ( // NewInfluxDBCommand creates the influxdb sub-command func NewInfluxDBCommand() *cobra.Command { influxdbCommand := &cobra.Command{ - Use: "influxdb SERVER_URL", + Use: "influxdb SERVER_URL [flags] [-- command [args...]]", Short: "Check InfluxDB connection", Args: func(cmd *cobra.Command, args []string) error { if len(args) < 1 { diff --git a/internal/app/wait4x/cmd/mongodb.go b/internal/app/wait4x/cmd/mongodb.go index b5f10d1..1765e9b 100644 --- a/internal/app/wait4x/cmd/mongodb.go +++ b/internal/app/wait4x/cmd/mongodb.go @@ -24,7 +24,7 @@ import ( // NewMongoDBCommand creates the mongodb sub-command func NewMongoDBCommand() *cobra.Command { mongodbCommand := &cobra.Command{ - Use: "mongodb DSN", + Use: "mongodb DSN [flags] [-- command [args...]]", Short: "Check MongoDB connection", Args: func(cmd *cobra.Command, args []string) error { if len(args) < 1 { diff --git a/internal/app/wait4x/cmd/mysql.go b/internal/app/wait4x/cmd/mysql.go index 7a1936d..f057733 100644 --- a/internal/app/wait4x/cmd/mysql.go +++ b/internal/app/wait4x/cmd/mysql.go @@ -24,7 +24,7 @@ import ( // NewMysqlCommand creates the mysql sub-command func NewMysqlCommand() *cobra.Command { mysqlCommand := &cobra.Command{ - Use: "mysql DSN", + Use: "mysql DSN [flags] [-- command [args...]]", Short: "Check MySQL connection.", Args: func(cmd *cobra.Command, args []string) error { if len(args) < 1 { diff --git a/internal/app/wait4x/cmd/postgresql.go b/internal/app/wait4x/cmd/postgresql.go index fe9a14c..cab3f48 100644 --- a/internal/app/wait4x/cmd/postgresql.go +++ b/internal/app/wait4x/cmd/postgresql.go @@ -24,7 +24,7 @@ import ( // NewPostgresqlCommand creates the postgresql sub-command func NewPostgresqlCommand() *cobra.Command { postgresqlCommand := &cobra.Command{ - Use: "postgresql DSN", + Use: "postgresql DSN [flags] [-- command [args...]]", Aliases: []string{"postgres", "postgre"}, Short: "Check PostgreSQL connection.", Args: func(cmd *cobra.Command, args []string) error { diff --git a/internal/app/wait4x/cmd/rabbitmq.go b/internal/app/wait4x/cmd/rabbitmq.go index 51a01e0..7165965 100644 --- a/internal/app/wait4x/cmd/rabbitmq.go +++ b/internal/app/wait4x/cmd/rabbitmq.go @@ -24,7 +24,7 @@ import ( // NewRabbitMQCommand creates the rabbitmq sub-command func NewRabbitMQCommand() *cobra.Command { rabbitmqCommand := &cobra.Command{ - Use: "rabbitmq DSN", + Use: "rabbitmq DSN [flags] [-- command [args...]]", Short: "Check RabbitMQ connection.", Args: func(cmd *cobra.Command, args []string) error { if len(args) < 1 { diff --git a/internal/app/wait4x/cmd/redis.go b/internal/app/wait4x/cmd/redis.go index bcdf40f..1dc3df3 100644 --- a/internal/app/wait4x/cmd/redis.go +++ b/internal/app/wait4x/cmd/redis.go @@ -26,7 +26,7 @@ import ( // NewRedisCommand creates the redis sub-command func NewRedisCommand() *cobra.Command { redisCommand := &cobra.Command{ - Use: "redis ADDRESS", + Use: "redis ADDRESS [flags] [-- command [args...]]", Short: "Check Redis connection or key existence.", Args: func(cmd *cobra.Command, args []string) error { if len(args) < 1 { diff --git a/internal/app/wait4x/cmd/root.go b/internal/app/wait4x/cmd/root.go index ff4e3db..5d88dff 100644 --- a/internal/app/wait4x/cmd/root.go +++ b/internal/app/wait4x/cmd/root.go @@ -20,6 +20,7 @@ import ( "github.com/go-logr/logr" "github.com/go-logr/zerologr" "os" + "os/exec" "os/signal" "time" @@ -67,6 +68,23 @@ func NewRootCommand() *cobra.Command { Logger() Logger = zerologr.New(&zl) + return nil + }, + PersistentPostRunE: func(cmd *cobra.Command, args []string) error { + if cmd.ArgsLenAtDash() != -1 && (len(args)-cmd.ArgsLenAtDash()) > 0 { + command := args[cmd.ArgsLenAtDash():][0] + arguments := args[cmd.ArgsLenAtDash():][1:] + for i, arg := range arguments { + arguments[i] = os.ExpandEnv(arg) + } + + c := exec.CommandContext(cmd.Context(), command, arguments...) + c.Stdout = os.Stdout + c.Stderr = os.Stderr + + return c.Run() + } + return nil }, } diff --git a/internal/app/wait4x/cmd/tcp.go b/internal/app/wait4x/cmd/tcp.go index 672a254..d72ecbb 100644 --- a/internal/app/wait4x/cmd/tcp.go +++ b/internal/app/wait4x/cmd/tcp.go @@ -26,7 +26,7 @@ import ( // NewTCPCommand creates the tcp sub-command func NewTCPCommand() *cobra.Command { tcpCommand := &cobra.Command{ - Use: "tcp ADDRESS", + Use: "tcp ADDRESS [flags] [-- command [args...]]", Short: "Check TCP connection.", Args: func(cmd *cobra.Command, args []string) error { if len(args) < 1 {