From 880c0b759132e884f71bf6890eaffcaa7cfffbbf Mon Sep 17 00:00:00 2001 From: Kiefer Chang Date: Fri, 6 Mar 2020 19:41:48 +0800 Subject: [PATCH] mgr/orch: fix ServiceSpec deserialization error cephadm fails to load Service spec data when deserializing HostPlacementSpec resource. Fix the issue by loading it properly. Renaming the call from_dict to from_json for consistency. This change also makes `spec` filed visible in JSON output of ServiceSpec list. Fixes: https://tracker.ceph.com/issues/44491 Fixes: https://tracker.ceph.com/issues/44392 Signed-off-by: Kiefer Chang --- src/pybind/mgr/orchestrator/_interface.py | 29 ++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/src/pybind/mgr/orchestrator/_interface.py b/src/pybind/mgr/orchestrator/_interface.py index 25627418aee..f0e0558f7b4 100644 --- a/src/pybind/mgr/orchestrator/_interface.py +++ b/src/pybind/mgr/orchestrator/_interface.py @@ -48,6 +48,17 @@ class HostPlacementSpec(namedtuple('HostPlacementSpec', ['hostname', 'network', res += '=' + self.name return res + @classmethod + def from_json(cls, data): + return cls(**data) + + def to_json(self): + return { + 'hostname': self.hostname, + 'network': self.network, + 'name': self.name + } + @classmethod def parse(cls, host, require_network=True): # type: (str, bool) -> HostPlacementSpec @@ -1277,10 +1288,21 @@ class PlacementSpec(object): return "PlacementSpec(%s)" % self.pretty_str() @classmethod - def from_dict(cls, data): + def from_json(cls, data): + hosts = data.get('hosts', []) + if hosts: + data['hosts'] = [HostPlacementSpec.from_json(host) for host in hosts] _cls = cls(**data) _cls.validate() return _cls + + def to_json(self): + return { + 'label': self.label, + 'hosts': [host.to_json() for host in self.hosts] if self.hosts else [], + 'count': self.count, + 'all_hosts': self.all_hosts + } def validate(self): if self.hosts and self.label: @@ -1539,6 +1561,7 @@ class ServiceDescription(object): 'service_url': self.service_url, 'size': self.size, 'running': self.running, + 'spec': self.spec.to_json() if self.spec is not None else None } for k in ['last_refresh', 'created']: if getattr(self, k): @@ -1595,7 +1618,7 @@ class ServiceSpec(object): _cls = ServiceSpec # type: ignore for k, v in json_spec.items(): if k == 'placement': - v = PlacementSpec.from_dict(v) + v = PlacementSpec.from_json(v) if k == 'spec': args.update(v) continue @@ -1612,7 +1635,7 @@ class ServiceSpec(object): # type: () -> Dict[str, Any] c = self.__dict__.copy() if self.placement: - c['placement'] = self.placement.__dict__ + c['placement'] = self.placement.to_json() return c def __repr__(self): -- 2.39.5