from kamaki.cli.errors import (
CLISyntaxError, CLIBaseUrlError, CLIInvalidArgument)
from kamaki.clients.cyclades import CycladesNetworkClient
-from kamaki.cli.argument import FlagArgument, ValueArgument, RepeatableArgument
+from kamaki.cli.argument import (
+ FlagArgument, ValueArgument, RepeatableArgument, IntArgument)
from kamaki.cli.commands import _command_init, errors, addLogSettings
from kamaki.cli.commands import (
_optional_output_cmd, _optional_json, _name_filter, _id_filter)
from kamaki.cli.utils import filter_dicts_by_dict
+from kamaki.cli.commands.cyclades import _service_wait
network_cmds = CommandTree('network', 'Networking API network commands')
\n* to set authentication token: /config set cloud.<cloud>.token <token>'
+class _network_wait(_service_wait):
+
+ def _wait(self, net_id, current_status, timeout=60):
+ super(_network_wait, self)._wait(
+ 'Network', net_id, self.client.wait_network, current_status,
+ timeout=timeout)
+
+
class _init_network(_command_init):
@errors.generic.all
@addLogSettings
@command(network_cmds)
-class network_create(_init_network, _optional_json):
+class network_create(_init_network, _optional_json, _network_wait):
"""Create a new network"""
arguments = dict(
'Make network shared (special privileges required)', '--shared'),
network_type=NetworkTypeArgument(
'Valid network types: %s' % (', '.join(NetworkTypeArgument.types)),
- '--type')
+ '--type'),
+ wait=FlagArgument('Wait network to build', ('-w', '--wait')),
)
required = ('network_type', )
def _run(self, network_type):
net = self.client.create_network(
network_type, name=self['name'], shared=self['shared'])
+ if self['wait']:
+ self._wait(net['id'], net['status'])
self._print(net, self.print_dict)
def main(self):
self._run(network_id=network_id)
+@command(network_cmds)
+class network_wait(_init_network, _network_wait):
+ """Wait for network to finish [PENDING, ACTIVE, DELETED]"""
+
+ arguments = dict(
+ timeout=IntArgument(
+ 'Wait limit in seconds (default: 60)', '--timeout', default=60)
+ )
+
+ @errors.generic.all
+ @errors.cyclades.connection
+ @errors.cyclades.network_id
+ def _run(self, network_id, current_status):
+ net = self.client.get_network_details(network_id)
+ if net['status'].lower() == current_status.lower():
+ self._wait(network_id, current_status, timeout=self['timeout'])
+ else:
+ self.error(
+ 'Network %s: Cannot wait for status %s, '
+ 'status is already %s' % (
+ network_id, current_status, net['status']))
+
+ def main(self, network_id, current_status='PENDING'):
+ super(self.__class__, self)._run()
+ self._run(network_id=network_id, current_status=current_status)
+
+
@command(subnet_cmds)
class subnet_list(_init_network, _optional_json, _name_filter, _id_filter):
"""List subnets
def move(self, path, **kwargs):
return self.request('move', path, **kwargs)
+
+
+class Waiter(object):
+
+ 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)
+
+ :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: (method(total steps)) returns a generator for
+ reporting progress or timeouts i.e., for a progress bar
+
+ :returns: (str) the new mode if successful, (bool) False if timed out
+ """
+ status, progress = get_status(self, item_id)
+
+ if wait_cb:
+ wait_gen = wait_cb(max_wait // delay)
+ wait_gen.next()
+
+ if status != current_status:
+ if wait_cb:
+ try:
+ wait_gen.next()
+ except Exception:
+ pass
+ return status
+ old_wait = total_wait = 0
+
+ while status == current_status and total_wait <= max_wait:
+ if wait_cb:
+ try:
+ for i in range(total_wait - old_wait):
+ wait_gen.next()
+ except Exception:
+ break
+ old_wait = total_wait
+ total_wait = progress or total_wait + 1
+ sleep(delay)
+ status, progress = get_status(self, item_id)
+
+ if total_wait < max_wait:
+ if wait_cb:
+ try:
+ for i in range(max_wait):
+ wait_gen.next()
+ except:
+ pass
+ return status if status != current_status else False
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
-from time import sleep
-
from kamaki.clients.cyclades.rest_api import CycladesRestClient
from kamaki.clients.network import NetworkClient
from kamaki.clients.utils import path4url
-from kamaki.clients import ClientError
+from kamaki.clients import ClientError, Waiter
-class CycladesClient(CycladesRestClient):
+class CycladesClient(CycladesRestClient, Waiter):
"""Synnefo Cyclades Compute API client"""
def create_server(
req = dict(remove=dict(attachment=nic))
self.networks_post(netid, 'action', json_data=req)
- 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)
-
- :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 progress bar is used to show progress
-
- :returns: (str) the new mode if successful, (bool) False if timed out
- """
- status, progress = get_status(self, item_id)
-
- if wait_cb:
- wait_gen = wait_cb(max_wait // delay)
- wait_gen.next()
-
- if status != current_status:
- if wait_cb:
- try:
- wait_gen.next()
- except Exception:
- pass
- return status
- old_wait = total_wait = 0
-
- while status == current_status and total_wait <= max_wait:
- if wait_cb:
- try:
- for i in range(total_wait - old_wait):
- wait_gen.next()
- except Exception:
- break
- old_wait = total_wait
- total_wait = progress or total_wait + 1
- sleep(delay)
- status, progress = get_status(self, item_id)
-
- if total_wait < max_wait:
- if wait_cb:
- try:
- for i in range(max_wait):
- wait_gen.next()
- except:
- pass
- return status if status != current_status else False
-
def wait_server(
self, server_id,
current_status='BUILD',
server_id, current_status, get_status, delay, max_wait, wait_cb)
-class CycladesNetworkClient(NetworkClient):
+class CycladesNetworkClient(NetworkClient, Waiter):
"""Cyclades Network API extentions"""
network_types = (
port['fixed_ips'] = fixed_ips
r = self.ports_post(json_data=dict(port=port), success=201)
return r.json['port']
+
+ def wait_network(
+ self, net_id,
+ current_status='PENDING', 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
+
+ :max_wait: (int) timeout in secconds
+
+ :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)