mgr/ssh -> mgr/cephadm

Signed-off-by: Sage Weil <sage@redhat.com>
This commit is contained in:
Sage Weil 2019-12-11 15:35:02 -06:00
parent f466b3a149
commit cd1c05acbb
54 changed files with 341 additions and 346 deletions

4
.github/CODEOWNERS vendored
View File

@ -13,13 +13,13 @@
/src/pybind/mgr/orchestrator_cli @ceph/orchestrators
/src/pybind/mgr/orchestrator.py @ceph/orchestrators
/src/pybind/mgr/rook @ceph/orchestrators
/src/pybind/mgr/ssh @ceph/orchestrators
/src/pybind/mgr/cephadm @ceph/orchestrators
/src/pybind/mgr/test_orchestrator @ceph/orchestrators
/src/python-common/ceph/deployment @ceph/orchestrators
/qa/workunits/cephadm/test_cephadm.sh @ceph/orchestrators
/qa/tasks/ceph2.py @ceph/orchestrators
/qa/tasks/mgr/test_orchestrator_cli.py @ceph/orchestrators
/qa/tasks/mgr/test_ssh_orchestrator.py @ceph/orchestrators
/qa/tasks/mgr/test_cephadm_orchestrator.py @ceph/orchestrators
/doc/mgr/orchestrator_cli.rst @ceph/orchestrators
/doc/mgr/orchestrator_modules.rst @ceph/orchestrators

View File

