Files
xc/cli/help.go
Воробьев Павел 157cda66b7 hosts files
2020-08-03 18:02:19 +03:00

464 lines
17 KiB
Go

package cli
import (
"fmt"
"strings"
"github.com/viert/xc/term"
)
type helpItem struct {
help string
usage string
isTopic bool
}
var (
execHelp = &helpItem{
usage: "<host_expression> <command>",
help: `Runs a command on a list of servers.
List of hosts is represented by <host_expression> in its own syntax which can be learned
by using "help expressions" command.
exec can proceed in 3 different modes: serial, parallel and collapse.
In ` + term.Colored("serial", term.CWhite, true) + ` mode the command will be called server by server sequentally. Between servers in list
xc will hold for a delay which can be set with command "delay".
In ` + term.Colored("parallel", term.CWhite, true) + ` mode the command will be executed simultaneously. All output will be prefixed by
host name which the output line belongs to. Output is (almost) non buffered so one can use
parallel mode to run "infinite" commands like "tail -f" which is handy for watching logs from
the whole cluster in real-time.
The ` + term.Colored("collapse", term.CWhite, true) + ` mode is a lot like the parallel mode however the whole output is hidden until
the execution is over. In this mode xc prints the result grouped by the output so the differences
between hosts become more obvious. Try running "exec %group cat /etc/redhat-release" on a big
group of hosts in collapse mode to see if they have the same version of OS for example.
While the execution mode can be switched by "mode" command, there's a couple of shortcuts:
c_exec
p_exec
s_exec
which are capable to run exec in collapse, parallel or serial mode correspondingly without switching
the execution mode`,
}
runScriptHelp = &helpItem{
usage: "<host_expression> <scriptname>",
help: `Runs a local script on a given list of hosts.
To learn mode about <host_expression> type "help expressions".
runscript simply copies the script to every server in the list and then
run it according to current execution mode (Type "help exec" to learn more
on execution modes), i.e. it can run in parallel or sequentally like exec does.
There are also shortcut aliases c_runscript, s_runscript and p_runscript for calling runscript
in a particular execution mode without permanent switching to it.`,
}
modeHelp = `Switches execution mode
To learn more about execution modes type "help exec".
Xc has shortcuts for switching modes: just type "parallel", "serial" or "collapse" and it will
switch the mode correspondingly.`
helpStrings = map[string]*helpItem{
"alias": &helpItem{
usage: "<aliasname> <cmd> [<args>]",
help: `Creates a local alias. This is handy for longer commands which are often in use.
Example:
alias ls local ls - this will create a local alias "ls" which actually runs "local ls"
alias uptime p_exec #1 uptime - this creates a local alias "uptime" which runs "p_exec <ARG> uptime"
<ARG> will be taken from the alias command and put into p_exec command,
i.e. uptime %mygroup will run p_exec %mygroup uptime
Every alias created disappears after xc exits. To make an alias persistent put it into rcfile.
See "help rcfiles" for further info.`,
},
"cd": &helpItem{
usage: "<dir>",
help: "Changes working directory",
},
"config": &helpItem{
isTopic: true,
help: `Configuration file is located in ~/.xc.conf.
The first time xc starts it creates a default configuration file with all the settings set
to default values:
[main]
user =
mode = parallel
history_file = ~/.xc_history
cache_dir = ~/.xc_cache
cache_ttl = 336 # 24 * 7 * 2
rc_file = ~/.xcrc
raise = none
exit_confirm = true
exec_confirm = false
log_file = ~/xc.log
distribute = scp
debug = false
[executer]
ssh_threads = 50
ssh_connect_timeout = 1
ssh_command = /usr/bin/ssh
progress_bar = true
prepend_hostnames = true
remote_tmpdir = /tmp
delay = 0
interpreter = bash
interpreter_sudo = sudo bash
interpreter_su = su -
[backend]
type = inventoree
url = http://inventory-stage.infra.cloud.devmail.ru
auth_token = <token>
work_groups = WorkGroup1,WorkGroup2
host_key_field = ssh_hostname
Configuration is split to 3 sections: main, executer and backend.
[main]
user is the user which will be set on xc startup. If empty, the current system user is used.
mode is the execution mode which will be set on xc startup. See "help mode" for more info on execution modes.
history_file sets the history file
cache_dir sets the cache dir for data derived from inventoree
cache_ttl sets cache ttl (in hours)
rc_file is the rcfile which will be executed on xc startup. See "help rcfiles" for more info.
raise is the raise mode which will be set on xc startup
exit_confirm is boolean setting for disable or enable confirmation on exit
distribute sets initial distribute type to either tar or scp. See "help distribute_type" to learn more.
debug sets initial debug logging on/off.
[executer]
ssh_threads limits the number of simultaneously running ssh commands.
ssh_connect_timeout sets the default ssh connect timeout. You can change it at any moment using connect_timeout command.
progress_bar sets progressbar on or off on xc startup
remote_tmpdir is a temporary directory used on remote servers for various xc needs
delay sets a delay in seconds between hosts when executing in serial mode. See "help delay" for more info
interpreter_* sets commands executed remotely to boot the necessary interpreter according to current "raise" mode
The [backend] section sets data storage backend. Three backends are currently supported: inventoree, conductor and ini. The backend type is set by a mandatory option "type".
1. "ini" backend stores hosts and groups in a local ini-file.
There's only one option "filename" to tell xc where to find the ini-file.
Example of ini-file:
[workgroups]
workgroup1
[groups]
group1 work_group=workgroup1
group2 work_grlup=workgroup2 parent=group1
[hosts]
host1.example.com group=group1 datacenter=dc1.1
host2.example.com group=group2 datacenter=dc1.1
[datacenters]
dc1
dc1.1 parent=dc1
2. "conductor" loads hosts and groups via inventoree v1 API which is deprecated
3. "inventoree" is the most modern way to store your data. Options are following:
url - a base url to inventoree instance (inventoree >= 7.0 is required)
auth_token - your personal auth token
work_groups - a comma-separated list of workgroups to load. If the list is empty, xc will load all the workgroups which could increase loading time dramatically.
host_key_field - may be set to either "fqdn" or "ssh_hostname", this tells xc what a host is identified by.
ssh_hostname in its turn is a computed field in inventoree >= 7.2-45 which may be configured
in custom data field "ssh_hostname" like aliases are configured (using $0, $1, $2 etc as domain parts)
`,
},
"rcfiles": &helpItem{
isTopic: true,
help: `Rcfile configured in .xc.conf file is executed every time xc starts.
It may be useful for configuring aliases (as they are dropped when xc exits) and other options.
Rcfile is just a number of xc commands in a text file.`,
},
"passmgr": &helpItem{
isTopic: true,
help: `Password manager is a golang plugin which must have two exported functions:
func Init(options map[string]string, debugf func(string, ...interface{})) error
func GetPass(host string) string
Init function is called on xc start passing all the options found in [passmgr] config section
as a map[string]string, and a debugf function which logs to xc shared log if it's enabled.
GetPass function is called to acquire proper password for a host. Xc passes a hostname as the
only argument and expects function to return a password.
For more info on how to write golang plugins, please refer to golang documentation or this article:
https://medium.com/learning-the-go-programming-language/writing-modular-go-programs-with-plugins-ec46381ee1a9`,
},
"debug": &helpItem{
usage: "<on/off>",
help: `An internal debug. May cause unexpected output. One shouldn't use it unless she knows what she's doing.`,
},
"delay": &helpItem{
usage: "<seconds>",
help: `Sets a delay between hosts when in serial mode. This is useful for soft restarting
i.e. when you want to give a service some time to warm up before restarting it on next host.`,
},
"distribute": &helpItem{
usage: "<host_expression> <filename>",
help: `Distributes a local file to a number of hosts listed in "host_expression" in parallel.
See "help expressions" for further info on <host_expression>.
Example: distribute %mygroup hello.txt`,
},
"distribute_type": &helpItem{
usage: "<scp/tar>",
help: `Sets the backend used for the "distribute" command.
"tar" option should work faster, it also supports symlinks but may spend
more memory. "scp" is slower and may let you down in copying directories
with symlinks. It's more stable though.`,
},
"expressions": &helpItem{
help: `A lot of commands in xc use host expressions with a certain syntax to represent a list of hosts.
Every expression is a comma-separated list of tokens, where token may be
- a single host,
- a single group,
- 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.
Some self-explanatory examples:
host1,host2 - simple host list containing 2 hosts
%group1 - a group of hosts taken from inventoree
%group1,host1 - all hosts from group1, plus host1
%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
&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.`,
isTopic: true,
},
"exec": execHelp,
"s_exec": execHelp,
"c_exec": execHelp,
"p_exec": execHelp,
"exit": &helpItem{
usage: "",
help: "Exits the xc program. You can also use Ctrl-D to quit xc.",
},
"help": &helpItem{
usage: "[<command>]",
help: "Shows help on various commands and topics",
},
"hostlist": &helpItem{
usage: "<host_expression>",
help: `Resolves the host expression and prints the resulting hostlist. To learn more about expressions
use "help expressions" command`,
},
"local": &helpItem{
usage: "<command>",
help: `Runs local command.
For example you may want to ping a host without leaving the xc.
This can be done by typing "local ping 1.1.1.1". For frequently used commands you may want to create
aliases like so: alias ping local ping #*. This will create an alias "ping" so you won't have to type
"local" in front of "ping" anymore. To learn more about aliases type "help alias"`,
},
"mode": &helpItem{
usage: "<serial/parallel/collapse>",
help: modeHelp,
},
"parallel": &helpItem{
usage: "",
help: modeHelp,
},
"serial": &helpItem{
usage: "",
help: modeHelp,
},
"collapse": &helpItem{
usage: "",
help: modeHelp,
},
"prepend_hostnames": &helpItem{
usage: "<on/off>",
help: `Sets prepend hostnames mode on or off. When calling without arguments, shows the current value.
This switches the appearence of hostnames before the output lines in parallel mode.
Switching them off is useful for copy-pasting the results.`,
},
"passwd": &helpItem{
usage: "",
help: `Sets the password for raising privileges`,
},
"progressbar": &helpItem{
usage: "[<on/off>]",
help: `Sets the progressbar on or off. If no value is given, prints the current value.`,
},
"natural_sort": &helpItem{
usage: "[<on/off>]",
help: `Sets natural sorting of host lists on or off. If no value is given, prints the current value.
Important note: sorting works only within one expression token, that is, if you
explicitly type the hostlist like "host5,host3,host1", the order is preserved,
xc considers you know what you are doing. Sorting is applied only within a group,
a workgroup or a pattern like "host{1..50}"`,
},
"raise": &helpItem{
usage: "<none/sudo/su>",
help: `Sets the type of raising privileges during running the "exec" command.
If the value is "none", no attempts to raise privileges will be made.`,
},
"reload": &helpItem{
usage: "",
help: `Reloads hosts and groups data from inventoree and rewrites the cache`,
},
"runscript": runScriptHelp,
"c_runscript": runScriptHelp,
"p_runscript": runScriptHelp,
"s_runscript": runScriptHelp,
"interpreter": &helpItem{
usage: "[raise_type interpreter]",
help: `When invoking without arguments, the command shows the current interpreters for each type
of privileges rasing ("help raise" to learn more on that). You can redefine interpreter
using this command as in the given examples:
interpreter su su -m
interpreter sudo sudo /bin/bash
interpreter none /bin/sh`,
},
"output": &helpItem{
usage: "[filename]",
help: `Copies the entire output of parallel(!) exec commands to a given logfile. To switch
the logging off, type "output _". When invoked without arguments, output command prints
the current output filename (or a message saying that the output logging is switched off)
and exits.`,
},
"ssh": &helpItem{
usage: "<host_expression>",
help: `Starts ssh session to hosts one by one, raising the privileges if raise type is not "none"
("help raise" to learn more) and gives the control to user. When user exits the session
xc moves on to the next server.`,
},
"threads": &helpItem{
usage: "[num_threads]",
help: `Sets max number of simultaneously running ssh threads to <num_threads>. When called
without arguments, prints the current value.`,
},
"use_password_manager": &helpItem{
usage: "[<on/off>]",
help: `Sets the password manager on/off. If no value is given, prints the current value.
If password manager is not ready, setting this value to "on" will print an error.`,
},
"user": &helpItem{
usage: "<username>",
help: `Sets the username for all the execution commands. This is used to get access to hosts via ssh/scp.`,
},
}
)
func (c *Cli) doHelp(name string, argsLine string, args ...string) {
if len(args) < 1 {
generalHelp()
return
}
if hs, found := helpStrings[args[0]]; found {
if hs.isTopic {
fmt.Printf("\nTopic: %s\n\n", term.Colored(args[0], term.CWhite, true))
} else {
fmt.Printf("\nCommand: %s %s\n\n", term.Colored(args[0], term.CWhite, true), hs.usage)
}
tokens := strings.Split(hs.help, "\n")
for _, token := range tokens {
fmt.Printf(" %s\n", token)
}
fmt.Println()
} else {
term.Errorf("There's no help on topic \"%s\"\n", args[0])
}
}
func generalHelp() {
fmt.Println(`
List of commands:
alias creates a local alias command
cd changes current working directory
collapse shortcut for "mode collapse"
debug one shouldn't use this
delay sets a delay between hosts in serial mode
distribute copies a file to a number of hosts in parallel
distribute_type sets the backend of the "distribute" command
exec/c_exec/s_exec/p_exec executes a remote command on a number of hosts
exit exits the xc
help shows help on various topics
hostlist resolves a host expression to a list of hosts
interpreter sets interpreter for each type of privileges raising
local starts a local command
mode switches between execution modes
natural_sort sets natural sorting on/off
parallel shortcut for "mode parallel"
passwd sets passwd for privilege raise
progressbar controls progressbar
raise sets the privilege raise mode
reload reloads hosts and groups data from inventoree
runscript runs a local script on a number of remote hosts
serial shortcut for "mode serial"
ssh starts ssh session to a number of hosts sequentally
use_password_manager turns password manager on/off
user sets current user`)
fmt.Println()
}