Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
itminedu
kamaki
Commits
7493ccb6
Commit
7493ccb6
authored
Sep 04, 2012
by
Stavros Sachtouris
Browse files
Correct repackaging, minor server list improvement
parent
14af08c0
Changes
10
Expand all
Hide whitespace changes
Inline
Side-by-side
kamaki/cli/__init__.py
0 → 100644
View file @
7493ccb6
#!/usr/bin/env python
# Copyright 2011-2012 GRNET S.A. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
# without modification, are permitted provided that the following
# conditions are met:
#
# 1. Redistributions of source code must retain the above
# copyright notice, this list of conditions and the following
# disclaimer.
#
# 2. Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# The views and conclusions contained in the software and
# documentation are those of the authors and should not be
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
from
__future__
import
print_function
import
gevent.monkey
#Monkey-patch everything for gevent early on
gevent
.
monkey
.
patch_all
()
import
inspect
import
logging
import
sys
from
argparse
import
ArgumentParser
from
base64
import
b64encode
from
os.path
import
abspath
,
basename
,
exists
from
sys
import
exit
,
stdout
,
stderr
try
:
from
collections
import
OrderedDict
except
ImportError
:
from
ordereddict
import
OrderedDict
from
colors
import
magenta
,
red
,
yellow
,
bold
from
kamaki
import
clients
from
.config
import
Config
_commands
=
OrderedDict
()
GROUPS
=
{}
CLI_LOCATIONS
=
[
'kamaki.cli.commands'
,
'kamaki.commands'
,
'kamaki.cli'
,
'kamaki'
,
''
]
class
CLIError
(
Exception
):
def
__init__
(
self
,
message
,
status
=
0
,
details
=
''
,
importance
=
0
):
"""importance is set by the raiser
0 is the lowest possible importance
Suggested values: 0, 1, 2, 3
"""
super
(
CLIError
,
self
).
__init__
(
message
,
status
,
details
)
self
.
message
=
message
self
.
status
=
status
self
.
details
=
details
self
.
importance
=
importance
def
__unicode__
(
self
):
return
unicode
(
self
.
message
)
def
command
(
group
=
None
,
name
=
None
,
syntax
=
None
):
"""Class decorator that registers a class as a CLI command."""
def
decorator
(
cls
):
grp
,
sep
,
cmd
=
cls
.
__name__
.
partition
(
'_'
)
if
not
sep
:
grp
,
cmd
=
None
,
cls
.
__name__
#cls.api = api
cls
.
group
=
group
or
grp
cls
.
name
=
name
or
cmd
short_description
,
sep
,
long_description
=
cls
.
__doc__
.
partition
(
'
\n
'
)
cls
.
description
=
short_description
cls
.
long_description
=
long_description
or
short_description
cls
.
syntax
=
syntax
if
cls
.
syntax
is
None
:
# Generate a syntax string based on main's arguments
spec
=
inspect
.
getargspec
(
cls
.
main
.
im_func
)
args
=
spec
.
args
[
1
:]
n
=
len
(
args
)
-
len
(
spec
.
defaults
or
())
required
=
' '
.
join
(
'<%s>'
%
x
.
replace
(
'____'
,
'[:'
).
replace
(
'___'
,
':'
).
replace
(
'__'
,
']'
).
replace
(
'_'
,
' '
)
for
x
in
args
[:
n
])
optional
=
' '
.
join
(
'[%s]'
%
x
.
replace
(
'____'
,
'[:'
).
replace
(
'___'
,
':'
).
replace
(
'__'
,
']'
).
replace
(
'_'
,
' '
)
for
x
in
args
[
n
:])
cls
.
syntax
=
' '
.
join
(
x
for
x
in
[
required
,
optional
]
if
x
)
if
spec
.
varargs
:
cls
.
syntax
+=
' <%s ...>'
%
spec
.
varargs
if
cls
.
group
not
in
_commands
:
_commands
[
cls
.
group
]
=
OrderedDict
()
_commands
[
cls
.
group
][
cls
.
name
]
=
cls
return
cls
return
decorator
def
set_api_description
(
api
,
description
):
"""Method to be called by api CLIs
Each CLI can set more than one api descriptions"""
GROUPS
[
api
]
=
description
def
main
():
def
print_groups
():
print
(
'
\n
Groups:'
)
for
group
in
_commands
:
description
=
GROUPS
.
get
(
group
,
''
)
print
(
' '
,
group
.
ljust
(
12
),
description
)
def
print_commands
(
group
):
description
=
GROUPS
.
get
(
group
,
''
)
if
description
:
print
(
'
\n
'
+
description
)
print
(
'
\n
Commands:'
)
for
name
,
cls
in
_commands
[
group
].
items
():
print
(
' '
,
name
.
ljust
(
14
),
cls
.
description
)
def
manage_logging_handlers
(
args
):
"""This is mostly to handle logging for clients package"""
def
add_handler
(
name
,
level
,
prefix
=
''
):
h
=
logging
.
StreamHandler
()
fmt
=
logging
.
Formatter
(
prefix
+
'%(message)s'
)
h
.
setFormatter
(
fmt
)
logger
=
logging
.
getLogger
(
name
)
logger
.
addHandler
(
h
)
logger
.
setLevel
(
level
)
if
args
.
silent
:
add_handler
(
''
,
logging
.
CRITICAL
)
elif
args
.
debug
:
add_handler
(
'requests'
,
logging
.
INFO
,
prefix
=
'* '
)
add_handler
(
'clients.send'
,
logging
.
DEBUG
,
prefix
=
'> '
)
add_handler
(
'clients.recv'
,
logging
.
DEBUG
,
prefix
=
'< '
)
elif
args
.
verbose
:
add_handler
(
'requests'
,
logging
.
INFO
,
prefix
=
'* '
)
add_handler
(
'clients.send'
,
logging
.
INFO
,
prefix
=
'> '
)
add_handler
(
'clients.recv'
,
logging
.
INFO
,
prefix
=
'< '
)
elif
args
.
include
:
add_handler
(
'clients.recv'
,
logging
.
INFO
)
else
:
add_handler
(
''
,
logging
.
WARNING
)
def
load_groups
(
config
):
"""load groups and import CLIs and Modules"""
loaded_modules
=
{}
for
api
in
config
.
apis
():
api_cli
=
config
.
get
(
api
,
'cli'
)
if
None
==
api_cli
or
len
(
api_cli
)
==
0
:
print
(
'Warnig: No Command Line Interface "%s" given for API "%s"'
%
(
api_cli
,
api
))
print
(
'
\t
(cli option in config file)'
)
continue
if
not
loaded_modules
.
has_key
(
api_cli
):
loaded_modules
[
api_cli
]
=
False
for
location
in
CLI_LOCATIONS
:
location
+=
api_cli
if
location
==
''
else
'.%s'
%
api_cli
try
:
__import__
(
location
)
loaded_modules
[
api_cli
]
=
True
break
except
ImportError
:
pass
if
not
loaded_modules
[
api_cli
]:
print
(
'Warning: failed to load Command Line Interface "%s" for API "%s"'
%
(
api_cli
,
api
))
print
(
'
\t
(No suitable cli in known paths)'
)
continue
if
not
GROUPS
.
has_key
(
api
):
GROUPS
[
api
]
=
'No description (interface: %s)'
%
api_cli
def
init_parser
(
exe
):
parser
=
ArgumentParser
(
add_help
=
False
)
parser
.
prog
=
'%s <group> <command>'
%
exe
parser
.
add_argument
(
'-h'
,
'--help'
,
dest
=
'help'
,
action
=
'store_true'
,
default
=
False
,
help
=
"Show this help message and exit"
)
parser
.
add_argument
(
'--config'
,
dest
=
'config'
,
metavar
=
'PATH'
,
help
=
"Specify the path to the configuration file"
)
parser
.
add_argument
(
'-d'
,
'--debug'
,
dest
=
'debug'
,
action
=
'store_true'
,
default
=
False
,
help
=
"Include debug output"
)
parser
.
add_argument
(
'-i'
,
'--include'
,
dest
=
'include'
,
action
=
'store_true'
,
default
=
False
,
help
=
"Include protocol headers in the output"
)
parser
.
add_argument
(
'-s'
,
'--silent'
,
dest
=
'silent'
,
action
=
'store_true'
,
default
=
False
,
help
=
"Silent mode, don't output anything"
)
parser
.
add_argument
(
'-v'
,
'--verbose'
,
dest
=
'verbose'
,
action
=
'store_true'
,
default
=
False
,
help
=
"Make the operation more talkative"
)
parser
.
add_argument
(
'-V'
,
'--version'
,
dest
=
'version'
,
action
=
'store_true'
,
default
=
False
,
help
=
"Show version number and quit"
)
parser
.
add_argument
(
'-o'
,
dest
=
'options'
,
action
=
'append'
,
default
=
[],
metavar
=
"KEY=VAL"
,
help
=
"Override a config value"
)
return
parser
def
find_term_in_args
(
arg_list
,
term_list
):
"""find an arg_list term in term_list. All other terms up to found
term are rearanged at the end of arg_list, preserving relative order
"""
arg_tail
=
[]
while
len
(
arg_list
)
>
0
:
group
=
arg_list
.
pop
(
0
)
if
group
not
in
term_list
:
arg_tail
.
append
(
group
)
else
:
arg_list
+=
arg_tail
return
group
return
None
"""Main Code"""
exe
=
basename
(
sys
.
argv
[
0
])
parser
=
init_parser
(
exe
)
args
,
argv
=
parser
.
parse_known_args
()
#print version
if
args
.
version
:
import
kamaki
print
(
"kamaki %s"
%
kamaki
.
__version__
)
exit
(
0
)
config
=
Config
(
args
.
config
)
if
args
.
config
else
Config
()
#load config options from command line
for
option
in
args
.
options
:
keypath
,
sep
,
val
=
option
.
partition
(
'='
)
if
not
sep
:
print
(
"Invalid option '%s'"
%
option
)
exit
(
1
)
section
,
sep
,
key
=
keypath
.
partition
(
'.'
)
if
not
sep
:
print
(
"Invalid option '%s'"
%
option
)
exit
(
1
)
config
.
override
(
section
.
strip
(),
key
.
strip
(),
val
.
strip
())
load_groups
(
config
)
group
=
find_term_in_args
(
argv
,
_commands
)
if
not
group
:
parser
.
print_help
()
print_groups
()
exit
(
0
)
parser
.
prog
=
'%s %s <command>'
%
(
exe
,
group
)
command
=
find_term_in_args
(
argv
,
_commands
[
group
])
if
not
command
:
parser
.
print_help
()
print_commands
(
group
)
exit
(
0
)
cmd
=
_commands
[
group
][
command
]()
parser
.
prog
=
'%s %s %s'
%
(
exe
,
group
,
command
)
if
cmd
.
syntax
:
parser
.
prog
+=
' %s'
%
cmd
.
syntax
parser
.
description
=
cmd
.
description
parser
.
epilog
=
''
if
hasattr
(
cmd
,
'update_parser'
):
cmd
.
update_parser
(
parser
)
#check other args
args
,
argv
=
parser
.
parse_known_args
()
if
group
!=
argv
[
0
]:
errmsg
=
red
(
'Invalid command group '
+
argv
[
0
])
print
(
errmsg
,
file
=
stderr
)
exit
(
1
)
if
command
!=
argv
[
1
]:
errmsg
=
red
(
'Invalid command "%s" in group "%s"'
%
(
argv
[
1
],
argv
[
0
]))
print
(
errmsg
,
file
=
stderr
)
exit
(
1
)
if
args
.
help
:
parser
.
print_help
()
exit
(
0
)
manage_logging_handlers
(
args
)
cmd
.
args
=
args
cmd
.
config
=
config
try
:
ret
=
cmd
.
main
(
*
argv
[
2
:])
exit
(
ret
)
except
TypeError
as
e
:
if
e
.
args
and
e
.
args
[
0
].
startswith
(
'main()'
):
parser
.
print_help
()
exit
(
1
)
else
:
raise
except
CLIError
as
err
:
errmsg
=
'CLI Error '
errmsg
+=
'(%s): '
%
err
.
status
if
err
.
status
else
': '
errmsg
+=
err
.
message
if
err
.
message
else
''
if
err
.
importance
==
1
:
errmsg
=
yellow
(
errmsg
)
elif
err
.
importance
==
2
:
errmsg
=
magenta
(
errmsg
)
elif
err
.
importance
>
2
:
errmsg
=
red
(
errmsg
)
print
(
errmsg
,
file
=
stderr
)
exit
(
1
)
if
__name__
==
'__main__'
:
main
()
kamaki/cli/commands/__init__.py
0 → 100644
View file @
7493ccb6
kamaki/cli/commands/astakos_cli.py
0 → 100644
View file @
7493ccb6
# Copyright 2011-2012 GRNET S.A. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
# without modification, are permitted provided that the following
# conditions are met:
#
# 1. Redistributions of source code must retain the above
# copyright notice, this list of conditions and the following
# disclaimer.
#
# 2. Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# The views and conclusions contained in the software and
# documentation are those of the authors and should not be
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.command
from
kamaki.cli
import
command
,
set_api_description
set_api_description
(
'astakos'
,
'Astakos API commands'
)
from
kamaki.clients.astakos
import
AstakosClient
,
ClientError
from
kamaki.cli.utils
import
raiseCLIError
,
print_dict
class
_astakos_init
(
object
):
def
main
(
self
):
token
=
self
.
config
.
get
(
'astakos'
,
'token'
)
or
self
.
config
.
get
(
'global'
,
'token'
)
base_url
=
self
.
config
.
get
(
'astakos'
,
'url'
)
or
self
.
config
.
get
(
'global'
,
'url'
)
if
base_url
is
None
:
raise
ClientError
(
'no URL for astakos'
)
self
.
client
=
AstakosClient
(
base_url
=
base_url
,
token
=
token
)
@
command
()
class
astakos_authenticate
(
_astakos_init
):
"""Authenticate a user"""
def
main
(
self
):
super
(
astakos_authenticate
,
self
).
main
()
try
:
reply
=
self
.
client
.
authenticate
()
except
ClientError
as
err
:
raiseCLIError
(
err
)
print_dict
(
reply
)
\ No newline at end of file
kamaki/cli/commands/config_cli.py
0 → 100644
View file @
7493ccb6
# Copyright 2011-2012 GRNET S.A. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
# without modification, are permitted provided that the following
# conditions are met:
#
# 1. Redistributions of source code must retain the above
# copyright notice, this list of conditions and the following
# disclaimer.
#
# 2. Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# The views and conclusions contained in the software and
# documentation are those of the authors and should not be
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
from
kamaki.cli
import
command
,
set_api_description
set_api_description
(
'config'
,
'Configuration commands'
)
@
command
()
class
config_list
(
object
):
"""List configuration options"""
def
update_parser
(
self
,
parser
):
parser
.
add_argument
(
'-a'
,
dest
=
'all'
,
action
=
'store_true'
,
default
=
False
,
help
=
'include default values'
)
def
main
(
self
):
include_defaults
=
self
.
args
.
all
for
section
in
sorted
(
self
.
config
.
sections
()):
items
=
self
.
config
.
items
(
section
,
include_defaults
)
for
key
,
val
in
sorted
(
items
):
print
(
'%s.%s = %s'
%
(
section
,
key
,
val
))
@
command
()
class
config_get
(
object
):
"""Show a configuration option"""
def
main
(
self
,
option
):
section
,
sep
,
key
=
option
.
rpartition
(
'.'
)
section
=
section
or
'global'
value
=
self
.
config
.
get
(
section
,
key
)
if
value
is
not
None
:
print
(
value
)
@
command
()
class
config_set
(
object
):
"""Set a configuration option"""
def
main
(
self
,
option
,
value
):
section
,
sep
,
key
=
option
.
rpartition
(
'.'
)
section
=
section
or
'globail'
self
.
config
.
set
(
section
,
key
,
value
)
self
.
config
.
write
()
@
command
()
class
config_delete
(
object
):
"""Delete a configuration option (and use the default value)"""
def
main
(
self
,
option
):
section
,
sep
,
key
=
option
.
rpartition
(
'.'
)
section
=
section
or
'global'
self
.
config
.
remove_option
(
section
,
key
)
self
.
config
.
write
()
kamaki/cli/commands/cyclades_cli.py
0 → 100644
View file @
7493ccb6
# Copyright 2012 GRNET S.A. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
# without modification, are permitted provided that the following
# conditions are met:
#
# 1. Redistributions of source code must retain the above
# copyright notice, this list of conditions and the following
# disclaimer.
#
# 2. Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# The views and conclusions contained in the software and
# documentation are those of the authors and should not be
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
from
kamaki.cli
import
command
,
set_api_description
,
CLIError
from
kamaki.cli.utils
import
print_dict
,
print_items
,
print_list
,
format_size
,
raiseCLIError
from
colors
import
bold
set_api_description
(
'server'
,
"Compute/Cyclades API server commands"
)
set_api_description
(
'flavor'
,
"Compute/Cyclades API flavor commands"
)
set_api_description
(
'image'
,
"Compute/Cyclades or Glance API image commands"
)
set_api_description
(
'network'
,
"Compute/Cyclades API network commands"
)
from
kamaki.clients.cyclades
import
CycladesClient
,
ClientError
class
_init_cyclades
(
object
):
def
main
(
self
):
token
=
self
.
config
.
get
(
'compute'
,
'token'
)
or
self
.
config
.
get
(
'global'
,
'token'
)
base_url
=
self
.
config
.
get
(
'compute'
,
'url'
)
or
self
.
config
.
get
(
'global'
,
'url'
)
self
.
client
=
CycladesClient
(
base_url
=
base_url
,
token
=
token
)
@
command
()
class
server_list
(
_init_cyclades
):
"""List servers"""
def
_print
(
self
,
servers
):
for
server
in
servers
:
sname
=
server
.
pop
(
'name'
)
sid
=
server
.
pop
(
'id'
)
print
(
'%s (%s)'
%
(
bold
(
sname
),
bold
(
unicode
(
sid
))))
if
getattr
(
self
.
args
,
'detail'
):
server_info
.
_print
(
server
)
print
(
'- - -'
)
def
update_parser
(
self
,
parser
):
parser
.
add_argument
(
'-l'
,
dest
=
'detail'
,
action
=
'store_true'
,
default
=
False
,
help
=
'show detailed output'
)
def
main
(
self
):
super
(
self
.
__class__
,
self
).
main
()
try
:
servers
=
self
.
client
.
list_servers
(
self
.
args
.
detail
)
self
.
_print
(
servers
)
#print_items(servers)
except
ClientError
as
err
:
raiseCLIError
(
err
)
@
command
()
class
server_info
(
_init_cyclades
):
"""Get server details"""
@
classmethod
def
_print
(
self
,
server
):
addr_dict
=
{}
if
server
.
has_key
(
'attachments'
):
for
addr
in
server
[
'attachments'
][
'values'
]:
ips
=
addr
.
pop
(
'values'
,
[])
for
ip
in
ips
:
addr
[
'IPv%s'
%
ip
[
'version'
]]
=
ip
[
'addr'
]
if
addr
.
has_key
(
'firewallProfile'
):
addr
[
'firewall'
]
=
addr
.
pop
(
'firewallProfile'
)
addr_dict
[
addr
.
pop
(
'id'
)]
=
addr
server
[
'attachments'
]
=
addr_dict
if
addr_dict
is
not
{}
else
None
if
server
.
has_key
(
'metadata'
):
server
[
'metadata'
]
=
server
[
'metadata'
][
'values'
]
print_dict
(
server
,
ident
=
14
)
def
main
(
self
,
server_id
):
super
(
self
.
__class__
,
self
).
main
()
try
:
server
=
self
.
client
.
get_server_details
(
int
(
server_id
))
except
ClientError
as
err
:
raiseCLIError
(
err
)
except
ValueError
as
err
:
raise
CLIError
(
message
=
'Server id must be positive integer'
,
importance
=
1
)
self
.
_print
(
server
)
@
command
()
class
server_create
(
_init_cyclades
):
"""Create a server"""
def
update_parser
(
self
,
parser
):
parser
.
add_argument
(
'--personality'
,
dest
=
'personalities'
,
action
=
'append'
,
default
=
[],
metavar
=
'PATH[,SERVER PATH[,OWNER[,GROUP,[MODE]]]]'
,
help
=
'add a personality file'
)
def
main
(
self
,
name
,
flavor_id
,
image_id
):
super
(
self
.
__class__
,
self
).
main
()
personalities
=
[]
for
personality
in
self
.
args
.
personalities
:
p
=
personality
.
split
(
','
)
p
.
extend
([
None
]
*
(
5
-
len
(
p
)))
# Fill missing fields with None
path
=
p
[
0
]
if
not
path
:
raise
CLIError
(
message
=
'Invalid personality argument %s'
%
p
,
importance
=
1
)
if
not
exists
(
path
):
raise
CLIError
(
message
=
"File %s does not exist"
%
path
,
importance
=
1
)
with
open
(
path
)
as
f
:
contents
=
b64encode
(
f
.
read
())
d
=
{
'path'
:
p
[
1
]
or
abspath
(
path
),
'contents'
:
contents
}
if
p
[
2
]:
d
[
'owner'
]
=
p
[
2
]
if
p
[
3
]:
d
[
'group'
]
=
p
[
3
]
if
p
[
4
]:
d
[
'mode'
]
=
int
(
p
[
4
])
personalities
.
append
(
d
)