]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
python-common: Add `host_pattern` to `PlacementSpec.from_string()`
authorSebastian Wagner <sebastian.wagner@suse.com>
Mon, 9 Mar 2020 16:08:57 +0000 (17:08 +0100)
committerSebastian Wagner <sebastian.wagner@suse.com>
Tue, 10 Mar 2020 12:28:22 +0000 (13:28 +0100)
Signed-off-by: Sebastian Wagner <sebastian.wagner@suse.com>
src/python-common/ceph/deployment/service_spec.py
src/python-common/ceph/tests/test_service_spec.py
src/python-common/tox.ini

index 481bad7254cb80eb343e70925c69630299379971..35d01facc4ba25ca54beefc2abd5ade12934488c 100644 (file)
@@ -159,7 +159,18 @@ class PlacementSpec(object):
         return ' '.join(kv)
 
     def __repr__(self):
-        return "PlacementSpec(%s)" % self.pretty_str()
+        kv = []
+        if self.count:
+            kv.append('count=%d' % self.count)
+        if self.label:
+            kv.append('label=%s' % repr(self.label))
+        if self.hosts:
+            kv.append('hosts={!r}'.format(self.hosts))
+        if self.all_hosts:
+            kv.append('all_hosts=True')
+        if self.host_pattern:
+            kv.append('host_pattern={!r}'.format(self.host_pattern))
+        return "PlacementSpec(%s)" % ', '.join(kv)
 
     @classmethod
     def from_json(cls, data):
@@ -196,18 +207,29 @@ class PlacementSpec(object):
         A single integer is parsed as a count:
         >>> PlacementSpec.from_string('3')
         PlacementSpec(count=3)
+
         A list of names is parsed as host specifications:
         >>> PlacementSpec.from_string('host1 host2')
-        PlacementSpec(label=[HostSpec(hostname='host1', network='', name=''), HostSpec(hostname='host2', network='', name='')])
+        PlacementSpec(hosts=[HostPlacementSpec(hostname='host1', network='', name=''), HostPlacemen\
+tSpec(hostname='host2', network='', name='')])
+
         You can also prefix the hosts with a count as follows:
         >>> PlacementSpec.from_string('2 host1 host2')
-        PlacementSpec(label=[HostSpec(hostname='host1', network='', name=''), HostSpec(hostname='host2', network='', name='')], count=2)
+        PlacementSpec(count=2, hosts=[HostPlacementSpec(hostname='host1', network='', name=''), Hos\
+tPlacementSpec(hostname='host2', network='', name='')])
+
         You can spefify labels using `label:<label>`
         >>> PlacementSpec.from_string('label:mon')
-        PlacementSpec(label='label:mon')
+        PlacementSpec(label='mon')
+
         Labels als support a count:
         >>> PlacementSpec.from_string('3 label:mon')
-        PlacementSpec(label='label:mon', count=3)
+        PlacementSpec(count=3, label='mon')
+
+        fnmatch is also supported:
+        >>> PlacementSpec.from_string('host_pattern:data[1-3]')
+        PlacementSpec(host_pattern='data[1-3]')
+
         >>> PlacementSpec.from_string(None)
         PlacementSpec()
         """
@@ -253,15 +275,21 @@ class PlacementSpec(object):
             all_hosts = True
             strings.remove('all:true')
 
-        hosts = [x for x in strings if x != '*' and 'label:' not in x]
+        hosts = [x for x in strings
+                 if x != '*' and 'label:' not in x and not x.startswith('host_pattern:')]
         labels = [x[6:] for x in strings if 'label:' in x]
         if len(labels) > 1:
             raise ServiceSpecValidationError('more than one label provided: {}'.format(labels))
+        host_patterns = [x[13:] for x in strings if x.startswith('host_pattern:')]
+        if len(host_patterns) > 1:
+            raise ServiceSpecValidationError('more than one host_patterns provided: {}'.format(
+                host_patterns))
 
         ps = PlacementSpec(count=count,
                            hosts=hosts,
                            label=labels[0] if labels else None,
-                           all_hosts=all_hosts)
+                           all_hosts=all_hosts,
+                           host_pattern=host_patterns[0] if host_patterns else None)
         ps.validate()
         return ps
 
index be33fd2da7efd8e75698df333e1be05ca61c126b..19553e9d6aacc19b8bf29a5c65f7e2310a998f28 100644 (file)
@@ -27,15 +27,15 @@ def test_parse_host_placement_specs(test_input, expected, require_network):
     "test_input,expected",
     [
         ('', "PlacementSpec()"),
-        ("count:2", "PlacementSpec(count:2)"),
-        ("3", "PlacementSpec(count:3)"),
-        ("host1 host2", "PlacementSpec(host1,host2)"),
-        ("host1=a host2=b", "PlacementSpec(host1=a,host2=b)"),
-        ("host1:1.2.3.4=a host2:1.2.3.5=b", "PlacementSpec(host1:1.2.3.4=a,host2:1.2.3.5=b)"),
-        ('2 host1 host2', "PlacementSpec(count:2 host1,host2)"),
-        ('label:foo', "PlacementSpec(label:foo)"),
-        ('3 label:foo', "PlacementSpec(count:3 label:foo)"),
-        ('*', 'PlacementSpec(all:true)'),
+        ("count:2", "PlacementSpec(count=2)"),
+        ("3", "PlacementSpec(count=3)"),
+        ("host1 host2", "PlacementSpec(hosts=[HostPlacementSpec(hostname='host1', network='', name=''), HostPlacementSpec(hostname='host2', network='', name='')])"),
+        ("host1=a host2=b", "PlacementSpec(hosts=[HostPlacementSpec(hostname='host1', network='', name='a'), HostPlacementSpec(hostname='host2', network='', name='b')])"),
+        ("host1:1.2.3.4=a host2:1.2.3.5=b", "PlacementSpec(hosts=[HostPlacementSpec(hostname='host1', network='1.2.3.4', name='a'), HostPlacementSpec(hostname='host2', network='1.2.3.5', name='b')])"),
+        ('2 host1 host2', "PlacementSpec(count=2, hosts=[HostPlacementSpec(hostname='host1', network='', name=''), HostPlacementSpec(hostname='host2', network='', name='')])"),
+        ('label:foo', "PlacementSpec(label='foo')"),
+        ('3 label:foo', "PlacementSpec(count=3, label='foo')"),
+        ('*', 'PlacementSpec(all_hosts=True)'),
     ])
 def test_parse_placement_specs(test_input, expected):
     ret = PlacementSpec.from_string(test_input)
index 47b280f336993eb84a5ce092cd360f9eda2e7eed..da7037b2d816958cc363652ef552ccc665fcfdeb 100644 (file)
@@ -5,7 +5,9 @@ skip_missing_interpreters = true
 [testenv:py3]
 deps=
     -rrequirements.txt
-commands=pytest --mypy --mypy-ignore-missing-imports {posargs}
+commands=
+    pytest --doctest-modules ceph/deployment/service_spec.py
+    pytest --mypy --mypy-ignore-missing-imports {posargs}
 
 [tool:pytest]
 norecursedirs = .* _* virtualenv