Esempio n. 1
0
    def deploy_osd_daemons_for_existing_osds(
            self,
            host: str,
            service_name: str,
            replace_osd_ids: Optional[List[str]] = None) -> str:

        if replace_osd_ids is None:
            replace_osd_ids = OsdIdClaims(self.mgr).filtered_by_host(host)
            assert replace_osd_ids is not None
        # check result
        osds_elems: dict = CephadmServe(self.mgr)._run_cephadm_json(
            host, 'osd', 'ceph-volume', [
                '--',
                'lvm',
                'list',
                '--format',
                'json',
            ])
        before_osd_uuid_map = self.mgr.get_osd_uuid_map(only_up=True)
        fsid = self.mgr._cluster_fsid
        osd_uuid_map = self.mgr.get_osd_uuid_map()
        created = []
        for osd_id, osds in osds_elems.items():
            for osd in osds:
                if osd['type'] == 'db':
                    continue
                if osd['tags']['ceph.cluster_fsid'] != fsid:
                    logger.debug('mismatched fsid, skipping %s' % osd)
                    continue
                if osd_id in before_osd_uuid_map and osd_id not in replace_osd_ids:
                    # if it exists but is part of the replacement operation, don't skip
                    continue
                if osd_id not in osd_uuid_map:
                    logger.debug(
                        'osd id {} does not exist in cluster'.format(osd_id))
                    continue
                if osd_uuid_map.get(osd_id) != osd['tags']['ceph.osd_fsid']:
                    logger.debug('mismatched osd uuid (cluster has %s, osd '
                                 'has %s)' % (osd_uuid_map.get(osd_id),
                                              osd['tags']['ceph.osd_fsid']))
                    continue

                created.append(osd_id)
                daemon_spec: CephadmDaemonDeploySpec = CephadmDaemonDeploySpec(
                    service_name=service_name,
                    daemon_id=osd_id,
                    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)

        if created:
            self.mgr.cache.invalidate_host_devices(host)
            self.mgr.cache.invalidate_autotune(host)
            return "Created osd(s) %s on host '%s'" % (','.join(created), host)
        else:
            return "Created no osd(s) on host %s; already created?" % host
Esempio n. 2
0
    def test_iscsi_client_caps(self):

        iscsi_daemon_spec = CephadmDaemonDeploySpec(
            host='host',
            daemon_id='a',
            service_name=self.iscsi_spec.service_name())

        self.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/"',
            'mgr', 'allow command "service status"', 'osd', 'allow rwx'
        ]

        expected_call = call({
            'prefix': 'auth get-or-create',
            'entity': 'client.iscsi.a',
            'caps': expected_caps
        })
        expected_call2 = call({
            'prefix': 'auth caps',
            'entity': 'client.iscsi.a',
            'caps': expected_caps
        })

        assert expected_call in self.mgr.mon_command.mock_calls
        assert expected_call2 in self.mgr.mon_command.mock_calls
Esempio n. 3
0
    def test_iscsi_client_caps(self):
        mgr = FakeMgr()
        iscsi_service = self._get_services(mgr)['iscsi']

        iscsi_spec = IscsiServiceSpec(service_type='iscsi', service_id="a")
        iscsi_spec.daemon_type = "iscsi"
        iscsi_spec.daemon_id = "a"
        iscsi_spec.spec = MagicMock()
        iscsi_spec.spec.daemon_type = "iscsi"
        iscsi_spec.spec.ssl_cert = ''

        mgr.spec_store = MagicMock()
        mgr.spec_store.__getitem__.return_value = iscsi_spec

        iscsi_daemon_spec = CephadmDaemonDeploySpec(
            host='host', daemon_id='a', service_name=iscsi_spec.service_name())

        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/"',
                         'mgr', 'allow command "service status"',
                         'osd', 'allow rwx']

        expected_call = call({'prefix': 'auth get-or-create',
                              'entity': 'client.iscsi.a',
                              'caps': expected_caps})
        expected_call2 = call({'prefix': 'auth caps',
                               'entity': 'client.iscsi.a',
                               'caps': expected_caps})

        assert expected_call in mgr.mon_command.mock_calls
        assert expected_call2 in mgr.mon_command.mock_calls
