Przeglądaj źródła

- Ignore IOError when attempting to close log file.

- Remove tailf in favor of tail -f.

- Handle status error.

- Add shutdown and reload verbs.
Chris McDonough 19 lat temu
rodzic
commit
0f9e7ed8f5
3 zmienionych plików z 92 dodań i 13 usunięć
  1. 4 1
      src/supervisor/options.py
  2. 53 10
      src/supervisor/supervisorctl.py
  3. 35 2
      src/supervisor/tests.py

+ 4 - 1
src/supervisor/options.py

@@ -55,7 +55,10 @@ class FileHandler(logging.StreamHandler):
         self.mode = mode
 
     def close(self):
-        self.stream.close()
+        try:
+            self.stream.close()
+        except IOError:
+            pass
 
     def reopen(self):
         self.close()

+ 53 - 10
src/supervisor/supervisorctl.py

@@ -119,7 +119,7 @@ class Controller(cmd.Cmd):
     def help_EOF(self):
         self._output("To quit, type ^D or use the quit command.")
 
-    def do_tailf(self, arg):
+    def _tailf(self, arg):
         # cant really unit test this, sorry.
         if not self._upcheck():
             return
@@ -142,12 +142,9 @@ class Controller(cmd.Cmd):
             handler.get(url)
             asyncore.loop()
         except KeyboardInterrupt:
+            self._output('')
             return
 
-    def help_tailf(self):
-        self._output("tailf <processname>\tContinuous tail of named process "
-                     "stdout, Ctrl-C to exit.")
-
     def do_tail(self, arg):
         if not self._upcheck():
             return
@@ -168,7 +165,7 @@ class Controller(cmd.Cmd):
             if args[0].startswith('-'):
                 what = args[0][1:]
                 if what == 'f':
-                    return self.do_tailf(args[1])
+                    return self._tailf(args[1])
                 try:
                     what = int(what)
                 except:
@@ -192,8 +189,7 @@ class Controller(cmd.Cmd):
             if e.faultCode == rpc.Faults.FAILED:
                 self._output("Error: Log file doesn't yet exist on server")
         else:
-            self.stdout.write(output)
-            self.stdout.flush()
+            self._output(output)
 
     def help_tail(self):
         self._output(
@@ -227,7 +223,7 @@ class Controller(cmd.Cmd):
         elif state == supervisord.ProcessStates.ERROR:
             desc = info['spawnerr']
             if not desc:
-                desc = 'unknown error (try "tailf %s")' % info['name']
+                desc = 'unknown error (try "tail %s")' % info['name']
 
         elif state in (supervisord.ProcessStates.STOPPED,
                        supervisord.ProcessStates.KILLED,
@@ -256,7 +252,14 @@ class Controller(cmd.Cmd):
 
         if processnames:
             for processname in processnames:
-                info = supervisor.getProcessInfo(processname)
+                try:
+                    info = supervisor.getProcessInfo(processname)
+                except xmlrpclib.Fault, e:
+                    if e.faultCode == rpc.Faults.BAD_NAME:
+                        self._output('No such process %s' % processname)
+                    else:
+                        raise
+                    continue
                 newinfo = self._interpretProcessInfo(info)
                 self._output(template % newinfo)
         else:
@@ -420,6 +423,46 @@ class Controller(cmd.Cmd):
                      "started in")
         self._output("  priority order (see config file)")
 
+    def do_shutdown(self, arg):
+        if self.options.interactive:
+            yesno = raw_input('Really shut the supervisord process down y/N? ')
+            really = yesno.lower().startswith('y')
+        else:
+            really = 1
+        if really:
+            supervisor = self._get_supervisor()
+            try:
+                supervisor.shutdown()
+            except xmlrpclib.Fault, e:
+                if e.faultCode == rpc.Faults.SHUTDOWN_STATE:
+                    self._output('ERROR: already shutting down')
+            else:
+                self._output('Shutting down')
+
+    def help_shutdown(self):
+        self._output("shutdown \t\tShut the remote supervisord down.")
+
+    def do_reload(self, arg):
+        if self.options.interactive:
+            yesno = raw_input('Really restart the remote supervisord process '
+                              'y/N? ')
+            really = yesno.lower().startswith('y')
+        else:
+            really = 1
+        if really:
+            supervisor = self._get_supervisor()
+            try:
+                supervisor.restart()
+            except xmlrpclib.Fault, e:
+                if e.faultCode == rpc.Faults.SHUTDOWN_STATE:
+                    self._output('ERROR: already shutting down')
+            else:
+                self._output('Restarting supervisord')
+
+    def help_reload(self):
+        self._output("reload \t\tRestart the remote supervisord.")
+
+
 def main(args=None, options=None):
     if options is None:
         options = ClientOptions()

+ 35 - 2
src/supervisor/tests.py

@@ -1264,7 +1264,7 @@ class ControllerTests(unittest.TestCase):
         result = controller.do_tail('foo')
         self.assertEqual(result, None)
         lines = controller.stdout.getvalue().split('\n')
-        self.assertEqual(len(lines), 11)
+        self.assertEqual(len(lines), 12)
         self.assertEqual(lines[0], 'output line')
 
     def test_tail_twoargs(self):
@@ -1274,7 +1274,7 @@ class ControllerTests(unittest.TestCase):
         result = controller.do_tail('-10 foo')
         self.assertEqual(result, None)
         lines = controller.stdout.getvalue().split('\n')
-        self.assertEqual(len(lines), 2)
+        self.assertEqual(len(lines), 3)
         self.assertEqual(lines[0], 'tput line')
 
     def test_status_oneprocess(self):
@@ -1415,6 +1415,39 @@ baz            STOPPED    Jun 26 11:42 PM (OK)
 
         self.assertEqual(controller.stdout.getvalue(),
          'foo: stopped\nfoo2: stopped\nfailed: ERROR (no such process)\n')
+
+    def test_restart_fail(self):
+        options = DummyClientOptions()
+        controller = self._makeOne(options)
+        controller.stdout = StringIO()
+        result = controller.do_restart('')
+        self.assertEqual(result, None)
+
+        self.assertEqual(controller.stdout.getvalue().split('\n')[0],
+         'Error: restart requires a process name')
+
+    def test_restart_one(self):
+        options = DummyClientOptions()
+        controller = self._makeOne(options)
+        controller.stdout = StringIO()
+        result = controller.do_restart('foo')
+        self.assertEqual(result, None)
+
+        self.assertEqual(controller.stdout.getvalue(),
+                         'foo: stopped\n\nfoo: OK\n')
+
+    def test_restart_all(self):
+        options = DummyClientOptions()
+        controller = self._makeOne(options)
+        controller.stdout = StringIO()
+        result = controller.do_restart('all')
+        self.assertEqual(result, None)
+
+        self.assertEqual(controller.stdout.getvalue(),
+                         ('foo: stopped\nfoo2: stopped\n'
+                          'failed: ERROR (no such process)\n\n'
+                          'foo: OK\nfoo2: OK\nfailed: ERROR (spawn error)\n'))
+        
         
 
 class TailFProducerTests(unittest.TestCase):