pax_global_header 0000666 0000000 0000000 00000000064 12524707522 0014520 g ustar 00root root 0000000 0000000 52 comment=cbae5c1be5e3e8e89d494586df7632cb74644e45
cc-cli-v7/ 0000775 0000000 0000000 00000000000 12524707522 0012550 5 ustar 00root root 0000000 0000000 cc-cli-v7/.gitignore 0000664 0000000 0000000 00000000016 12524707522 0014535 0 ustar 00root root 0000000 0000000 *.pyc
*~
TODO
cc-cli-v7/COPYRIGHT 0000664 0000000 0000000 00000000040 12524707522 0014035 0 ustar 00root root 0000000 0000000 Copytight © 2010-2015 Smartjog
cc-cli-v7/LICENSE 0000664 0000000 0000000 00000016743 12524707522 0013570 0 ustar 00root root 0000000 0000000 GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
cc-cli-v7/README 0000664 0000000 0000000 00000003307 12524707522 0013433 0 ustar 00root root 0000000 0000000 =======
Profile
=======
A profile in a set of configuration options.
cc-cli support FreeDesktop BaseDirectory specifications, see
http://standards.freedesktop.org/basedir-spec/0.6/ to store his config files.
Profiles are stored in ~/.config/cc-cli/profile. This file format is ini in which
every profile is a section.
cc-cli load at every start the cli profile. You can specify
a default profile in cli profile with option "profile".
You will find examples in examples subdirectory in git repository.
To quickly connect to mulptiple servers, you can define a profile by server.
=======
Loading
=======
Configuration is loaded in this order:
1 Check CC_DEBUG, to set early debugging mode
2 load [cli] profile from ~/.config/cc-cli/profile
3 load profile specified by option profile (arg line, env, cli profile)
4 load options from environment
5 load options from command line
===========
Environment
===========
You can set some options by environment variables.
The following variables are recognised: CC_SERVER, CC_PORT, CC_LOGIN, CC_PASS,
CC_DEBUG, CC_PROFILE.
=====
Alias
=====
CLI support aliasing. This is a very useful command substitution
Alias is stored in ~/.config/cc-cli/alias
You can use the alias command to set alias.
Setting an alias w, which list online client
alias w "list a&con!=offline&role=client"
Setting an alias vm, which list running vm (and show cpu)
alias vm "list vm&status=running$cpu"
=======
History
=======
CLI history is stored in ~/.local/share/cc-cli/history
Expoert mode history is stored in ~/.local/share/cc-cli/expert
===
TQL
===
You can look in TQL file to see the power of tql.
===========
New release
===========
Update version in cccli/__init__.py
Update version in debian/changelog
cc-cli-v7/TQL 0000664 0000000 0000000 00000011451 12524707522 0013135 0 ustar 00root root 0000000 0000000 ==================
Tag Query Languag
==================
== by examples ==
seblu> list id #list all ids, same as list
seblu> list a #list all accounts
seblu> list h:fw* #list all hostname starting by fw
seblu> list r=hv #list all hypervisor
seblu> list r=vm #list all vm
seblu> list hv=toto #list vm of hypervisor toto
seblu> list hv=toto&h=chiche #list vm chiche of hypervisor toto
seblu> list r=vm&cpu=2 #list vm with 2 cpu
seblu> list r=vm&cpu=2&mem>10g #list vm with 2 cpu and mem > 10g
seblu> list r=hv&cpu=2&mem>10g #list hypervisor with no vm
seblu> list cpu>=2$pop$alloc #list object with at least 2cpu and show tags pop and alloc
seblu> list r=vm^10 #list first 10 vm
seblu> list r=vm^:10 #list last 10 vm
seblu> list r=vm^5:10 #list vm
seblu> list r=vm%vm #list vm sorted by vm
seblu> list r=vm%vm%cpu #list vm sorted by vm and cpu
seblu> list r=vm&-cpu #list vm without tag cpu
seblu> list a-con #list disconnected account
== Basics ==
- TQL build a list of objects in one query
- An object is a list of tags
- TQL can select and sort object by tags
- TQL can choose tags in object
- TQL can limit number of objects to select
- TQL is a list statement mixed by separators
- TQL build his object list from left to right (left parenthesis)
- Each statement update the builded list regarding his separators
- Selecting, sorting and showing separators are followed by tags
- Limiting separators are followed by limiting conditions
- TQL always return id tag
- By default separators is &
- By default object list is sorted id
== Tags ==
- Every tag is composed by a tagname and a tagvalue
- Tagname are case insensitive, tagvalue is case sensitive
- You can use globin on tagname
- tagname starting by - means all tag except this one
- Operators machtes on tagvalues
== statement separators ==
& selection intersection
| selection union
/ selection complement
^ selection limit
$ tag showing
% tag sorting
== tags operators ==
= strict equality
: globing matching (no case)
~ regex matching
> superior strict
>= superior
< inferior
<= inferior strict
Each previous operators can be negated by adding ! before it.
== limiting conditions ==
n limit to n first objects
:n limit to last n objects
n:m limit from n to m objects
== number facility ==
10k = 1000
10ki = 1024
1m = 1000 ^ 2
1mi = 1024 ^ 2
1g = 1000 ^ 3
1gi = 1024 ^ 3
== reserverd tags ==
Reserved tags are tags with a special meaning and cannot be set or remove
directly by clients
id: object unique identifier (eg: kvmlab-1.test5)
a: account name (eg: bobby)
r: account role (host/hv/vm/cli/web/spv)
closed: account close status
con: connection uptime in seconds (eg: 3600)
ip: ipv4 of connection
hv: hypervisor id (eg: kvmlab-1)
== well known tags ==
h: hostname (eg: access)
htype: hypervisor type (xen/kvm)
libvirtver: Libvirt version
status: VM status (running/paused/stopped)
cpu: cpu count
rcpu: reserved cpu count
mem: memory total size
memused: memory used
memfree: memory free
arch: hardware architecture (x86/x64)
uname: output of uname command
uptime: uptime of hostname
load: load average
os: operating system (linux/windows)
alloc: host is allowed to be selected to a migration
hvm: hardware virtualisation enabled
nvm: vm count on an hypervisor
vmstarted: started vm count on an hypervisor
vmstopped: stopped vm count on an hypervisor
vmpaused: paused vm count on an hypervisor
version: account reported version
sto: storage pool names (eg: vg fg)
stovg_type: vg storage pool type (eg: lvm)
stovg_size: vg storage pool size (eg: 1042)
stovg_used: vg storage pool used space (eg: 1)
stovg_free: vg storage pool free space (eg: 1041)
stovg_path: vg storage pool path (eg: /dev/vg/)
stovg_vol: vg storage pool volume list (eg: sex titi toto)
disk: disk index list (eg: 1 2 3 4)
disk1_path: disk 1 path (eg: /dev/vg/sex)
disk1_size: disk 1 size (eg: 1024)
disk1_pool: storage pool back reference (eg: vg) [vmonly]
disk1_vol: storage pool volume back reference (eg: titi) [vmonly]
vncport: vnc local port (eg: 5001)
hvver: hypervisor version (eg: 0.14)
hserial: host serial number (eg: Dell service tag)
hvendor: host vendor (eg: Dell Computer Corporation)
hmodel: host model (eg: PowerEdge 2850)
hbios: host bios version and/or date (eg: A05 (01/09/2006))
cputhread: total number of cpu thread
cpufreq: cpu core frequency
cpuuse: global cpu usage (percentage)
platform: python platform info
chaserial: blade chassis serial number (dell tag)
chaasset: blade chassis asset tag (dell tag)
== grammar ==
input: [ prop ] EOL
prop: "(" prop ")" | stat
stat: [ prop ] sep prop | [ prop ] mod word | clause
clause: word [ op word ]
sep: "&" | "|" | "/"
mod: "^" | "%" | "$"
op: "=" | "!=" | ":" | "!:" | "~" | "!~" | ">" | ">=" | "<" | "<="
cc-cli-v7/bin/ 0000775 0000000 0000000 00000000000 12524707522 0013320 5 ustar 00root root 0000000 0000000 cc-cli-v7/bin/cc-cli 0000775 0000000 0000000 00000014145 12524707522 0014405 0 ustar 00root root 0000000 0000000 #!/usr/bin/env python
#coding=utf8
# This file is part of CloudControl.
#
# CloudControl is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# CloudControl is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with CloudControl. If not, see .
'''
CloudControl CLI Binary
'''
import os, os.path
import sys
import optparse
import ConfigParser
import pprint
import re
import warnings
from xdg import BaseDirectory
import cloudcontrol.cli as cccli
from cloudcontrol.cli.cli import Cli
from cloudcontrol.cli.printer import Printer
from cloudcontrol.cli.exception import *
settings = {
"port": "1984",
"contimeout": "5",
"cmdtimeout" : "20",
"hsize": "100",
"alias": "%s/alias"%BaseDirectory.save_config_path(cccli.canonical_name),
"tagdisplay": "%s/tagdisplay"%BaseDirectory.save_config_path(cccli.canonical_name),
"history": "%s/history"%BaseDirectory.save_data_path(cccli.canonical_name),
"expert": "%s/expert"%BaseDirectory.save_data_path(cccli.canonical_name),
}
try:
# Early debug loading
if "CC_DEBUG" in os.environ:
cccli.debug = True
settings["debug"] = "True"
# load a printer
printer = Printer()
# Parse line argument
oparser = optparse.OptionParser(usage="usage: %prog [options] [commands]",
version=cccli.version)
oparser.add_option("-d", "--debug", action="store_true",dest="debug",
help="Debug mode")
oparser.add_option("-D", "--no-debug", action="store_false",dest="debug",
help="Unset debug mode")
oparser.add_option("-L", "--login",action="store",dest="login",
help="Server login")
oparser.add_option("-H", "--hostname",action="store",dest="server",
help="Server hostname")
oparser.add_option("-P", "--port",action="store",dest="port",
help="Server port")
oparser.add_option("-t", "--con-timeout", action="store", dest="contimeout",
help="Connection timeout")
oparser.add_option("-T", "--cmd-timeout",action="store",dest="cmdtimeout",
help="Command timeout")
oparser.add_option("-p", "--profile",action="store",dest="profile",
help="Profile name")
oparser.add_option("-l", "--list-profile", action="store_true",dest="proflist",
help="List available profile")
oparser.add_option("--history-file",action="store",dest="history",
help="History file")
oparser.add_option("--history-size",action="store",dest="hsize",
help="History max entry count")
(options, args) = oparser.parse_args()
# try loading profiles
try:
# parse profile file
propath = "%s/profile"%BaseDirectory.save_config_path(cccli.canonical_name)
fparser = ConfigParser.RawConfigParser()
fparser.read(propath)
# profile listing
if options.proflist:
l = list(fparser.sections())
l.remove("cli")
printer.out(os.linesep.join(l))
sys.exit(0)
# load default profile
if fparser.has_section("cli"):
settings.update(fparser.items("cli"))
# choose next profile to load
if options.profile:
settings["profile"] = options.profile
elif "CC_PROFILE" in os.environ:
settings["profile"] = os.environ["CC_PROFILE"]
# load next profile
if fparser.has_section(settings["profile"]):
settings.update(fparser.items(settings["profile"]))
else:
printer.warn("Unable to load profile %s"%settings["profile"])
except Exception as e:
if cccli.debug:
raise
pass
# Load environment variables
if "CC_SERVER" in os.environ:
settings["server"] = os.environ["CC_SERVER"]
if "CC_PORT" in os.environ:
settings["port"] = os.environ["CC_PORT"]
if "CC_LOGIN" in os.environ:
settings["login"] = os.environ["CC_LOGIN"]
if "CC_PASS" in os.environ:
settings["pass"] = os.environ["CC_PASS"]
# Load command line options
for i in [ x.dest for x in oparser.option_list if x.dest ]:
if hasattr(options, i):
o = getattr(options, i)
if o is not None:
settings[i] = o
# debug stuff
if "debug" in settings:
cccli.debug = bool(settings["debug"])
else:
warnings.filterwarnings("ignore")
printer.debug("Debugging on")
# checking server name
if "server" not in settings:
raise BadArgument("No server address")
# check int values
for i in "port", "contimeout", "cmdtimeout", "hsize":
try:
settings[i] = int(settings[i])
except:
raise BadArgument("Invalid %s number"%i)
# check login
if "login" not in settings:
printer.set_interactive()
settings["login"] = printer.ask("Login: ")
# check password
if "pass" not in settings:
printer.set_interactive()
settings["pass"] = printer.getpass("Password: ")
# print settings
printer.debug("Settings: %s"%settings)
# start cli
cli = Cli(settings)
cli.start(" ".join(args))
except BadArgument as e:
printer.error("Bad Argument: %s"%str(e))
oparser.print_help()
except KeyboardInterrupt:
sys.exit("Interrupted")
except cliError as e:
printer.error("%s: %s"%(type(e), str(e)))
except Exception as e:
if cccli.debug:
if "printer" in locals():
printer.fatal("%s: %s"%(type(e), str(e)), quit=False)
raise
printer.warn("This is a not expected error, please report it!")
printer.fatal(str(e))
cc-cli-v7/cc-cli.1 0000664 0000000 0000000 00000062500 12524707522 0013767 0 ustar 00root root 0000000 0000000 .TH CC-CLI "MARCH 2011" LINUX "USER MAN"
.SH NAME
cc-cli - Command Line Interface to CloudControl
.SH SYNOPSIS
\fBcc-cli\fP [\fIOPTION\fP] [\fICOMMANDS\fP]
.SH DESCRIPTION
.TP
\fB--version\fP
show program's version number and exit
.TP
\fB-h\fP, \fB--help\fP
show this help message and exit
.TP
\fB-d\fP, \fB--debug\fP
Debug mode
.TP
\fB-D\fP, \fB--no-debug\fP
Unset debug mode
.TP
\fB-L\fP \fILOGIN\fP, \fB--login=\fP\fILOGIN\fP
Server login
.TP
\fB-H\fP \fISERVER\fP, \fB--hostname=\fP\fISERVER\fP
Server hostname
.TP
\fB-P\fP \fIPORT\fP, \fB--port=\fP\fIPORT\fP
Server port
.TP
\fB-t\fP \fITIMEOUT\fP, \fB--timeout=\fP\fITIMEOUT\fP
Connection timeout
.TP
\fB-p\fP \fIPROFILE\fP, \fB--profile=\fP\fIPROFILE\fP
Profile name
.TP
\fB-l\fP, \fB--list-profile\fP
List available profile
.TP
\fB--history-file=\fP\fIHISTORY\fP
History file
.TP
\fB--history-size=\fP\fIHSIZE\fP
History max entry count
.SS Loading procedure:
Configuration is loaded in this order:
.br
1 - Check \fBCC_DEBUG\fP, to set early debugging mode
.br
2 - load [cli] profile from \fB~/.config/cc-cli/profile\fP
.br
3 - load profile specified by option profile (arg line, env, cli profile)
.br
4 - load options from environment
.br
5 - load options from command line
.SH TQL
TQL (text query language)
.br
- TQL build a list of objects in one query
.br
- An object is a list of tags
.br
- TQL can select and sort object by tags
.br
- TQL can choose tags in object
.br
- TQL can limit number of objects to select
.br
- TQL is a list statement mixed by separators
.br
- TQL build his object list from left to right (left parenthesis)
.br
- Each statement update the builded list regarding his separators
.br
- Selecting, sorting and showing separators are followed by tags
.br
- Limiting separators are followed by limiting conditions
.br
- TQL always return id tag
.br
- By default separators is &
.br
- By default object list is sorted id
.br
.SS SEPERATORS
\fB&\fP selection intersection
.br
\fB|\fP selection union
.br
\fB^\fP selection limit
.br
\fB$\fP tag showing
.br
\fB%\fP tag sorting
.SS OPERATORS
\fB=\fP strict equality
.br
\fB:\fP globing matching (no case)
.br
\fB~\fP regex matching
.br
\fB>\fP superior strict
.br
\fB>=\fP superior
.br
\fB<\fP inferior strict
.br
\fB<=\fP inferior
.br
Each previous operators can be negated by adding \fB!\fP before it.
.SS LIMITING CONDITIONS
\fBn\fP limit to n first objects
.br
\fB,n\fP limit from n object to last object
.SS NUMBER FACILITY
\fB1k\fP = 1 000
.br
\fB1ki\fP = 1 024
.br
\fB1m\fP = 1 000 ^ 2
.br
\fB1mi\fP = 1 024 ^ 2
.br
\fB1g\fP = 1 000 ^ 3
.br
\fB1gi\fP = 1 024 ^ 3
.SS EXAMPLE
For examples, See the command \fBlist\fP
.SH GENERIC COMMANDS
.SS addaccount [\fIoptions\fP] \fI \fP [\fIpassword\fP]
Create an account
.TP
\fBOptions :\fP
.TP
\fB-h\fP, \fB-help\fP
show this help message and exit
.TP
\fB-q\fP, \fB--quiet\fP
Don't status of call request
.TP
\fB-i\fP, \fB--index\fP
Print TQL line index
.TP
\fB--print-tql\fP
Print TQL before sending to server
.TP
\fB--no-tagdisplay\fP
No tagdisplay custom display
.TP
\fB--no-color\fP
No output coloration
.TP
\fBExample :\fP
.TP
\fBaddacount toto cli azerty\fP
Create account toto in role cli (user) whith password azerty
.SS addright [\fIoptions\fP] \fI \fP [\fIindex\fP]
Add or edit account right
.br
All is deny by default
.br
When a user tape a command, cli check the rights from index 0 to the last, if the method and the right tql match whith command, right is applied, else it check the next rights, and if not found a matching rights, it deny the command
.TP
\fBExample :\fP
\fB[0] tql: method:* target:allow\fP
.br
\fB[1] tql: method:list target:deny\fP
.br
if the user tape the command \fBlist\fP whith any tql, the command will be allowed because it matches with index 0
\fB[0] tql: method:list target:deny\fP
.br
\fB[1] tql: method:* target:allow\fP
.br
if the user tape the command \fBlist\fP whith any tql, the command will be denied because it matches with index 0
.TP
\fI\fP
is the name of the rpc command to allow
.TP
\fI\fP
can be allow or deny
.TP
\fBOptions :\fP
.TP
\fB-h\fP, \fB--help\fP
show this help message and exit
.TP
\fB-r\fP, \fB--raw\fP
Don't append security filter to TQL
.TP
\fB-d\fP, \fB--direct\fP
Directly send TQL to server
.TP
\fB-q\fP, \fB--quiet\fP
Don't status of call request
.TP
\fB-i\fP, \fB--index\fP
Print TQL line index
.TP
\fB--print-tql\fP
Print TQL before sending to server
.TP
\fB--no-tagdisplay\fP
No tagdisplay custom display
.TP
\fB--no-color\fP
No output coloration
.TP
\fBExample :\fP
.TP
\fBaddright id=toto "" * allow 0\fP
Allow all method whith all query tql in index 0 for account toto
\fBaddright id=toto "id=toto" list deny 0\fP
Deny method list whith tql "id=toto" for account toto in index 0 (deny commands' example: list id=toto, list id:t*, ...)
.SS alias [\fIoptions\fP] [\fIname\fP] [\fIvalue\fP]
Show or create alias
.TP
CLI support aliasing. This is a very useful command substitution. Alias is stored in \fB~/.config/cc-cli/alias\fP
.TP
\fBOptions :\fP
.TP
\fB-h\fP, \fB--help\fP
show this help message and exit
.TP
\fBExample :\fP
.TP
\fBalias w "list a&con!=offline&r=cli"\fP
Setting an alias w, which list online client
.TP
\fBalias vm "list r=vm&status=running$cpu"\fP
Setting an alias vm, which list running vm (and show cpu)
.SS clear
.TP
Clear tty
.SS close [\fIoptions\fP] \fI\fP
Disable accounts
.TP
\fBOptions :\fP
.TP
\fB-h\fP, \fB--help\fP
show this help message and exit
.TP
\fB-r\fP, \fB--raw\fP
Don't append security filter to TQL
.TP
\fB-d\fP, \fB--direct\fP
Directly send TQL to server
.TP
\fB-q\fP, \fB--quiet\fP
Don't status of call request
.TP
\fB-i\fP, \fB--index\fP
Print TQL line index
.TP
\fB--print-tql\fP
Print TQL before sending to server
.TP
\fB--no-tagdisplay\fP
No tagdisplay custom display
.TP
\fB--no-color\fP
No output coloration
.SS declose [\fIoptions\fP] \fI\fP
Enable accounts
.TP
\fBOptions :\fP
.TP
\fB-h\fP, \fB--help\fP
show this help message and exit
.TP
\fB-r\fP, \fB--raw\fP
Don't append security filter to TQL
.TP
\fB-d\fP, \fB--direct\fP
Directly send TQL to server
.TP
\fB-q\fP, \fB--quiet\fP
Don't status of call request
.TP
\fB-i\fP, \fB--index\fP
Print TQL line index
.TP
\fB--print-tql\fP
Print TQL before sending to server
.TP
\fB--no-tagdisplay\fP
No tagdisplay custom display
.TP
\fB--no-color\fP
No output coloration
.SS delaccount [\fIoptions\fP] \fI\fP
Delete an account
.TP
\fBOptions :\fP
.TP
\fB-h\fP, \fB--help\fP
show this help message and exit
.TP
\fB-r\fP, \fB--raw\fP
Don't append security filter to TQL
.TP
\fB-d\fP, \fB--direct\fP
Directly send TQL to server
.TP
\fB-q\fP, \fB--quiet\fP
Don't status of call request
.TP
\fB-i\fP, \fB--index\fP
Print TQL line index
.TP
\fB--print-tql\fP
Print TQL before sending to server
.TP
\fB--no-tagdisplay\fP
No tagdisplay custom display
.TP
\fB--no-color\fP
No output coloration
.SS delright [\fIoptions\fP] \fI \fP
Delete account right
.TP
\fI\fP
* means all
.TP
\fBOptions :\fP
.TP
\fB-h\fP, \fB--help\fP
show this help message and exit
.TP
\fB-r\fP, \fB--raw\fP
Don't append security filter to TQL
.TP
\fB-d\fP, \fB--direct\fP
Directly send TQL to server
.TP
\fB-q\fP, \fB--quiet\fP
Don't status of call request
.TP
\fB-i\fP, \fB--index\fP
Print TQL line index
.TP
\fB--print-tql\fP
Print TQL before sending to server
.TP
\fB--no-tagdisplay\fP
No tagdisplay custom display
.TP
\fB--no-color\fP
No output coloration
.TP
\fBNotes :\fP
.TP
if you have deny rights in the command list, for delete account right, you must use options --raw and -direct
\fBdelright -r -d id=toto x\fP
.SS expert
Switch in expert mode
Expert mode history is stored in \fB~/.local/share/cc-cli/expert\fP
.SS help
.TP
Print help
.SS history
Show commands history
CLI history is stored in \fB~/.local/share/cc-cli/history\fP
.SS kill [\fIoptions\fP] \fI\fP
Kill a server connection
.TP
\fBOptions :\fP
.TP
\fB-h\fP, \fB--help\fP
show this help message and exit
.TP
\fB-r\fP, \fB--raw\fP
Don't append security filter to TQL
.TP
\fB-d\fP, \fB--direct\fP
Directly send TQL to server
.TP
\fB-q\fP, \fB--quiet\fP
Don't status of call request
.TP
\fB-i\fP, \fB--index\fP
Print TQL line index
.TP
\fB--print-tql\fP
Print TQL before sending to server
.TP
\fB--no-tagdisplay\fP
No tagdisplay custom display
.TP
\fB--no-color\fP
No output coloration
.SS list [\fIoptions\fP] [\fItql\fP]
List objects
.TP
\fBOptions :\fP
.TP
\fB-h\fP, \fB--help\fP
show this help message and exit
.TP
\fB-r\fP, \fB--raw\fP
Don't append security filter to TQL
.TP
\fB-i\fP, \fB--index\fP
Print TQL line index
.TP
\fB--print-tql\fP
Print TQL before sending to server
.TP
\fB--no-tagdisplay\fP
No tagdisplay custom display
.TP
\fB--no-color\fP
No output coloration
.TP
\fB-t\fP
column aligment display
.TP
\fB-l\fP
line aligment display
.P
\fBExample :\fP
\fBlist\fP
.br
list all accounts
\fBlist h:fw*\fP
.br
list all hostname starting by fw
\fBlist r=hv\fP
.br
list all hypervisor
\fBlist r=vm\fP
.br
list all vm
\fBlist hv=toto\fP
.br
list vm of hypervisor toto
\fBlist r=vm&cpu=2\fP
.br
list vm with 2 cpu
\fBlist r=vm&cpu=2&mem>10g\fP
.br
list vm with 2 cpu and mem > 10g
\fBlist r=hv&cpu=2&mem>10g\fP
.br
list hypervisor with 2 cpu and 10G memory
\fBlist cpu>=2$pop$alloc\fP
.br
list object with at least 2cpu and show tags pop and alloc
\fBlist r=vm^10\fP
.br
list first 10 vm
\fBlist r=vm%cpu\fP
.br
list vm sorted by cpu
.SS passwd [\fIoptions\fP] [\fItql\fP] [\fIpassword\fP]
Change account password
.TP
\fBOptions :\fP
.TP
\fB-h\fP, \fB--help\fP
show this help message and exit
.TP
\fB-r\fP, \fB--raw\fP
Don't append security filter to TQL
.TP
\fB-d\fP, \fB--direct\fP
Directly send TQL to server
.TP
\fB-q\fP, \fB--quiet\fP
Don't status of call request
.TP
\fB-i\fP, \fB--index\fP
Print TQL line index
.TP
\fB--print-tql\fP
Print TQL before sending to server
.TP
\fB--no-tagdisplay\fP
No tagdisplay custom display
.TP
\fB--no-color\fP
No output coloration
.SS quit
Quit application with respect
.SS rights [\fIoptions\fP] [\fItql\fP]
List account rights
.TP
\fBOptions :\fP
.TP
\fB-h\fP, \fB--help\fP
show this help message and exit
.TP
\fB-r\fP, \fB--raw\fP
Don't append security filter to TQL
.TP
\fB--print-tql\fP
Print TQL before sending to server
.TP
\fB--no-tagdisplay\fP
No tagdisplay custom display
.TP
\fBExample :\fP
\fB>>right id=toto\fP
.br
a:toto
.br
[0] tql:id=toto method:list target:deny
Display right for account with id toto.
.br
The user toto doesn't have right use method list whith a tql conained "id=toto" (deny commands' example: list id=toto, list id:t*, ...)
.SS server \fI\fP
Server manipulation command
.TP
\fBOptions :\fP
.TP
\fB-h\fP, \fB--help\fP
show this help message and exit
.TP
\fB-c\fP
show server cache
.TP
\fB-f\fP
show server functions
.TP
\fB-v\fP
show server version
.SS shutdown [\fIoptions\fP] \fI\fP
Shutdown a physical host
The command add tql \fB&con&r~'host|hv'\fP
.TP
\fBOptions :\fP
.TP
\fB-h\fP, \fB--help\fP
show this help message and exit
.TP
\fB-r\fP, \fB--raw\fP
Don't append security filter to TQL
.TP
\fB-d\fP, \fB--direct\fP
Directly send TQL to server
.TP
\fB-q\fP, \fB--quiet\fP
Don't status of call request
.TP
\fB-i\fP, \fB--index\fP
Print TQL line index
.TP
\fB--print-tql\fP
Print TQL before sending to server
.TP
\fB--no-tagdisplay\fP
No tagdisplay custom display
.TP
\fB--no-color\fP
No output coloration
.TP
\fB-R\fP, \fB--reboot\fP
Reboot after shutdown (default)
.TP
\fB-H\fP, \fB--halt\fP
Halt after shutdown
.TP
\fB-F\fP
.br
do not go through init but go down real fast
.SS unalias [\fIoptions\fP] [\fIname\fP]
Remove an alias
.TP
\fBOptions :\fP
.TP
\fB-h\fP, \fB--help\fP
show this help message and exit
.SS usage \fI\fP
Print usage of a command
.SS version
Print cli version
.SS whoami
Show connection login
.SH TAG COMMANDS
Every tag is composed by a tagname and a tagvalue
.br
- Tagname are case insensitive, tagvalue is case sensitive
.br
- You can use globin on tagname
.br
- tagname starting by - means all tag except this one
.br
- Operators machtes on tagvalues
./certain tag sont reservé et ne peuvent etre cree modfie ou supprimer par le client
.SS RESERVERD TAGS
Reserved tags are tags with a special meaning and cannot be set or remove directly by clients
.br
\fBid\fP : object unique identifier (eg: kvmlab-1.test5)
.br
\fBp\fP : parent object identifier (eg: kvmlab-1)
.br
\fBa\fP : account name (eg: bobby)
.br
\fBr\fP : account role (host/hv/vm/cli/web/spv)
.br
\fBclosed\fP : account close status
.br
\fBcon\fP : connection uptime in seconds (eg: 3600)
.br
\fBip\fP : ipv4 of connection
.SS WELL KNOWN TAGS
\fBalloc\fP : host is allowed to be selected to a migration
.br
\fBarch\fP : hardware architecture (x86/x64)
.br
\fBchaasset\fP : blade chassis asset tag (dell tag)
.br
\fBchaserial\fP : blade chassis serial number (dell tag)
.br
\fBcpu\fP : cpu count
.br
\fBcpufreq\fP : cpu core frequency
.br
\fBcputhread\fP : total number of cpu thread
.br
\fBcpuuse\fP : global cpu usage (percentage)
.br
\fBdisk\fP : disk index list (eg: 1 2 3 4)
.br
\fBdisk1_path\fP : disk 1 path (eg: /dev/vg/sex)
.br
\fBdisk1_pool\fP : storage pool back reference (eg: vg) [vmonly]
.br
\fBdisk1_size\fP : disk 1 size (eg: 1024)
.br
\fBdisk1_vol\fP : storage pool volume back reference (eg: titi) [vmonly]
.br
\fBh\fP : hostname (eg: access)
.br
\fBhbios\fP : host bios version and/or date (eg: A05 (01/09/2006))
.br
\fBhmodel\fP : host model (eg: PowerEdge 2850)
.br
\fBhserial\fP : host serial number (eg: Dell service tag)
.br
\fBhtype\fP : hypervisor type (xen/kvm)
.br
\fBhv\fP : hypervisor name (eg: kvmlab-1)
.br
\fBhvm\fP : hardware virtualisation enabled
.br
\fBhvendor\fP : host vendor (eg: Dell Computer Corporation)
.br
\fBhvver\fP : hypervisor version (eg: 0.14)
.br
\fBlibvirtver\fP : Libvirt version
.br
\fBload\fP : load average
.br
\fBmem\fP : memory total size
.br
\fBmemfree\fP : memory free
.br
\fBmemused\fP : memory used
.br
\fBnvm\fP : vm count on an hypervisor
.br
\fBos\fP : operating system (linux/windows)
.br
\fBplatform\fP : python platform info
.br
\fBrcpu\fP : reserved cpu count
.br
\fBstatus\fP : VM status (running/paused/stopped)
.br
\fBsto\fP : storage pool names (eg: vg fg)
.br
\fBstovg_free\fP : vg storage pool free space (eg: 1041)
.br
\fBstovg_path\fP : vg storage pool path (eg: /dev/vg/)
.br
\fBstovg_size\fP : vg storage pool size (eg: 1042)
.br
\fBstovg_type\fP : vg storage pool type (eg: lvm)
.br
\fBstovg_used\fP : vg storage pool used space (eg: 1)
.br
\fBstovg_vol\fP : vg storage pool volume list (eg: sex titi toto)
.br
\fBuname\fP : output of uname command
.br
\fBuptime\fP : uptime of hostname
.br
\fBversion\fP : account reported version
.br
\fBvmpaused\fP : paused vm count on an hypervisor
.br
\fBvmstarted\fP : started vm count on an hypervisor
.br
\fBvmstopped\fP : stopped vm count on an hypervisor
.br
\fBvncport\fP : vnc local port (eg: 5001)
.SS addtag [\fIoptions\fP] \fI \fP
Add/Modify a static tag on an account
.TP
\fBOptions :\fP
.TP
\fB-h\fP, \fB--help\fP
show this help message and exit
.TP
\fB-r\fP, \fB--raw\fP
Don't append security filter to TQL
.TP
\fB-d\fP, \fB--direct\fP
Directly send TQL to server
.TP
\fB-q\fP, \fB--quiet\fP
Don't status of call request
.TP
\fB-i\fP, \fB--index\fP
Print TQL line index
.TP
\fB--print-tql\fP
Print TQL before sending to server
.TP
\fB--no-tagdisplay\fP
No tagdisplay custom display
.TP
\fB--no-color\fP
No output coloration
.TP
\fBExample :\fP
.TP
\fBaddtag id=toto hello foo\fP
Create tag hello whith value foo for account toto
.TP
\fBaddtag r=vm hello foo\fP
Create tag hello whith value foo for all vm
.SS deltag [\fIoptions\fP] \fI \fP
Delete a static tag from an account
.TP
\fBOptions :\fP
.TP
\fB-h\fP, \fB--help\fP
show this help message and exit
.TP
\fB-r\fP, \fB--raw\fP
Don't append security filter to TQL
.TP
\fB-d\fP, \fB--direct\fP
Directly send TQL to server
.TP
\fB-q\fP, \fB--quiet\fP
Don't status of call request
.TP
\fB-i\fP, \fB--index\fP
Print TQL line index
.TP
\fB--print-tql\fP
Print TQL before sending to server
.TP
\fB--no-tagdisplay\fP
No tagdisplay custom display
.TP
\fB--no-color\fP
No output coloration
.TP
\fBExample :\fP
.TP
\fBdeltag id=toto hello\fP
Delete tag hello from account toto
.SS tagdisplay [\fIoptions\fP] [\fItag\fP] ...
Tagdisplay tool
.TP
\fBOptions :\fP
.TP
\fB-h\fP, \fB--help\fP
show this help message and exit
.TP
\fB-c\fP \fISET-COLOR\fP
Set custom color on [\fItag\fP].
.br
Color available :
.br
\fBregular :\fP
\fIblack\fP, \fIred\fP, \fIgreen\fP, \fIyellow\fP, \fIblue\fP, \fIpurple\fP, \fIcyan\fP, \fIwhite\fP
\fBlighted :\fP
\fIlgrey\fP, \fIlred\fP, \fIlgreen\fP, \fIlyellow\fP, \fIlblue\fP, \fIlpurple\fP, \fIlcyan\fP, \fIlwhite\fP
\fBunderline :\fP
\fIured\fP, \fIugreen\fP, \fIuyellow\fP, \fIublue\fP, \fIupurple\fP, \fIucyan\fP
.TP
\fB-C\fP
Remove custom color on [\fItag\fP]
.TP
\fB-t\fP \fISET-TYPE\fP
Set custom type on [\fItag\fP].
.br
Type available :
\fIstring\fP, \fIlower\fP, \fIupper\fP, \fIsi\fP (system international), \fIsecond\fP, \fIdate\fP, \fItime\fP, \fIdatetime\fP.
.TP
\fB-T\fP
Remove custom type on [\fItag\fP]
.TP
\fB-f\fP \fISET-TITLE-COLOR\fP
Set custom title color on [\fItag\fP]
.TP
\fB-F\fP
Remove custom title color on [\fItag\fP]
.TP
\fB--list-colors\fP
List allowed color
.TP
\fB--list-types\fP
List allowed types
.TP
\fBExample :\fP
.TP
\fBtagdisplay -c red hv\fP
The tag hv is displayed with color red
.SS tags [\fIoptions\fP] [\fItql\fP]
List only static tags
.TP
\fBOptions :\fP
.TP
\fB-h\fP, \fB--help\fP
show this help message and exit
.TP
\fB-r\fP, \fB--raw\fP
Don't append security filter to TQL
.TP
\fB-i\fP, \fB--index\fP
Print TQL line index
.TP
\fB--print-tql\fP
Print TQL before sending to server
.TP
\fB--no-tagdisplay\fP
No tagdisplay custom display
.TP
\fB--no-color\fP
No output coloration
.TP
\fBExample :\fP
\fB>>tags r=cli\fP
id=\fBtoto\fP foo=bar hello=bye
.br
id=\fBtiti\fP az=qwerty
List all clients' static tags
.SH JOB COMMANDS
.SS cancel [\fIoptions\fP] \fI\fP ...
Cancel a job
.TP
\fBOptions :\fP
.TP
\fB-h\fP, \fB--help\fP
show this help message and exit
.SS destroy [\fIoptions\fP] \fI\fP
Force a vm to stop
Immediately terminate the VM. This doesn't give the domain OS any chance to
react, and it's the equivalent of ripping the power cord out on a physical machine. In most
cases you will want to use the stop command instead.
The command add tql \fI&r=vm&status!=stopped\fP
.TP
\fBOptions :\fP
.TP
\fB-h\fP, \fB--help\fP
show this help message and exit
.TP
\fB-r\fP, \fB--raw\fP
Don't append security filter to TQL
.TP
\fB-d\fP, \fB--direct\fP
Directly send TQL to server
.TP
\fB-q\fP, \fB--quiet\fP
Don't status of call request
.TP
\fB-i\fP, \fB--index\fP
Print TQL line index
.TP
\fB--print-tql\fP
Print TQL before sending to server
.TP
\fB--no-tagdisplay\fP
No tagdisplay custom display
.TP
\fB--no-color\fP
No output coloration
.SS execute [\fIoptions\fP] \fI \fP
Execute a command on the remote host
The command add tql \fI&con&r~'host|hv'\fP
.TP
\fBOptions :\fP
.TP
\fB-h\fP, \fB--help\fP
show this help message and exit
.TP
\fB-r\fP, \fB--raw\fP
Don't append security filter to TQL
.TP
\fB-d\fP, \fB--direct\fP
Directly send TQL to server
.TP
\fB-q\fP, \fB--quiet\fP
Don't status of call request
.TP
\fB-i\fP, \fB--index\fP
Print TQL line index
.TP
\fB--print-tql\fP
Print TQL before sending to server
.TP
\fB--no-tagdisplay\fP
No tagdisplay custom display
.TP
\fB--no-color\fP
No output coloration
.TP
\fBExample :\fP
.TP
\fBexecute r=hv ls\fP
Execute command ls in all hosts
.SS jobs [\fIoptions\fP] [\fItql\fP]
List jobs
.TP
\fBOptions :\fP
.TP
\fB-h\fP, \fB--help\fP
show this help message and exit
.TP
\fB-r\fP, \fB--raw\fP
Don't append security filter to TQL
.TP
\fB-i\fP, \fB--index\fP
Print TQL line index
.TP
\fB--print-tql\fP
Print TQL before sending to server
.TP
\fB--no-tagdisplay\fP
No tagdisplay custom display
.TP
\fB--no-color\fP
No output coloration
.TP
\fB-d\fP, \fB--done\fP
Show done jobs
.TP
\fB-R\fP, \fB--no-running\fP
Don't show running jobs
.SS migrate [\fIoptions\fP] [\fIsource-tql\fP] [\fIdest-tql\fP]
Migrate vm
Migrate vm from host [\fIsource-tql\fP] to another host [\fIdest-tql\fP]. Only \fBcold\fP (the virtual machine stop to execute any currently working program and copy the current page table to the machine where the virtual machine migrate) type migration and \fBfair\fP algorithm are available.
.TP
\fBOptions :\fP
.TP
\fB-h\fP, \fB--help\fP
show this help message and exit
.TP
\fB-q\fP, \fB--quiet\fP
Don't status of call request
.TP
\fB-i\fP, \fB--index\fP
Print TQL line index
.TP
\fB--no-tagdisplay\fP
No tagdisplay custom display
.TP
\fB--no-color\fP
No output coloration
.TP
\fB-l\fP, \fB--list\fP
List migration types and algo
.TP
\fB-t\fP \fITYPE\fP, \fB--type=\fP\fITYPE\fP
Selection migration type
.TP
\fB-a\fP \fIALGO\fP, \fB--algo=\fP\fIALGO\fP
Select migration algorithm
.TP
\fBExample :\fP
.TP
\fBmigrate -t cold -a fair r=vm&p=host1 id=host2\fP
Migrate all vm from host1 to host2
.SS pause [\fIoptions\fP] \fI\fP
Pause a running vm
The command add tql \fI&r=vm&status=running\fP
.TP
\fBOptions :\fP
.TP
\fB-h\fP, \fB--help\fP
show this help message and exit
.TP
\fB-r\fP, \fB--raw\fP
Don't append security filter to TQL
.TP
\fB-d\fP, \fB--direct\fP
Directly send TQL to server
.TP
\fB-q\fP, \fB--quiet\fP
Don't status of call request
.TP
\fB-i\fP, \fB--index\fP
Print TQL line index
.TP
\fB--print-tql\fP
Print TQL before sending to server
.TP
\fB--no-tagdisplay\fP
No tagdisplay custom display
.TP
\fB--no-color\fP
No output coloration
.TP
\fBExample :\fP
.TP
\fBpause r=vm&status=running&p=host1\fP
Pause all vm started in the hypervisor host1
.SS resume [\fIoptions\fP] \fI\fP
Resume a paused vm
This will allow a previously paused vm to
now be eligible for scheduling by the underlying hypervisor.
The command add tql \fI&r=vm&status=paused\fP
.TP
\fBOptions :\fP
.TP
\fB-h\fP, \fB--help\fP
show this help message and exit
.TP
\fB-r\fP, \fB--raw\fP
Don't append security filter to TQL
.TP
\fB-d\fP, \fB--direct\fP
Directly send TQL to server
.TP
\fB-q\fP, \fB--quiet\fP
Don't status of call request
.TP
\fB-i\fP, \fB--index\fP
Print TQL line index
.TP
\fB--print-tql\fP
Print TQL before sending to server
.TP
\fB--no-tagdisplay\fP
No tagdisplay custom display
.TP
\fB--no-color\fP
No output coloration
.SS start [\fIoptions\fP] \fI\fP
Start a stopped vm
The command add tql \fI&r=vm&status=stopped\fP
.TP
\fBOptions :\fP
.TP
\fB-h\fP, \fB--help\fP
show this help message and exit
.TP
\fB-r\fP, \fB--raw\fP
Don't append security filter to TQL
.TP
\fB-d\fP, \fB--direct\fP
Directly send TQL to server
.TP
\fB-q\fP, \fB--quiet\fP
Don't status of call request
.TP
\fB-i\fP, \fB--index\fP
Print TQL line index
.TP
\fB--print-tql\fP
Print TQL before sending to server
.TP
\fB--no-tagdisplay\fP
No tagdisplay custom display
.TP
\fB--no-color\fP
No output coloration
.SS stop [\fIoptions\fP] \fI\fP
Stop a running vm
This coordinates with the domain OS to perform graceful
stop, so there is no guarantee that it will succeed, and may take a variable length of
time depending on what services must be shutdown in the domain
The command add tql \fI&r=vm&status=running\fP
.TP
\fBOptions :\fP
.TP
\fB-h\fP, \fB--help\fP
show this help message and exit
.TP
\fB-r\fP, \fB--raw\fP
Don't append security filter to TQL
.TP
\fB-d\fP, \fB--direct\fP
Directly send TQL to server
.TP
\fB-q\fP, \fB--quiet\fP
Don't status of call request
.TP
\fB-i\fP, \fB--index\fP
Print TQL line index
.TP
\fB--print-tql\fP
Print TQL before sending to server
.TP
\fB--no-tagdisplay\fP
No tagdisplay custom display
.TP
\fB--no-color\fP
No output coloration
.SH FILES
.TP
\fB~/.config/cc-cli/profile\fP
file where cli profile is stored
\fBExample :\fP
# Options in this section is loaded is each others section
[DEFAULT]
hsize = 1000
#debug = true
# This section is loaded at start
[cli]
profile = lab
[lab]
login = snoopy
pass = toto
server = 192.168.0.162
[prod]
login = snoopy
pass = titi
server = 14.8.25.32
.TP
\fB~/.local/share/cc-cli/history\fP
file where cli history are stored
.TP
\fB~/.local/share/cc-cli/expert\fP
file where expert mode history are stored
.TP
\fB~/.config/cc-cli/tagdisplay\fP
file where tagdisplay options are stored
\fBExample :\fP
[color]
a = lpurple
h = lred
pop = lyellow
mem* = lyellow
r = red
id = lblue
cpu = lyellow
con = cyan
[titlecolor]
h = red
id = cyan
[type]
uptime = second
con = second
disk* = si
sto* = si
mem* = bit
[option]
quotespace = 1
.TP
\fB~/.config/cc-cli/alias\fP
file where alias are stored
\fBExample :\fP
[alias]
zzz = list r=cli&idle>300
versions = list -t version
hv = list r=hv&con$cpu$mem$arch%id
vm = list r=vm&status=running$h$cpu$mem$arch%h
userrights = rights r=cli
lt = list -t &con%r%h$h$cpu$r$os$version$-con$mem
ls = list &con$h$cpu$r$os$version
w = list -l r=cli&con$os
host = list r=host&con$cpu$mem
.SH ENVIRONNEMENT
.TP
\fBCC_SERVER\fP
.TP
\fBCC_PORT\fP
.TP
\fBCC_LOGIN\fP
.TP
\fBCC_PASS\fP
.TP
\fBCC_DEBUG\fP
.TP
\fBCC_PROFILE\fP
.TP
\fBCC_PAGER\fP
.SH AUTHOR
SmartJog IT
cc-cli-v7/cloudcontrol/ 0000775 0000000 0000000 00000000000 12524707522 0015257 5 ustar 00root root 0000000 0000000 cc-cli-v7/cloudcontrol/__init__.py 0000664 0000000 0000000 00000001360 12524707522 0017370 0 ustar 00root root 0000000 0000000 # This file is part of CloudControl.
#
# CloudControl is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# CloudControl is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with CloudControl. If not, see .
__import__('pkg_resources').declare_namespace(__name__)
cc-cli-v7/cloudcontrol/cli/ 0000775 0000000 0000000 00000000000 12524707522 0016026 5 ustar 00root root 0000000 0000000 cc-cli-v7/cloudcontrol/cli/__init__.py 0000664 0000000 0000000 00000002626 12524707522 0020145 0 ustar 00root root 0000000 0000000 #coding=utf8
# This file is part of CloudControl.
#
# CloudControl is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# CloudControl is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with CloudControl. If not, see .
'''
CloudControl CLI
'''
import os
def git_version():
global version
import os
import sys
from subprocess import Popen, PIPE, CalledProcessError
cwd = os.getcwd()
try:
os.chdir(os.path.dirname(sys.argv[0]))
p = Popen(["git", "log", "--pretty=format:%H" ],
stdout=PIPE, stderr=open(os.devnull, "wb"))
p.wait()
if p.returncode == 0:
githash = p.stdout.readline().strip()
if len(githash) > 0:
version += "-git-%s" % githash
except OSError:
pass
finally:
os.chdir(cwd)
canonical_name="cc-cli"
debug = False
# set version
version = "7"
if version.find("dev") != -1:
git_version()
cc-cli-v7/cloudcontrol/cli/cli.py 0000664 0000000 0000000 00000017444 12524707522 0017161 0 ustar 00root root 0000000 0000000 #coding=utf8
# This file is part of CloudControl.
#
# CloudControl is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# CloudControl is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with CloudControl. If not, see .
'''
CloudControl CLI main module
'''
from cloudcontrol.cli import debug
from cloudcontrol.cli.exception import *
from cloudcontrol.cli.printer import Printer, color
from cloudcontrol.cli.command import Commands, Aliases
from cloudcontrol.cli.handler import CliHandler
from cloudcontrol.cli.tagdisplay import TagDisplay
from sjrpc.core import RpcConnection
from sjrpc.utils import RpcHandler
import threading
import os, os.path
import sys
import re
import subprocess
import platform
import shlex
import StringIO
class Cli(object):
def __init__(self, settings):
self.settings = settings
self.rpc = None
self.aliases = Aliases()
self.tagdisplay = TagDisplay()
self.forwards = {}
self.prompt = ""
def start(self, line=""):
'''Start a CLI'''
# line stuff
if line:
sys.stdin = StringIO.StringIO(line)
# start printer
self.printer = Printer()
# set interactive mode
if sys.stderr.isatty() and sys.stdin.isatty():
self.printer.debug("Interactive mode")
self.prompt = "%s%s%s%s>%s%s%s "%(color["["],
color["light"],
color["]"],
self.settings["login"],
color["["],
color["reset"],
color["]"])
self.printer.set_interactive()
# load history
self.printer.history.read(self.settings.get("history", ""))
self.printer.history.maxsize(self.settings.get("hsize", None))
self.printer.debug("Loaded history: %s"%len(self.printer.history))
# enable completion
self.printer.completion.set_completer(self._command_completer)
# connecting
self._connect()
# auth
self._auth()
# load commands (need to be done after connection)
self.commands = Commands(self)
self.printer.debug("Remote functions: %d"%len(self.commands.functions))
self.printer.debug("Loaded commands: %d"%len(self.commands))
# load alias
self.aliases.load(self.settings.get("alias", None))
self.printer.debug("Loaded aliases: %d"%len(self.aliases))
# load tagdisplay
self.tagdisplay.load(self.settings.get("tagdisplay", ""))
# export tags to server
self.rpc.call('tags_register', name='version', ttl=None)
self.rpc.call('tags_register', name='os', ttl=None)
self.rpc.call('tags_register', name='uname', ttl=None)
self.rpc.call('tags_register', name='uptime', ttl=3)
# parsing
self._parse_loop()
# save history
self.printer.history.write(self.settings.get("history", None))
def _connect(self):
'''Connect to a cloud control server'''
self.printer.debug("Connecting...")
try:
self.rpc = RpcConnection.from_addr_ssl(self.settings["server"],
self.settings["port"],
handler=CliHandler(),
on_disconnect="quit",
timeout=self.settings["cmdtimeout"],
conn_timeout=self.settings["contimeout"]
)
rpcthread = threading.Thread(target=self.rpc.run)
rpcthread.daemon = True
rpcthread.start()
except Exception as e:
s = "Connection failure!" if not str(e) else "Connection failure: %s"%str(e)
raise cliError(s)
self.printer.debug("Connected.")
def _auth(self):
'''Handle server authentification'''
self.printer.debug("Authenticating...")
try:
self.rpc.call("authentify", self.settings["login"], self.settings["pass"])
except Exception as e:
s = "Authentication failure!" if not str(e) else "Authentication failure: %s"%str(e)
raise cliError(s)
self.printer.debug("Authenticated.")
def _parse_loop(self):
'''Parse lines'''
while True:
try:
line = self.printer.getline(self.prompt)
self._parse(line)
except KeyboardInterrupt:
self.printer.out("")
except EOFError:
break
except SystemExit:
break
self.printer.interactive("tcho!")
def _parse(self, line):
'''Parse a string'''
try:
argv = shlex.split(line, comments=True)
except ValueError as e:
self.printer.error("Lexer: %s"%str(e))
return
if len(argv) == 0:
return
# alias subsitution
argv = self.aliases.substitute(argv)
# command execution
self._exec_command(argv)
def _exec_command(self, argv):
'''Execute command'''
try:
# handle ! in command name
if argv[0][0] == "!":
argv[0] = argv[0][1:]
if not len(argv[0]):
return
p = subprocess.Popen(argv, close_fds=True, shell=True)
p.wait()
ret = p.returncode
return
# handle ? in command name
if argv[0][0] == "?":
if len(argv[0]) > 1:
argv.insert(1, argv[0][1:])
argv[0] = "help"
# execute command
self.printer.debug("argv: %s"%argv)
self.commands(argv)
except cmdExit:
pass
except cmdBadArgument as e:
if str(e):
self.printer.error("Bad argument: %s."%str(e))
else:
self.printer.error("Bad argument.")
usage = self.commands.usage(argv[0])
if usage != "":
self.printer.out(usage)
except cmdBadName:
self.printer.error("No command: %s."%argv[0])
except cmdWarning as e:
self.printer.warn("%s: %s"%(argv[0], str(e)))
except cmdError as e:
self.printer.error("%s: %s"%(argv[0], str(e)))
except EOFError:
self.printer.out("")
except Exception as e:
if debug: raise
self.printer.error("%s: %s"%(type(e), str(e)))
self.printer.warn("This is a not expected error, please report it!")
def _command_completer(self, texte):
'''Return the list of completion'''
comp = self.printer.completion
stripped = comp.get_buf()[:comp.get_begin() + 1].lstrip()
if texte == "" and stripped != "":
return ()
if len(texte) > 0 and texte[0] == "!":
return ()
if len(texte) > 0 and texte[0] == "?":
return [ "?%s"%c for c in list(self.commands) + self.aliases.keys() if c.startswith(texte[1:]) ]
return [ c for c in list(self.commands) + self.aliases.keys() if c.startswith(texte) ]
cc-cli-v7/cloudcontrol/cli/command.py 0000664 0000000 0000000 00000037271 12524707522 0020030 0 ustar 00root root 0000000 0000000 #coding=utf8
# This file is part of CloudControl.
#
# CloudControl is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# CloudControl is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with CloudControl. If not, see .
'''
CloudControl CLI command module
'''
import re
import ConfigParser
import os
import shlex
import imp
import sys
from cloudcontrol.cli.exception import *
from cloudcontrol.cli.printer import Printer, color
from optparse import OptionParser
from sjrpc.core import RpcError
import cloudcontrol.cli.commands as commands
class Commands(object):
'''Command manager'''
def __init__(self, cli):
# save cli context
self.cli = cli
# build command list
self.cmds = self.load_commands(commands.__path__[0], Command)
# build remote function list
try:
self.functions = set([ c["name"] for c in self.cli.rpc.call("functions") ])
except RpcError as e:
raise cliError("RPCError: Unable to retrieve remote commands: %s"%str(e))
# remove not available remote commands
for cname in tuple(self.cmds):
cobj = self.cmds[cname](self.cli, cname)
if isinstance(cobj, RemoteCommand):
try:
if len(cobj.remote_functions()) == 0:
raise NotImplementedError("No remote function")
if not cobj.remote_functions().issubset(self.functions):
del self.cmds[cname]
self.cli.printer.debug("Command %s not available"%cname)
except NotImplementedError as e:
self.cli.printer.debug("Command %s lack of remote_functions"%cname)
del self.cmds[cname]
def __len__(self):
return len(self.cmds)
def __contains__(self, item):
return item in self.cmds.keys()
def __iter__(self):
return iter(self.cmds.keys())
def __repr__(self):
return repr(self.cmds.keys())
def __call__(self, argv):
# check argv
if len(argv) == 0:
raise cmdBadName()
# find right commands to call
if argv[0] not in self:
matchlist = [ x for x in self if re.match("%s.+"%re.escape(argv[0]), x) ]
if len(matchlist) == 1:
argv[0] = matchlist[0]
else:
raise cmdBadName()
# create class and call it
cmd = self.cmds[argv[0]](self.cli, argv[0])
return cmd(argv)
def usage(self, argv0):
'''Return usage of a command'''
u = self.cmds[argv0](self.cli, argv0).usage()
return u if u is not None else ""
def help(self, argv0):
'''Return of a command'''
h = self.cmds[argv0](self.cli, argv0).help()
return h if h is not None else ""
@staticmethod
def load_commands(path, cls):
'''Load subclass of cls from package name'''
cmds=dict()
for name in os.listdir(path):
if (name.endswith(".py")
and not name.startswith("__")
and not name.startswith(".")):
fpath = os.path.join(path, name)
module = imp.load_source(os.path.splitext(name)[0], fpath)
for key, entry in module.__dict__.items():
try:
if issubclass(entry, cls) and entry.__name__.startswith("Command_"):
cmds[entry.__name__[8:]] = entry
except TypeError:
continue
return cmds
class Aliases(dict):
''' Aliases manager'''
def load(self, filename):
'''load alias from file'''
if filename is not None:
fparser = ConfigParser.RawConfigParser()
fparser.read(filename)
if fparser.has_section("alias"):
self.clear()
self.update(fparser.items("alias"))
def save(self, filename):
'''save alias on file'''
if filename is not None:
fparser = ConfigParser.RawConfigParser()
fparser.read(filename)
fparser.remove_section("alias")
fparser.add_section("alias")
for n,v in self.items():
fparser.set("alias", n, v)
fparser.write(open(filename, "w"))
def substitute(self, argv):
# trip is the number of subtitution of an alias
# maximum number of trip is set to 10
for trip in range(10):
if argv[0] in self:
oldargv = argv[1:]
argv = shlex.split(self[argv[0]])
argv.extend(oldargv)
return argv
class Command(object):
'''Base of all command class'''
def __init__(self, cli, argv0):
self.cli = cli
self.printer = self.cli.printer
self.name = argv0
def __call__(self, argv):
'''Code called when command is invoked'''
raise NotImplementedError
def usage(self):
return "Usage: %s" % self.name
def help(self):
return self.__doc__
class OptionCommand(Command):
'''Commands with options handling'''
class OptionCommandParser(OptionParser):
'''Parser of Option for OptionCommand'''
@staticmethod
def error(e):
raise cmdBadArgument(e)
@staticmethod
def exit():
raise cmdExit()
def __init__(self, cli, argv0):
Command.__init__(self, cli, argv0)
self.optionparser = OptionCommand.OptionCommandParser(prog=argv0)
self.set_usage("%prog [options]")
self.options = None
self.args = list()
def usage(self):
'''Return usage string'''
return self.optionparser.format_help().strip()
def parse_args(self, argv):
'''Wrapper to parse_args'''
(self.options, self.args) = self.optionparser.parse_args(argv[1:])
def add_option(self, *args, **kwargs):
'''Proxy to OptionParser'''
self.optionparser.add_option(*args, **kwargs)
def remove_option(self, *args, **kwargs):
'''Proxy to OptionParser'''
self.optionparser.remove_option(*args, **kwargs)
def set_usage(self, *args, **kwargs):
'''Proxy to OptionParser'''
self.optionparser.set_usage(*args, **kwargs)
class RemoteCommand(OptionCommand):
'''Command which needs connection to server'''
def __init__(self, cli, argv0):
OptionCommand.__init__(self, cli, argv0)
# ignore tag option
self.add_option("-I", "--ignore-tag", action="append",
dest="ignore", default=[],
help="Don't display a tag in objects")
# no print count at end option
self.add_option("--no-count", action="store_true",
dest="nocount", default=False,
help="Don't print count at end of objects")
# index printing
self.add_option("-i", "--index", action="store_true",
dest="index", default=False,
help="Print object lines indexed")
self.rpc = cli.rpc
@staticmethod
def remote_functions():
'''Return a set of needed remote functions'''
raise NotImplementedError
def print_objects(self, objectlist):
'''Trivial objectlist printing of tag'''
if objectlist is None:
return
# get default index from local options
_order = objectlist.get("order", None)
for (i, o) in enumerate(objectlist["objects"]):
if self.options.index:
self.printer.out("[%s] "%i, nl="")
self.print_tags(o, order=_order)
if not self.options.nocount:
length = len(objectlist["objects"])
if length > 1:
self.printer.out("Objects count: %s" % length)
def print_tags(self, taglist, order=None):
'''Display a tag with tagdisplay settings'''
order = () if order is None else order
# copy dict to show
tl = taglist.copy()
# remove ignore tags
for tn in self.options.ignore:
tl.pop(tn, None)
# list to print
pls = []
# print firstly order tags
for tn in order:
tv = tl.pop(tn, None)
if tv is not None:
pls.append("%s%s:%s%s"%(self.tdtc(tn), tn, self.tdc(tn), self.tdr(tn, tv)))
# print tags without order, alpha ordered
for tn in sorted(tl.keys()):
pls.append("%s%s:%s%s"%(self.tdtc(tn), tn, self.tdc(tn), self.tdr(tn, tl[tn])))
self.printer.out("%s%s"%(" ".join(pls), color["reset"]))
class TqlCommand(RemoteCommand):
'''Command which handle TQL stuff'''
def __init__(self, cli, argv0):
RemoteCommand.__init__(self, cli, argv0)
self.set_usage("%prog [options] ")
# set tql filter stuff
self.tql_filter = ""
self.add_option("-r", "--raw", action="callback", dest="raw",
callback=self._cb_raw,
help="Don't append security filter to TQL")
# set tql check stuff
self.add_option("-d", "--direct", action="store_true",
dest="direct", default=False,
help="Directly send TQL to server")
# set tql status stuff
self.add_option("-q", "--quiet", action="store_false",
dest="status", default=True,
help="Dont status of call request")
# tql printer option
self.add_option("--print-tql", action="store_true",
dest="tql_print", default=False,
help="Print TQL before sending to server")
# set tagdisplay stuff
self.tdr = self.cli.tagdisplay.resolve
self.tdc = self.cli.tagdisplay.color
self.tdtc = self.cli.tagdisplay.titlecolor
self.add_option("--no-tagdisplay", action="callback",
callback=self._cb_notagdisplay,
help="No tagdisplay custom display")
self.add_option("--no-color", action="callback",
callback=self._cb_nocolor,
help="No output coloration")
def _cb_notagdisplay(self, option, opt, value, parser):
'''Callback for option --no-tagdisplay'''
self.tdr = lambda tagname, tagvalue: tagvalue
self.tdc = self.cli.tagdisplay.default_color
self.tdtc = self.cli.tagdisplay.default_titlecolor
def _cb_nocolor(self, option, opt, value, parser):
'''Callback for option --no-color'''
self.tdr = lambda tagname, tagvalue: tagvalue
self.tdc = lambda tagname: ""
self.tdtc = lambda tagname: ""
def _cb_raw(self, option, opt, value, parser):
'''Callback for option --raw'''
self.tql_filter = ""
def rpccall(self, *args, **kwargs):
'''
Call a RPC method an show tql return
_callback: call function _callback after each rpccall
_status: display call status
_tql_index: is index in args where filter should be appended (def: 1)
_tql_print: print tql with filter
_exception: catch or not RPCError exception
_direct: call directly, no listing before
_arg_list: list of arg which are added to args one by one (=> multiple call)
'''
# set on line modified options
_saved_options = {}
for _o in kwargs.copy():
if _o.startswith("_"):
o = _o[1:]
_saved_options[o] = getattr(self.options, o) if hasattr(self.options, o) else None
setattr(self.options, o, kwargs[_o])
kwargs.pop(_o)
# set tql_index to 1 if any
if not hasattr(self.options, "tql_index"):
self.options.tql_index = 1
# check tql index
if self.options.tql_index < 0 or self.options.tql_index >= len(args):
raise cmdError("No indexed TQL")
# append filter (empty if raw mode)
if self.tql_filter != "":
l = list(args)
l[self.options.tql_index] += self.tql_filter
args = tuple(l)
# Tql printer
if self.options.tql_print:
self.printer.out("TQL: %s"%args[self.options.tql_index])
# Tql check
if self.options.direct:
out= self._unsecure_rpccall(args, **kwargs)
else:
out = self._secure_rpccall(args, **kwargs)
# restore saved options
for (k, v) in _saved_options.items():
if v is None:
delattr(self.options, k)
else:
setattr(self.options, k, v)
# return output
return out
def _unsecure_rpccall(self, args, **kwargs):
'''Just call an RPC without checking before'''
try:
if not hasattr(self.options, "arg_list"):
d = self.rpc.call(*args, **kwargs)
if hasattr(self.options, "callback"):
self.options.callback(d)
if hasattr(self.options, "status") and self.options.status:
self.options.ignore += [ "output" ]
self.print_objects(d)
else:
# arg_list mode call command for each argument
# return is returned as a list
d = []
for arg in self.options.arg_list:
args2 = args + [ arg ]
r = self.rpc.call(*args2, **kwargs)
d.append(r)
if hasattr(self.options, "callback"):
self.options.callback(r)
if hasattr(self.options, "status") and self.options.status:
self.options.ignore += [ "output" ]
self.print_objects(r)
return d
except RpcError as e:
if hasattr(self.options, "exception"):
raise
raise cmdError("RPCError: %s"%str(e))
def _secure_rpccall(self, args, **kwargs):
'''Call RPC after listing, confirmation and with id'''
# get objects id
try:
objs = self.cli.rpc.call("list", args[self.options.tql_index])
except RpcError as e:
raise cmdError("RPCError: %s"%str(e))
# no result, goodbye
if len(objs["objects"]) == 0:
raise cmdError("No selected object by TQL")
self.printer.out("Objects:")
self.print_objects(objs)
# be sure boby want do that
if self.printer.ask("%sProceed?%s (yes): "%(color["lred"], color["reset"])) != "yes":
raise cmdWarning("User aborted")
# bobby doing many things, he needs to be really sure!
if len(objs["objects"]) > 5:
self.printer.out("%sYou will act on more than 5 objects!%s"%(color["uyellow"], color["reset"]))
if self.printer.ask("%sAre you really sure?%s (Yes Mistress): "
%(color["lred"], color["reset"])) != "Yes Mistress":
raise cmdWarning("User aborted")
# per validated id execution (this is a kind of atomic implementation)
for obj in objs["objects"]:
# make a list from tupe for editing
args2 = list(args)
# ovewrite tql object by id from object
args2[self.options.tql_index] = "id=%s"%obj["id"]
# now we can make call
self._unsecure_rpccall(args2, **kwargs)
cc-cli-v7/cloudcontrol/cli/commands/ 0000775 0000000 0000000 00000000000 12524707522 0017627 5 ustar 00root root 0000000 0000000 cc-cli-v7/cloudcontrol/cli/commands/__init__.py 0000664 0000000 0000000 00000001375 12524707522 0021746 0 ustar 00root root 0000000 0000000 #coding=utf8
# This file is part of CloudControl.
#
# CloudControl is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# CloudControl is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with CloudControl. If not, see .
'''
CloudControl CLI Commands Package
'''
__all__ = []
cc-cli-v7/cloudcontrol/cli/commands/account.py 0000664 0000000 0000000 00000011146 12524707522 0021640 0 ustar 00root root 0000000 0000000 #coding=utf8
# This file is part of CloudControl.
#
# CloudControl is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# CloudControl is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with CloudControl. If not, see .
'''
CloudControl accounts related commands
'''
from cloudcontrol.cli.exception import *
from cloudcontrol.cli.printer import Printer, color
from cloudcontrol.cli.command import TqlCommand
from sjrpc.core.exceptions import *
class Command_addaccount(TqlCommand):
'''Create an account'''
def __init__(self, cli, argv0):
TqlCommand.__init__(self, cli, argv0)
self.remove_option("--direct")
self.remove_option("--raw")
self.set_usage("%prog [options] [password]")
def __call__(self, argv):
# parse args
self.parse_args(argv)
if len(self.args) == 2:
_pass = None
elif len(self.args) == 3:
_pass = self.args[2]
if self.printer.isinteractive():
self.printer.warn("Password detected, removing last line from history")
self.printer.history.removelast()
else:
raise cmdBadArgument()
try:
# add account
self.cli.rpc.call("addaccount", self.args[0], self.args[1])
except RpcError as e:
raise cmdError("RPCError: %s"%str(e))
# set password
if _pass is not None:
self.rpccall("passwd", "a=%s"%self.args[0], _pass, _direct=True)
def remote_functions(self):
return set(("addaccount", "passwd"))
class Command_delaccount(TqlCommand):
'''Delete an account'''
def __init__(self, cli, argv0):
TqlCommand.__init__(self, cli, argv0)
self.tql_filter += "&a"
def __call__(self, argv):
self.parse_args(argv)
if len(self.args) != 1:
raise cmdBadArgument("")
self.rpccall("delaccount", self.args[0])
def remote_functions(self):
return set(("delaccount",))
class Command_close(TqlCommand):
'''Disable accounts'''
def __init__(self, cli, argv0):
TqlCommand.__init__(self, cli, argv0)
self.tql_filter += "&a&-close"
def __call__(self, argv):
self.parse_args(argv)
if len(self.args) != 1:
raise cmdBadArgument("")
self.rpccall("close", self.args[0])
def remote_functions(self):
return set(("close",))
class Command_declose(TqlCommand):
'''Enable accounts'''
def __init__(self, cli, argv0):
TqlCommand.__init__(self, cli, argv0)
self.tql_filter += "&a&close"
def __call__(self, argv):
self.parse_args(argv)
if len(self.args) != 1:
raise cmdBadArgument("")
self.rpccall("declose", self.args[0])
def remote_functions(self):
return set(("declose",))
class Command_passwd(TqlCommand):
'''Change account password'''
def __init__(self, cli, argv0):
TqlCommand.__init__(self, cli, argv0)
self.tql_filter += "&a"
def __init__(self, cli, argv0):
TqlCommand.__init__(self, cli, argv0)
self.set_usage("%prog [options] [tql] [password]")
def __call__(self, argv):
# parse args
self.parse_args(argv)
_tql = None
_pass = None
if len(self.args) == 0:
_tql = "a=%s"%self.cli.settings["login"]
elif len(self.args) == 1:
_tql = self.args[0]
elif len(self.args) == 2:
_tql = self.args[0]
_pass = self.args[1]
_check = self.args[1]
if self.printer.isinteractive():
self.printer.warn("Removing last line from history")
self.printer.history.removelast()
else:
raise cmdBadArgument()
# get password
if _pass is None:
_pass = self.printer.getpass("Password: ")
_check = self.printer.getpass("Again: ")
if _pass != _check:
raise cmdError("You don't type twice the same password. Aborted")
# execute command
self.rpccall("passwd", _tql, _pass)
def remote_functions(self):
return set(("passwd",))
cc-cli-v7/cloudcontrol/cli/commands/addforward.py 0000664 0000000 0000000 00000005661 12524707522 0022326 0 ustar 00root root 0000000 0000000 #coding=utf8
# This file is part of CloudControl.
#
# CloudControl is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# CloudControl is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with CloudControl. If not, see .
'''
CloudControl addforward command
'''
from cloudcontrol.cli.command import TqlCommand
from cloudcontrol.cli.tunnel import Forward
from cloudcontrol.cli.exception import *
class Command_addforward(TqlCommand):
'''Create a forward'''
def __init__(self, cli, argv0):
TqlCommand.__init__(self, cli, argv0)
self.tql_filter += "&con&r~'host|hv'"
self.remove_option("--quiet")
self.remove_option("--direct")
self.add_option("-s", "--source", default="127.0.0.1",
help="Tunnel local source ip address and port. "
"Default 127.0.0.1")
self.add_option("-d", "--destination", default="127.0.0.1:22",
help="Tunnel remote destination ip address and port. "
"Default 127.0.0.1:22")
def __call__(self, argv):
# argv check
self.parse_args(argv)
if len(self.args) != 1:
raise cmdBadArgument()
# checking source info
splitted_source = map(str.strip, self.options.source.split(":"))
self.source_ip = splitted_source[0]
if len(splitted_source) == 1 or splitted_source[1] == "":
self.source_port = 0
else:
self.source_port = int(splitted_source[1])
# checking dest info
splitted_dest = map(str.strip, self.options.destination.split(":"))
self.dest_ip = splitted_dest[0]
if len(splitted_dest) == 1 or splitted_dest[1] == "":
self.dest_port = 0
else:
self.dest_port = int(splitted_dest[1])
# list using method forward to check rights
ans = self.rpccall("list", self.args[0], method="forward",
_direct=True, _status=False)
for obj in ans["objects"]:
# Create forward object
fwd = Forward(self.rpc, obj["id"],
self.source_ip, self.source_port,
self.dest_ip, self.dest_port)
# register it into cli
self.cli.forwards[fwd.id] = fwd
# start it
fwd.start()
# print
self.cli.printer.out("Forward %s added." % fwd.id)
def remote_functions(self):
return set(("list", "forward"))
cc-cli-v7/cloudcontrol/cli/commands/alias.py 0000664 0000000 0000000 00000005244 12524707522 0021277 0 ustar 00root root 0000000 0000000 #coding=utf8
# This file is part of CloudControl.
#
# CloudControl is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# CloudControl is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with CloudControl. If not, see .
'''
CloudControl alias related command
'''
from cloudcontrol.cli.exception import *
from cloudcontrol.cli.command import OptionCommand
import re
class Command_alias(OptionCommand):
'''Show or create alias'''
def __init__(self, cli, argv0):
OptionCommand.__init__(self, cli, argv0)
self.set_usage("%prog [options] [name] [value]")
def __call__(self, argv):
# args parse
self.parse_args(argv)
_value = None
if len(self.args) == 0:
_alias = sorted(self.cli.aliases.keys())
elif len(self.args) == 1:
_alias = [ self.args[0] ]
elif len(self.args) == 2:
_alias = self.args[0]
_value = self.args[1]
else:
raise cmdBadArgument()
# printing
if _value is None:
for a in _alias:
if a in self.cli.aliases:
self.printer.out("%s \"%s\""%(a, re.sub("\"", "\\\"", self.cli.aliases[a])))
else:
self.printer.warn("No alias %s"%a)
# editing
else:
self.cli.aliases[_alias] = _value
try:
self.cli.aliases.save(self.cli.settings.get("alias", None))
except Exception as e:
raise cmdError(e)
class Command_unalias(OptionCommand):
'''Remove an alias'''
def __init__(self, cli, argv0):
OptionCommand.__init__(self, cli, argv0)
self.set_usage("%prog [options] [name]")
def __call__(self, argv):
# parse args
self.parse_args(argv)
if len(self.args) != 1:
raise cmdBadArgument()
# check alias existance
if self.args[0] not in self.cli.aliases:
raise cmdBadArgument("%s: No such alias"%self.args[0])
# deleting aliases
del self.cli.aliases[self.args[0]]
try:
self.cli.aliases.save(self.cli.settings.get("alias", None))
except Exception as e:
raise cmdError(e)
cc-cli-v7/cloudcontrol/cli/commands/attachment.py 0000664 0000000 0000000 00000003265 12524707522 0022337 0 ustar 00root root 0000000 0000000 #coding=utf8
# This file is part of CloudControl.
#
# CloudControl is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# CloudControl is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with CloudControl. If not, see .
'''
CloudControl attachment command
'''
import os
import subprocess
from cloudcontrol.cli.exception import *
from cloudcontrol.cli.command import TqlCommand
class Command_attachment(TqlCommand):
'''Retrieve an attachment'''
def __init__(self, cli, argv0):
TqlCommand.__init__(self, cli, argv0)
self.set_usage("%prog [options] attachment [attachment] ...")
self.tql_filter += "&r=job"
def __call__(self, argv):
# Parse argline
self.parse_args(argv)
# append current login if nothing asked
if len(self.args) != 2:
raise cmdBadArgument()
# ask server
objs = self.rpc.call("attachment", self.args[0], self.args[1])
for out in objs['objects']:
if out['status'] == 'success':
self.printer.pager(out['output'])
else:
self.printer.warn('%s: %s' % (out['id'], out['message']))
def remote_functions(self):
return set(("attachment",))
cc-cli-v7/cloudcontrol/cli/commands/cancel.py 0000664 0000000 0000000 00000002557 12524707522 0021437 0 ustar 00root root 0000000 0000000 #coding=utf8
# This file is part of CloudControl.
#
# CloudControl is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# CloudControl is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with CloudControl. If not, see .
'''
CloudControl cancel command
'''
from cloudcontrol.cli.exception import *
from sjrpc.core.exceptions import *
from cloudcontrol.cli.printer import Printer, color
from cloudcontrol.cli.command import TqlCommand
class Command_cancel(TqlCommand):
'''Cancel a job'''
def __init__(self, cli, argv0):
TqlCommand.__init__(self, cli, argv0)
self.tql_filter += "&r=job&state=running"
def __call__(self, argv):
# arg parse
self.parse_args(argv)
if len(self.args) != 1:
raise cmdBadArgument()
# rpc call
self.rpccall("cancel", self.args[0])
def remote_functions(self):
return set(("cancel",))
cc-cli-v7/cloudcontrol/cli/commands/console.py 0000664 0000000 0000000 00000007662 12524707522 0021656 0 ustar 00root root 0000000 0000000 #coding=utf8
# This file is part of CloudControl.
#
# CloudControl is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# CloudControl is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with CloudControl. If not, see .
'''
CloudControl Console related commands
'''
from cloudcontrol.cli.command import TqlCommand
from cloudcontrol.cli.exception import *
from cloudcontrol.cli.printer import FakeTtySocket
from sjrpc.core.exceptions import *
import fcntl
import signal
import struct
import termios
class Command_shell(TqlCommand):
'''Start a shell on the provided host'''
def __init__(self, cli, argv0):
TqlCommand.__init__(self, cli, argv0)
self.remove_option("--direct")
self.remove_option("--quiet")
self.tql_filter = "&con"
def __call__(self, argv):
# args parse
self.parse_args(argv)
if len(self.args) != 1:
raise cmdBadArgument()
# rpccall
ans = self.rpccall("shell", self.args[0], _status=False, _direct=True)
# alias first object
obj = ans['objects'][0]
# check response is successful
if obj['status'] != 'success':
raise cmdError("%s: %s" % (obj["status"], obj["message"]))
# create a callbeck function for sigwinch
def _cb_sig_resize(*args):
'''Callback for terminal resized'''
size = struct.pack('HHHH', 0, 0, 0, 0)
size = fcntl.ioctl(0, termios.TIOCGWINSZ, size)
size = struct.unpack('HHHH', size)
try:
self.rpc.call('resize', None, *size)
except RpcError as e:
# we dont care of failure of this
self.printer.debug("Terminal resize failed: %s" % e)
# Connect to remote end using sjrpc
tun = self.rpc.create_tunnel(obj["output"], endpoint=FakeTtySocket())
try:
signal.signal(signal.SIGWINCH, _cb_sig_resize)
# set initial size of term
_cb_sig_resize()
tun.wait_shutdown()
finally:
# restore original signal
signal.signal(signal.SIGWINCH, signal.SIG_DFL)
# close tunnel if sjrpc doesn't do it
tun.shutdown()
# print prompt at beginning of a new line
self.printer.out()
def remote_functions(self):
return set(("shell",))
class Command_console(TqlCommand):
'''Start a vm console using libvirt'''
def __init__(self, cli, argv0):
TqlCommand.__init__(self, cli, argv0)
self.remove_option("--direct")
self.remove_option("--quiet")
self.tql_filter = "&r=vm&status=running"
def __call__(self, argv):
# args parse
self.parse_args(argv)
if len(self.args) != 1:
raise cmdBadArgument()
# rpccall
ans = self.rpccall("console", self.args[0], _status=False, _direct=True)
# alias first object
obj = ans['objects'][0]
# check everything is ok
if obj['status'] != 'success':
raise cmdError("%s: %s" % (obj["status"], obj["message"]))
# Connect to remote end using sjrpc
tun = self.rpc.create_tunnel(obj["output"], endpoint=FakeTtySocket())
try:
tun.wait_shutdown()
finally:
# close tunnel if sjrpc doesn't do it
tun.shutdown()
# print prompt at beginning of a new line
self.printer.out()
def remote_functions(self):
return set(("console",))
cc-cli-v7/cloudcontrol/cli/commands/delforward.py 0000664 0000000 0000000 00000002732 12524707522 0022336 0 ustar 00root root 0000000 0000000 #coding=utf8
# This file is part of CloudControl.
#
# CloudControl is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# CloudControl is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with CloudControl. If not, see .
'''
CloudControl delforward command
'''
from cloudcontrol.cli.command import Command
from cloudcontrol.cli.exception import *
class Command_delforward(Command):
'''Delete forwarded connection'''
def __init__(self, cli, argv0):
Command.__init__(self, cli, argv0)
def __call__(self, argv):
# argv check
if len(argv) < 2:
raise cmdBadArgument()
for fwd_id in argv[1:]:
if fwd_id in self.cli.forwards:
self.printer.out("Closing %s" % fwd_id)
self.cli.forwards[fwd_id].stop()
del self.cli.forwards[fwd_id]
else:
self.printer.warn("No such forward: %s" % fwd_id)
def usage(self):
return "Usage: delforward [tunnel id]..."
cc-cli-v7/cloudcontrol/cli/commands/execute.py 0000664 0000000 0000000 00000003477 12524707522 0021656 0 ustar 00root root 0000000 0000000 #coding=utf8
# This file is part of CloudControl.
#
# CloudControl is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# CloudControl is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with CloudControl. If not, see .
'''
CloudControl execute command
'''
from cloudcontrol.cli.exception import *
from sjrpc.core.exceptions import *
from cloudcontrol.cli.printer import Printer, color
from cloudcontrol.cli.command import TqlCommand
class Command_execute(TqlCommand):
'''Execute a command on the remote host'''
def __init__(self, cli, argv0):
TqlCommand.__init__(self, cli, argv0)
self.set_usage("%prog [options] ")
self.tql_filter += "&con&r~'host|hv'"
def __call__(self, argv):
# arg parse
self.parse_args(argv)
if len(self.args) != 2:
raise cmdBadArgument()
# rpc call
self.rpccall("execute", self.args[0], self.args[1], _callback=self._cb_print_output)
def _cb_print_output(self, d):
'''Print output of execute by object'''
for o in d["objects"]:
self.printer.out("%sid:%s%s%s output:"%(self.tdtc("id"), self.tdc("id"),
o["id"], color["reset"]))
self.printer.out(o.get("output", ""), nl="")
def remote_functions(self):
return set(("execute",))
cc-cli-v7/cloudcontrol/cli/commands/expert.py 0000664 0000000 0000000 00000003243 12524707522 0021512 0 ustar 00root root 0000000 0000000 #coding=utf8
# This file is part of CloudControl.
#
# CloudControl is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# CloudControl is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with CloudControl. If not, see .
'''
CloudControl expert command
'''
from cloudcontrol.cli.exception import *
from cloudcontrol.cli.printer import Printer, color
from cloudcontrol.cli.command import Command
from sjrpc.utils import ConnectionProxy
import code
class Command_expert(Command):
'''Switch in expert mode'''
def __call__(self, argv):
if len(argv) != 1:
raise cmdBadArgument()
h = list(self.printer.history)
self.printer.history.read(self.cli.settings.get("expert", ""))
try:
local = dict()
local["cli"] = self.cli
local["rpc"] = self.cli.rpc
local["proxy"] = ConnectionProxy(self.cli.rpc)
c = code.InteractiveConsole(local)
c.interact("Use Ctrl+D to go back in CLI. Type dir() to see variables.")
finally:
self.printer.history.write(self.cli.settings.get("expert", None))
self.printer.history.load(h)
def usage(self):
return "usage: expert"
cc-cli-v7/cloudcontrol/cli/commands/forwards.py 0000664 0000000 0000000 00000003664 12524707522 0022041 0 ustar 00root root 0000000 0000000 #coding=utf8
# This file is part of CloudControl.
#
# CloudControl is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# CloudControl is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with CloudControl. If not, see .
'''
CloudControl forwards command
'''
from cloudcontrol.cli.command import Command
from cloudcontrol.cli.printer import color
from cloudcontrol.cli.exception import *
class Command_forwards(Command):
'''List open forwards'''
def __init__(self, cli, argv0):
Command.__init__(self, cli, argv0)
def __call__(self, argv):
# argv check
if len(argv) != 1:
raise cmdBadArgument()
out = self.printer.out
for fwd in self.cli.forwards.values():
out("Forward: %s%s%s" % (color["lpurple"], fwd.id, color["reset"]))
out(" HostID: %s" % fwd.host_id)
out(" Local socket: %s %s" % (fwd.source_ip, fwd.source_port))
out(" Remote socket: %s %s" % (fwd.dest_ip, fwd.dest_port))
out(" Tunnels:")
out(" count: %s" % len(fwd.tunnels))
for label, tun in fwd.tunnels.items():
remote_ip, remote_port = tun.endpoint.getpeername()
out(" label: %s, remote ip: %s, remote port: %s"
% (label, remote_ip, remote_port))
out("Forward count: %d, Tunnels count: %d" %
(len(self.cli.forwards),
sum(len(f.tunnels) for f in self.cli.forwards.values())))
cc-cli-v7/cloudcontrol/cli/commands/kill.py 0000664 0000000 0000000 00000002562 12524707522 0021141 0 ustar 00root root 0000000 0000000 #coding=utf8
# This file is part of CloudControl.
#
# CloudControl is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# CloudControl is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with CloudControl. If not, see .
'''
CloudControl Connection related commands
'''
from cloudcontrol.cli.exception import *
from sjrpc.core.exceptions import *
from cloudcontrol.cli.printer import Printer, color
from cloudcontrol.cli.command import TqlCommand
class Command_kill(TqlCommand):
'''Kill a server connection'''
def __init__(self, cli, argv0):
TqlCommand.__init__(self, cli, argv0)
self.tql_filter += "&con"
def __call__(self, argv):
# args parse
self.parse_args(argv)
if len(self.args) != 1:
raise cmdBadArgument()
# rpccall
self.rpccall("kill", self.args[0])
def remote_functions(self):
return set(("kill",))
cc-cli-v7/cloudcontrol/cli/commands/list.py 0000664 0000000 0000000 00000033342 12524707522 0021161 0 ustar 00root root 0000000 0000000 #coding=utf8
# This file is part of CloudControl.
#
# CloudControl is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# CloudControl is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with CloudControl. If not, see .
'''
CloudControl list command
'''
from cloudcontrol.cli.exception import *
from sjrpc.core.exceptions import *
from cloudcontrol.cli.printer import Printer, color
from cloudcontrol.cli.command import TqlCommand
import math
import os
class Command_list(TqlCommand):
'''List objects'''
def __init__(self, cli, argv0):
TqlCommand.__init__(self, cli, argv0)
self.set_usage("%prog [options] [tql]")
self.add_option("-t", action="store_true", dest="table",
help="column aligment display")
self.add_option("-l", action="store_true", dest="align",
help="line aligment display")
self.add_option("-v", action="store_true", dest="vertical",
help="vertical display")
self.add_option("-m", action="store_true", dest="mikrotik",
help="mikrotik display")
self.remove_option("--quiet")
self.remove_option("--direct")
def __call__(self, argv):
self.parse_args(argv)
if len(self.args) == 0:
self.args.append("id")
# smart merge argument to have a tql
tql = self.args[0]
for arg in self.args[1:]:
if len(arg) == 0 or arg[0] in ("&", "|", "$", "^", "%"):
tql += arg
else:
tql += "&%s" % arg
objs = self.rpccall("list", tql, _status=False, _direct=True)
if len(objs["objects"]) == 0:
return
if self.options.align:
self.list_align(objs)
elif self.options.table:
self.list_table(objs)
elif self.options.mikrotik:
self.list_mikrotik(objs)
elif self.options.vertical:
self.list_vertical(objs)
else:
self.print_objects(objs)
def remote_functions(self):
return set(("list",))
def list_align(self, objs):
'''Listing line aligned'''
term_height, term_width = self.printer.get_term_size()
# remove ignored tags
for tag in self.options.ignore:
if tag in objs["order"]:
objs["order"].remove(tag)
for row in objs["objects"]:
if tag in row:
row.pop(tag)
# get max size by tag
tags = dict()
for o in objs["objects"]:
for (t,v) in o.items():
tags[t] = max(len(self.tdr(t, v)), tags.get(t, 0))
# build initial print order
order = [ t for t in objs.get("order", []) if t in tags ]
order.extend(sorted(set(tags.keys()) - set(order)))
# compute index width
indexw = int(math.log10(len(objs["objects"]))) + 1
# dislay each object by line
for (i,o) in enumerate(objs["objects"]):
line_pos = 0
num_pos = 0
# tag position on the line
pos = dict()
if self.options.index:
line = ("[%d]"%i).ljust(indexw + 3)
line_pos = len(line)
else:
line = ""
# variable for create a newline
new_line = False
first_line = True
for t in order:
# if tag doesn't fit into the space left, newline
if line_pos + len(t) + len(":") + tags[t] + len(" ") >= term_width or new_line:
line += os.linesep
line_pos = 0
num_pos = 0
new_line = False
first_line = False
line += "%s%s:%s%s "%(self.tdtc(t),
t,
self.tdc(t),
self.tdr(t, o.get(t, u"")).ljust(tags[t]))
pos[num_pos] = line_pos
line_pos += len(t) + len(":") + tags[t] + len(" ")
num_pos += 1
# align the next tag on the tag above and right
tmp_pos = num_pos
found_pos = False
while tmp_pos in pos:
# if the tag position above is greater than the line position, add space to align the next tag
if pos[tmp_pos] > line_pos:
line += " " * (pos[tmp_pos] - line_pos)
line_pos = pos[tmp_pos]
found_pos = True
break
else:
tmp_pos += 1
new_line = not found_pos and not first_line
self.printer.out("%s%s"%(line, color["reset"]))
if not self.options.nocount:
self.printer.out("Objects count: %s" % len(objs["objects"]))
def list_table(self, objs):
'''Listing table style'''
term_height, term_width = self.printer.get_term_size()
# remove ignored tags
for tag in self.options.ignore:
if tag in objs["order"]:
objs["order"].remove(tag)
for row in objs["objects"]:
if tag in row:
row.pop(tag)
# get max size by tag
tags = dict()
for o in objs["objects"]:
for (t,v) in o.items():
tags[t] = max(len(self.tdr(t, v)), tags.get(t, len(t)))
size_id = tags["id"] + len(" ")
# compute index width
indexw = max(int(math.log10(len(objs["objects"]))+1), len("index "))
if size_id + indexw >= term_width:
raise cmdError("Term width is too small")
# build initial print order
order = [ t for t in objs.get("order", []) if t in tags ]
order.extend(sorted(set(tags.keys()) - set(order)))
# print tag table by title group
while order:
tag_index = 0
line_pos = 0
if self.options.index:
# print index title
self.printer.out("index ", nl="")
line_pos = indexw
# print tags title section in order
for t in order:
# if the tag don't fit in space left, stop the title loop
if line_pos + tags[t] + len(" ") > term_width and tag_index != 0:
break
self.printer.out(self.tdtc(t) + t.ljust(tags[t]), nl=" ")
line_pos += tags[t] + len(" ")
tag_index += 1
self.printer.out(color["reset"])
# print tags corresponding to the title
for (i,o) in enumerate(objs["objects"]):
line_pos = 0
if self.options.index:
self.printer.out(("%d "%i).ljust(indexw), nl="")
line_pos += indexw
# print tag value
for t in order[:tag_index]:
self.printer.out(self.tdc(t), nl="")
buf, line_pos = self._format_indent_text(self.tdr(t, o.get(t, u"")).ljust(tags[t]) + " ", line_pos, size_id, term_width)
self.printer.out(buf, nl="")
self.printer.out(color["reset"])
order = order[tag_index:]
if not self.options.nocount:
self.printer.out("Objects count: %s" % len(objs["objects"]))
def list_vertical(self, objs):
'''Vertical display'''
term_height, term_width = self.printer.get_term_size()
# set margin for tags
margin = 3
# remove ignored tags
for tag in self.options.ignore:
if tag in objs["order"]:
objs["order"].remove(tag)
for row in objs["objects"]:
if tag in row:
row.pop(tag)
# build full tag order list:
tags = set((t for o in objs['objects'] for t in o.keys()))
order = [t for t in objs.get("order", []) if t in tags]
order.extend(sorted(tags - set(order)))
# compute index width
indexw = int(math.log10(len(objs["objects"]))) + 1
for (i, o) in enumerate(objs["objects"]):
line = ""
if self.options.index:
# +3 is the len("["), len("]"), len(" ")
line = ("[%d]"%i).ljust(indexw + 3)
# write id
tag = order[0]
line += "%s%s:%s%s "%(self.tdtc(tag), tag, self.tdc(tag), self.tdr(tag, o.get(tag)))
line += os.linesep
for t in order[1:]:
# write tag
if o.get(t) is not None:
# write tag title
buf, line_pos = self._format_indent_text(t + ":", margin, margin, term_width)
line += " " * margin + self.tdtc(t) + buf
# write tag value
buf, line_pos = self._format_indent_text(self.tdr(t, o.get(t)) + " ", line_pos, margin, term_width)
line += self.tdc(t)
if line_pos != margin:
line += (buf + os.linesep)
else:
line += (buf[:-(margin + 1)] + os.linesep)
self.printer.out("%s%s"%(line[:-1], color["reset"]))
if not self.options.nocount:
self.printer.out("Objects count: %s" % len(objs["objects"]))
def list_mikrotik(self, objs):
'''Mikrotik style display'''
term_height, term_width = self.printer.get_term_size()
# check if the line width is not too small for this kind of listing,
# 10 seem to be a good minimum value:
if term_width < 10:
raise cmdError("Term width is too small")
# remove ignored tags
for tag in self.options.ignore:
if tag in objs["order"]:
objs["order"].remove(tag)
for row in objs["objects"]:
if tag in row:
row.pop(tag)
# calculate the size of the marge, the taken value is equal to the
# maximum id length, capped to the 1/3 of the terminal width:
list_id = [len(o['id']) for o in objs['objects'] if len(o['id']) < term_width / 3]
if list_id:
margin = max(list_id) + 4
else:
margin = term_width / 3
# compute index width (part of the margin if apply):
if self.options.index:
indexw = int(math.log10(len(objs["objects"]))) + 1
margin += indexw
# build full tag order list:
tags = set((t for o in objs['objects'] for t in o.keys()))
order = [t for t in objs.get("order", []) if t in tags]
order.extend(sorted(tags - set(order)))
# dislay each object
for i, o in enumerate(objs["objects"]):
line_pos = 0
line = ""
if self.options.index:
line = ("[%d]"%i).ljust(indexw + 3)
line_pos = len(line)
# write the id tag on the margin:
tag = order[0]
# +2 is the size of space and ":"
id_size = line_pos + len(tag) + len(self.tdr(tag, o.get(tag))) + 2
line += "%s%s:%s%s "%(self.tdtc(tag), tag, self.tdc(tag), self.tdr(tag, o.get(tag, u"")))
line_pos = margin
if id_size <= term_width / 3:
line += " " * (margin - id_size)
else:
line += os.linesep + " " * margin
# write all other tags after id:
for tag in order[1:]:
if o.get(tag) is not None:
# the +2 is the size of space and ":"
tag_size = len(tag) + len(self.tdr(tag, o.get(tag))) + 2
# if tag doesn't fit into the space left on current line,
# we jump on a new line:
if line_pos + tag_size > term_width and margin != line_pos:
line_pos = margin
line += os.linesep + " " * margin
# write tag name:
buf, line_pos = self._format_indent_text(tag + ":", line_pos, margin, term_width)
line += self.tdtc(tag) + buf
# write tag value:
buf, line_pos = self._format_indent_text(self.tdr(tag, o.get(tag)) + " ", line_pos, margin, term_width)
line += self.tdc(tag) + buf
self.printer.out("%s%s%s"%(line, color["reset"], os.linesep))
if not self.options.nocount:
self.printer.out("Objects count: %s" % len(objs["objects"]))
def _format_indent_text(self, text, current_pos, min_pos, max_pos):
'''Reformat text to start in current_pos and fit in column between min_pos and max_pos
For example format_indent_text("tototatatiti", 3, 2, 6) return line = "tot\n otat\n atit\n i", current_pos = 3'''
buf = ""
last_size = 0
while text:
# the loop insert newline and indent in text
tmp = text[:max_pos - current_pos]
text = text[max_pos - current_pos:]
last_size = current_pos + len(tmp)
buf += tmp
# if next text is not empty, newline and indent
if text != "":
buf += os.linesep + " " * min_pos
# if next text is just a space, stop loop
if text == " ":
last_size = min_pos
break
current_pos = min_pos
return buf, last_size
cc-cli-v7/cloudcontrol/cli/commands/migrate.py 0000664 0000000 0000000 00000007564 12524707522 0021645 0 ustar 00root root 0000000 0000000 #coding=utf8
# This file is part of CloudControl.
#
# CloudControl is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# CloudControl is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with CloudControl. If not, see .
'''
CloudControl migrate command
'''
from cloudcontrol.cli.exception import *
from sjrpc.core.exceptions import *
from cloudcontrol.cli.printer import Printer, color
from cloudcontrol.cli.command import TqlCommand
class Command_migrate(TqlCommand):
'''Migrate vm'''
def __init__(self, cli, argv0):
TqlCommand.__init__(self, cli, argv0)
self.set_usage("%prog [options]