From 61c34caa978931a2d46147a81ff67fa2a469035f Mon Sep 17 00:00:00 2001 From: Zack Cerza Date: Thu, 27 Apr 2017 15:01:08 -0600 Subject: [PATCH] orchestra/daemon: Convert to a subpackage Signed-off-by: Zack Cerza --- teuthology/orchestra/daemon/__init__.py | 1 + teuthology/orchestra/daemon/group.py | 163 +++++++++++++++++ .../orchestra/{daemon.py => daemon/state.py} | 173 +----------------- 3 files changed, 167 insertions(+), 170 deletions(-) create mode 100644 teuthology/orchestra/daemon/__init__.py create mode 100644 teuthology/orchestra/daemon/group.py rename teuthology/orchestra/{daemon.py => daemon/state.py} (59%) diff --git a/teuthology/orchestra/daemon/__init__.py b/teuthology/orchestra/daemon/__init__.py new file mode 100644 index 0000000000..ff8be0c674 --- /dev/null +++ b/teuthology/orchestra/daemon/__init__.py @@ -0,0 +1 @@ +from teuthology.orchestra.daemon.group import DaemonGroup # noqa diff --git a/teuthology/orchestra/daemon/group.py b/teuthology/orchestra/daemon/group.py new file mode 100644 index 0000000000..37d5d49f7c --- /dev/null +++ b/teuthology/orchestra/daemon/group.py @@ -0,0 +1,163 @@ +from teuthology import misc +from teuthology.orchestra.daemon.state import DaemonState + + +class DaemonGroup(object): + """ + Collection of daemon state instances + """ + def __init__(self, use_init=False): + """ + self.daemons is a dictionary indexed by role. Each entry is a + dictionary of DaemonState values indexed by an id parameter. + """ + self.daemons = {} + self.use_init = use_init + + def add_daemon(self, remote, type_, id_, *args, **kwargs): + """ + Add a daemon. If there already is a daemon for this id_ and role, stop + that daemon. (Re)start the daemon once the new value is set. + + :param remote: Remote site + :param type_: type of daemon (osd, mds, mon, rgw, for example) + :param id_: Id (index into role dictionary) + :param args: Daemonstate positional parameters + :param kwargs: Daemonstate keyword parameters + """ + # for backwards compatibility with older ceph-qa-suite branches, + # we can only get optional args from unused kwargs entries + self.register_daemon(remote, type_, id_, *args, **kwargs) + cluster = kwargs.pop('cluster', 'ceph') + role = cluster + '.' + type_ + if not self.use_init: + self.daemons[role][id_].restart() + + def register_daemon(self, remote, type_, id_, *args, **kwargs): + """ + Add a daemon. If there already is a daemon for this id_ and role, stop + that daemon. + + :param remote: Remote site + :param type_: type of daemon (osd, mds, mon, rgw, for example) + :param id_: Id (index into role dictionary) + :param args: Daemonstate positional parameters + :param kwargs: Daemonstate keyword parameters + """ + # for backwards compatibility with older ceph-qa-suite branches, + # we can only get optional args from unused kwargs entries + cluster = kwargs.pop('cluster', 'ceph') + role = cluster + '.' + type_ + if role not in self.daemons: + self.daemons[role] = {} + if id_ in self.daemons[role]: + self.daemons[role][id_].stop() + self.daemons[role][id_] = None + self.daemons[role][id_] = DaemonState( + remote, role, id_, self.use_init, *args, **kwargs) + + def get_daemon(self, type_, id_, cluster='ceph'): + """ + get the daemon associated with this id_ for this role. + + :param type_: type of daemon (osd, mds, mon, rgw, for example) + :param id_: Id (index into role dictionary) + """ + role = cluster + '.' + type_ + if role not in self.daemons: + return None + return self.daemons[role].get(str(id_), None) + + def iter_daemons_of_role(self, type_, cluster='ceph'): + """ + Iterate through all daemon instances for this role. Return dictionary + of daemon values. + + :param type_: type of daemon (osd, mds, mon, rgw, for example) + """ + role = cluster + '.' + type_ + return self.daemons.get(role, {}).values() + + def resolve_role_list(self, roles, types, cluster_aware=False): + """ + Resolve a configuration setting that may be None or contain wildcards + into a list of roles (where a role is e.g. 'mds.a' or 'osd.0'). This + is useful for tasks that take user input specifying a flexible subset + of the available roles. + + The task calling this must specify what kinds of roles it can can + handle using the ``types`` argument, where a role type is 'osd' or + 'mds' for example. When selecting roles this is used as a filter, or + when an explicit list of roles is passed, the an exception is raised if + any are not of a suitable type. + + Examples: + + :: + + # Passing None (i.e. user left config blank) defaults to all roles + # (filtered by ``types``) + None, types=['osd', 'mds', 'mon'] -> + ['osd.0', 'osd.1', 'osd.2', 'mds.a', mds.b', 'mon.a'] + # Wildcards are expanded + roles=['mds.*', 'osd.0'], types=['osd', 'mds', 'mon'] -> + ['mds.a', 'mds.b', 'osd.0'] + # Boring lists are unaltered + roles=['osd.0', 'mds.a'], types=['osd', 'mds', 'mon'] -> + ['osd.0', 'mds.a'] + # Entries in role list that don't match types result in an + # exception + roles=['osd.0', 'mds.a'], types=['osd'] -> RuntimeError + + :param roles: List (of roles or wildcards) or None (select all suitable + roles) + :param types: List of acceptable role types, for example + ['osd', 'mds']. + :param cluster_aware: bool to determine whether to consider include + cluster in the returned roles - just for + backwards compatibility with pre-jewel versions + of ceph-qa-suite + :return: List of strings like ["mds.0", "osd.2"] + """ + assert (isinstance(roles, list) or roles is None) + + resolved = [] + if roles is None: + # Handle default: all roles available + for type_ in types: + for role, daemons in self.daemons.items(): + if not role.endswith('.' + type_): + continue + for daemon in daemons.values(): + prefix = type_ + if cluster_aware: + prefix = daemon.role + resolved.append(prefix + '.' + daemon.id_) + else: + # Handle explicit list of roles or wildcards + for raw_role in roles: + try: + cluster, role_type, role_id = misc.split_role(raw_role) + except ValueError: + msg = ("Invalid role '{0}', roles must be of format " + "[.].").format(raw_role) + raise RuntimeError(msg) + + if role_type not in types: + msg = "Invalid role type '{0}' in role '{1}'".format( + role_type, raw_role) + raise RuntimeError(msg) + + if role_id == "*": + # Handle wildcard, all roles of the type + for daemon in self.iter_daemons_of_role(role_type, + cluster=cluster): + prefix = role_type + if cluster_aware: + prefix = daemon.role + resolved.append(prefix + '.' + daemon.id_) + else: + # Handle explicit role + resolved.append(raw_role) + + return resolved \ No newline at end of file diff --git a/teuthology/orchestra/daemon.py b/teuthology/orchestra/daemon/state.py similarity index 59% rename from teuthology/orchestra/daemon.py rename to teuthology/orchestra/daemon/state.py index 7bd231066d..3f8672894d 100644 --- a/teuthology/orchestra/daemon.py +++ b/teuthology/orchestra/daemon/state.py @@ -1,15 +1,12 @@ import logging -import struct import re - +import struct from cStringIO import StringIO -from . import run -from .. import misc from teuthology.exceptions import CommandFailedError +from teuthology.orchestra import run log = logging.getLogger(__name__) - systemd_cmd_templ = 'sudo systemctl {action} {daemon}@{id_}' @@ -297,168 +294,4 @@ class DaemonState(object): exit_code, self.remote, ) - return exit_code - - - - - -class DaemonGroup(object): - """ - Collection of daemon state instances - """ - def __init__(self, use_init=False): - """ - self.daemons is a dictionary indexed by role. Each entry is a - dictionary of DaemonState values indexed by an id parameter. - """ - self.daemons = {} - self.use_init = use_init - - def add_daemon(self, remote, type_, id_, *args, **kwargs): - """ - Add a daemon. If there already is a daemon for this id_ and role, stop - that daemon. (Re)start the daemon once the new value is set. - - :param remote: Remote site - :param type_: type of daemon (osd, mds, mon, rgw, for example) - :param id_: Id (index into role dictionary) - :param args: Daemonstate positional parameters - :param kwargs: Daemonstate keyword parameters - """ - # for backwards compatibility with older ceph-qa-suite branches, - # we can only get optional args from unused kwargs entries - self.register_daemon(remote, type_, id_, *args, **kwargs) - cluster = kwargs.pop('cluster', 'ceph') - role = cluster + '.' + type_ - if not self.use_init: - self.daemons[role][id_].restart() - - def register_daemon(self, remote, type_, id_, *args, **kwargs): - """ - Add a daemon. If there already is a daemon for this id_ and role, stop - that daemon. - - :param remote: Remote site - :param type_: type of daemon (osd, mds, mon, rgw, for example) - :param id_: Id (index into role dictionary) - :param args: Daemonstate positional parameters - :param kwargs: Daemonstate keyword parameters - """ - # for backwards compatibility with older ceph-qa-suite branches, - # we can only get optional args from unused kwargs entries - cluster = kwargs.pop('cluster', 'ceph') - role = cluster + '.' + type_ - if role not in self.daemons: - self.daemons[role] = {} - if id_ in self.daemons[role]: - self.daemons[role][id_].stop() - self.daemons[role][id_] = None - self.daemons[role][id_] = DaemonState( - remote, role, id_, self.use_init, *args, **kwargs) - - def get_daemon(self, type_, id_, cluster='ceph'): - """ - get the daemon associated with this id_ for this role. - - :param type_: type of daemon (osd, mds, mon, rgw, for example) - :param id_: Id (index into role dictionary) - """ - role = cluster + '.' + type_ - if role not in self.daemons: - return None - return self.daemons[role].get(str(id_), None) - - def iter_daemons_of_role(self, type_, cluster='ceph'): - """ - Iterate through all daemon instances for this role. Return dictionary - of daemon values. - - :param type_: type of daemon (osd, mds, mon, rgw, for example) - """ - role = cluster + '.' + type_ - return self.daemons.get(role, {}).values() - - def resolve_role_list(self, roles, types, cluster_aware=False): - """ - Resolve a configuration setting that may be None or contain wildcards - into a list of roles (where a role is e.g. 'mds.a' or 'osd.0'). This - is useful for tasks that take user input specifying a flexible subset - of the available roles. - - The task calling this must specify what kinds of roles it can can - handle using the ``types`` argument, where a role type is 'osd' or - 'mds' for example. When selecting roles this is used as a filter, or - when an explicit list of roles is passed, the an exception is raised if - any are not of a suitable type. - - Examples: - - :: - - # Passing None (i.e. user left config blank) defaults to all roles - # (filtered by ``types``) - None, types=['osd', 'mds', 'mon'] -> - ['osd.0', 'osd.1', 'osd.2', 'mds.a', mds.b', 'mon.a'] - # Wildcards are expanded - roles=['mds.*', 'osd.0'], types=['osd', 'mds', 'mon'] -> - ['mds.a', 'mds.b', 'osd.0'] - # Boring lists are unaltered - roles=['osd.0', 'mds.a'], types=['osd', 'mds', 'mon'] -> - ['osd.0', 'mds.a'] - # Entries in role list that don't match types result in an - # exception - roles=['osd.0', 'mds.a'], types=['osd'] -> RuntimeError - - :param roles: List (of roles or wildcards) or None (select all suitable - roles) - :param types: List of acceptable role types, for example - ['osd', 'mds']. - :param cluster_aware: bool to determine whether to consider include - cluster in the returned roles - just for - backwards compatibility with pre-jewel versions - of ceph-qa-suite - :return: List of strings like ["mds.0", "osd.2"] - """ - assert (isinstance(roles, list) or roles is None) - - resolved = [] - if roles is None: - # Handle default: all roles available - for type_ in types: - for role, daemons in self.daemons.items(): - if not role.endswith('.' + type_): - continue - for daemon in daemons.values(): - prefix = type_ - if cluster_aware: - prefix = daemon.role - resolved.append(prefix + '.' + daemon.id_) - else: - # Handle explicit list of roles or wildcards - for raw_role in roles: - try: - cluster, role_type, role_id = misc.split_role(raw_role) - except ValueError: - msg = ("Invalid role '{0}', roles must be of format " - "[.].").format(raw_role) - raise RuntimeError(msg) - - if role_type not in types: - msg = "Invalid role type '{0}' in role '{1}'".format( - role_type, raw_role) - raise RuntimeError(msg) - - if role_id == "*": - # Handle wildcard, all roles of the type - for daemon in self.iter_daemons_of_role(role_type, - cluster=cluster): - prefix = role_type - if cluster_aware: - prefix = daemon.role - resolved.append(prefix + '.' + daemon.id_) - else: - # Handle explicit role - resolved.append(raw_role) - - return resolved + return exit_code \ No newline at end of file -- 2.39.5