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
93a4d595
Commit
93a4d595
authored
Jun 26, 2013
by
Stavros Sachtouris
Browse files
Merge branch 'feature-expand-wait-functionality' into develop
parents
e3f01d64
77df3d4a
Changes
5
Hide whitespace changes
Inline
Side-by-side
Changelog
View file @
93a4d595
...
...
@@ -26,5 +26,7 @@ Features:
- Implement floating IP commands
floatingip list/create/delete/info/pools
server ip attach/detach
- Implement --wait for server_create/delete/start/reboot/shutdown [#3867]
- Implement network_wait [#3862]
kamaki/cli/__init__.py
View file @
93a4d595
...
...
@@ -39,7 +39,7 @@ from inspect import getargspec
from
kamaki.cli.argument
import
ArgumentParseManager
from
kamaki.cli.history
import
History
from
kamaki.cli.utils
import
print_dict
,
red
,
magenta
,
yellow
from
kamaki.cli.errors
import
CLIError
from
kamaki.cli.errors
import
CLIError
,
CLICmdSpecError
from
kamaki.cli
import
logger
_help
=
False
...
...
@@ -146,9 +146,13 @@ def command(cmd_tree, prefix='', descedants_depth=1):
kloger
.
warning
(
'%s failed max_len test'
%
cls_name
)
return
None
(
cls
.
description
,
sep
,
cls
.
long_description
)
=
cls
.
__doc__
.
partition
(
'
\n
'
)
try
:
(
cls
.
description
,
sep
,
cls
.
long_description
)
=
cls
.
__doc__
.
partition
(
'
\n
'
)
except
AttributeError
:
raise
CLICmdSpecError
(
'No commend in %s (acts as cmd description)'
%
cls
.
__name__
)
_construct_command_syntax
(
cls
)
cmd_tree
.
add_command
(
cls_name
,
cls
.
description
,
cls
)
...
...
kamaki/cli/commands/__init__.py
View file @
93a4d595
...
...
@@ -66,6 +66,10 @@ class _command_init(object):
arguments
.
update
(
self
.
oo_arguments
)
if
isinstance
(
self
,
_optional_json
):
arguments
.
update
(
self
.
oj_arguments
)
try
:
arguments
.
update
(
self
.
wait_arguments
)
except
AttributeError
:
pass
self
.
arguments
=
dict
(
arguments
)
try
:
self
.
config
=
self
[
'config'
]
...
...
kamaki/cli/commands/cyclades.py
View file @
93a4d595
...
...
@@ -67,6 +67,64 @@ howto_personality = [
' MODEL: permition in octal (e.g. 0777 or o+rwx)'
]
class
_server_wait
(
object
):
wait_arguments
=
dict
(
progress_bar
=
ProgressBarArgument
(
'do not show progress bar'
,
(
'-N'
,
'--no-progress-bar'
),
False
)
)
def
_wait
(
self
,
server_id
,
currect_status
):
(
progress_bar
,
wait_cb
)
=
self
.
_safe_progress_bar
(
'Server %s still in %s mode'
%
(
server_id
,
currect_status
))
try
:
new_mode
=
self
.
client
.
wait_server
(
server_id
,
currect_status
,
wait_cb
=
wait_cb
)
except
Exception
:
raise
finally
:
self
.
_safe_progress_bar_finish
(
progress_bar
)
if
new_mode
:
print
(
'Server %s is now in %s mode'
%
(
server_id
,
new_mode
))
else
:
raiseCLIError
(
None
,
'Time out'
)
class
_network_wait
(
object
):
wait_arguments
=
dict
(
progress_bar
=
ProgressBarArgument
(
'do not show progress bar'
,
(
'-N'
,
'--no-progress-bar'
),
False
)
)
def
_wait
(
self
,
net_id
,
currect_status
):
(
progress_bar
,
wait_cb
)
=
self
.
_safe_progress_bar
(
'Network %s still in %s mode'
%
(
net_id
,
currect_status
))
try
:
new_mode
=
self
.
client
.
wait_network
(
net_id
,
currect_status
,
wait_cb
=
wait_cb
)
except
Exception
:
raise
finally
:
self
.
_safe_progress_bar_finish
(
progress_bar
)
if
new_mode
:
print
(
'Network %s is now in %s mode'
%
(
net_id
,
new_mode
))
else
:
raiseCLIError
(
None
,
'Time out'
)
class
_init_cyclades
(
_command_init
):
@
errors
.
generic
.
all
@
addLogSettings
...
...
@@ -191,7 +249,7 @@ class PersonalityArgument(KeyValueArgument):
@
command
(
server_cmds
)
class
server_create
(
_init_cyclades
,
_optional_json
):
class
server_create
(
_init_cyclades
,
_optional_json
,
_server_wait
):
"""Create a server (aka Virtual Machine)
Parameters:
- name: (single quoted text)
...
...
@@ -201,7 +259,8 @@ class server_create(_init_cyclades, _optional_json):
arguments
=
dict
(
personality
=
PersonalityArgument
(
(
80
*
' '
).
join
(
howto_personality
),
(
'-p'
,
'--personality'
))
(
80
*
' '
).
join
(
howto_personality
),
(
'-p'
,
'--personality'
)),
wait
=
FlagArgument
(
'Wait server to build'
,
(
'-w'
,
'--wait'
))
)
@
errors
.
generic
.
all
...
...
@@ -209,10 +268,11 @@ class server_create(_init_cyclades, _optional_json):
@
errors
.
plankton
.
id
@
errors
.
cyclades
.
flavor_id
def
_run
(
self
,
name
,
flavor_id
,
image_id
):
self
.
_print
(
self
.
client
.
create_server
(
name
,
int
(
flavor_id
),
image_id
,
self
[
'personality'
]),
print_dict
)
r
=
self
.
client
.
create_server
(
name
,
int
(
flavor_id
),
image_id
,
self
[
'personality'
])
self
.
_print
(
r
,
print_dict
)
if
self
[
'wait'
]:
self
.
_wait
(
r
[
'id'
],
r
[
'status'
])
def
main
(
self
,
name
,
flavor_id
,
image_id
):
super
(
self
.
__class__
,
self
).
_run
()
...
...
@@ -238,14 +298,27 @@ class server_rename(_init_cyclades, _optional_output_cmd):
@
command
(
server_cmds
)
class
server_delete
(
_init_cyclades
,
_optional_output_cmd
):
class
server_delete
(
_init_cyclades
,
_optional_output_cmd
,
_server_wait
):
"""Delete a server (VM)"""
arguments
=
dict
(
wait
=
FlagArgument
(
'Wait server to be destroyed'
,
(
'-w'
,
'--wait'
))
)
@
errors
.
generic
.
all
@
errors
.
cyclades
.
connection
@
errors
.
cyclades
.
server_id
def
_run
(
self
,
server_id
):
self
.
_optional_output
(
self
.
client
.
delete_server
(
int
(
server_id
)))
status
=
'DELETED'
if
self
[
'wait'
]:
details
=
self
.
client
.
get_server_details
(
server_id
)
status
=
details
[
'status'
]
r
=
self
.
client
.
delete_server
(
int
(
server_id
))
self
.
_optional_output
(
r
)
if
self
[
'wait'
]:
self
.
_wait
(
server_id
,
status
)
def
main
(
self
,
server_id
):
super
(
self
.
__class__
,
self
).
_run
()
...
...
@@ -253,19 +326,23 @@ class server_delete(_init_cyclades, _optional_output_cmd):
@
command
(
server_cmds
)
class
server_reboot
(
_init_cyclades
,
_optional_output_cmd
):
class
server_reboot
(
_init_cyclades
,
_optional_output_cmd
,
_server_wait
):
"""Reboot a server (VM)"""
arguments
=
dict
(
hard
=
FlagArgument
(
'perform a hard reboot'
,
(
'-f'
,
'--force'
))
hard
=
FlagArgument
(
'perform a hard reboot'
,
(
'-f'
,
'--force'
)),
wait
=
FlagArgument
(
'Wait server to be destroyed'
,
(
'-w'
,
'--wait'
))
)
@
errors
.
generic
.
all
@
errors
.
cyclades
.
connection
@
errors
.
cyclades
.
server_id
def
_run
(
self
,
server_id
):
self
.
_optional_output
(
self
.
client
.
reboot_server
(
int
(
server_id
),
self
[
'hard'
]))
r
=
self
.
client
.
reboot_server
(
int
(
server_id
),
self
[
'hard'
])
self
.
_optional_output
(
r
)
if
self
[
'wait'
]:
self
.
_wait
(
server_id
,
'REBOOT'
)
def
main
(
self
,
server_id
):
super
(
self
.
__class__
,
self
).
_run
()
...
...
@@ -273,14 +350,29 @@ class server_reboot(_init_cyclades, _optional_output_cmd):
@
command
(
server_cmds
)
class
server_start
(
_init_cyclades
,
_optional_output_cmd
):
class
server_start
(
_init_cyclades
,
_optional_output_cmd
,
_server_wait
):
"""Start an existing server (VM)"""
arguments
=
dict
(
wait
=
FlagArgument
(
'Wait server to be destroyed'
,
(
'-w'
,
'--wait'
))
)
@
errors
.
generic
.
all
@
errors
.
cyclades
.
connection
@
errors
.
cyclades
.
server_id
def
_run
(
self
,
server_id
):
self
.
_optional_output
(
self
.
client
.
start_server
(
int
(
server_id
)))
status
=
'ACTIVE'
if
self
[
'wait'
]:
details
=
self
.
client
.
get_server_details
(
server_id
)
status
=
details
[
'status'
]
if
status
in
(
'ACTIVE'
,
):
return
r
=
self
.
client
.
start_server
(
int
(
server_id
))
self
.
_optional_output
(
r
)
if
self
[
'wait'
]:
self
.
_wait
(
server_id
,
status
)
def
main
(
self
,
server_id
):
super
(
self
.
__class__
,
self
).
_run
()
...
...
@@ -288,14 +380,29 @@ class server_start(_init_cyclades, _optional_output_cmd):
@
command
(
server_cmds
)
class
server_shutdown
(
_init_cyclades
,
_optional_output_cmd
):
class
server_shutdown
(
_init_cyclades
,
_optional_output_cmd
,
_server_wait
):
"""Shutdown an active server (VM)"""
arguments
=
dict
(
wait
=
FlagArgument
(
'Wait server to be destroyed'
,
(
'-w'
,
'--wait'
))
)
@
errors
.
generic
.
all
@
errors
.
cyclades
.
connection
@
errors
.
cyclades
.
server_id
def
_run
(
self
,
server_id
):
self
.
_optional_output
(
self
.
client
.
shutdown_server
(
int
(
server_id
)))
status
=
'STOPPED'
if
self
[
'wait'
]:
details
=
self
.
client
.
get_server_details
(
server_id
)
status
=
details
[
'status'
]
if
status
in
(
'STOPPED'
,
):
return
r
=
self
.
client
.
shutdown_server
(
int
(
server_id
))
self
.
_optional_output
(
r
)
if
self
[
'wait'
]:
self
.
_wait
(
server_id
,
status
)
def
main
(
self
,
server_id
):
super
(
self
.
__class__
,
self
).
_run
()
...
...
@@ -476,38 +583,14 @@ class server_stats(_init_cyclades, _optional_json):
@
command
(
server_cmds
)
class
server_wait
(
_init_cyclades
):
class
server_wait
(
_init_cyclades
,
_server_wait
):
"""Wait for server to finish [BUILD, STOPPED, REBOOT, ACTIVE]"""
arguments
=
dict
(
progress_bar
=
ProgressBarArgument
(
'do not show progress bar'
,
(
'-N'
,
'--no-progress-bar'
),
False
)
)
@
errors
.
generic
.
all
@
errors
.
cyclades
.
connection
@
errors
.
cyclades
.
server_id
def
_run
(
self
,
server_id
,
currect_status
):
(
progress_bar
,
wait_cb
)
=
self
.
_safe_progress_bar
(
'Server %s still in %s mode'
%
(
server_id
,
currect_status
))
try
:
new_mode
=
self
.
client
.
wait_server
(
server_id
,
currect_status
,
wait_cb
=
wait_cb
)
except
Exception
:
self
.
_safe_progress_bar_finish
(
progress_bar
)
raise
finally
:
self
.
_safe_progress_bar_finish
(
progress_bar
)
if
new_mode
:
print
(
'Server %s is now in %s mode'
%
(
server_id
,
new_mode
))
else
:
raiseCLIError
(
None
,
'Time out'
)
self
.
_wait
(
server_id
,
currect_status
)
def
main
(
self
,
server_id
,
currect_status
=
'BUILD'
):
super
(
self
.
__class__
,
self
).
_run
()
...
...
@@ -613,7 +696,7 @@ class network_list(_init_cyclades, _optional_json):
@
command
(
network_cmds
)
class
network_create
(
_init_cyclades
,
_optional_json
):
class
network_create
(
_init_cyclades
,
_optional_json
,
_network_wait
):
"""Create an (unconnected) network"""
arguments
=
dict
(
...
...
@@ -624,19 +707,24 @@ class network_create(_init_cyclades, _optional_json):
'Valid network types are '
'CUSTOM, IP_LESS_ROUTED, MAC_FILTERED (default), PHYSICAL_VLAN'
,
'--with-type'
,
default
=
'MAC_FILTERED'
)
default
=
'MAC_FILTERED'
),
wait
=
FlagArgument
(
'Wait network to build'
,
(
'-w'
,
'--wait'
))
)
@
errors
.
generic
.
all
@
errors
.
cyclades
.
connection
@
errors
.
cyclades
.
network_max
def
_run
(
self
,
name
):
self
.
_print
(
self
.
client
.
create_network
(
r
=
self
.
client
.
create_network
(
name
,
cidr
=
self
[
'cidr'
],
gateway
=
self
[
'gateway'
],
dhcp
=
self
[
'dhcp'
],
type
=
self
[
'type'
]),
print_dict
)
type
=
self
[
'type'
])
self
.
_print
(
r
,
print_dict
)
if
self
[
'wait'
]:
self
.
_wait
(
r
[
'id'
],
'PENDING'
)
def
main
(
self
,
name
):
super
(
self
.
__class__
,
self
).
_run
()
...
...
@@ -660,15 +748,30 @@ class network_rename(_init_cyclades, _optional_output_cmd):
@
command
(
network_cmds
)
class
network_delete
(
_init_cyclades
,
_optional_output_cmd
):
class
network_delete
(
_init_cyclades
,
_optional_output_cmd
,
_network_wait
):
"""Delete a network"""
arguments
=
dict
(
wait
=
FlagArgument
(
'Wait network to build'
,
(
'-w'
,
'--wait'
))
)
@
errors
.
generic
.
all
@
errors
.
cyclades
.
connection
@
errors
.
cyclades
.
network_id
@
errors
.
cyclades
.
network_in_use
def
_run
(
self
,
network_id
):
self
.
_optional_output
(
self
.
client
.
delete_network
(
int
(
network_id
)))
status
=
'DELETED'
if
self
[
'wait'
]:
r
=
self
.
client
.
get_network_details
(
network_id
)
status
=
r
[
'status'
]
if
status
in
(
'DELETED'
,
):
return
r
=
self
.
client
.
delete_network
(
int
(
network_id
))
self
.
_optional_output
(
r
)
if
self
[
'wait'
]:
self
.
_wait
(
network_id
,
status
)
def
main
(
self
,
network_id
):
super
(
self
.
__class__
,
self
).
_run
()
...
...
@@ -723,6 +826,21 @@ class network_disconnect(_init_cyclades):
self
.
_run
(
nic_id
=
nic_id
,
server_id
=
server_id
)
@
command
(
network_cmds
)
class
network_wait
(
_init_cyclades
,
_network_wait
):
"""Wait for server to finish [PENDING, ACTIVE, DELETED]"""
@
errors
.
generic
.
all
@
errors
.
cyclades
.
connection
@
errors
.
cyclades
.
network_id
def
_run
(
self
,
network_id
,
currect_status
):
self
.
_wait
(
network_id
,
currect_status
)
def
main
(
self
,
network_id
,
currect_status
=
'PENDING'
):
super
(
self
.
__class__
,
self
).
_run
()
self
.
_run
(
network_id
=
network_id
,
currect_status
=
currect_status
)
@
command
(
floatingip_cmds
)
class
floatingip_pools
(
_init_cyclades
,
_optional_json
):
"""List all floating pools of floating ips"""
...
...
kamaki/clients/cyclades/__init__.py
View file @
93a4d595
...
...
@@ -257,66 +257,104 @@ class CycladesClient(CycladesRestClient):
req
=
dict
(
remove
=
dict
(
attachment
=
nic
))
self
.
networks_post
(
netid
,
'action'
,
json_data
=
req
)
def
wait_server
(
self
,
server_id
,
current_status
=
'BUILD'
,
delay
=
0.5
,
max_wait
=
128
,
wait_cb
=
None
):
"""Wait for server while its status is current_status
def
_wait
(
self
,
item_id
,
current_status
,
get_status
,
delay
=
1
,
max_wait
=
100
,
wait_cb
=
None
):
"""Wait for item while its status is current_status
:param server_id: integer (str or int)
:param current_status: (str) BUILD|ACTIVE|STOPPED|DELETED|REBOOT
:param current_status: (str)
:param get_status: (method(self, item_id)) if called, returns
(status, progress %) If no way to tell progress, return None
:param delay: time interval between retries
:param wait_cb: if set a progressbar is used to show progress
:param wait_cb: if set a progress
bar is used to show progress
:returns: (str) the new mode if succesful
l
, (bool) False if timed out
:returns: (str) the new mode if succes
s
ful, (bool) False if timed out
"""
r
=
self
.
get_server_details
(
server
_id
)
if
r
[
'
status
'
]
!=
current_status
:
return
r
[
'
status
'
]
status
,
progress
=
get_status
(
self
,
item
_id
)
if
status
!=
current_status
:
return
status
old_wait
=
total_wait
=
0
if
current_status
==
'BUILD'
:
max_wait
=
100
wait_gen
=
wait_cb
(
max_wait
)
if
wait_cb
else
None
elif
wait_cb
:
if
wait_cb
:
wait_gen
=
wait_cb
(
1
+
max_wait
//
delay
)
wait_gen
.
next
()
while
r
[
'status'
]
==
current_status
and
total_wait
<=
max_wait
:
if
current_status
==
'BUILD'
:
total_wait
=
int
(
r
[
'progress'
])
if
wait_cb
:
for
i
in
range
(
int
(
old_wait
),
int
(
total_wait
)):
while
status
==
current_status
and
total_wait
<=
max_wait
:
if
wait_cb
:
try
:
for
i
in
range
(
total_wait
-
old_wait
):
wait_gen
.
next
()
old_wait
=
total_wait
else
:
stdout
.
write
(
'.'
)
stdout
.
flush
()
except
Exception
:
break
else
:
if
wait_cb
:
wait_gen
.
next
()
else
:
stdout
.
write
(
'.'
)
stdout
.
flush
()
total_wait
+=
delay
stdout
.
write
(
'.'
)
stdout
.
flush
()
old_wait
=
total_wait
total_wait
=
progress
or
(
total_wait
+
1
)
sleep
(
delay
)
r
=
self
.
get_server_details
(
server
_id
)
status
,
progress
=
get_status
(
self
,
item
_id
)
if
r
[
'status'
]
!=
current_status
:
if
total_wait
<
max_wait
:
if
wait_cb
:
try
:
while
True
:
for
i
in
range
(
max_wait
)
:
wait_gen
.
next
()
except
:
pass
return
r
[
'status'
]
return
False
return
status
if
status
!=
current_status
else
False
def
wait_server
(
self
,
server_id
,
current_status
=
'BUILD'
,
delay
=
1
,
max_wait
=
100
,
wait_cb
=
None
):
"""Wait for server while its status is current_status
:param server_id: integer (str or int)
:param current_status: (str) BUILD|ACTIVE|STOPPED|DELETED|REBOOT
:param delay: time interval between retries
:param wait_cb: if set a progressbar is used to show progress
:returns: (str) the new mode if succesfull, (bool) False if timed out
"""
def
get_status
(
self
,
server_id
):
r
=
self
.
get_server_details
(
server_id
)
return
r
[
'status'
],
(
r
.
get
(
'progress'
,
None
)
if
(
current_status
in
(
'BUILD'
,
))
else
None
)
return
self
.
_wait
(
server_id
,
current_status
,
get_status
,
delay
,
max_wait
,
wait_cb
)
def
wait_network
(
self
,
net_id
,
current_status
=
'LALA'
,
delay
=
1
,
max_wait
=
100
,
wait_cb
=
None
):
"""Wait for network while its status is current_status
:param net_id: integer (str or int)
:param current_status: (str) PENDING | ACTIVE | DELETED
:param delay: time interval between retries
:param wait_cb: if set a progressbar is used to show progress
:returns: (str) the new mode if succesfull, (bool) False if timed out
"""
def
get_status
(
self
,
net_id
):
r
=
self
.
get_network_details
(
net_id
)
return
r
[
'status'
],
None
return
self
.
_wait
(
net_id
,
current_status
,
get_status
,
delay
,
max_wait
,
wait_cb
)
def
get_floating_ip_pools
(
self
):
"""
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment