# Get and check ports explicitly required to be opened
daemon_ports = [] # type: List[int]
- if ctx.tcp_ports:
- daemon_ports = list(map(int, ctx.tcp_ports.split()))
+
+ # only check port in use if not reconfig or redeploy since service
+ # we are redeploying/reconfiguring will already be using the port
+ if not ctx.reconfig and not redeploy:
+ if ctx.tcp_ports:
+ daemon_ports = list(map(int, ctx.tcp_ports.split()))
if daemon_type in Ceph.daemons:
config, keyring = get_config_and_keyring(ctx)
if haspec.keepalived_container_image:
image = haspec.keepalived_container_image
- cephadm_config, deps = self.mgr.cephadm_services[daemon_type_to_service(daemon_spec.daemon_type)].generate_config(
- daemon_spec)
-
# TCP port to open in the host firewall
if len(ports) > 0:
daemon_spec.extra_args.extend([
[
'--name', daemon_spec.name(),
] + daemon_spec.extra_args,
- stdin=json.dumps(cephadm_config),
+ stdin=json.dumps(daemon_spec.final_config),
image=image)
if not code and daemon_spec.host in self.mgr.cache.daemons:
# prime cached service state with what we (should have)
self.mgr.requires_post_actions.add(daemon_spec.daemon_type)
self.mgr.cache.invalidate_host_daemons(daemon_spec.host)
self.mgr.cache.update_daemon_config_deps(
- daemon_spec.host, daemon_spec.name(), deps, start_time)
+ daemon_spec.host, daemon_spec.name(), daemon_spec.deps, start_time)
self.mgr.cache.save_host(daemon_spec.host)
msg = "{} {} on host '{}'".format(
'Reconfigured' if reconfig else 'Deployed', daemon_spec.name(), daemon_spec.host)
# TCP ports used by the daemon
self.ports: List[int] = ports or []
+ # values to be populated during generate_config calls
+ # and then used in _run_cephadm
+ self.final_config: Dict[str, Any] = {}
+ self.deps: List[str] = []
+
def name(self) -> str:
return '%s.%s' % (self.daemon_type, self.daemon_id)
daemon_spec.ceph_conf = extra_config
daemon_spec.keyring = keyring
+ daemon_spec.final_config, daemon_spec.deps = self.generate_config(daemon_spec)
+
return daemon_spec
def _check_safe_to_destroy(self, mon_id: str) -> None:
daemon_spec.keyring = keyring
+ daemon_spec.final_config, daemon_spec.deps = self.generate_config(daemon_spec)
+
return daemon_spec
def get_active_daemon(self, daemon_descrs: List[DaemonDescription]) -> DaemonDescription:
})
daemon_spec.keyring = keyring
+ daemon_spec.final_config, daemon_spec.deps = self.generate_config(daemon_spec)
+
return daemon_spec
def get_active_daemon(self, daemon_descrs: List[DaemonDescription]) -> DaemonDescription:
daemon_spec.keyring = keyring
+ daemon_spec.final_config, daemon_spec.deps = self.generate_config(daemon_spec)
+
return daemon_spec
def get_keyring(self, rgw_id: str) -> str:
daemon_spec.keyring = keyring
+ daemon_spec.final_config, daemon_spec.deps = self.generate_config(daemon_spec)
+
return daemon_spec
daemon_spec.keyring = keyring
+ daemon_spec.final_config, daemon_spec.deps = self.generate_config(daemon_spec)
+
return daemon_spec
from ceph.deployment.service_spec import CustomContainerSpec
+from orchestrator import OrchestratorError
+
from .cephadmservice import CephadmService, CephadmDaemonSpec
logger = logging.getLogger(__name__)
def prepare_create(self, daemon_spec: CephadmDaemonSpec[CustomContainerSpec]) \
-> CephadmDaemonSpec:
assert self.TYPE == daemon_spec.daemon_type
+ if daemon_spec.spec is None:
+ # Exit here immediately because the required service
+ # spec to create a daemon is not provided. This is only
+ # provided when a service is applied via 'orch apply'
+ # command.
+ msg = "Required service specification not provided"
+ raise OrchestratorError(msg)
+ daemon_spec.final_config, daemon_spec.deps = self.generate_config(daemon_spec)
return daemon_spec
def generate_config(self, daemon_spec: CephadmDaemonSpec[CustomContainerSpec]) \
def prepare_create(self, daemon_spec: CephadmDaemonSpec[HA_RGWSpec]) -> CephadmDaemonSpec:
assert daemon_spec.daemon_type == 'haproxy' or daemon_spec.daemon_type == 'keepalived'
+ # if spec is not attached to daemon_spec it is likely a redeploy or reconfig and
+ # spec should be in spec store
+ if not daemon_spec.spec:
+ service_name: str = "ha-rgw." + daemon_spec.daemon_id.split('.')[0]
+ if service_name in self.mgr.spec_store.specs:
+ daemon_spec.spec = cast(
+ HA_RGWSpec, self.mgr.spec_store.specs.get(service_name))
assert daemon_spec.spec
if daemon_spec.daemon_type == 'haproxy':
logger.info('Create daemon %s on host %s with spec %s' % (
daemon_id, host, spec))
+
+ daemon_spec.final_config, daemon_spec.deps = self.haproxy_generate_config(daemon_spec)
+
return daemon_spec
def keepalived_prepare_create(self, daemon_spec: CephadmDaemonSpec[HA_RGWSpec]) -> CephadmDaemonSpec:
logger.info('Create daemon %s on host %s with spec %s' % (
daemon_id, host, spec))
+
+ daemon_spec.final_config, daemon_spec.deps = self.keepalived_generate_config(daemon_spec)
+
return daemon_spec
def haproxy_generate_config(self, daemon_spec: CephadmDaemonSpec) -> Tuple[Dict[str, Any], List[str]]:
def prepare_create(self, daemon_spec: CephadmDaemonSpec[IscsiServiceSpec]) -> CephadmDaemonSpec:
assert self.TYPE == daemon_spec.daemon_type
+ # if spec is not attached to daemon_spec it is likely a redeploy or reconfig and
+ # spec should be in spec store
+ if not daemon_spec.spec:
+ service_name: str = "iscsi." + daemon_spec.daemon_id.split('.')[0]
+ if service_name in self.mgr.spec_store.specs:
+ daemon_spec.spec = cast(
+ IscsiServiceSpec, self.mgr.spec_store.specs.get(service_name))
assert daemon_spec.spec
spec = daemon_spec.spec
daemon_spec.keyring = keyring
daemon_spec.extra_files = {'iscsi-gateway.cfg': igw_conf}
+ daemon_spec.final_config, daemon_spec.deps = self.generate_config(daemon_spec)
+
return daemon_spec
def config_dashboard(self, daemon_descrs: List[DaemonDescription]) -> None:
import errno
import logging
import os
-from typing import List, Any, Tuple, Dict
+from typing import List, Any, Tuple, Dict, cast
from mgr_module import HandleCommandResult
def prepare_create(self, daemon_spec: CephadmDaemonSpec) -> CephadmDaemonSpec:
assert self.TYPE == daemon_spec.daemon_type
+ daemon_spec.final_config, daemon_spec.deps = self.generate_config(daemon_spec)
return daemon_spec
def generate_config(self, daemon_spec: CephadmDaemonSpec) -> Tuple[Dict[str, Any], List[str]]:
def prepare_create(self, daemon_spec: CephadmDaemonSpec[AlertManagerSpec]) -> CephadmDaemonSpec:
assert self.TYPE == daemon_spec.daemon_type
+ # if spec is not attached to daemon_spec it is likely a redeploy or reconfig and
+ # spec should be in spec store
+ if not daemon_spec.spec:
+ service_name: str = "alertmanager"
+ if service_name in self.mgr.spec_store.specs:
+ daemon_spec.spec = cast(
+ AlertManagerSpec, self.mgr.spec_store.specs.get(service_name))
assert daemon_spec.spec
+ daemon_spec.final_config, daemon_spec.deps = self.generate_config(daemon_spec)
return daemon_spec
def generate_config(self, daemon_spec: CephadmDaemonSpec[AlertManagerSpec]) -> Tuple[Dict[str, Any], List[str]]:
def prepare_create(self, daemon_spec: CephadmDaemonSpec) -> CephadmDaemonSpec:
assert self.TYPE == daemon_spec.daemon_type
+ daemon_spec.final_config, daemon_spec.deps = self.generate_config(daemon_spec)
return daemon_spec
def generate_config(self, daemon_spec: CephadmDaemonSpec) -> Tuple[Dict[str, Any], List[str]]:
def prepare_create(self, daemon_spec: CephadmDaemonSpec) -> CephadmDaemonSpec:
assert self.TYPE == daemon_spec.daemon_type
+ daemon_spec.final_config, daemon_spec.deps = self.generate_config(daemon_spec)
return daemon_spec
def generate_config(self, daemon_spec: CephadmDaemonSpec) -> Tuple[Dict[str, Any], List[str]]:
import logging
-from typing import Dict, Tuple, Any, List
+from typing import Dict, Tuple, Any, List, cast
from ceph.deployment.service_spec import NFSServiceSpec
import rados
def prepare_create(self, daemon_spec: CephadmDaemonSpec[NFSServiceSpec]) -> CephadmDaemonSpec:
assert self.TYPE == daemon_spec.daemon_type
+ # if spec is not attached to daemon_spec it is likely a redeploy or reconfig and
+ # spec should be in spec store
+ if not daemon_spec.spec:
+ service_name: str = "nfs." + daemon_spec.daemon_id.split('.')[0]
+ if service_name in self.mgr.spec_store.specs:
+ daemon_spec.spec = cast(
+ NFSServiceSpec, self.mgr.spec_store.specs.get(service_name))
assert daemon_spec.spec
daemon_id = daemon_spec.daemon_id
host = daemon_spec.host
spec = daemon_spec.spec
+ daemon_spec.final_config, daemon_spec.deps = self.generate_config(daemon_spec)
+
logger.info('Create daemon %s on host %s with spec %s' % (
daemon_id, host, spec))
return daemon_spec
host=host,
daemon_type='osd',
)
+ daemon_spec.final_config, daemon_spec.deps = self.generate_config(daemon_spec)
CephadmServe(self.mgr)._create_daemon(
daemon_spec,
osd_uuid_map=osd_uuid_map)
_run_cephadm.assert_called_with('test', 'mon.test', 'deploy', [
'--name', 'mon.test', '--reconfig', '--config-json', '-'],
- stdin='{"config": "\\n\\n[mon]\\nk=v\\n", "keyring": ""}',
+ stdin='{"config": "\\n\\n[mon]\\nk=v\\n[mon.test]\\npublic network = 127.0.0.0/8\\n", '
+ + '"keyring": "", "files": {"config": "[mon.test]\\npublic network = 127.0.0.0/8\\n"}}',
image='')
@mock.patch("cephadm.serve.CephadmServe._run_cephadm", _run_cephadm('{}'))
from unittest.mock import MagicMock, call
from cephadm.services.cephadmservice import MonService, MgrService, MdsService, RgwService, \
- RbdMirrorService, CrashService, CephadmExporter
+ RbdMirrorService, CrashService, CephadmExporter, CephadmDaemonSpec
from cephadm.services.iscsi import IscsiService
from cephadm.services.nfs import NFSService
from cephadm.services.osd import OSDService
return 0, 'value set', ''
return -1, '', 'error'
+ def get_minimal_ceph_conf(self) -> str:
+ return ''
+
class TestCephadmService:
def test_set_service_url_on_dashboard(self):
iscsi_spec.spec.daemon_type = "iscsi"
iscsi_spec.spec.ssl_cert = ''
- iscsi_service.prepare_create(iscsi_spec)
+ iscsi_daemon_spec = CephadmDaemonSpec(host='host', daemon_id='a', spec=iscsi_spec)
+
+ iscsi_service.prepare_create(iscsi_daemon_spec)
expected_caps = ['mon',
'profile rbd, allow command "osd blocklist", allow command "config-key get" with "key" prefix "iscsi/"',