]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/pybind/mgr/orchestrator/module.py
update ceph source to reef 18.2.1
[ceph.git] / ceph / src / pybind / mgr / orchestrator / module.py
index 7d8703bde7b4f565b58d2093790e46845da115d8..de4777e0defa48ff63b34f044054a41989e736e1 100644 (file)
@@ -1,7 +1,7 @@
 import enum
 import errno
 import json
-from typing import List, Set, Optional, Iterator, cast, Dict, Any, Union, Sequence, Mapping
+from typing import List, Set, Optional, Iterator, cast, Dict, Any, Union, Sequence, Mapping, Tuple
 import re
 import datetime
 import math
@@ -19,6 +19,7 @@ from ceph.deployment.inventory import Device  # noqa: F401; pylint: disable=unus
 from ceph.deployment.drive_group import DriveGroupSpec, DeviceSelection, OSDMethod
 from ceph.deployment.service_spec import PlacementSpec, ServiceSpec, service_spec_allow_invalid_from_json, TracingSpec
 from ceph.deployment.hostspec import SpecValidationError
+from ceph.deployment.utils import unwrap_ipv6
 from ceph.utils import datetime_now
 
 from mgr_util import to_pretty_timedelta, format_bytes
@@ -30,7 +31,8 @@ from ._interface import OrchestratorClientMixin, DeviceLightLoc, _cli_read_comma
     NoOrchestrator, OrchestratorValidationError, NFSServiceSpec, \
     RGWSpec, InventoryFilter, InventoryHost, HostSpec, CLICommandMeta, \
     ServiceDescription, DaemonDescription, IscsiServiceSpec, json_to_generic_spec, \
-    GenericSpec, DaemonDescriptionStatus, SNMPGatewaySpec, MDSSpec, TunedProfileSpec
+    GenericSpec, DaemonDescriptionStatus, SNMPGatewaySpec, MDSSpec, TunedProfileSpec, \
+    NvmeofServiceSpec
 
 
 def nice_delta(now: datetime.datetime, t: Optional[datetime.datetime], suffix: str = '') -> str:
@@ -46,6 +48,10 @@ def nice_bytes(v: Optional[int]) -> str:
     return format_bytes(v, 5)
 
 