@ -486,7 +486,7 @@ Recommends: ceph-mgr-diskprediction-local = %{_epoch_prefix}%{version}-%{release
Recommends: ceph-mgr-diskprediction-cloud = %{_epoch_prefix}%{version}-%{release}
Recommends: ceph-mgr-rook = %{_epoch_prefix}%{version}-%{release}
Recommends: ceph-mgr-k8sevents = %{_epoch_prefix}%{version}-%{release}
Recommends: ceph-mgr-ssh = %{_epoch_prefix}%{version}-%{release}
Recommends: ceph-mgr-cephadm = %{_epoch_prefix}%{version}-%{release}
Recommends: python%{_python_buildid}-influxdb
%endif
%if 0%{?rhel} == 7
@ -596,8 +596,8 @@ Requires: python%{_python_buildid}-PyYAML
ceph-mgr-k8sevents is a ceph-mgr plugin that sends every ceph-events
to kubernetes' events API
%package mgr-ssh
Summary: Ceph Manager plugin for SSH-based orchestration
%package mgr-cephadm
Summary: Ceph Manager plugin for cephadm-based orchestration
BuildArch: noarch
%if 0%{?suse_version}
Group: System/Filesystems
@ -611,9 +611,9 @@ Requires: openssh
%if 0%{?rhel} || 0%{?fedora}
Requires: openssh-clients
%endif
%description mgr-ssh
ceph-mgr-ssh is a ceph-mgr module for orchestration functions using
direct SSH connections for management operations.
%description mgr-cephadm
ceph-mgr-cephadm is a ceph-mgr module for orchestration functions using
the integrated cephadm deployment tool management operations.
%package fuse
Summary: Ceph fuse-based client
@ -1040,7 +1040,7 @@ Group: Development/Libraries/Python
%{?python_provide:%python_provide python-ceph-common}
%description -n python-ceph-common
This package contains data structures, classes and functions used by Ceph.
It also contains utilities used for the SSH orchestrator.
It also contains utilities used for the cephadm orchestrator.
%endif
%package -n python%{python3_pkgversion}-ceph-common
@ -1051,7 +1051,7 @@ Group: Development/Libraries/Python
%{?python_provide:%python_provide python%{python3_pkgversion}-ceph-common}
%description -n python%{python3_pkgversion}-ceph-common
This package contains data structures, classes and functions used by Ceph.
It also contains utilities used for the SSH orchestrator.
It also contains utilities used for the cephadm orchestrator.
%if 0%{with cephfs_shell}
%package -n cephfs-shell
@ -1513,7 +1513,7 @@ fi
%pre -n cephadm
# create user
if ! getent passwd | grep -q '^cephadm:'; then
useradd -r -s /bin/bash -c "cephadm user for mgr/ssh" -m cephadm
useradd -r -s /bin/bash -c "cephadm user for mgr/cephadm" -m cephadm
fi
# set up (initially empty) .ssh/authorized_keys file
if ! test -d /home/cephadm/.ssh; then
@ -1819,15 +1819,15 @@ if [ $1 -eq 1 ] ; then
/usr/bin/systemctl try-restart ceph-mgr.target >/dev/null 2>&1 || :
fi
%files mgr-ssh
%{_datadir}/ceph/mgr/ssh
%files mgr-cephadm
%{_datadir}/ceph/mgr/cephadm
%post mgr-ssh
%post mgr-cephadm
if [ $1 -eq 1 ] ; then
/usr/bin/systemctl try-restart ceph-mgr.target >/dev/null 2>&1 || :
fi
%postun mgr-ssh
%postun mgr-cephadm
if [ $1 -eq 1 ] ; then
/usr/bin/systemctl try-restart ceph-mgr.target >/dev/null 2>&1 || :
fi

1
debian/ceph-mgr-cephadm.install vendored Normal file
View File

@ -0,0 +1 @@
usr/share/ceph/mgr/cephadm

View File

@ -1,6 +1,6 @@
#!/bin/sh
# vim: set noet ts=8:
# postinst script for ceph-mgr-ssh
# postinst script for ceph-mgr-cephadm
#
# see: dh_installdeb(1)
@ -39,5 +39,3 @@ esac
#DEBHELPER#
exit 0

View File

@ -1 +0,0 @@
usr/share/ceph/mgr/ssh

View File

@ -25,7 +25,7 @@ case "$1" in
# 1. create user if not existing
if ! getent passwd | grep -q "^cephadm:"; then
echo -n "Adding system user cephadm.."
adduser --quiet --system --disabled-password --gecos 'Ceph-dameon user for mgr/ssh' --shell /bin/bash cephadm 2>/dev/null || true
adduser --quiet --system --disabled-password --gecos 'Ceph-dameon user for cephadm' --shell /bin/bash cephadm 2>/dev/null || true
echo "..done"
fi

12
debian/control vendored
View File

@ -227,7 +227,7 @@ Recommends: ceph-mgr-dashboard,
ceph-mgr-diskprediction-cloud,
ceph-mgr-rook,
ceph-mgr-k8sevents,
ceph-mgr-ssh
ceph-mgr-cephadm
Suggests: python-influxdb
Replaces: ceph (<< 0.93-417),
Breaks: ceph (<< 0.93-417),
@ -326,7 +326,7 @@ Description: kubernetes events plugin for ceph-mgr
ceph related events to the kubernetes events API, and track all events
that occur within the rook-ceph namespace.
Package: ceph-mgr-ssh
Package: ceph-mgr-cephadm
Architecture: all
Depends: ceph-mgr (= ${binary:Version}),
cephadm,
@ -334,12 +334,12 @@ Depends: ceph-mgr (= ${binary:Version}),
${misc:Depends},
${python:Depends},
openssh-client
Description: ssh orchestrator plugin for ceph-mgr
Description: cephadm orchestrator plugin for ceph-mgr
Ceph is a massively scalable, open-source, distributed
storage system that runs on commodity hardware and delivers object,
block and file system storage.
.
This package contains the SSH plugin for ceph-mgr's orchestration
This package contains the CEPHADM plugin for ceph-mgr's orchestration
functionality, to allow ceph-mgr to perform orchestration functions
over a standard SSH connection.
@ -1249,7 +1249,7 @@ Description: Python 2 utility libraries for Ceph
block and file system storage.
.
This package contains data structures, classes and functions used by Ceph.
It also contains utilities used for the SSH orchestrator.
It also contains utilities used for the cephadm orchestrator.
Package: python3-ceph-common
Architecture: all
@ -1262,7 +1262,7 @@ Description: Python 3 utility libraries for Ceph
block and file system storage.
.
This package contains data structures, classes and functions used by Ceph.
It also contains utilities used for the SSH orchestrator.
It also contains utilities used for the cephadm orchestrator.
Package: libcephfs-java
Section: java

View File

@ -1,13 +1,13 @@
================
SSH orchestrator
================
====================
cephadm orchestrator
====================
The SSH orchestrator is an orchestrator module that does not rely on a separate
The cephadm orchestrator is an orchestrator module that does not rely on a separate
system such as Rook or Ansible, but rather manages nodes in a cluster by
establishing an SSH connection and issuing explicit management commands.
Orchestrator modules only provide services to other modules, which in turn
provide user interfaces. To try out the SSH module, you might like
provide user interfaces. To try out the cephadm module, you might like
to use the :ref:`Orchestrator CLI <orchestrator-cli-module>` module.
Requirements
@ -18,22 +18,22 @@ Requirements
Configuration
-------------
The SSH orchestrator can be configured to use an SSH configuration file. This is
The cephadm orchestrator can be configured to use an SSH configuration file. This is
useful for specifying private keys and other SSH connection options.
::
# ceph config set mgr mgr/ssh/ssh_config_file /path/to/config
# ceph config set mgr mgr/cephadm/ssh_config_file /path/to/config
An SSH configuration file can be provided without requiring an accessible file
system path as the method above does.
::
# ceph ssh set-ssh-config -i /path/to/config
# ceph cephadm set-ssh-config -i /path/to/config
To clear this value use the command:
::
# ceph ssh clear-ssh-config
# ceph cephadm clear-ssh-config

View File

@ -41,9 +41,9 @@ sensible.
Telemetry module <telemetry>
Iostat module <iostat>
Crash module <crash>
Insights module <insights>
Orchestrator CLI module <orchestrator_cli>
Cephadm orchestrator <cephadm>
Rook module <rook>
DeepSea module <deepsea>
Insights module <insights>
Ansible module <ansible>
SSH orchestrator <ssh>

View File

@ -41,7 +41,7 @@ ceph:
- ceph-mgr-diskprediction-cloud
- ceph-mgr-diskprediction-local
- ceph-mgr-rook
- ceph-mgr-ssh
- ceph-mgr-cephadm
- ceph-fuse
- libcephfs2
- libcephfs-devel

View File

@ -15,4 +15,4 @@ tasks:
- No standby daemons available
- cephfs_test_runner:
modules:
- tasks.mgr.test_ssh_orchestrator
- tasks.mgr.test_cephadm_orchestrator

View File

@ -20,7 +20,7 @@ tasks:
- ceph-mgr-diskprediction-local
- ceph-mgr-diskprediction-cloud
- ceph-mgr-rook
- ceph-mgr-ssh
- ceph-mgr-cephadm
- cephadm
- ceph-mgr
- libcephfs2

View File

@ -17,7 +17,7 @@ tasks:
- ceph-mgr-diskprediction-local
- ceph-mgr-diskprediction-cloud
- ceph-mgr-rook
- ceph-mgr-ssh
- ceph-mgr-cephadm
- cephadm
- ceph-mgr
- libcephfs2

View File

@ -16,7 +16,7 @@ tasks:
- ceph-mgr-diskprediction-local
- ceph-mgr-diskprediction-cloud
- ceph-mgr-rook
- ceph-mgr-ssh
- ceph-mgr-cephadm
- cephadm
- ceph-mgr
- libcephfs2

View File

@ -17,7 +17,7 @@ tasks:
- ceph-mgr-diskprediction-local
- ceph-mgr-diskprediction-cloud
- ceph-mgr-rook
- ceph-mgr-ssh
- ceph-mgr-cephadm
- cephadm
extra_packages: ['librados2']
- install.upgrade:

View File

@ -16,7 +16,7 @@ tasks:
- ceph-mgr-diskprediction-local
- ceph-mgr-diskprediction-cloud
- ceph-mgr-rook
- ceph-mgr-ssh
- ceph-mgr-cephadm
- cephadm
extra_packages: ['librados2']
- install.upgrade:

View File

@ -17,7 +17,7 @@ tasks:
- ceph-mgr-diskprediction-local
- ceph-mgr-diskprediction-cloud
- ceph-mgr-rook
- ceph-mgr-ssh
- ceph-mgr-cephadm
- cephadm
extra_packages: ['librados2']
- install.upgrade:

View File

@ -17,7 +17,7 @@ tasks:
- ceph-mgr-diskprediction-local
- ceph-mgr-diskprediction-cloud
- ceph-mgr-rook
- ceph-mgr-ssh
- ceph-mgr-cephadm
- cephadm
extra_packages: ['librados2']
- install.upgrade:

View File

@ -15,7 +15,7 @@ tasks:
- ceph-mgr-diskprediction-local
- ceph-mgr-diskprediction-cloud
- ceph-mgr-rook
- ceph-mgr-ssh
- ceph-mgr-cephadm
- cephadm
extra_packages: ['librados2']
- print: "**** done install mimic"

View File

@ -12,7 +12,7 @@ tasks:
- ceph-mgr-diskprediction-local
- ceph-mgr-diskprediction-cloud
- ceph-mgr-rook
- ceph-mgr-ssh
- ceph-mgr-cephadm
- cephadm
extra_packages: ['librados2']
- print: "**** done installing mimic"

View File

@ -9,7 +9,7 @@ tasks:
- ceph-mgr-diskprediction-local
- ceph-mgr-diskprediction-cloud
- ceph-mgr-rook
- ceph-mgr-ssh
- ceph-mgr-cephadm
- cephadm
extra_packages: ['librados2']
- print: "**** done install mimic"

View File

@ -15,7 +15,7 @@ tasks:
- ceph-mgr-diskprediction-local
- ceph-mgr-diskprediction-cloud
- ceph-mgr-rook
- ceph-mgr-ssh
- ceph-mgr-cephadm
- cephadm
extra_packages: ['librados2']
- print: "**** done install nautilus"

View File

@ -15,8 +15,8 @@ class TestOrchestratorCli(MgrTestCase):
def setUp(self):
super(TestOrchestratorCli, self).setUp()
self._load_module("orchestrator_cli")
self._load_module("ssh")
self._orch_cmd("set", "backend", "ssh")
self._load_module("cephadm")
self._orch_cmd("set", "backend", "cephadm")
def test_host_ls(self):
self._orch_cmd("host", "add", "osd0")

View File

@ -1243,14 +1243,14 @@ def command_bootstrap():
# ssh
if not args.skip_ssh:
logger.info('Enabling ssh module...')
cli(['mgr', 'module', 'enable', 'ssh'])
logger.info('Enabling cephadm module...')
cli(['mgr', 'module', 'enable', 'cephadm'])
logger.info('Setting orchestrator backend to ssh...')
cli(['orchestrator', 'set', 'backend', 'ssh'])
cli(['orchestrator', 'set', 'backend', 'cephadm'])
logger.info('Generating ssh key...')
cli(['ssh', 'generate-key'])
ssh_pub = cli(['ssh', 'get-pub-key'])
cli(['cephadm', 'generate-key'])
ssh_pub = cli(['cephadm', 'get-pub-key'])
with open(args.output_pub_ssh_key, 'w') as f:
f.write(ssh_pub)

View File

@ -437,7 +437,7 @@ std::vector<Option> get_global_options() {
.add_see_also("mon_host"),
Option("container_image", Option::TYPE_STR, Option::LEVEL_BASIC)
.set_description("container image (used by ssh orchestrator)")
.set_description("container image (used by cephadm orchestrator)")
.set_flag(Option::FLAG_STARTUP)
.set_default("ceph/daemon-base:latest-master-devel"),

View File

@ -202,7 +202,7 @@ void MonCapGrant::expand_profile(const EntityName& name) const
profile_grants.push_back(MonCapGrant("auth", MON_CAP_R | MON_CAP_X));
profile_grants.push_back(MonCapGrant("config-key", MON_CAP_R | MON_CAP_W));
profile_grants.push_back(MonCapGrant("config", MON_CAP_R | MON_CAP_W));
// ssh orchestrator provisions new daemon keys
// cephadm orchestrator provisions new daemon keys
profile_grants.push_back(MonCapGrant("auth get-or-create"));
profile_grants.push_back(MonCapGrant("auth rm"));
// tell commands (this is a bit of a kludge)

View File

@ -12,23 +12,23 @@ In the following I'll use the `vstart` method.
::
# ../src/vstart.sh -n --ssh
# ../src/vstart.sh -n --cephadm
*Note that when you specify `--ssh` you have to have passwordless ssh access to localhost*
*Note that when you specify `--cephadm` you have to have passwordless ssh access to localhost*
It will add your ~/.ssh/id_rsa and ~/.ssh/id_rsa.pub to `mgr/ssh/ssh_identity_{key, pub}`
and add your $HOSTNAME to the list of known hosts.
This will also enable the ssh mgr module and enable it as the orchestrator backend.
This will also enable the cephadm mgr module and enable it as the orchestrator backend.
*Optional:*
While the above is sufficient for most operations, you may want to add a second host to the mix.
There is `Vagrantfile` for creating a minimal cluster in `src/pybind/mgr/ssh/`.
There is `Vagrantfile` for creating a minimal cluster in `src/pybind/mgr/cephadm/`.
If you wish to extend the one-node-localhost cluster to i.e. test more sophisticated OSD deployments you can follow the next steps:
From within the `src/pybind/mgr/ssh` directory.
From within the `src/pybind/mgr/cephadm` directory.
1) Spawn VMs
@ -43,12 +43,12 @@ mon0, mgr0, osd0
NUM_DAEMONS can be used to increase the number of VMs created. (defaults to 1)
If will also come with the necessary packages preinstalled as well as your ~/.ssh/id_rsa.pub key
injected. (to users root and vagrant; the SSH-orchestrator currently connects as root)
injected. (to users root and vagrant; the cephadm-orchestrator currently connects as root)
2) Update the ssh-config
The SSH-orchestrator needs to understand how to connect to the new node. Most likely the VM isn't reachable with the default settings used:
The cephadm orchestrator needs to understand how to connect to the new node. Most likely the VM isn't reachable with the default settings used:
```
Host *
@ -67,7 +67,7 @@ Now set the newly created config for Ceph.
::
# ceph ssh set-ssh-config -i <path_to_ssh_conf>
# ceph cephadm set-ssh-config -i <path_to_ssh_conf>
3) Add the new host

View File

@ -3,4 +3,4 @@ import os
if 'UNITTEST' in os.environ:
import tests
from .module import SSHOrchestrator
from .module import CephadmOrchestrator

View File

@ -88,7 +88,7 @@ class AsyncCompletion(orchestrator.Completion):
many=False, # type: bool
):
assert SSHOrchestrator.instance is not None
assert CephadmOrchestrator.instance is not None
self.many = many
if name is None and on_complete is not None:
name = on_complete.__name__
@ -128,24 +128,24 @@ class AsyncCompletion(orchestrator.Completion):
self.fail(e)
def run(value):
assert SSHOrchestrator.instance
assert CephadmOrchestrator.instance
if self.many:
if not value:
logger.info('calling map_async without values')
callback([])
if six.PY3:
SSHOrchestrator.instance._worker_pool.map_async(_callback, value,
CephadmOrchestrator.instance._worker_pool.map_async(_callback, value,
callback=callback,
error_callback=error_callback)
else:
SSHOrchestrator.instance._worker_pool.map_async(_callback, value,
CephadmOrchestrator.instance._worker_pool.map_async(_callback, value,
callback=callback)
else:
if six.PY3:
SSHOrchestrator.instance._worker_pool.apply_async(_callback, (value,),
CephadmOrchestrator.instance._worker_pool.apply_async(_callback, (value,),
callback=callback, error_callback=error_callback)
else:
SSHOrchestrator.instance._worker_pool.apply_async(_callback, (value,),
CephadmOrchestrator.instance._worker_pool.apply_async(_callback, (value,),
callback=callback)
return self.ASYNC_RESULT
@ -229,7 +229,7 @@ def trivial_result(val):
return AsyncCompletion(value=val, name='trivial_result')
class SSHOrchestrator(MgrModule, orchestrator.Orchestrator):
class CephadmOrchestrator(MgrModule, orchestrator.Orchestrator):
_STORE_HOST_PREFIX = "host"
@ -271,7 +271,7 @@ class SSHOrchestrator(MgrModule, orchestrator.Orchestrator):
]
def __init__(self, *args, **kwargs):
super(SSHOrchestrator, self).__init__(*args, **kwargs)
super(CephadmOrchestrator, self).__init__(*args, **kwargs)
self._cluster_fsid = self.get('mon_map')['fsid']
self.config_notify()
@ -288,7 +288,7 @@ class SSHOrchestrator(MgrModule, orchestrator.Orchestrator):
self._reconfig_ssh()
SSHOrchestrator.instance = self
CephadmOrchestrator.instance = self
self.all_progress_references = list() # type: List[orchestrator.ProgressReference]
# load inventory
@ -325,7 +325,7 @@ class SSHOrchestrator(MgrModule, orchestrator.Orchestrator):
del self.service_cache[h]
def shutdown(self):
self.log.error('ssh: shutdown')
self.log.error('shutdown')
self._worker_pool.close()
self._worker_pool.join()
@ -430,7 +430,7 @@ class SSHOrchestrator(MgrModule, orchestrator.Orchestrator):
def available(self):
"""
The SSH orchestrator is always available.
The cephadm orchestrator is always available.
"""
return self.can_run()
@ -459,7 +459,7 @@ class SSHOrchestrator(MgrModule, orchestrator.Orchestrator):
unregistered_hosts))))
@orchestrator._cli_write_command(
prefix='ssh set-ssh-config',
prefix='cephadm set-ssh-config',
desc='Set the ssh_config file (use -i <ssh_config>)')
def _set_ssh_config(self, inbuf=None):
"""
@ -474,7 +474,7 @@ class SSHOrchestrator(MgrModule, orchestrator.Orchestrator):
return 0, "", ""
@orchestrator._cli_write_command(
prefix='ssh clear-ssh-config',
prefix='cephadm clear-ssh-config',
desc='Clear the ssh_config file')
def _clear_ssh_config(self):
"""
@ -485,7 +485,7 @@ class SSHOrchestrator(MgrModule, orchestrator.Orchestrator):
return 0, "", ""
@orchestrator._cli_write_command(
'ssh generate-key',
'cephadm generate-key',
desc='Generate a cluster SSH key (if not present)')
def _generate_key(self):
if not self.ssh_pub or not self.ssh_key:
@ -513,7 +513,7 @@ class SSHOrchestrator(MgrModule, orchestrator.Orchestrator):
return 0, '', ''
@orchestrator._cli_write_command(
'ssh clear-key',
'cephadm clear-key',
desc='Clear cluster SSH key')
def _clear_key(self):
self.set_store('ssh_identity_key', None)
@ -522,7 +522,7 @@ class SSHOrchestrator(MgrModule, orchestrator.Orchestrator):
return 0, '', ''
@orchestrator._cli_read_command(
'ssh get-pub-key',
'cephadm get-pub-key',
desc='Show SSH public key for connecting to cluster hosts')
def _get_pub_key(self):
if self.ssh_pub:
@ -531,13 +531,13 @@ class SSHOrchestrator(MgrModule, orchestrator.Orchestrator):
return -errno.ENOENT, '', 'No cluster SSH key defined'
@orchestrator._cli_read_command(
'ssh get-user',
'cephadm get-user',
desc='Show user for SSHing to cluster hosts')
def _get_user(self):
return 0, self.ssh_user, ''
@orchestrator._cli_read_command(
'ssh check-host',
'cephadm check-host',
'name=host,type=CephString',
'Check whether we can access and manage a remote host')
def _check_host(self, host):
@ -548,7 +548,7 @@ class SSHOrchestrator(MgrModule, orchestrator.Orchestrator):
return 0, 'host ok', err
@orchestrator._cli_write_command(
'ssh prepare-host',
'cephadm prepare-host',
'name=host,type=CephString',
'Try to prepare a host for remote management')
def _prepare_host(self, host):

View File

@ -0,0 +1,46 @@
from contextlib import contextmanager
import pytest
from cephadm import CephadmOrchestrator
from tests import mock
def set_store(self, k, v):
if v is None:
del self._store[k]
else:
self._store[k] = v
def get_store(self, k):
return self._store[k]
def get_store_prefix(self, prefix):
return {
k: v for k, v in self._store.items()
if k.startswith(prefix)
}
def get_ceph_option(_, key):
return __file__
@pytest.yield_fixture()
def cephadm_module():
with mock.patch("cephadm.module.CephadmOrchestrator.get_ceph_option", get_ceph_option),\
mock.patch("cephadm.module.CephadmOrchestrator._configure_logging", lambda *args: None),\
mock.patch("cephadm.module.CephadmOrchestrator.set_store", set_store),\
mock.patch("cephadm.module.CephadmOrchestrator.get_store", get_store),\
mock.patch("cephadm.module.CephadmOrchestrator.get_store_prefix", get_store_prefix):
CephadmOrchestrator._register_commands('')
m = CephadmOrchestrator.__new__ (CephadmOrchestrator)
m._root_logger = mock.MagicMock()
m._store = {
'ssh_config': '',
'ssh_identity_key': '',
'ssh_identity_pub': '',
'inventory': {},
}
m.__init__('cephadm', 0, 0)
yield m

View File

@ -0,0 +1,174 @@
import json
import time
from contextlib import contextmanager
from ceph.deployment.drive_group import DriveGroupSpec, DeviceSelection
try:
from typing import Any
except ImportError:
pass
from orchestrator import ServiceDescription, raise_if_exception, Completion, InventoryNode, \
StatelessServiceSpec, PlacementSpec, RGWSpec, parse_host_specs
from ..module import CephadmOrchestrator
from tests import mock
from .fixtures import cephadm_module
"""
TODOs:
There is really room for improvement here. I just quickly assembled theses tests.
I general, everything should be testes in Teuthology as well. Reasons for
also testing this here is the development roundtrip time.
"""
def _run_cephadm(ret):
def foo(*args, **kwargs):
return ret, '', 0
return foo
def mon_command(*args, **kwargs):
return 0, '', ''
class TestSSH(object):
def _wait(self, m, c):
# type: (CephadmOrchestrator, Completion) -> Any
m.process([c])
m.process([c])
for _ in range(30):
if c.is_finished:
raise_if_exception(c)
return c.result
time.sleep(0.1)
assert False, "timeout" + str(c._state)
@contextmanager
def _with_host(self, m, name):
self._wait(m, m.add_host(name))
yield
self._wait(m, m.remove_host(name))
def test_get_unique_name(self, cephadm_module):
existing = [
ServiceDescription(service_instance='mon.a')
]
new_mon = cephadm_module.get_unique_name(existing, 'mon')
assert new_mon.startswith('mon.')
assert new_mon != 'mon.a'
def test_host(self, cephadm_module):
with self._with_host(cephadm_module, 'test'):
assert self._wait(cephadm_module, cephadm_module.get_hosts()) == [InventoryNode('test')]
c = cephadm_module.get_hosts()
assert self._wait(cephadm_module, c) == []
@mock.patch("cephadm.module.CephadmOrchestrator._run_cephadm", _run_cephadm('[]'))
def test_service_ls(self, cephadm_module):
with self._with_host(cephadm_module, 'test'):
c = cephadm_module.describe_service()
assert self._wait(cephadm_module, c) == []
@mock.patch("cephadm.module.CephadmOrchestrator._run_cephadm", _run_cephadm('[]'))
def test_device_ls(self, cephadm_module):
with self._with_host(cephadm_module, 'test'):
c = cephadm_module.get_inventory()
assert self._wait(cephadm_module, c) == [InventoryNode('test')]
@mock.patch("cephadm.module.CephadmOrchestrator._run_cephadm", _run_cephadm('[]'))
@mock.patch("cephadm.module.CephadmOrchestrator.send_command")
@mock.patch("cephadm.module.CephadmOrchestrator.mon_command", mon_command)
@mock.patch("cephadm.module.CephadmOrchestrator._get_connection")
def test_mon_update(self, _send_command, _get_connection, cephadm_module):
with self._with_host(cephadm_module, 'test'):
c = cephadm_module.update_mons(1, [parse_host_specs('test:0.0.0.0=a')])
assert self._wait(cephadm_module, c) == ["(Re)deployed mon.a on host 'test'"]
@mock.patch("cephadm.module.CephadmOrchestrator._run_cephadm", _run_cephadm('[]'))
@mock.patch("cephadm.module.CephadmOrchestrator.send_command")
@mock.patch("cephadm.module.CephadmOrchestrator.mon_command", mon_command)
@mock.patch("cephadm.module.CephadmOrchestrator._get_connection")
def test_mgr_update(self, _send_command, _get_connection, cephadm_module):
with self._with_host(cephadm_module, 'test'):
c = cephadm_module.update_mgrs(1, [parse_host_specs('test:0.0.0.0')])
[out] = self._wait(cephadm_module, c)
assert "(Re)deployed mgr." in out
assert " on host 'test'" in out
@mock.patch("cephadm.module.CephadmOrchestrator._run_cephadm", _run_cephadm('{}'))
@mock.patch("cephadm.module.CephadmOrchestrator.send_command")
@mock.patch("cephadm.module.CephadmOrchestrator.mon_command", mon_command)
@mock.patch("cephadm.module.CephadmOrchestrator._get_connection")
def test_create_osds(self, _send_command, _get_connection, cephadm_module):
with self._with_host(cephadm_module, 'test'):
dg = DriveGroupSpec('test', DeviceSelection(paths=['']))
c = cephadm_module.create_osds(dg)
assert self._wait(cephadm_module, c) == "Created osd(s) on host 'test'"
@mock.patch("cephadm.module.CephadmOrchestrator._run_cephadm", _run_cephadm('{}'))
@mock.patch("cephadm.module.CephadmOrchestrator.send_command")
@mock.patch("cephadm.module.CephadmOrchestrator.mon_command", mon_command)
@mock.patch("cephadm.module.CephadmOrchestrator._get_connection")
def test_mds(self, _send_command, _get_connection, cephadm_module):
with self._with_host(cephadm_module, 'test'):
ps = PlacementSpec(nodes=['test'])
c = cephadm_module.add_mds(StatelessServiceSpec('name', ps))
[out] = self._wait(cephadm_module, c)
assert "(Re)deployed mds.name." in out
assert " on host 'test'" in out
@mock.patch("cephadm.module.CephadmOrchestrator._run_cephadm", _run_cephadm('{}'))
@mock.patch("cephadm.module.CephadmOrchestrator.send_command")
@mock.patch("cephadm.module.CephadmOrchestrator.mon_command", mon_command)
@mock.patch("cephadm.module.CephadmOrchestrator._get_connection")
def test_rgw(self, _send_command, _get_connection, cephadm_module):
with self._with_host(cephadm_module, 'test'):
ps = PlacementSpec(nodes=['test'])
c = cephadm_module.add_rgw(RGWSpec('realm', 'zone', ps))
[out] = self._wait(cephadm_module, c)
assert "(Re)deployed rgw.realm.zone." in out
assert " on host 'test'" in out
@mock.patch("cephadm.module.CephadmOrchestrator._run_cephadm", _run_cephadm(
json.dumps([
dict(
name='rgw.myrgw.foobar',
style='cephadm',
fsid='fsid',
container_id='container_id',
version='version',
state='running',
)
])
))
def test_remove_rgw(self, cephadm_module):
cephadm_module._cluster_fsid = "fsid"
with self._with_host(cephadm_module, 'test'):
c = cephadm_module.remove_rgw('myrgw')
out = self._wait(cephadm_module, c)
assert out == ["Removed rgw.myrgw.foobar from host 'test'"]
@mock.patch("cephadm.module.CephadmOrchestrator._run_cephadm", _run_cephadm('{}'))
@mock.patch("cephadm.module.CephadmOrchestrator.send_command")
@mock.patch("cephadm.module.CephadmOrchestrator.mon_command", mon_command)
@mock.patch("cephadm.module.CephadmOrchestrator._get_connection")
def test_rbd_mirror(self, _send_command, _get_connection, cephadm_module):
with self._with_host(cephadm_module, 'test'):
ps = PlacementSpec(nodes=['test'])
c = cephadm_module.add_rbd_mirror(StatelessServiceSpec('name', ps))
[out] = self._wait(cephadm_module, c)
assert "(Re)deployed rbd-mirror." in out
assert " on host 'test'" in out
@mock.patch("cephadm.module.CephadmOrchestrator._run_cephadm", _run_cephadm('{}'))
@mock.patch("cephadm.module.CephadmOrchestrator.send_command")
@mock.patch("cephadm.module.CephadmOrchestrator.mon_command", mon_command)
@mock.patch("cephadm.module.CephadmOrchestrator._get_connection")
def test_blink_device_light(self, _send_command, _get_connection, cephadm_module):
with self._with_host(cephadm_module, 'test'):
c = cephadm_module.blink_device_light('ident', True, [('test', '')])
assert self._wait(cephadm_module, c) == ['Set ident light for test: on']

View File

@ -11,13 +11,13 @@ import pytest
from orchestrator import raise_if_exception, Completion
from .fixtures import ssh_module
from ..module import trivial_completion, async_completion, async_map_completion, SSHOrchestrator
from .fixtures import cephadm_module
from ..module import trivial_completion, async_completion, async_map_completion, CephadmOrchestrator
class TestCompletion(object):
def _wait(self, m, c):
# type: (SSHOrchestrator, Completion) -> Any
# type: (CephadmOrchestrator, Completion) -> Any
m.process([c])
m.process([c])
@ -28,11 +28,11 @@ class TestCompletion(object):
time.sleep(0.1)
assert False, "timeout" + str(c._state)
def test_trivial(self, ssh_module):
def test_trivial(self, cephadm_module):
@trivial_completion
def run(x):
return x+1
assert self._wait(ssh_module, run(1)) == 2
assert self._wait(cephadm_module, run(1)) == 2
@pytest.mark.parametrize("input", [
((1, ), ),
@ -40,12 +40,12 @@ class TestCompletion(object):
(("hallo", ), ),
(("hallo", "foo"), ),
])
def test_async(self, input, ssh_module):
def test_async(self, input, cephadm_module):
@async_completion
def run(*args):
return str(args)
assert self._wait(ssh_module, run(*input)) == str(input)
assert self._wait(cephadm_module, run(*input)) == str(input)
@pytest.mark.parametrize("input,expected", [
([], []),
@ -55,16 +55,16 @@ class TestCompletion(object):
(list(range(5)), [str((x, )) for x in range(5)]),
([(1, 2), (3, 4)], ["(1, 2)", "(3, 4)"]),
])
def test_async_map(self, input, expected, ssh_module):
def test_async_map(self, input, expected, cephadm_module):
@async_map_completion
def run(*args):
return str(args)
c = run(input)
self._wait(ssh_module, c)
self._wait(cephadm_module, c)
assert c.result == expected
def test_async_self(self, ssh_module):
def test_async_self(self, cephadm_module):
class Run(object):
def __init__(self):
self.attr = 1
@ -74,7 +74,7 @@ class TestCompletion(object):
assert self.attr == 1
return x + 1
assert self._wait(ssh_module, Run().run(1)) == 2
assert self._wait(cephadm_module, Run().run(1)) == 2
@pytest.mark.parametrize("input,expected", [
([], []),
@ -84,7 +84,7 @@ class TestCompletion(object):
(list(range(5)), [str((x, )) for x in range(5)]),
([(1, 2), (3, 4)], ["(1, 2)", "(3, 4)"]),
])
def test_async_map_self(self, input, expected, ssh_module):
def test_async_map_self(self, input, expected, cephadm_module):
class Run(object):
def __init__(self):
self.attr = 1
@ -95,17 +95,17 @@ class TestCompletion(object):
return str(args)
c = Run().run(input)
self._wait(ssh_module, c)
self._wait(cephadm_module, c)
assert c.result == expected
def test_then1(self, ssh_module):
def test_then1(self, cephadm_module):
@async_map_completion
def run(x):
return x+1
assert self._wait(ssh_module, run([1,2]).then(str)) == '[2, 3]'
assert self._wait(cephadm_module, run([1,2]).then(str)) == '[2, 3]'
def test_then2(self, ssh_module):
def test_then2(self, cephadm_module):
@async_map_completion
def run(x):
time.sleep(0.1)
@ -117,10 +117,10 @@ class TestCompletion(object):
c = run([1,2]).then(async_str)
self._wait(ssh_module, c)
self._wait(cephadm_module, c)
assert c.result == '[2, 3]'
def test_then3(self, ssh_module):
def test_then3(self, cephadm_module):
@async_map_completion
def run(x):
time.sleep(0.1)
@ -131,10 +131,10 @@ class TestCompletion(object):
c = run([1,2]).then(async_str)
self._wait(ssh_module, c)
self._wait(cephadm_module, c)
assert c.result == '[2, 3]'
def test_then4(self, ssh_module):
def test_then4(self, cephadm_module):
@async_map_completion
def run(x):
time.sleep(0.1)
@ -145,11 +145,11 @@ class TestCompletion(object):
c = run([1,2]).then(async_str)
self._wait(ssh_module, c)
self._wait(cephadm_module, c)
assert c.result == '[2, 3]hello'
@pytest.mark.skip(reason="see limitation of async_map_completion")
def test_then5(self, ssh_module):
def test_then5(self, cephadm_module):
@async_map_completion
def run(x):
time.sleep(0.1)
@ -157,14 +157,13 @@ class TestCompletion(object):
c = run([1,2])
self._wait(ssh_module, c)
self._wait(cephadm_module, c)
assert c.result == "['2', '3']"
def test_raise(self, ssh_module):
def test_raise(self, cephadm_module):
@async_completion
def run(x):
raise ZeroDivisionError()
with pytest.raises(ZeroDivisionError):
self._wait(ssh_module, run(1))
self._wait(cephadm_module, run(1))

View File

@ -27,7 +27,7 @@ class OrchestratorCli(orchestrator.OrchestratorClientMixin, MgrModule):
'type': 'str',
'default': None,
'desc': 'Orchestrator backend',
'enum_allowed': ['ssh', 'rook', 'ansible', 'deepsea',
'enum_allowed': ['cephadm', 'rook', 'ansible', 'deepsea',
'test_orchestrator'],
'runtime': True,
},

View File

@ -1,46 +0,0 @@
from contextlib import contextmanager
import pytest
from ssh import SSHOrchestrator
from tests import mock
def set_store(self, k, v):
if v is None:
del self._store[k]
else:
self._store[k] = v
def get_store(self, k):
return self._store[k]
def get_store_prefix(self, prefix):
return {
k: v for k, v in self._store.items()
if k.startswith(prefix)
}
def get_ceph_option(_, key):
return __file__
@pytest.yield_fixture()
def ssh_module():
with mock.patch("ssh.module.SSHOrchestrator.get_ceph_option", get_ceph_option),\
mock.patch("ssh.module.SSHOrchestrator._configure_logging", lambda *args: None),\
mock.patch("ssh.module.SSHOrchestrator.set_store", set_store),\
mock.patch("ssh.module.SSHOrchestrator.get_store", get_store),\
mock.patch("ssh.module.SSHOrchestrator.get_store_prefix", get_store_prefix):
SSHOrchestrator._register_commands('')
m = SSHOrchestrator.__new__ (SSHOrchestrator)
m._root_logger = mock.MagicMock()
m._store = {
'ssh_config': '',
'ssh_identity_key': '',
'ssh_identity_pub': '',
'inventory': {},
}
m.__init__('ssh', 0, 0)
yield m

View File

@ -1,176 +0,0 @@
import json
import time
from contextlib import contextmanager
from ceph.deployment.drive_group import DriveGroupSpec, DeviceSelection
try:
from typing import Any
except ImportError:
pass
from orchestrator import ServiceDescription, raise_if_exception, Completion, InventoryNode, \
StatelessServiceSpec, PlacementSpec, RGWSpec, parse_host_specs
from ..module import SSHOrchestrator
from tests import mock
from .fixtures import ssh_module
"""
TODOs:
There is really room for improvement here. I just quickly assembled theses tests.
I general, everything should be testes in Teuthology as well. Reasons for
also testing this here is the development roundtrip time.
"""
def _run_cephadm(ret):
def foo(*args, **kwargs):
return ret, '', 0
return foo
def mon_command(*args, **kwargs):
return 0, '', ''
class TestSSH(object):
def _wait(self, m, c):
# type: (SSHOrchestrator, Completion) -> Any
m.process([c])
m.process([c])
for _ in range(30):
if c.is_finished:
raise_if_exception(c)
return c.result
time.sleep(0.1)
assert False, "timeout" + str(c._state)
@contextmanager
def _with_host(self, m, name):
self._wait(m, m.add_host(name))
yield
self._wait(m, m.remove_host(name))
def test_get_unique_name(self, ssh_module):
existing = [
ServiceDescription(service_instance='mon.a')
]
new_mon = ssh_module.get_unique_name(existing, 'mon')
assert new_mon.startswith('mon.')
assert new_mon != 'mon.a'
def test_host(self, ssh_module):
with self._with_host(ssh_module, 'test'):
assert self._wait(ssh_module, ssh_module.get_hosts()) == [InventoryNode('test')]
c = ssh_module.get_hosts()
assert self._wait(ssh_module, c) == []
@mock.patch("ssh.module.SSHOrchestrator._run_cephadm", _run_cephadm('[]'))
def test_service_ls(self, ssh_module):
with self._with_host(ssh_module, 'test'):
c = ssh_module.describe_service()
assert self._wait(ssh_module, c) == []
@mock.patch("ssh.module.SSHOrchestrator._run_cephadm", _run_cephadm('[]'))
def test_device_ls(self, ssh_module):
with self._with_host(ssh_module, 'test'):
c = ssh_module.get_inventory()
assert self._wait(ssh_module, c) == [InventoryNode('test')]
@mock.patch("ssh.module.SSHOrchestrator._run_cephadm", _run_cephadm('[]'))
@mock.patch("ssh.module.SSHOrchestrator.send_command")
@mock.patch("ssh.module.SSHOrchestrator.mon_command", mon_command)
@mock.patch("ssh.module.SSHOrchestrator._get_connection")
def test_mon_update(self, _send_command, _get_connection, ssh_module):
with self._with_host(ssh_module, 'test'):
c = ssh_module.update_mons(1, [parse_host_specs('test:0.0.0.0=a')])
assert self._wait(ssh_module, c) == ["(Re)deployed mon.a on host 'test'"]
@mock.patch("ssh.module.SSHOrchestrator._run_cephadm", _run_cephadm('[]'))
@mock.patch("ssh.module.SSHOrchestrator.send_command")
@mock.patch("ssh.module.SSHOrchestrator.mon_command", mon_command)
@mock.patch("ssh.module.SSHOrchestrator._get_connection")
def test_mgr_update(self, _send_command, _get_connection, ssh_module):
with self._with_host(ssh_module, 'test'):
c = ssh_module.update_mgrs(1, [parse_host_specs('test:0.0.0.0')])
[out] = self._wait(ssh_module, c)
assert "(Re)deployed mgr." in out
assert " on host 'test'" in out
@mock.patch("ssh.module.SSHOrchestrator._run_cephadm", _run_cephadm('{}'))
@mock.patch("ssh.module.SSHOrchestrator.send_command")
@mock.patch("ssh.module.SSHOrchestrator.mon_command", mon_command)
@mock.patch("ssh.module.SSHOrchestrator._get_connection")
def test_create_osds(self, _send_command, _get_connection, ssh_module):
with self._with_host(ssh_module, 'test'):
dg = DriveGroupSpec('test', DeviceSelection(paths=['']))
c = ssh_module.create_osds(dg)
assert self._wait(ssh_module, c) == "Created osd(s) on host 'test'"
@mock.patch("ssh.module.SSHOrchestrator._run_cephadm", _run_cephadm('{}'))
@mock.patch("ssh.module.SSHOrchestrator.send_command")
@mock.patch("ssh.module.SSHOrchestrator.mon_command", mon_command)
@mock.patch("ssh.module.SSHOrchestrator._get_connection")
def test_mds(self, _send_command, _get_connection, ssh_module):
with self._with_host(ssh_module, 'test'):
ps = PlacementSpec(nodes=['test'])
c = ssh_module.add_mds(StatelessServiceSpec('name', ps))
[out] = self._wait(ssh_module, c)
assert "(Re)deployed mds.name." in out
assert " on host 'test'" in out
@mock.patch("ssh.module.SSHOrchestrator._run_cephadm", _run_cephadm('{}'))
@mock.patch("ssh.module.SSHOrchestrator.send_command")
@mock.patch("ssh.module.SSHOrchestrator.mon_command", mon_command)
@mock.patch("ssh.module.SSHOrchestrator._get_connection")
def test_rgw(self, _send_command, _get_connection, ssh_module):
with self._with_host(ssh_module, 'test'):
ps = PlacementSpec(nodes=['test'])
c = ssh_module.add_rgw(RGWSpec('realm', 'zone', ps))
[out] = self._wait(ssh_module, c)
assert "(Re)deployed rgw.realm.zone." in out
assert " on host 'test'" in out
@mock.patch("ssh.module.SSHOrchestrator._run_cephadm", _run_cephadm(
json.dumps([
dict(
name='rgw.myrgw.foobar',
style='cephadm',
fsid='fsid',
container_id='container_id',
version='version',
state='running',
)
])
))
def test_remove_rgw(self, ssh_module):
ssh_module._cluster_fsid = "fsid"
with self._with_host(ssh_module, 'test'):
c = ssh_module.remove_rgw('myrgw')
out = self._wait(ssh_module, c)
assert out == ["Removed rgw.myrgw.foobar from host 'test'"]
@mock.patch("ssh.module.SSHOrchestrator._run_cephadm", _run_cephadm('{}'))
@mock.patch("ssh.module.SSHOrchestrator.send_command")
@mock.patch("ssh.module.SSHOrchestrator.mon_command", mon_command)
@mock.patch("ssh.module.SSHOrchestrator._get_connection")
def test_rbd_mirror(self, _send_command, _get_connection, ssh_module):
with self._with_host(ssh_module, 'test'):
ps = PlacementSpec(nodes=['test'])
c = ssh_module.add_rbd_mirror(StatelessServiceSpec('name', ps))
[out] = self._wait(ssh_module, c)
assert "(Re)deployed rbd-mirror." in out
assert " on host 'test'" in out
@mock.patch("ssh.module.SSHOrchestrator._run_cephadm", _run_cephadm('{}'))
@mock.patch("ssh.module.SSHOrchestrator.send_command")
@mock.patch("ssh.module.SSHOrchestrator.mon_command", mon_command)
@mock.patch("ssh.module.SSHOrchestrator._get_connection")
def test_blink_device_light(self, _send_command, _get_connection, ssh_module):
with self._with_host(ssh_module, 'test'):
c = ssh_module.blink_device_light('ident', True, [('test', '')])
assert self._wait(ssh_module, c) == ['Set ident light for test: on']

View File

@ -5,11 +5,11 @@ skipsdist = true
[testenv]
setenv = UNITTEST = true
deps = -r requirements.txt
commands = pytest -v --cov --cov-append --cov-report=term --doctest-modules {posargs:mgr_util.py tests/ ssh/}
commands = pytest -v --cov --cov-append --cov-report=term --doctest-modules {posargs:mgr_util.py tests/ cephadm/}
[testenv:mypy]
basepython = python3
deps =
-r requirements.txt
mypy
commands = mypy --config-file=../../mypy.ini orchestrator.py ssh/module.py rook/module.py
commands = mypy --config-file=../../mypy.ini orchestrator.py cephadm/module.py rook/module.py

View File

@ -152,7 +152,7 @@ redirect=0
smallmds=0
short=0
ec=0
ssh=0
cephadm=0
parallel=true
hitset=""
overwrite_conf=1
@ -237,7 +237,7 @@ usage=$usage"\t--crimson: use crimson-osd instead of ceph-osd\n"
usage=$usage"\t--osd-args: specify any extra osd specific options\n"
usage=$usage"\t--bluestore-devs: comma-separated list of blockdevs to use for bluestore\n"
usage=$usage"\t--inc-osd: append some more osds into existing vcluster\n"
usage=$usage"\t--ssh: enable ssh orchestrator with ~/.ssh/id_rsa[.pub]\n"
usage=$usage"\t--cephadm: enable cephadm orchestrator with ~/.ssh/id_rsa[.pub]\n"
usage=$usage"\t--no-parallel: dont start all OSDs in parallel\n"
usage_exit() {
@ -299,8 +299,8 @@ case $1 in
--msgr21 )
msgr="21"
;;
--ssh )
ssh=1
--cephadm )
cephadm=1
;;
--no-parallel )
parallel=false
@ -999,12 +999,12 @@ EOF
fi
fi
if [ "$ssh" -eq 1 ]; then
debug echo Enabling ssh orchestrator
if [ "$cephadm" -eq 1 ]; then
debug echo Enabling cephadm orchestrator
ceph_adm config-key set mgr/ssh/ssh_identity_key -i ~/.ssh/id_rsa
ceph_adm config-key set mgr/ssh/ssh_identity_pub -i ~/.ssh/id_rsa.pub
ceph_adm mgr module enable ssh
ceph_adm orchestrator set backend ssh
ceph_adm mgr module enable cephadm
ceph_adm orchestrator set backend cephadm
ceph_adm orchestrator host add $HOSTNAME
fi
}