Esempio n. 4
0
 def test_grafana_initial_admin_pw(self,
                                   cephadm_module: CephadmOrchestrator):
     with with_host(cephadm_module, 'test'):
         with with_service(cephadm_module, ServiceSpec('mgr')) as _, \
                 with_service(cephadm_module, GrafanaSpec(initial_admin_password='******')):
             out = cephadm_module.cephadm_services[
                 'grafana'].generate_config(
                     CephadmDaemonDeploySpec('test', 'daemon', 'grafana'))
             assert out == ({
                 'files': {
                     'grafana.ini':
                     '# This file is generated by cephadm.\n'
                     '[users]\n'
                     '  default_theme = light\n'
                     '[auth.anonymous]\n'
                     '  enabled = true\n'
                     "  org_name = 'Main Org.'\n"
                     "  org_role = 'Viewer'\n"
                     '[server]\n'
                     "  domain = 'bootstrap.storage.lab'\n"
                     '  protocol = https\n'
                     '  cert_file = /etc/grafana/certs/cert_file\n'
                     '  cert_key = /etc/grafana/certs/cert_key\n'
                     '  http_port = 3000\n'
                     '  http_addr = \n'
                     '[security]\n'
                     '  admin_user = admin\n'
                     '  admin_password = secure\n'
                     '  cookie_secure = true\n'
                     '  cookie_samesite = none\n'
                     '  allow_embedding = true',
                     'provisioning/datasources/ceph-dashboard.yml':
                     "# This file is generated by cephadm.\n"
                     'deleteDatasources:\n\n'
                     "  - name: 'Loki'\n"
                     '    orgId: 2\n\n'
                     'datasources:\n\n'
                     "  - name: 'Loki'\n"
                     "    type: 'loki'\n"
                     "    access: 'proxy'\n"
                     '    orgId: 2\n'
                     "    url: 'http://[1::4]:3100'\n"
                     '    basicAuth: false\n'
                     '    isDefault: true\n'
                     '    editable: false',
                     'certs/cert_file':
                     ANY,
                     'certs/cert_key':
                     ANY
                 }
             }, [])
Esempio n. 5
0
    def test_ingress_config(self, _run_cephadm,
                            cephadm_module: CephadmOrchestrator):
        _run_cephadm.side_effect = async_side_effect(('{}', '', 0))

        with with_host(cephadm_module, 'test'):
            cephadm_module.cache.update_host_networks(
                'test', {'1.2.3.0/24': {
                    'if0': ['1.2.3.4/32']
                }})

            # the ingress backend
            s = RGWSpec(service_id="foo",
                        placement=PlacementSpec(count=1),
                        rgw_frontend_type='beast')

            ispec = IngressSpec(service_type='ingress',
                                service_id='test',
                                backend_service='rgw.foo',
                                frontend_port=8089,
                                monitor_port=8999,
                                monitor_user='******',
                                monitor_password='******',
                                keepalived_password='******',
                                virtual_interface_networks=['1.2.3.0/24'],
                                virtual_ip="1.2.3.4/32")
            with with_service(cephadm_module,
                              s) as _, with_service(cephadm_module,
                                                    ispec) as _:
                # generate the keepalived conf based on the specified spec
                keepalived_generated_conf = cephadm_module.cephadm_services[
                    'ingress'].keepalived_generate_config(
                        CephadmDaemonDeploySpec(
                            host='test',
                            daemon_id='ingress',
                            service_name=ispec.service_name()))

                keepalived_expected_conf = {
                    'files': {
                        'keepalived.conf':
                        '# This file is generated by cephadm.\n'
                        'vrrp_script check_backend {\n    '
                        'script "/usr/bin/curl http://localhost:8999/health"\n    '
                        'weight -20\n    '
                        'interval 2\n    '
                        'rise 2\n    '
                        'fall 2\n}\n\n'
                        'vrrp_instance VI_0 {\n  '
                        'state MASTER\n  '
                        'priority 100\n  '
                        'interface if0\n  '
                        'virtual_router_id 51\n  '
                        'advert_int 1\n  '
                        'authentication {\n      '
                        'auth_type PASS\n      '
                        'auth_pass 12345\n  '
                        '}\n  '
                        'unicast_src_ip 1::4\n  '
                        'unicast_peer {\n  '
                        '}\n  '
                        'virtual_ipaddress {\n    '
                        '1.2.3.4/32 dev if0\n  '
                        '}\n  '
                        'track_script {\n      '
                        'check_backend\n  }\n'
                        '}'
                    }
                }

                # check keepalived config
                assert keepalived_generated_conf[0] == keepalived_expected_conf

                # generate the haproxy conf based on the specified spec
                haproxy_generated_conf = cephadm_module.cephadm_services[
                    'ingress'].haproxy_generate_config(
                        CephadmDaemonDeploySpec(
                            host='test',
                            daemon_id='ingress',
                            service_name=ispec.service_name()))

                haproxy_expected_conf = {
                    'files': {
                        'haproxy.cfg':
                        '# This file is generated by cephadm.'
                        '\nglobal\n    log         '
                        '127.0.0.1 local2\n    '
                        'chroot      /var/lib/haproxy\n    '
                        'pidfile     /var/lib/haproxy/haproxy.pid\n    '
                        'maxconn     8000\n    '
                        'daemon\n    '
                        'stats socket /var/lib/haproxy/stats\n'
                        '\ndefaults\n    '
                        'mode                    http\n    '
                        'log                     global\n    '
                        'option                  httplog\n    '
                        'option                  dontlognull\n    '
                        'option http-server-close\n    '
                        'option forwardfor       except 127.0.0.0/8\n    '
                        'option                  redispatch\n    '
                        'retries                 3\n    '
                        'timeout queue           20s\n    '
                        'timeout connect         5s\n    '
                        'timeout http-request    1s\n    '
                        'timeout http-keep-alive 5s\n    '
                        'timeout client          1s\n    '
                        'timeout server          1s\n    '
                        'timeout check           5s\n    '
                        'maxconn                 8000\n'
                        '\nfrontend stats\n    '
                        'mode http\n    '
                        'bind 1.2.3.4:8999\n    '
                        'bind localhost:8999\n    '
                        'stats enable\n    '
                        'stats uri /stats\n    '
                        'stats refresh 10s\n    '
                        'stats auth admin:12345\n    '
                        'http-request use-service prometheus-exporter if { path /metrics }\n    '
                        'monitor-uri /health\n'
                        '\nfrontend frontend\n    '
                        'bind 1.2.3.4:8089\n    '
                        'default_backend backend\n\n'
                        'backend backend\n    '
                        'option forwardfor\n    '
                        'balance static-rr\n    '
                        'option httpchk HEAD / HTTP/1.0\n    '
                        'server ' + haproxy_generated_conf[1][0] +
                        ' 1::4:80 check weight 100\n'
                    }
                }

                assert haproxy_generated_conf[0] == haproxy_expected_conf