+class ArgumentError(Exception):
+    pass
+
+
 class HostDetails:
     def __init__(self,
                  host: Optional[HostSpec] = None,
@@ -129,6 +135,19 @@ class HostDetails:
 yaml.add_representer(HostDetails, HostDetails.yaml_representer)
 
 
+class DaemonFields(enum.Enum):
+    service_name = 'service_name'
+    daemon_type = 'daemon_type'
+    name = 'name'
+    host = 'host'
+    status = 'status'
+    refreshed = 'refreshed'
+    age = 'age'
+    mem_use = 'mem_use'
+    mem_lim = 'mem_lim'
+    image = 'image'
+
+
 class ServiceType(enum.Enum):
     mon = 'mon'
     mgr = 'mgr'
@@ -146,6 +165,7 @@ class ServiceType(enum.Enum):
     rgw = 'rgw'
     nfs = 'nfs'
     iscsi = 'iscsi'
+    nvmeof = 'nvmeof'
     snmp_gateway = 'snmp-gateway'
     elasticsearch = 'elasticsearch'
     jaeger_agent = 'jaeger-agent'
@@ -173,6 +193,13 @@ class DaemonAction(enum.Enum):
 class IngressType(enum.Enum):
     default = 'default'
     keepalive_only = 'keepalive-only'
+    haproxy_standard = 'haproxy-standard'
+    haproxy_protocol = 'haproxy-protocol'
+
+    def canonicalize(self) -> "IngressType":
+        if self == self.default:
+            return IngressType(self.haproxy_standard)
+        return IngressType(self)
 
 
 def to_format(what: Any, format: Format, many: bool, cls: Any) -> Any:
@@ -453,6 +480,9 @@ class OrchestratorCli(OrchestratorClientMixin, MgrModule,
         if labels and len(labels) == 1:
             labels = labels[0].split(',')
 
+        if addr is not None:
+            addr = unwrap_ipv6(addr)
+
         s = HostSpec(hostname=hostname, addr=addr, labels=labels, status=_status)
 
         return self._apply_misc([s], False, Format.plain)
@@ -465,9 +495,9 @@ class OrchestratorCli(OrchestratorClientMixin, MgrModule,
         return HandleCommandResult(stdout=completion.result_str())
 
     @_cli_write_command('orch host drain')
-    def _drain_host(self, hostname: str, force: bool = False) -> HandleCommandResult:
+    def _drain_host(self, hostname: str, force: bool = False, keep_conf_keyring: bool = False, zap_osd_devices: bool = False) -> HandleCommandResult:
         """drain all daemons from a host"""
-        completion = self.drain_host(hostname, force)
+        completion = self.drain_host(hostname, force, keep_conf_keyring, zap_osd_devices)
         raise_if_exception(completion)
         return HandleCommandResult(stdout=completion.result_str())
 
@@ -801,6 +831,7 @@ class OrchestratorCli(OrchestratorClientMixin, MgrModule,
                       service_name: Optional[str] = None,
                       daemon_type: Optional[str] = None,
                       daemon_id: Optional[str] = None,
+                      sort_by: Optional[DaemonFields] = DaemonFields.name,
                       format: Format = Format.plain,
                       refresh: bool = False) -> HandleCommandResult:
         """
@@ -816,6 +847,31 @@ class OrchestratorCli(OrchestratorClientMixin, MgrModule,
 
         def ukn(s: Optional[str]) -> str:
             return '<unknown>' if s is None else s
+
+        def sort_by_field(d: DaemonDescription) -> Any:
+            if sort_by == DaemonFields.name:
+                return d.name()
+            elif sort_by == DaemonFields.host:
+                return d.hostname
+            elif sort_by == DaemonFields.status:
+                return d.status.name if d.status else None
+            elif sort_by == DaemonFields.refreshed:
+                return d.last_refresh
+            elif sort_by == DaemonFields.age:
+                return d.created
+            elif sort_by == DaemonFields.mem_use:
+                return d.memory_usage
+            elif sort_by == DaemonFields.mem_lim:
+                return d.memory_request
+            elif sort_by == DaemonFields.image:
+                return d.container_image_id
+            elif sort_by == DaemonFields.daemon_type:
+                return d.daemon_type
+            elif sort_by == DaemonFields.service_name:
+                return d.service_name()
+            else:
+                return None
+
         # Sort the list for display
         daemons.sort(key=lambda s: (ukn(s.daemon_type), ukn(s.hostname), ukn(s.daemon_id)))
 
@@ -839,7 +895,7 @@ class OrchestratorCli(OrchestratorClientMixin, MgrModule,
             table._align['MEM LIM'] = 'r'
             table.left_padding_width = 0
             table.right_padding_width = 2
-            for s in natsorted(daemons, key=lambda d: d.name()):
+            for s in natsorted(daemons, key=lambda d: sort_by_field(d)):
                 if s.status_desc:
                     status = s.status_desc
                 else:
@@ -874,13 +930,57 @@ class OrchestratorCli(OrchestratorClientMixin, MgrModule,
 
             return HandleCommandResult(stdout=table.get_string())
 
-    @_cli_write_command('orch prometheus access info')
+    def _get_credentials(self, username: Optional[str] = None, password: Optional[str] = None, inbuf: Optional[str] = None) -> Tuple[str, str]:
+
+        _username = username
+        _password = password
+        if inbuf:
+            try:
+                credentials = json.loads(inbuf)
+                _username = credentials['username'].strip()
+                _password = credentials['password'].strip()
+            except (KeyError, json.JSONDecodeError):
+                raise ArgumentError("""
+                json provided for credentials did not include all necessary fields. Please setup json file as:
+
+                {
+                   "username": "USERNAME",
+                   "password": "PASSWORD"
+                }
+                """)
+
+        if not _username or not _password:
+            raise ArgumentError("Invalid arguments. Please provide arguments <username> <password> or -i <credentials_json_file>")
+
+        return _username, _password
+
+    @_cli_write_command('orch prometheus set-credentials')
+    def _set_prometheus_access_info(self, username: Optional[str] = None, password: Optional[str] = None, inbuf: Optional[str] = None) -> HandleCommandResult:
+        try:
+            username, password = self._get_credentials(username, password, inbuf)
+            completion = self.set_prometheus_access_info(username, password)
+            result = raise_if_exception(completion)
+            return HandleCommandResult(stdout=json.dumps(result))
+        except ArgumentError as e:
+            return HandleCommandResult(-errno.EINVAL, "", (str(e)))
+
+    @_cli_write_command('orch alertmanager set-credentials')
+    def _set_alertmanager_access_info(self, username: Optional[str] = None, password: Optional[str] = None, inbuf: Optional[str] = None) -> HandleCommandResult:
+        try:
+            username, password = self._get_credentials(username, password, inbuf)
+            completion = self.set_alertmanager_access_info(username, password)
+            result = raise_if_exception(completion)
+            return HandleCommandResult(stdout=json.dumps(result))
+        except ArgumentError as e:
+            return HandleCommandResult(-errno.EINVAL, "", (str(e)))
+
+    @_cli_write_command('orch prometheus get-credentials')
     def _get_prometheus_access_info(self) -> HandleCommandResult:
         completion = self.get_prometheus_access_info()
         access_info = raise_if_exception(completion)
         return HandleCommandResult(stdout=json.dumps(access_info))
 
-    @_cli_write_command('orch alertmanager access info')
+    @_cli_write_command('orch alertmanager get-credentials')
     def _get_alertmanager_access_info(self) -> HandleCommandResult:
         completion = self.get_alertmanager_access_info()
         access_info = raise_if_exception(completion)
@@ -1148,6 +1248,22 @@ Usage:
         )
         return self._daemon_add_misc(spec)
 
+    @_cli_write_command('orch daemon add nvmeof')
+    def _nvmeof_add(self,
+                    pool: str,
+                    placement: Optional[str] = None,
+                    inbuf: Optional[str] = None) -> HandleCommandResult:
+        """Start nvmeof daemon(s)"""
+        if inbuf:
+            raise OrchestratorValidationError('unrecognized command -i; -h or --help for usage')
+
+        spec = NvmeofServiceSpec(
+            service_id='nvmeof',
+            pool=pool,
+            placement=PlacementSpec.from_string(placement),
+        )
+        return self._daemon_add_misc(spec)
+
     @_cli_write_command('orch')
     def _service_action(self, action: ServiceAction, service_name: str) -> HandleCommandResult:
         """Start, stop, restart, redeploy, or reconfig an entire service (i.e. all daemons)"""
@@ -1296,6 +1412,7 @@ Usage:
                    realm: Optional[str] = None,
                    zonegroup: Optional[str] = None,
                    zone: Optional[str] = None,
+                   networks: Optional[List[str]] = None,
                    port: Optional[int] = None,
                    ssl: bool = False,
                    dry_run: bool = False,
@@ -1319,6 +1436,7 @@ Usage:
             rgw_realm=realm,
             rgw_zonegroup=zonegroup,
             rgw_zone=zone,
+            networks=networks,
             rgw_frontend_port=port,
             ssl=ssl,
             placement=PlacementSpec.from_string(placement),
@@ -1387,6 +1505,31 @@ Usage:
 
         return self._apply_misc([spec], dry_run, format, no_overwrite)
 
+    @_cli_write_command('orch apply nvmeof')
+    def _apply_nvmeof(self,
+                      pool: str,
+                      placement: Optional[str] = None,
+                      unmanaged: bool = False,
+                      dry_run: bool = False,
+                      format: Format = Format.plain,
+                      no_overwrite: bool = False,
+                      inbuf: Optional[str] = None) -> HandleCommandResult:
+        """Scale an nvmeof service"""
+        if inbuf:
+            raise OrchestratorValidationError('unrecognized command -i; -h or --help for usage')
+
+        spec = NvmeofServiceSpec(
+            service_id=pool,
+            pool=pool,
+            placement=PlacementSpec.from_string(placement),
+            unmanaged=unmanaged,
+            preview_only=dry_run
+        )
+
+        spec.validate()  # force any validation exceptions to be caught correctly
+
+        return self._apply_misc([spec], dry_run, format, no_overwrite)
+
     @_cli_write_command('orch apply snmp-gateway')
     def _apply_snmp_gateway(self,
                             snmp_version: SNMPGatewaySpec.SNMPVersion,