فهرست منبع

'plum up' is now the special magic

'start' and 'stop' are now analogous to their Docker namesakes.
Aanand Prasad 12 سال پیش
والد
کامیت
a4710fa9e1
6فایلهای تغییر یافته به همراه119 افزوده شده و 69 حذف شده
  1. 25 19
      plum/cli/main.py
  2. 7 2
      plum/container.py
  3. 20 4
      plum/project.py
  4. 7 17
      plum/service.py
  5. 43 9
      tests/project_test.py
  6. 17 18
      tests/service_test.py

+ 25 - 19
plum/cli/main.py

@@ -140,37 +140,43 @@ class TopLevelCommand(Command):
                 service.start_container(container, ports=None)
                 c.run()
 
-    def start(self, options):
+    def up(self, options):
         """
-        Start all services
+        Create and start containers
 
-        Usage: start [options]
+        Usage: up [options]
 
         Options:
             -d    Detached mode: Run containers in the background, print new container names
         """
-        if options['-d']:
-            self.project.start()
-            return
+        detached = options['-d']
 
-        running = []
-        unstarted = []
+        unstarted = self.project.create_containers()
 
-        for s in self.project.services:
-            if len(s.containers()) == 0:
-                unstarted.append((s, s.create_container()))
-            else:
-                running += s.containers(stopped=False)
-
-        log_printer = LogPrinter(running + [c for (s, c) in unstarted])
+        if not detached:
+            to_attach = self.project.containers() + [c for (s, c) in unstarted]
+            print "Attaching to", list_containers(to_attach)
+            log_printer = LogPrinter(to_attach, attach_params={'logs': True})
 
         for (s, c) in unstarted:
             s.start_container(c)
 
-        try:
-            log_printer.run()
-        finally:
-            self.project.stop()
+        if detached:
+            for (s, c) in unstarted:
+                print c.name
+        else:
+            try:
+                log_printer.run()
+            finally:
+                self.project.kill_and_remove(unstarted)
+
+    def start(self, options):
+        """
+        Start all services
+
+        Usage: start
+        """
+        self.project.start()
 
     def stop(self, options):
         """

+ 7 - 2
plum/container.py

@@ -83,13 +83,18 @@ class Container(object):
             out[k] = v
         return out
 
+    @property
+    def is_running(self):
+        self.inspect_if_not_inspected()
+        return self.dictionary['State']['Running']
+
     def start(self, **options):
         log.info("Starting %s..." % self.name)
         return self.client.start(self.id, **options)
 
-    def stop(self):
+    def stop(self, **options):
         log.info("Stopping %s..." % self.name)
-        return self.client.stop(self.id)
+        return self.client.stop(self.id, **options)
 
     def kill(self):
         log.info("Killing %s..." % self.name)

+ 20 - 4
plum/project.py

@@ -50,13 +50,29 @@ class Project(object):
             if service.name == name:
                 return service
 
-    def start(self):
+    def create_containers(self):
+        """
+        Returns a list of (service, container) tuples,
+        one for each service with no running containers.
+        """
+        containers = []
+        for service in self.services:
+            if len(service.containers()) == 0:
+                containers.append((service, service.create_container()))
+        return containers
+
+    def kill_and_remove(self, tuples):
+        for (service, container) in tuples:
+            container.kill()
+            container.remove()
+
+    def start(self, **options):
         for service in self.services:
-            service.start()
+            service.start(**options)
 
-    def stop(self):
+    def stop(self, **options):
         for service in self.services:
-            service.stop()
+            service.stop(**options)
 
     def containers(self, *args, **kwargs):
         l = []

+ 7 - 17
plum/service.py

@@ -38,19 +38,14 @@ class Service(object):
                 l.append(Container.from_ps(self.client, container))
         return l
 
-    def start(self):
-        if len(self.containers()) == 0:
-            return self.start_container()
+    def start(self, **options):
+        for c in self.containers(stopped=True):
+            if not c.is_running:
+                self.start_container(c, **options)
 
-    def stop(self):
-        self.scale(0)
-
-    def scale(self, num):
-        while len(self.containers()) < num:
-            self.start_container()
-
-        while len(self.containers()) > num:
-            self.stop_container()
+    def stop(self, **options):
+        for c in self.containers():
+            c.stop(**options)
 
     def create_container(self, one_off=False, **override_options):
         """
@@ -99,11 +94,6 @@ class Service(object):
         )
         return container
 
-    def stop_container(self):
-        container = self.containers()[-1]
-        container.kill()
-        container.remove()
-
     def next_container_name(self, one_off=False):
         bits = [self.project, self.name]
         if one_off:

+ 43 - 9
tests/project_test.py

@@ -42,18 +42,52 @@ class ProjectTest(DockerClientTestCase):
         project = Project('test', [web], self.client)
         self.assertEqual(project.get_service('web'), web)
 
