From 157cda66b7dc2f78d078caff1c84ccd81f980103 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=92=D0=BE=D1=80=D0=BE=D0=B1=D1=8C=D0=B5=D0=B2=20=D0=9F?=
=?UTF-8?q?=D0=B0=D0=B2=D0=B5=D0=BB?=
Date: Mon, 3 Aug 2020 18:02:19 +0300
Subject: [PATCH] hosts files
---
cli/completer.go | 5 +++++
cli/handlers.go | 12 ++++++++++++
cli/help.go | 8 +++++---
cmd/xc/main.go | 6 ++++++
store/parser.go | 21 +++++++++++++++++++++
store/store.go | 18 ++++++++++++++++++
6 files changed, 67 insertions(+), 3 deletions(-)
diff --git a/cli/completer.go b/cli/completer.go
index 85dfb65..4248957 100644
--- a/cli/completer.go
+++ b/cli/completer.go
@@ -176,6 +176,11 @@ func (x *completer) completeExec(line []rune) ([][]rune, int) {
return x.completeTag(line[1:])
}
+ if len(line) > 0 && line[0] == '&' {
+ comp, ll := completeFiles(line[1:])
+ return comp, ll + 1
+ }
+
return x.completeHost(line)
}
diff --git a/cli/handlers.go b/cli/handlers.go
index c7ef912..dac5594 100644
--- a/cli/handlers.go
+++ b/cli/handlers.go
@@ -6,6 +6,7 @@ import (
"os/exec"
"os/signal"
"runtime"
+ "runtime/debug"
"strconv"
"syscall"
@@ -56,6 +57,7 @@ func (c *Cli) setupCmdHandlers() {
c.handlers["version"] = c.doVersion
c.handlers["goruntime"] = c.doGoruntime
c.handlers["natural_sort"] = c.doNaturalSort
+ c.handlers["_mem"] = c.doMemoryDump
commands := make([]string, len(c.handlers))
i := 0
@@ -74,6 +76,16 @@ func (c *Cli) doExit(name string, argsLine string, args ...string) {
c.stopped = true
}
+func (c *Cli) doMemoryDump(name string, argsLine string, args ...string) {
+ f, err := os.Create("/tmp/xcheap.dump")
+ if err != nil {
+ term.Errorf("Can't dump: %s\n", err)
+ return
+ }
+ defer f.Close()
+ debug.WriteHeapDump(f.Fd())
+}
+
func (c *Cli) doMode(name string, argsLine string, args ...string) {
if len(args) < 1 {
term.Errorf("Usage: mode <[serial,parallel,collapse]>\n")
diff --git a/cli/help.go b/cli/help.go
index 40781e1..4198387 100644
--- a/cli/help.go
+++ b/cli/help.go
@@ -252,7 +252,8 @@ with symlinks. It's more stable though.`,
Every expression is a comma-separated list of tokens, where token may be
- a single host,
- a single group,
- - a single workgroup,
+ - a single workgroup,
+ - a filename containing a list of hosts
and every item may optionally be limited to a particular datacenter, a given tag,
or even be completely excluded from the list.
@@ -263,8 +264,9 @@ Some self-explanatory examples:
%group1,-host2 - all hosts from group1, excluding(!) host2
%group2@dc1 - all hosts from group2, located in datacenter dc1
*myworkgroup@dc2,-%group3,host5 - all hosts from wg "myworkgroup" excluding hosts from group3, plus host5
- %group5#tag1 - all hosts from group5 tagged with tag1
-
+ %group5#tag1 - all hosts from group5 tagged with tag1
+ &hosts.txt - hosts from file hosts.txt
+
You may combine any number of tokens keeping in mind that they are resolved left to right, so exclusions
almost always should be on the righthand side. For example, "-host1,host1" will end up with host1 in list
despite being excluded previously.`,
diff --git a/cmd/xc/main.go b/cmd/xc/main.go
index 6db9036..e6bb7c7 100644
--- a/cmd/xc/main.go
+++ b/cmd/xc/main.go
@@ -1,6 +1,7 @@
package main
import (
+ "net/http"
"os"
"path"
"strings"
@@ -9,12 +10,17 @@ import (
"github.com/viert/xc/backend/inventoree"
"github.com/viert/xc/backend/localini"
+ _ "net/http/pprof"
+
"github.com/viert/xc/cli"
"github.com/viert/xc/config"
"github.com/viert/xc/term"
)
func main() {
+
+ go http.ListenAndServe(":5001", nil)
+
var tool *cli.Cli
var err error
diff --git a/store/parser.go b/store/parser.go
index 3a957df..65c8f0a 100644
--- a/store/parser.go
+++ b/store/parser.go
@@ -14,6 +14,7 @@ const (
tTypeGroup
tTypeWorkGroup
tTypeHostRegexp
+ tTypeHostListFile
)
const (
@@ -25,6 +26,7 @@ const (
stateReadTag
stateReadHostBracePattern
stateReadRegexp
+ stateReadHostListFile
)
type token struct {
@@ -83,6 +85,12 @@ func parseExpression(expr []rune) ([]*token, error) {
continue
}
+ if sym == '&' {
+ ct.Type = tTypeHostListFile
+ state = stateReadHostListFile
+ continue
+ }
+
if sym == '/' || sym == '~' {
state = stateReadHost
ct.Type = tTypeHostRegexp
@@ -214,6 +222,19 @@ func parseExpression(expr []rune) ([]*token, error) {
}
ct.Value += string(sym)
+
+ case stateReadHostListFile:
+ if sym == ',' || last {
+ if last && sym != ',' {
+ ct.Value += string(sym)
+ }
+ res = append(res, ct)
+ ct = newToken()
+ state = stateWait
+ continue
+ }
+ ct.Value += string(sym)
+
case stateReadHostBracePattern:
if sym == '{' {
return nil, fmt.Errorf("nested patterns are not allowed (at %d)", i)
diff --git a/store/store.go b/store/store.go
index 1026bbf..f67046e 100644
--- a/store/store.go
+++ b/store/store.go
@@ -1,6 +1,8 @@
package store
import (
+ "bufio"
+ "os"
"regexp"
"sort"
"strings"
@@ -179,6 +181,22 @@ func (s *Store) HostList(expr []rune) ([]string, error) {
}
switch token.Type {
+ case tTypeHostListFile:
+ filename := token.Value
+ f, err := os.Open(filename)
+ if err != nil {
+ return nil, err
+ }
+ sc := bufio.NewScanner(f)
+ for sc.Scan() {
+ hostname := strings.Trim(sc.Text(), " \t\r\n")
+ if hostname == "" || strings.Contains(hostname, " ") || strings.HasPrefix(hostname, "#") {
+ continue
+ }
+ etoken.hosts = append(etoken.hosts, hostname)
+ }
+ f.Close()
+
case tTypeHostRegexp:
for _, host := range s.matchHost(token.RegexpFilter) {
etoken.hosts = append(etoken.hosts, host)