mirror of
https://github.com/kemko/xc.git
synced 2026-01-01 15:55:43 +03:00
hosts files
This commit is contained in:
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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,7 +264,8 @@ 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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user