call one completion from another completion. I.e. making them re-usable
using Promises E.g.::
- >>> return Orchestrator().get_hosts().then(self._create_osd)
+ >>> #doctest: +SKIP
+ ... return Orchestrator().get_hosts().then(self._create_osd)
where ``get_hosts`` returns a Completion of list of hosts and
``_create_osd`` takes a list of hosts.
The concept behind this is to store the computation steps
explicit and then explicitly evaluate the chain:
- >>> p = Completion(on_complete=lambda x: x*2).then(on_complete=lambda x: str(x))
+ >>> #doctest: +SKIP
+ ... p = Completion(on_complete=lambda x: x*2).then(on_complete=lambda x: str(x))
... p.finalize(2)
... assert p.result = "4"
is actually available in the orchestrator. I.e. this
won't work as expected::
- >>> if OrchestratorClientMixin().available()[0]: # wrong.
+ >>> #doctest: +SKIP
+ ... if OrchestratorClientMixin().available()[0]: # wrong.
... OrchestratorClientMixin().get_hosts()
:return: two-tuple of boolean, string
is actually possible in the orchestrator. I.e. this
won't work as expected::
- >>> api = OrchestratorClientMixin()
+ >>> #doctest: +SKIP
+ ... api = OrchestratorClientMixin()
... if api.get_feature_set()['get_hosts']['available']: # wrong.
... api.get_hosts()
It's better to ask for forgiveness instead::
- >>> try:
+ >>> #doctest: +SKIP
+ ... try:
... OrchestratorClientMixin().get_hosts()
... except (OrchestratorError, NotImplementedError):
... ...
>>> import mgr_module
- >>> class MyImplentation(mgr_module.MgrModule, Orchestrator):
+ >>> #doctest: +SKIP
+ ... class MyImplentation(mgr_module.MgrModule, Orchestrator):
... def __init__(self, ...):
... self.orch_client = OrchestratorClientMixin()
... self.orch_client.set_mgr(self.mgr))
import errno
import json
from typing import List, Set, Optional, Iterator
+import re
import yaml
import six
c = TrivialReadCompletion(result=True)
assert c.has_result
+ @staticmethod
+ def _upgrade_check_image_name(image, ceph_version):
+ """
+ >>> OrchestratorCli._upgrade_check_image_name('v15.2.0', None)
+ Traceback (most recent call last):
+ orchestrator._interface.OrchestratorValidationError: Error: unable to pull image name `v15.2.0`.
+ Maybe you meant `--ceph-version 15.2.0`?
+
+ """
+ if image and re.match(r'^v?\d+\.\d+\.\d+$', image) and ceph_version is None:
+ ver = image[1:] if image.startswith('v') else image
+ s = f"Error: unable to pull image name `{image}`.\n" \
+ f" Maybe you meant `--ceph-version {ver}`?"
+ raise OrchestratorValidationError(s)
+
@_cli_write_command(
'orch upgrade check',
'name=image,type=CephString,req=false '
'name=ceph_version,type=CephString,req=false',
desc='Check service versions vs available and target containers')
def _upgrade_check(self, image=None, ceph_version=None):
+ self._upgrade_check_image_name(image, ceph_version)
completion = self.upgrade_check(image=image, version=ceph_version)
self._orchestrator_wait([completion])
raise_if_exception(completion)
'name=ceph_version,type=CephString,req=false',
desc='Initiate upgrade')
def _upgrade_start(self, image=None, ceph_version=None):
+ self._upgrade_check_image_name(image, ceph_version)
completion = self.upgrade_start(image, ceph_version)
self._orchestrator_wait([completion])
raise_if_exception(completion)