From 8e0988513acf6d8200c8f4e2b7cb78a778b61cde Mon Sep 17 00:00:00 2001 From: Renan DelValle Date: Sun, 3 Dec 2017 12:41:23 -0800 Subject: [PATCH] Adding new verbs and fleshing out the skeleton. Drain works while Kill has an error tha requires a deeper dive. --- cmd/create.go | 27 +++++++++++++++++++++++ cmd/drain.go | 27 ----------------------- cmd/kill.go | 34 +++++++++++++++++++++++----- cmd/root.go | 60 ++++++++++++++++++++++++++++++++++++++++++++++---- cmd/start.go | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++ cmd/stop.go | 57 +++++++++++++++++++++++++++++++++++++++++++++++ main.go | 6 ++--- 7 files changed, 232 insertions(+), 40 deletions(-) create mode 100644 cmd/create.go delete mode 100644 cmd/drain.go create mode 100644 cmd/start.go create mode 100644 cmd/stop.go diff --git a/cmd/create.go b/cmd/create.go new file mode 100644 index 0000000..9ebdfcd --- /dev/null +++ b/cmd/create.go @@ -0,0 +1,27 @@ +package cmd + +import ( + "fmt" + + "github.com/spf13/cobra" +) + +func init() { + rootCmd.AddCommand(createCmd) + createCmd.Flags().StringVarP(&env, "environment", "e", "", "Aurora Environment") + createCmd.Flags().StringVarP(&role, "role", "r", "", "Aurora Role") + createCmd.Flags().StringVarP(&name, "name", "n", "", "Aurora Name") + createCmd.MarkFlagRequired("environment") + createCmd.MarkFlagRequired("role") + createCmd.MarkFlagRequired("name") +} + +var createCmd = &cobra.Command{ + Use: "create", + Short: "Create an Aurora Job", + Run: createJob, +} + +func createJob(cmd *cobra.Command, args []string) { + fmt.Println("Not implemented yet.") +} diff --git a/cmd/drain.go b/cmd/drain.go deleted file mode 100644 index 82fed86..0000000 --- a/cmd/drain.go +++ /dev/null @@ -1,27 +0,0 @@ -package cmd - -import ( - "fmt" - - "github.com/spf13/cobra" -) - -func init() { - rootCmd.AddCommand(drainCmd) -} - -var drainCmd = &cobra.Command{ - Use: "drain [space separated host list]", - Short: "Place a list of space separated Mesos Agents into maintenance mode.", - Long: `Adds a Mesos Agent to Aurora's Drain list. Agents in this list - are not allowed to schedule new tasks and any tasks already running on this Agent - are killed and rescheduled in an Agent that is not in maintenance mode. Command - expects a space separated list of hosts to place into maintenance mode.`, - Args: cobra.MinimumNArgs(1), - Run: drain, -} - -func drain(cmd *cobra.Command, args []string) { - - fmt.Print(args) -} diff --git a/cmd/kill.go b/cmd/kill.go index 7710474..971c3a0 100644 --- a/cmd/kill.go +++ b/cmd/kill.go @@ -2,12 +2,14 @@ package cmd import ( "fmt" + "log" + "os" + realis "github.com/paypal/gorealis" + "github.com/paypal/gorealis/gen-go/apache/aurora" "github.com/spf13/cobra" ) -var env, role, name string - func init() { rootCmd.AddCommand(killCmd) killCmd.Flags().StringVarP(&env, "environment", "e", "", "Aurora Environment") @@ -20,8 +22,28 @@ func init() { var killCmd = &cobra.Command{ Use: "kill", - Short: "kill an Aurora Job", - Run: func(cmd *cobra.Command, args []string) { - fmt.Printf("%s %s %s", env, role, name) - }, + Short: "Kill an Aurora Job", + Run: killJob, +} + +func killJob(cmd *cobra.Command, args []string) { + log.Printf("Killing job [Env:%s Role:%s Name:%s]\n", env, role, name) + + job := realis.NewJob(). + Environment(env). + Role(role). + Name(name) + resp, err := client.KillJob(job.JobKey()) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + if resp.ResponseCode == aurora.ResponseCode_OK { + if ok, err := monitor.Instances(job.JobKey(), 0, 5, 50); !ok || err != nil { + log.Println("Unable to kill all instances of job") + os.Exit(1) + } + } + fmt.Println(resp.String()) } diff --git a/cmd/root.go b/cmd/root.go index a1f295d..ee8e8f4 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -1,13 +1,65 @@ package cmd -import "github.com/spf13/cobra" +import ( + "fmt" + "os" + "time" + + "github.com/paypal/gorealis" + "github.com/spf13/cobra" +) var rootCmd = &cobra.Command{ - Use: "ionbeam", - Short: "ionbeam is a client for Apache Aurora", - Long: `A light-weight, intuitive command line client for use with Apache Aurora.`, + Use: "australis", + Short: "australis is a client for Apache Aurora", + Long: `A light-weight command line client for use with Apache Aurora built using gorealis.`, + PersistentPreRun: connect, + PersistentPostRun: func(cmd *cobra.Command, args []string) { + // Make all children close the client by default upon terminating + client.Close() + }, +} + +var username, password, zkurl string +var env, role, name string +var client realis.Realis +var monitor *realis.Monitor + +func init() { + rootCmd.PersistentFlags().StringVarP(&zkurl, "zookeeper", "z", "", "Zookeeper node(s) where Aurora stores information.") + rootCmd.PersistentFlags().StringVarP(&username, "username", "u", "", "Username to use for API authentification") + rootCmd.PersistentFlags().StringVarP(&password, "password", "p", "", "Password to use for API authentification") + + // TODO(rdelvalle): Add plain URL support. Enforce that url or zookeepr is set. Consider adding support for clusters.json. + // For now make ZK mandatory + rootCmd.MarkPersistentFlagRequired("zookeeper") } func Execute() { rootCmd.Execute() } + +func connect(cmd *cobra.Command, args []string) { + + var err error + + // Connect to Aurora Scheduler and create a client object + client, err = realis.NewRealisClient( + realis.BasicAuth(username, password), + realis.ThriftJSON(), + realis.TimeoutMS(20000), + realis.BackOff(&realis.Backoff{ + Steps: 2, + Duration: 10 * time.Second, + Factor: 2.0, + Jitter: 0.1, + }), + realis.ZKUrl(zkurl)) + + if err != nil { + fmt.Println(err) + os.Exit(1) + } + monitor = &realis.Monitor{Client: client} + +} diff --git a/cmd/start.go b/cmd/start.go new file mode 100644 index 0000000..7138e9d --- /dev/null +++ b/cmd/start.go @@ -0,0 +1,61 @@ +package cmd + +import ( + "fmt" + "os" + + "github.com/paypal/gorealis/gen-go/apache/aurora" + "github.com/spf13/cobra" +) + +func init() { + rootCmd.AddCommand(startCmd) + + // Sub-commands + startCmd.AddCommand(startMaintCmd) +} + +var startCmd = &cobra.Command{ + Use: "start", + Short: "Start a service or maintenance on a host (DRAIN).", +} + +var startMaintCmd = &cobra.Command{ + Use: "drain [space separated host list]", + Short: "Place a list of space separated Mesos Agents into maintenance mode.", + Long: `Adds a Mesos Agent to Aurora's Drain list. Agents in this list +are not allowed to schedule new tasks and any tasks already running on this Agent +are killed and rescheduled in an Agent that is not in maintenance mode. Command +expects a space separated list of hosts to place into maintenance mode.`, + Args: cobra.MinimumNArgs(1), + Run: drain, +} + +func drain(cmd *cobra.Command, args []string) { + fmt.Println("Setting hosts to DRAINING") + fmt.Println(args) + _, result, err := client.DrainHosts(args...) + if err != nil { + fmt.Printf("error: %+v\n", err.Error()) + os.Exit(1) + } + + // Monitor change to DRAINING and DRAINED mode + hostResult, err := monitor.HostMaintenance( + args, + []aurora.MaintenanceMode{aurora.MaintenanceMode_DRAINED, aurora.MaintenanceMode_DRAINING}, + 5, + 10) + if err != nil { + for host, ok := range hostResult { + if !ok { + fmt.Printf("Host %s did not transtion into desired mode(s)\n", host) + } + } + + fmt.Printf("error: %+v\n", err.Error()) + return + } + + fmt.Print(result.String()) +} diff --git a/cmd/stop.go b/cmd/stop.go new file mode 100644 index 0000000..fde50da --- /dev/null +++ b/cmd/stop.go @@ -0,0 +1,57 @@ +package cmd + +import ( + "fmt" + "os" + + "github.com/paypal/gorealis/gen-go/apache/aurora" + "github.com/spf13/cobra" +) + +func init() { + rootCmd.AddCommand(stopCmd) + + // Stop subcommands + stopCmd.AddCommand(stopMaintCmd) +} + +var stopCmd = &cobra.Command{ + Use: "stop", + Short: "Stop a service or maintenance on a host (DRAIN).", +} + +var stopMaintCmd = &cobra.Command{ + Use: "drain [space separated host list]", + Short: "Stop maintenance on a host (move to NONE).", + Long: `Transition a list of hosts currently in a maintenance status out of it.`, + Run: endMaintenance, +} + +func endMaintenance(cmd *cobra.Command, args []string) { + fmt.Println("Setting hosts to NONE maintenance status.") + fmt.Println(args) + _, result, err := client.EndMaintenance(args...) + if err != nil { + fmt.Printf("error: %+v\n", err.Error()) + os.Exit(1) + } + + // Monitor change to NONE mode + hostResult, err := monitor.HostMaintenance( + args, + []aurora.MaintenanceMode{aurora.MaintenanceMode_NONE}, + 5, + 10) + if err != nil { + for host, ok := range hostResult { + if !ok { + fmt.Printf("Host %s did not transtion into desired mode(s)\n", host) + } + } + + fmt.Printf("error: %+v\n", err.Error()) + return + } + + fmt.Print(result.String()) +} diff --git a/main.go b/main.go index 85038fc..7724b03 100644 --- a/main.go +++ b/main.go @@ -1,9 +1,9 @@ package main import ( - "github.com/rdelval/ionbeam/cmd" + "github.com/rdelval/australis/cmd" ) func main() { - cmd.Execute() -} \ No newline at end of file + cmd.Execute() +}