+    def test_up(self):
+        web = self.create_service('web')
+        db = self.create_service('db')
+        project = Project('test', [web, db], self.client)
+
+        web.create_container()
+
+        self.assertEqual(len(web.containers()), 0)
+        self.assertEqual(len(db.containers()), 0)
+        self.assertEqual(len(web.containers(stopped=True)), 1)
+        self.assertEqual(len(db.containers(stopped=True)), 0)
+
+        unstarted = project.create_containers()
+        self.assertEqual(len(unstarted), 2)
+        self.assertEqual(unstarted[0][0], web)
+        self.assertEqual(unstarted[1][0], db)
+
+        self.assertEqual(len(web.containers()), 0)
+        self.assertEqual(len(db.containers()), 0)
+        self.assertEqual(len(web.containers(stopped=True)), 2)
+        self.assertEqual(len(db.containers(stopped=True)), 1)
+
+        project.kill_and_remove(unstarted)
+
+        self.assertEqual(len(web.containers()), 0)
+        self.assertEqual(len(db.containers()), 0)
+        self.assertEqual(len(web.containers(stopped=True)), 1)
+        self.assertEqual(len(db.containers(stopped=True)), 0)
+
     def test_start_stop(self):
-        project = Project('test', [
-            self.create_service('web'),
-            self.create_service('db'),
-        ], self.client)
+        web = self.create_service('web')
+        db = self.create_service('db')
+        project = Project('test', [web, db], self.client)
+
+        project.start()
+
+        self.assertEqual(len(web.containers()), 0)
+        self.assertEqual(len(db.containers()), 0)
 
+        web.create_container()
         project.start()
 
-        self.assertEqual(len(project.get_service('web').containers()), 1)
-        self.assertEqual(len(project.get_service('db').containers()), 1)
+        self.assertEqual(len(web.containers()), 1)
+        self.assertEqual(len(db.containers()), 0)
 
-        project.stop()
+        project.stop(timeout=1)
 
-        self.assertEqual(len(project.get_service('web').containers()), 0)
-        self.assertEqual(len(project.get_service('db').containers()), 0)
+        self.assertEqual(len(web.containers()), 0)
+        self.assertEqual(len(db.containers()), 0)

+ 17 - 18
tests/service_test.py

@@ -26,13 +26,14 @@ class ServiceTest(DockerClientTestCase):
         foo = self.create_service('foo')
         bar = self.create_service('bar')
 
-        foo.start()
+        foo.start_container()
 
         self.assertEqual(len(foo.containers()), 1)
         self.assertEqual(foo.containers()[0].name, '/default_foo_1')
         self.assertEqual(len(bar.containers()), 0)
 
-        bar.scale(2)
+        bar.start_container()
+        bar.start_container()
 
         self.assertEqual(len(foo.containers()), 1)
         self.assertEqual(len(bar.containers()), 2)
@@ -49,30 +50,28 @@ class ServiceTest(DockerClientTestCase):
 
     def test_project_is_added_to_container_name(self):
         service = self.create_service('web', project='myproject')
-        service.start()
+        service.start_container()
         self.assertEqual(service.containers()[0].name, '/myproject_web_1')
 
-    def test_up_scale_down(self):
+    def test_start_stop(self):
         service = self.create_service('scalingtest')
-        self.assertEqual(len(service.containers()), 0)
+        self.assertEqual(len(service.containers(stopped=True)), 0)
 
-        service.start()
-        self.assertEqual(len(service.containers()), 1)
+        service.create_container()
+        self.assertEqual(len(service.containers()), 0)
+        self.assertEqual(len(service.containers(stopped=True)), 1)
 
         service.start()
         self.assertEqual(len(service.containers()), 1)
+        self.assertEqual(len(service.containers(stopped=True)), 1)
 
-        service.scale(2)
-        self.assertEqual(len(service.containers()), 2)
-
-        service.scale(1)
-        self.assertEqual(len(service.containers()), 1)
-
-        service.stop()
+        service.stop(timeout=1)
         self.assertEqual(len(service.containers()), 0)
+        self.assertEqual(len(service.containers(stopped=True)), 1)
 
-        service.stop()
+        service.stop(timeout=1)
         self.assertEqual(len(service.containers()), 0)
+        self.assertEqual(len(service.containers(stopped=True)), 1)
 
     def test_create_container_with_one_off(self):
         db = self.create_service('db')
@@ -101,8 +100,8 @@ class ServiceTest(DockerClientTestCase):
         db.start_container()
         web.start_container()
         self.assertIn('default_db_1', web.containers()[0].links())
-        db.stop()
-        web.stop()
+        db.stop(timeout=1)
+        web.stop(timeout=1)
 
     def test_start_container_builds_images(self):
         service = Service(
@@ -110,7 +109,7 @@ class ServiceTest(DockerClientTestCase):
             client=self.client,
             build='tests/fixtures/simple-dockerfile',
         )
-        container = service.start()
+        container = service.start_container()
         container.wait()
         self.assertIn('success', container.logs())
         self.assertEqual(len(self.client.images(name='default_test')), 1)