From a559137fe366ad95999ee7a133679bfe68855036 Mon Sep 17 00:00:00 2001 From: Renan DelValle Date: Fri, 16 Nov 2018 21:54:18 -0800 Subject: [PATCH] Adding initial support for printing results in JSON format. Adding Logrus logging and adding a logging level argument. Adding StartMaintenance API. --- cmd/fetch.go | 13 +++--- cmd/root.go | 2 +- cmd/start.go | 121 +++++++++++++++++++++++++++++++++++++++------------ cmd/stop.go | 27 ++---------- cmd/util.go | 43 ++++++++++++++++-- 5 files changed, 145 insertions(+), 61 deletions(-) diff --git a/cmd/fetch.go b/cmd/fetch.go index b90203d..1b9b9fb 100644 --- a/cmd/fetch.go +++ b/cmd/fetch.go @@ -31,7 +31,6 @@ func init() { help := leaderCmd.HelpFunc() leaderCmd.SetHelpFunc(func(cmd *cobra.Command, s []string){ if cmd.HasInheritedFlags(){ - cmd.InheritedFlags().VisitAll(func(f *pflag.Flag){ if f.Name != "logLevel" { f.Hidden = true @@ -63,9 +62,7 @@ var taskConfigCmd = &cobra.Command{ var leaderCmd = &cobra.Command{ Use: "leader [zkNode0, zkNode1, ...zkNodeN]", - PersistentPreRun: func(cmd *cobra.Command, args []string) { - - }, //We don't need a realis client for this cmd + PersistentPreRun: func(cmd *cobra.Command, args []string) {}, //We don't need a realis client for this cmd PersistentPostRun: func(cmd *cobra.Command, args []string) {}, //We don't need a realis client for this cmd PreRun: setConfig, Args: cobra.MinimumNArgs(1), @@ -172,7 +169,13 @@ func fetchJobs(cmd *cobra.Command, args []string) { } if toJson { - fmt.Println(toJSON(result.GetConfigs())) + var configSlice []*aurora.JobConfiguration + + for config := range result.GetConfigs() { + configSlice = append(configSlice, config) + } + + fmt.Println(toJSON(configSlice)) } else { for jobConfig := range result.GetConfigs() { fmt.Println(jobConfig) diff --git a/cmd/root.go b/cmd/root.go index ede47b4..c5ecf64 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -39,7 +39,7 @@ func init() { rootCmd.PersistentFlags().StringVarP(&caCertsPath, "caCertsPath", "a", "", "Path where CA certificates can be found.") rootCmd.PersistentFlags().BoolVarP(&skipCertVerification, "skipCertVerification", "i", false, "Skip CA certificate hostname verification.") rootCmd.PersistentFlags().StringVar(&configFile, "config", "/etc/aurora/australis.yml", "Config file to use.") - rootCmd.PersistentFlags().BoolVar(&toJson, "jsonOutput", false, "Print output in JSON format.") + rootCmd.PersistentFlags().BoolVar(&toJson, "toJSON", false, "Print output in JSON format.") rootCmd.PersistentFlags().StringVarP(&logLevel, "logLevel", "l", "info", "Set logging level [" + getLoggingLevels() + "].") } diff --git a/cmd/start.go b/cmd/start.go index 849cb2b..fc74480 100644 --- a/cmd/start.go +++ b/cmd/start.go @@ -1,7 +1,6 @@ package cmd import ( - "fmt" "github.com/paypal/gorealis/gen-go/apache/aurora" "github.com/spf13/cobra" @@ -13,12 +12,23 @@ func init() { // Sub-commands - startCmd.AddCommand(startMaintCmd) + startCmd.AddCommand(startDrainCmd) // Maintenance specific flags - startMaintCmd.Flags().IntVar(&monitorInterval,"interval", 5, "Interval at which to poll scheduler.") - startMaintCmd.Flags().IntVar(&monitorTimeout,"timeout", 50, "Time after which the monitor will stop polling and throw an error.") + startDrainCmd.Flags().IntVar(&monitorInterval,"interval", 5, "Interval at which to poll scheduler.") + startDrainCmd.Flags().IntVar(&monitorTimeout,"timeout", 50, "Time after which the monitor will stop polling and throw an error.") + startCmd.AddCommand(startSLADrainCmd) + + // SLA Maintenance specific flags + startSLADrainCmd.Flags().IntVar(&monitorInterval,"interval", 5, "Interval at which to poll scheduler.") + startSLADrainCmd.Flags().IntVar(&monitorTimeout,"timeout", 50, "Time after which the monitor will stop polling and throw an error.") + + startCmd.AddCommand(startMaintenanceCmd) + + // SLA Maintenance specific flags + startMaintenanceCmd.Flags().IntVar(&monitorInterval,"interval", 5, "Interval at which to poll scheduler.") + startMaintenanceCmd.Flags().IntVar(&monitorTimeout,"timeout", 50, "Time after which the monitor will stop polling and throw an error.") } var startCmd = &cobra.Command{ @@ -26,9 +36,9 @@ var startCmd = &cobra.Command{ Short: "Start a service, maintenance on a host (DRAIN), a snapshot, or a backup.", } -var startMaintCmd = &cobra.Command{ +var startDrainCmd = &cobra.Command{ Use: "drain [space separated host list]", - Short: "Place a list of space separated Mesos Agents into maintenance mode.", + Short: "Place a list of space separated Mesos Agents into draining 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 @@ -37,6 +47,27 @@ expects a space separated list of hosts to place into maintenance mode.`, Run: drain, } +var startSLADrainCmd = &cobra.Command{ + Use: "sla-drain [space separated host list]", + Short: "Place a list of space separated Mesos Agents into maintenance mode using SLA awareness.", + 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: SLAdrain, +} + +var startMaintenanceCmd = &cobra.Command{ + Use: "maintenance [space separated host list]", + Short: "Place a list of space separated Mesos Agents into maintenance mode.", + Long: `Places Mesos Agent into Maintenance mode. Agents in this list +are de-prioritized for scheduling a task. Command +expects a space separated list of hosts to place into maintenance mode.`, + Args: cobra.MinimumNArgs(1), + Run: maintenance, +} + func drain(cmd *cobra.Command, args []string) { log.Infoln("Setting hosts to DRAINING") log.Infoln(args) @@ -54,30 +85,62 @@ func drain(cmd *cobra.Command, args []string) { monitorInterval, monitorTimeout) - transitioned := make([]string, 0,0) + + maintenanceMonitorPrint(hostResult, []aurora.MaintenanceMode{aurora.MaintenanceMode_DRAINED}) + if err != nil { - nonTransitioned := make([]string, 0,0) - - for host, ok := range hostResult { - if ok { - transitioned = append(transitioned, host) - } else { - nonTransitioned = append(nonTransitioned, host) - } - } - - log.Printf("error: %+v\n", err) - if toJson { - fmt.Println(toJSON(nonTransitioned)) - } else { - fmt.Println("Did not enter DRAINED status: ", nonTransitioned) - } + log.Fatalln("error: %+v", err) } - - if toJson { - fmt.Println(toJSON(transitioned)) - } else { - fmt.Println("Entered DRAINED status: ", transitioned) - } } +func SLAdrain(cmd *cobra.Command, args []string) { + log.Infoln("Setting hosts to DRAINING with SLA awareness") + log.Infoln(args) + + policy := aurora.SlaPolicy{CountSlaPolicy: &aurora.CountSlaPolicy{Count: 1, DurationSecs: 60*30}} + result, err := client.SLADrainHosts(&policy, 60*60, args...) + if err != nil { + log.Fatalf("error: %+v\n", err) + } + + log.Debugln(result) + + // Monitor change to DRAINING and DRAINED mode + hostResult, err := monitor.HostMaintenance( + args, + []aurora.MaintenanceMode{aurora.MaintenanceMode_DRAINED}, + monitorInterval, + monitorTimeout) + + maintenanceMonitorPrint(hostResult, []aurora.MaintenanceMode{aurora.MaintenanceMode_DRAINED}) + + if err != nil { + log.Fatalln("error: %+v", err) + } + +} + +func maintenance(cmd *cobra.Command, args []string) { + log.Infoln("Setting hosts to Maintenance mode") + log.Infoln(args) + _, result, err := client.StartMaintenance(args...) + if err != nil { + log.Fatalf("error: %+v\n", err) + } + + log.Debugln(result) + + // Monitor change to DRAINING and DRAINED mode + hostResult, err := monitor.HostMaintenance( + args, + []aurora.MaintenanceMode{aurora.MaintenanceMode_SCHEDULED}, + monitorInterval, + monitorTimeout) + + + maintenanceMonitorPrint(hostResult, []aurora.MaintenanceMode{aurora.MaintenanceMode_SCHEDULED}) + + if err != nil { + log.Fatalln("error: %+v", err) + } +} diff --git a/cmd/stop.go b/cmd/stop.go index 1d89068..a4bde17 100644 --- a/cmd/stop.go +++ b/cmd/stop.go @@ -61,30 +61,11 @@ func endMaintenance(cmd *cobra.Command, args []string) { monitorInterval, monitorTimeout) - transitioned := make([]string, 0,0) + + maintenanceMonitorPrint(hostResult,[]aurora.MaintenanceMode{aurora.MaintenanceMode_NONE}) + if err != nil { - nonTransitioned := make([]string, 0,0) - - for host, ok := range hostResult { - if ok { - transitioned = append(transitioned, host) - } else { - nonTransitioned = append(nonTransitioned, host) - } - } - - log.Printf("error: %+v\n", err) - if toJson { - fmt.Println(toJSON(nonTransitioned)) - } else { - fmt.Println("Did not enter NONE status: ", nonTransitioned) - } - } - - if toJson { - fmt.Println(toJSON(transitioned)) - } else { - fmt.Println("Entered NONE status: ", transitioned) + log.Fatalln("error: %+v", err) } } diff --git a/cmd/util.go b/cmd/util.go index 781233c..e39e179 100644 --- a/cmd/util.go +++ b/cmd/util.go @@ -3,8 +3,10 @@ package cmd import ( "bytes" "encoding/json" + "fmt" + "github.com/paypal/gorealis/gen-go/apache/aurora" - log "github.com/sirupsen/logrus" + log "github.com/sirupsen/logrus" ) func toJSON(v interface{}) string { @@ -12,7 +14,7 @@ func toJSON(v interface{}) string { output, err := json.Marshal(v) if err != nil { - log.Fatalln("Unable to serialize statuses") + log.Fatalln("Unable to serialize Aurora response: %+v", v) } return string(output) @@ -32,4 +34,39 @@ func getLoggingLevels() string { return buffer.String() -} \ No newline at end of file +} + + +func maintenanceMonitorPrint(hostResult map[string]bool, desiredStates []aurora.MaintenanceMode) { + if len(hostResult) > 0 { + // Create anonymous struct for JSON formatting + output := struct{ + DesiredStates []string `json:desired_states` + Transitioned []string `json:transitioned` + NonTransitioned []string `json:non-transitioned` + }{ + make([]string, 0), + make([]string, 0), + make([]string, 0), + } + + for _,state := range desiredStates { + output.DesiredStates = append(output.DesiredStates, state.String()) + } + + for host, ok := range hostResult { + if ok { + output.Transitioned = append(output.Transitioned, host) + } else { + output.NonTransitioned = append(output.NonTransitioned, host) + } + } + + if toJson { + fmt.Println(toJSON(output)) + } else { + fmt.Printf("Entered %v status: %v", output.DesiredStates, output.Transitioned) + fmt.Printf("Did not enter %v status: %v", output.DesiredStates, output.NonTransitioned) + } + } +}