Преглед на файлове

Check that names are compatible with the eventlistener protocol. Fixes #181

Mike Naberezny преди 12 години
родител
ревизия
3335519990
променени са 5 файла, в които са добавени 66 реда и са изтрити 5 реда
  1. 3 0
      CHANGES.txt
  2. 8 0
      supervisor/datatypes.py
  3. 8 5
      supervisor/options.py
  4. 12 0
      supervisor/tests/test_datatypes.py
  5. 35 0
      supervisor/tests/test_options.py

+ 3 - 0
CHANGES.txt

@@ -1,6 +1,9 @@
 3.0b3-dev (Next Release)
 ------------------------
 
+- Parsing the config file will now fail with an error message if a process
+  or group name contains characters that are not compatible with the
+  eventlistener protocol.
 
 3.0b2 (2013-05-28)
 ------------------

+ 8 - 0
supervisor/datatypes.py

@@ -21,6 +21,14 @@ def set_here(v):
     global here
     here = v
 
+def process_or_group_name(name):
+    """Ensures that a process or group name is not created with
+       characters that break the eventlistener protocol"""
+    s = str(name).strip()
+    if ' ' in s or ':' in s:
+        raise ValueError("Invalid name: " + repr(name))
+    return s
+
 def integer(value):
     try:
         return int(value)

+ 8 - 5
supervisor/options.py

@@ -23,6 +23,7 @@ from fcntl import F_SETFL, F_GETFL
 
 from supervisor.medusa import asyncore_25 as asyncore
 
+from supervisor.datatypes import process_or_group_name
 from supervisor.datatypes import boolean
 from supervisor.datatypes import integer
 from supervisor.datatypes import name_to_uid
@@ -606,7 +607,7 @@ class ServerOptions(Options):
         for section in all_sections:
             if not section.startswith('group:'):
                 continue
-            group_name = section.split(':', 1)[1]
+            group_name = process_or_group_name(section.split(':', 1)[1])
             programs = list_of_strings(get(section, 'programs', None))
             priority = integer(get(section, 'priority', 999))
             group_processes = []
@@ -629,7 +630,7 @@ class ServerOptions(Options):
             if ( (not section.startswith('program:') )
                  or section in homogeneous_exclude ):
                 continue
-            program_name = section.split(':', 1)[1]
+            program_name = process_or_group_name(section.split(':', 1)[1])
             priority = integer(get(section, 'priority', 999))
             processes=self.processes_from_section(parser, section, program_name,
                                                   ProcessConfig)
@@ -681,7 +682,7 @@ class ServerOptions(Options):
             if ( (not section.startswith('fcgi-program:') )
                  or section in homogeneous_exclude ):
                 continue
-            program_name = section.split(':', 1)[1]
+            program_name = process_or_group_name(section.split(':', 1)[1])
             priority = integer(get(section, 'priority', 999))
 
             # find proc_uid from "user" option
@@ -774,7 +775,7 @@ class ServerOptions(Options):
             klass = ProcessConfig
         programs = []
         get = parser.saneget
-        program_name = section.split(':', 1)[1]
+        program_name = process_or_group_name(section.split(':', 1)[1])
         priority = integer(get(section, 'priority', 999))
         autostart = boolean(get(section, 'autostart', 'true'))
         autorestart = auto_restart(get(section, 'autorestart', 'unexpected'))
@@ -788,7 +789,6 @@ class ServerOptions(Options):
         redirect_stderr = boolean(get(section, 'redirect_stderr','false'))
         numprocs = integer(get(section, 'numprocs', 1))
         numprocs_start = integer(get(section, 'numprocs_start', 0))
-        process_name = get(section, 'process_name', '%(program_name)s')
         environment_str = get(section, 'environment', '')
         stdout_cmaxbytes = byte_size(get(section,'stdout_capture_maxbytes','0'))
         stdout_events = boolean(get(section, 'stdout_events_enabled','false'))
@@ -815,6 +815,9 @@ class ServerOptions(Options):
             raise ValueError, (
                 'program section %s does not specify a command' % section)
 
+        process_name = process_or_group_name(
+            get(section, 'process_name', '%(program_name)s'))
+
         if numprocs > 1:
             if process_name.find('%(process_num)') == -1:
                 # process_name needs to include process_num when we

+ 12 - 0
supervisor/tests/test_datatypes.py

@@ -143,6 +143,18 @@ class DatatypesTest(unittest.TestCase):
         self.assertRaises(ValueError,
                           datatypes.dict_of_key_value_pairs, kvp)
 
+    def test_process_or_group_name_strips_surrounding_whitespace(self):
+        name = " foo\t"
+        self.assertEqual("foo", datatypes.process_or_group_name(name))
+
+    def test_process_or_group_name_disallows_inner_spaces(self):
+        name = "foo bar"
+        self.assertRaises(ValueError, datatypes.process_or_group_name, name)
+
+    def test_process_or_group_name_disallows_colons(self):
+        name = "foo:bar"
+        self.assertRaises(ValueError, datatypes.process_or_group_name, name)
+
     def test_logfile_name_returns_none_for_none_values(self):
         for thing in datatypes.LOGFILE_NONES:
             actual = datatypes.logfile_name(thing)

+ 35 - 0
supervisor/tests/test_options.py

@@ -758,6 +758,28 @@ class ServerOptionsTests(unittest.TestCase):
         expected = "/bin/foo --path='%s'" % os.environ['PATH']
         self.assertEqual(pconfigs[0].command, expected)
 
+    def test_processes_from_section_bad_program_name_spaces(self):
+        instance = self._makeOne()
+        text = lstrip("""\
+        [program:spaces are bad]
+        """)
+        from supervisor.options import UnhosedConfigParser
+        config = UnhosedConfigParser()
+        config.read_string(text)
+        self.assertRaises(ValueError, instance.processes_from_section,
+                          config, 'program:spaces are bad', None)
+
+    def test_processes_from_section_bad_program_name_colons(self):
+        instance = self._makeOne()
+        text = lstrip("""\
+        [program:colons:are:bad]
+        """)
+        from supervisor.options import UnhosedConfigParser
+        config = UnhosedConfigParser()
+        config.read_string(text)
+        self.assertRaises(ValueError, instance.processes_from_section,
+                          config, 'program:colons:are:bad', None)
+
     def test_processes_from_section_no_procnum_in_processname(self):
         instance = self._makeOne()
         text = lstrip("""\
@@ -809,6 +831,19 @@ class ServerOptionsTests(unittest.TestCase):
         self.assertRaises(ValueError, instance.processes_from_section,
                           config, 'program:foo', None)
 
+    def test_processes_from_section_bad_chars_in_process_name(self):
+        instance = self._makeOne()
+        text = lstrip("""\
+        [program:foo]
+        command = /bin/cat
+        process_name = colons:are:bad
+        """)
+        from supervisor.options import UnhosedConfigParser
+        config = UnhosedConfigParser()
+        config.read_string(text)
+        self.assertRaises(ValueError, instance.processes_from_section,
+                          config, 'program:foo', None)
+
     def test_processes_from_section_stopasgroup_implies_killasgroup(self):
         instance = self._makeOne()
         text = lstrip("""\