From ddf56da2e4092bc0b37ec04c028cf11d4a4a8e86 Mon Sep 17 00:00:00 2001
From: dobli <dobler.alex@gmail.com>
Date: Wed, 24 Apr 2019 12:19:41 +0200
Subject: [PATCH] added basic building move command

---
 building_manager.py | 77 +++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 71 insertions(+), 6 deletions(-)

diff --git a/building_manager.py b/building_manager.py
index 4dd9bf9..41b4505 100755
--- a/building_manager.py
+++ b/building_manager.py
@@ -1266,6 +1266,29 @@ def get_service_list(manager=None):
     return [s.name for s in client.services.list()]
 
 
+def remove_label_from_nodes(label, value, manager=None):
+    """Removes label with matching value from all nodes
+
+    :label: Label you want to remove
+    :value: The value to match before removing
+    :manager: Docker machine to use for command, otherwise local
+    """
+    client = get_docker_client(manager)
+
+    nodes = client.nodes.list()
+    matching_nodes = [n for n in nodes
+                      if label in n.attrs['Spec']['Labels']
+                      and n.attrs['Spec']['Labels'][label] == value]
+    print(f'Matches {matching_nodes}')
+    for m in matching_nodes:
+        spec = m.attrs['Spec']
+        spec['Labels'].pop(label)
+        m.update(spec)
+        logging.info(f'Remove label {label} with value {value} from {m}')
+
+    client.close()
+
+
 def assign_label_to_node(nodeid, label, value, manager=None):
     """Assigns a label to a node (e.g. building)
 
@@ -1330,7 +1353,7 @@ def get_docker_client(manager=None):
     return client
 
 
-def restore_building_backup(manager, building):
+def restore_building_backup(manager, building, new_machine=None):
     client = get_docker_client(manager)
     # get backup services of the building
     services = client.services.list(filters={'label': f'backup={building}'})
@@ -1343,13 +1366,24 @@ def restore_building_backup(manager, building):
     print("Wait for services to shutdown...")
     sleep(10)
 
-    # execute restore command in backup service
-    run_command_in_service('backup', 'restore', manager)
+    # When a new machine is used, (un-)assign labels
+    if new_machine:
+        remove_label_from_nodes('building', building, manager)
+        assign_label_to_node(new_machine, 'building', building, manager)
+        print("Wait for services to start on new machine")
+        sleep(10)
+        run_command_in_service('backup', 'restore', new_machine)
+    else:
+        # execute restore command in backup service
+        run_command_in_service('backup', 'restore', manager)
 
     # reload and scale up services again
     for s in services:
         s.reload()
         s.scale(1)
+
+    # close client
+    client.close()
 # >>>
 
 
@@ -1807,15 +1841,16 @@ def backup_menu(args):
     """
     # Ask for action
     choice = qust.select("What do you want to do?", choices=[
-        'Execute backup', 'Restore backup', 'Exit'],
+        'Execute backup', 'Restore backup', 'Move building', 'Exit'],
         style=st).ask()
     if "Execute" in choice:
         execute_backup_menu()
     elif "Restore" in choice:
         restore_backup_menu()
         print("Restore")
-    else:
-        print(get_current_building_constraints())
+    elif "Move" in choice:
+        restore_new_building_menu()
+        print("Move")
 
 
 def execute_backup_menu():
@@ -1851,6 +1886,25 @@ def restore_backup_menu():
         print("Restore canceled")
 
 
+def restore_new_building_menu():
+    """Submenu for backup execution on a new building
+    """
+    machine = docker_client_prompt(" to execute restores with.")
+    current_building = compose_building_prompt(" to move")
+    new_machine = docker_client_prompt(" to move building to")
+    confirm = qust.confirm(
+        f'Recreate {current_building} from last backup'
+        f' on machine {new_machine}',
+        default=False,
+        style=st).ask()
+
+    if confirm:
+        restore_building_backup(machine, current_building, new_machine)
+        print("Restore completed")
+    else:
+        print("Restore canceled")
+
+
 # *** Menu Helper Functions ***
 def generate_cb_choices(list, checked=False):
     """Generates checkbox entries for lists of strings
@@ -1884,6 +1938,17 @@ def docker_client_prompt(message_details=''):
     machine = qust.select(f'Choose manager machine{message_details}',
                           choices=get_machine_list(), style=st).ask()
     return machine
+
+
+def compose_building_prompt(message_details=''):
+    """Show list of building contraints used in compose
+
+    :returns: Docker client instance
+    """
+    building = qust.select(f'Choose building{message_details}:',
+                           choices=get_current_building_constraints(),
+                           style=st).ask()
+    return building
 # >>>
 
 
-- 
GitLab