out = [dict(o.to_json()) for o in wait(cephadm_module, c)]
expected = [
{
- 'placement': {'hosts': [{'hostname': 'test', 'name': '', 'network': ''}]},
+ 'placement': {'hosts': ['test']},
'service_id': 'name',
'service_name': 'mds.name',
'service_type': 'mds',
{
'placement': {
'count': 1,
- 'hosts': [{'hostname': 'test', 'name': '', 'network': ''}]
+ 'hosts': ["test"]
},
'spec': {
'rgw_realm': 'r',
import pytest
from ceph.deployment.service_spec import ServiceSpec, NFSServiceSpec, RGWSpec, \
- IscsiServiceSpec, AlertManagerSpec
+ IscsiServiceSpec, AlertManagerSpec, HostPlacementSpec
from orchestrator import DaemonDescription, OrchestratorError
if 'spec' in j_c:
spec = j_c.pop('spec')
j_c.update(spec)
+ if 'placement' in j_c:
+ if 'hosts' in j_c['placement']:
+ j_c['placement']['hosts'] = [
+ {
+ 'hostname': HostPlacementSpec.parse(h).hostname,
+ 'network': HostPlacementSpec.parse(h).network,
+ 'name': HostPlacementSpec.parse(h).name
+ }
+ for h in j_c['placement']['hosts']
+ ]
j_c.pop('objectstore', None)
j_c.pop('filter_logic', None)
return j_c
@classmethod
@handle_type_error
def from_json(cls, data):
+ if isinstance(data, str):
+ return cls.parse(data)
return cls(**data)
- def to_json(self):
- return {
- 'hostname': self.hostname,
- 'network': self.network,
- 'name': self.name
- }
+ def to_json(self) -> str:
+ return str(self)
@classmethod
def parse(cls, host, require_network=True):
return len(self.filter_matching_hostspecs(hostspecs))
def pretty_str(self):
+ """
+ >>> #doctest: +SKIP
+ ... ps = PlacementSpec(...) # For all placement specs:
+ ... PlacementSpec.from_string(ps.pretty_str()) == ps
+ """
kv = []
+ if self.hosts:
+ kv.append(';'.join([str(h) for h in self.hosts]))
if self.count:
kv.append('count:%d' % self.count)
if self.label:
kv.append('label:%s' % self.label)
- if self.hosts:
- kv.append('%s' % ','.join([str(h) for h in self.hosts]))
if self.host_pattern:
kv.append(self.host_pattern)
- return ' '.join(kv)
+ return ';'.join(kv)
def __repr__(self):
kv = []
if hosts:
c['hosts'] = []
for host in hosts:
- c['hosts'].append(HostPlacementSpec.parse(host) if
- isinstance(host, str) else
- HostPlacementSpec.from_json(host))
+ c['hosts'].append(HostPlacementSpec.from_json(host))
_cls = cls(**c)
_cls.validate()
return _cls
assert ret == expected
assert str(ret) == test_input
+ ps = PlacementSpec.from_string(test_input)
+ assert ps.pretty_str() == test_input
+ assert ps == PlacementSpec.from_string(ps.pretty_str())
+
+ # Testing the old verbose way of generating json. Don't remove:
+ assert ret == HostPlacementSpec.from_json({
+ 'hostname': ret.hostname,
+ 'network': ret.network,
+ 'name': ret.name
+ })
+
+ assert ret == HostPlacementSpec.from_json(ret.to_json())
+
+
+
@pytest.mark.parametrize(
"test_input,expected",
def test_parse_placement_specs(test_input, expected):
ret = PlacementSpec.from_string(test_input)
assert str(ret) == expected
+ assert PlacementSpec.from_string(ret.pretty_str()) == ret, f'"{ret.pretty_str()}" != "{test_input}"'
@pytest.mark.parametrize(
"test_input",
service_name: rgw.default-rgw-realm.eu-central-1.1
placement:
hosts:
- - hostname: ceph-001
- name: ''
- network: ''
+ - ceph-001
spec:
rgw_realm: default-rgw-realm
rgw_zone: eu-central-1