Allow to move routers during upgrade

This patch adds functionality that allows to move legacy routers
from one agent to another during upgrade.
Also it adds waiter to check for availability of agents.

Change-Id: I6df53d99348a8a635f5712f5144be331d4188a4c
diff --git a/_modules/neutronv2/agents.py b/_modules/neutronv2/agents.py
index 15703d2..b8f35eb 100644
--- a/_modules/neutronv2/agents.py
+++ b/_modules/neutronv2/agents.py
@@ -1,7 +1,14 @@
+import logging
+import time
+from salt.exceptions import CommandExecutionError
+
 from neutronv2.common import send
 from neutronv2.arg_converter import get_by_name_or_uuid_multiple
+from neutronv2.lists import agent_list
 
 
+log = logging.getLogger(__name__)
+
 try:
     from urllib.parse import urlencode
 except ImportError:
@@ -87,3 +94,40 @@
 def dhcp_agent_by_network_list(network_id, **kwargs):
     url = '/networks/{}/dhcp-agents'.format(network_id)
     return url, {}
+
+
+def wait_for_network_services(cloud_name, host_id=None,
+                              admin_up_only=True,
+                              retries=18, timeout=10):
+    """
+    Ensure services on specified host are alive, othervise fail with exception.
+
+    :param host_id:              host name to wait or None (to check for all hosts)
+    :param cloud_name:           name of cloud from os client config
+    :param admin_up_only:        do not check for admin disabled agents
+    :param timeout:              number of seconds to wait before retries
+    :param retries:              number of retries
+    """
+
+    kwargs = {'alive': False}
+
+    if admin_up_only:
+      kwargs['admin_state_up'] = True
+
+    if host_id is not None:
+      kwargs['host'] = host_id
+
+    res = None
+    for i in range(retries):
+        try:
+          agents = agent_list(cloud_name=cloud_name, **kwargs)['agents']
+          res = len(agents)
+        except Exception as e:
+          msg = "Failed to get agent list {0}".format(e)
+          log.trace(msg)
+          raise CommandExecutionError(e)
+
+        if res == 0:
+            return "All services are up"
+        time.sleep(timeout)
+    raise CommandExecutionError("Some agents are still down {}".format(agents))