// HTTPClientConfig is used to return a new API client and modify its // configuration by passing in a config modifier function. func HTTPClientConfig(fn func(c *consulapi.Config)) (*consulapi.Client, error) { conf := consulapi.DefaultConfig() fn(conf) return consulapi.NewClient(conf) }
func (c *LockCommand) Run(args []string) int { var name, token string var limit int cmdFlags := flag.NewFlagSet("watch", flag.ContinueOnError) cmdFlags.Usage = func() { c.Ui.Output(c.Help()) } cmdFlags.IntVar(&limit, "n", 1, "") cmdFlags.StringVar(&name, "name", "", "") cmdFlags.StringVar(&token, "token", "", "") cmdFlags.BoolVar(&c.verbose, "verbose", false, "") httpAddr := HTTPAddrFlag(cmdFlags) if err := cmdFlags.Parse(args); err != nil { return 1 } // Check the limit if limit <= 0 { c.Ui.Error(fmt.Sprintf("Lock holder limit must be positive")) return 1 } // Verify the prefix and child are provided extra := cmdFlags.Args() if len(extra) < 2 { c.Ui.Error("Key prefix and child command must be specified") c.Ui.Error("") c.Ui.Error(c.Help()) return 1 } prefix := extra[0] script := strings.Join(extra[1:], " ") // Calculate a session name if none provided if name == "" { name = fmt.Sprintf("Consul lock for '%s' at '%s'", script, prefix) } // Create and test the HTTP client conf := api.DefaultConfig() conf.Address = *httpAddr conf.Token = token client, err := api.NewClient(conf) if err != nil { c.Ui.Error(fmt.Sprintf("Error connecting to Consul agent: %s", err)) return 1 } _, err = client.Agent().NodeName() if err != nil { c.Ui.Error(fmt.Sprintf("Error querying Consul agent: %s", err)) return 1 } // Setup the lock or semaphore var lu *LockUnlock if limit == 1 { lu, err = c.setupLock(client, prefix, name) } else { lu, err = c.setupSemaphore(client, limit, prefix, name) } if err != nil { c.Ui.Error(fmt.Sprintf("Lock setup failed: %s", err)) return 1 } // Attempt the acquisition if c.verbose { c.Ui.Info("Attempting lock acquisition") } lockCh, err := lu.lockFn(c.ShutdownCh) if err != nil || lockCh == nil { c.Ui.Error(fmt.Sprintf("Lock acquisition failed: %s", err)) return 1 } // Start the child process childDone := make(chan struct{}) go func() { if err := c.startChild(script, childDone); err != nil { c.Ui.Error(fmt.Sprintf("%s", err)) } }() // Monitor for shutdown, child termination, or lock loss select { case <-c.ShutdownCh: if c.verbose { c.Ui.Info("Shutdown triggered, killing child") } case <-lockCh: if c.verbose { c.Ui.Info("Lock lost, killing child") } case <-childDone: if c.verbose { c.Ui.Info("Child terminated, releasing lock") } goto RELEASE } // Kill the child if err := c.killChild(childDone); err != nil { c.Ui.Error(fmt.Sprintf("%s", err)) } RELEASE: // Release the lock before termination if err := lu.unlockFn(); err != nil { c.Ui.Error(fmt.Sprintf("Lock release failed: %s", err)) return 1 } // Cleanup the lock if no longer in use if err := lu.cleanupFn(); err != nil { if err != lu.inUseErr { c.Ui.Error(fmt.Sprintf("Lock cleanup failed: %s", err)) return 1 } else if c.verbose { c.Ui.Info("Cleanup aborted, lock in use") } } else if c.verbose { c.Ui.Info("Cleanup succeeded") } return 0 }
// Run is used to run a watch plan func (p *WatchPlan) Run(address string) error { // Setup the client p.address = address conf := consulapi.DefaultConfig() conf.Address = address conf.Datacenter = p.Datacenter conf.Token = p.Token client, err := consulapi.NewClient(conf) if err != nil { return fmt.Errorf("Failed to connect to agent: %v", err) } p.client = client // Create the logger output := p.LogOutput if output == nil { output = os.Stderr } logger := log.New(output, "", log.LstdFlags) // Loop until we are canceled failures := 0 OUTER: for !p.shouldStop() { // Invoke the handler index, result, err := p.Func(p) // Check if we should terminate since the function // could have blocked for a while if p.shouldStop() { break } // Handle an error in the watch function if err != nil { // Perform an exponential backoff failures++ retry := retryInterval * time.Duration(failures*failures) if retry > maxBackoffTime { retry = maxBackoffTime } logger.Printf("consul.watch: Watch (type: %s) errored: %v, retry in %v", p.Type, err, retry) select { case <-time.After(retry): continue OUTER case <-p.stopCh: return nil } } // Clear the failures failures = 0 // If the index is unchanged do nothing if index == p.lastIndex { continue } // Update the index, look for change oldIndex := p.lastIndex p.lastIndex = index if oldIndex != 0 && reflect.DeepEqual(p.lastResult, result) { continue } // Handle the updated result p.lastResult = result if p.Handler != nil { p.Handler(index, result) } } return nil }
func (c *MaintCommand) Run(args []string) int { var enable bool var disable bool var reason string var serviceID string var token string cmdFlags := flag.NewFlagSet("maint", flag.ContinueOnError) cmdFlags.Usage = func() { c.Ui.Output(c.Help()) } cmdFlags.BoolVar(&enable, "enable", false, "enable maintenance mode") cmdFlags.BoolVar(&disable, "disable", false, "disable maintenance mode") cmdFlags.StringVar(&reason, "reason", "", "maintenance reason") cmdFlags.StringVar(&serviceID, "service", "", "service maintenance") cmdFlags.StringVar(&token, "token", "", "") httpAddr := HTTPAddrFlag(cmdFlags) if err := cmdFlags.Parse(args); err != nil { return 1 } // Ensure we don't have conflicting args if enable && disable { c.Ui.Error("Only one of -enable or -disable may be provided") return 1 } if !enable && reason != "" { c.Ui.Error("Reason may only be provided with -enable") return 1 } if !enable && !disable && serviceID != "" { c.Ui.Error("Service requires either -enable or -disable") return 1 } // Create and test the HTTP client conf := api.DefaultConfig() conf.Address = *httpAddr conf.Token = token client, err := api.NewClient(conf) if err != nil { c.Ui.Error(fmt.Sprintf("Error connecting to Consul agent: %s", err)) return 1 } a := client.Agent() nodeName, err := a.NodeName() if err != nil { c.Ui.Error(fmt.Sprintf("Error querying Consul agent: %s", err)) return 1 } if !enable && !disable { // List mode - list nodes/services in maintenance mode checks, err := a.Checks() if err != nil { c.Ui.Error(fmt.Sprintf("Error getting checks: %s", err)) return 1 } for _, check := range checks { if check.CheckID == "_node_maintenance" { c.Ui.Output("Node:") c.Ui.Output(" Name: " + nodeName) c.Ui.Output(" Reason: " + check.Notes) c.Ui.Output("") } else if strings.HasPrefix(check.CheckID, "_service_maintenance:") { c.Ui.Output("Service:") c.Ui.Output(" ID: " + check.ServiceID) c.Ui.Output(" Reason: " + check.Notes) c.Ui.Output("") } } return 0 } if enable { // Enable node maintenance if serviceID == "" { if err := a.EnableNodeMaintenance(reason); err != nil { c.Ui.Error(fmt.Sprintf("Error enabling node maintenance: %s", err)) return 1 } c.Ui.Output("Node maintenance is now enabled") return 0 } // Enable service maintenance if err := a.EnableServiceMaintenance(serviceID, reason); err != nil { c.Ui.Error(fmt.Sprintf("Error enabling service maintenance: %s", err)) return 1 } c.Ui.Output(fmt.Sprintf("Service maintenance is now enabled for %q", serviceID)) return 0 } if disable { // Disable node maintenance if serviceID == "" { if err := a.DisableNodeMaintenance(); err != nil { c.Ui.Error(fmt.Sprintf("Error disabling node maintenance: %s", err)) return 1 } c.Ui.Output("Node maintenance is now disabled") return 0 } // Disable service maintenance if err := a.DisableServiceMaintenance(serviceID); err != nil { c.Ui.Error(fmt.Sprintf("Error disabling service maintenance: %s", err)) return 1 } c.Ui.Output(fmt.Sprintf("Service maintenance is now disabled for %q", serviceID)) return 0 } return 0 }