Repository: conjure-up/conjure-up

Issue:
Conjure-up uses double the deployed hardware when deploying openstack-base and kubernetes-core
cs:kubernetes-core uses 2 physical machines to deploy the services for kubernetes. Conjure-up bootstraps one node for juju, then 4 more for the services. Not sure why this is the case

Discussion:
mikemccracken: @canonical-cgregan this PR should fix the issues you noticed. Thanks for the bug report!

Patch:
diff --git a/conjureup/controllers/deploy/gui.py b/conjureup/controllers/deploy/gui.py
index 4d65132..66958e6 100644
--- a/conjureup/controllers/deploy/gui.py
+++ b/conjureup/controllers/deploy/gui.py
@@ -24,6 +24,16 @@ class DeployController:
         self.assignments = defaultdict(list)
         self.deployed_juju_machines = {}
         self.maas_machine_map = {}
+        self.sync_with_bundle()
+
+    def sync_with_bundle(self):
+        # If no machines are specified, add a machine for each app:
+        bundle = app.metadata_controller.bundle
+
+        if len(bundle.machines) == 0:
+            self.generate_juju_machines()
+        else:
+            self.sync_assignments()
 
     def _handle_exception(self, tag, exc):
         track_exception(exc.args[0])
@@ -86,11 +96,6 @@ class DeployController:
         app.ui.set_body(cv)
 
     def do_architecture(self, application, sender):
-        # If no machines are specified, add a machine for each app:
-        bundle = app.metadata_controller.bundle
-        if len(bundle.machines) == 0:
-            self.generate_juju_machines()
-
         av = AppArchitectureView(application,
                                  self)
         app.ui.set_header(av.header)
@@ -99,11 +104,17 @@ class DeployController:
     def generate_juju_machines(self):
         """ Add a separate juju machine for each app.
         Intended for bundles with no machines defined.
+
+        NOTE: assumes there are no placement specs in the bundle.
         """
         bundle = app.metadata_controller.bundle
         midx = 0
         for bundle_application in sorted(bundle.services,
                                          key=attrgetter('service_name')):
+            if bundle_application.placement_spec:
+                app.log.warning("Ignoring placement spec because no machines "
+                                "were set in the bundle: {}".format(
+                                    bundle.application.placement_spec))
             for n in range(bundle_application.num_units):
                 bundle.add_machine(dict(series=bundle.series),
                                    str(midx))
@@ -111,6 +122,18 @@ class DeployController:
                                     AssignmentType.DEFAULT)
                 midx += 1
 
+    def sync_assignments(self):
+        bundle = app.metadata_controller.bundle
+        for bundle_application in bundle.services:
+            deployargs = bundle_application.as_deployargs()
+            spec_list = deployargs.get('placement', [])
+            for spec in spec_list:
+                juju_machine_id = spec['directive']
+                atype = {"lxd": AssignmentType.LXD,
+                         "kvm": AssignmentType.KVM,
+                         "#": AssignmentType.BareMetal}[spec['scope']]
+                self.add_assignment(bundle_application, juju_machine_id, atype)
+
     def add_assignment(self, application, juju_machine_id, atype):
         self.assignments[juju_machine_id].append((application, atype))
 
diff --git a/conjureup/log.py b/conjureup/log.py
index 3e3b1eb..1f3036b 100644
--- a/conjureup/log.py
+++ b/conjureup/log.py
@@ -22,6 +22,9 @@ class _log:
     def exception(self, msg):
         self.logger.exception("{}: {}".format(self.app, msg))
 
+    def warning(self, msg):
+        self.logger.warning("{}: {}".format(self.app, msg))
+
 
 def setup_logging(app, logfile, debug=False):
     try:


Test patch:
diff --git a/test/test_controllers_deploy_gui.py b/test/test_controllers_deploy_gui.py
index 5b68a94..1b72ad3 100644
--- a/test/test_controllers_deploy_gui.py
+++ b/test/test_controllers_deploy_gui.py
@@ -14,7 +14,8 @@ from conjureup.controllers.deploy.gui import DeployController
 class DeployGUIRenderTestCase(unittest.TestCase):
 
     def setUp(self):
-        self.controller = DeployController()
+        with patch.object(DeployController, 'sync_with_bundle'):
+            self.controller = DeployController()
 
         self.utils_patcher = patch(
             'conjureup.controllers.deploy.gui.utils')
@@ -73,7 +74,8 @@ class DeployGUIRenderTestCase(unittest.TestCase):
 class DeployGUIFinishTestCase(unittest.TestCase):
 
     def setUp(self):
-        self.controller = DeployController()
+        with patch.object(DeployController, 'sync_with_bundle'):
+            self.controller = DeployController()
 
         self.controllers_patcher = patch(
             'conjureup.controllers.deploy.gui.controllers')