Esempio n. 6
0
    def create_single_host(self,
                           drive_group: DriveGroupSpec,
                           host: str,
                           cmd: str,
                           replace_osd_ids: List[str],
                           env_vars: Optional[List[str]] = None) -> str:
        out, err, code = self._run_ceph_volume_command(host,
                                                       cmd,
                                                       env_vars=env_vars)

        if code == 1 and ', it is already prepared' in '\n'.join(err):
            # HACK: when we create against an existing LV, ceph-volume
            # returns an error and the above message.  To make this
            # command idempotent, tolerate this "error" and continue.
            logger.debug('the device was already prepared; continuing')
            code = 0
        if code:
            raise RuntimeError(
                'cephadm exited with an error code: %d, stderr:%s' %
                (code, '\n'.join(err)))

        # check result
        out, err, code = CephadmServe(self.mgr)._run_cephadm(
            host, 'osd', 'ceph-volume', [
                '--',
                'lvm',
                'list',
                '--format',
                'json',
            ])
        before_osd_uuid_map = self.mgr.get_osd_uuid_map(only_up=True)
        try:
            osds_elems = json.loads('\n'.join(out))
        except ValueError:
            logger.exception('Cannot decode JSON: \'%s\'' % '\n'.join(out))
            osds_elems = {}
        fsid = self.mgr._cluster_fsid
        osd_uuid_map = self.mgr.get_osd_uuid_map()
        created = []
        for osd_id, osds in osds_elems.items():
            for osd in osds:
                if osd['tags']['ceph.cluster_fsid'] != fsid:
                    logger.debug('mismatched fsid, skipping %s' % osd)
                    continue
                if osd_id in before_osd_uuid_map and osd_id not in replace_osd_ids:
                    # if it exists but is part of the replacement operation, don't skip
                    continue
                if osd_id not in osd_uuid_map:
                    logger.debug(
                        'osd id {} does not exist in cluster'.format(osd_id))
                    continue
                if osd_uuid_map.get(osd_id) != osd['tags']['ceph.osd_fsid']:
                    logger.debug('mismatched osd uuid (cluster has %s, osd '
                                 'has %s)' % (osd_uuid_map.get(osd_id),
                                              osd['tags']['ceph.osd_fsid']))
                    continue

                created.append(osd_id)
                daemon_spec: CephadmDaemonDeploySpec = CephadmDaemonDeploySpec(
                    service_name=drive_group.service_name(),
                    daemon_id=osd_id,
                    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)

        if created:
            self.mgr.cache.invalidate_host_devices(host)
            return "Created osd(s) %s on host '%s'" % (','.join(created), host)
        else:
            return "Created no osd(s) on host %s; already created?" % host