by the `rbd-target-api` service of the `ceph-iscsi <https://github.com/ceph/ceph-iscsi>`_
project. Please make sure that it's installed and enabled on the iSCSI gateways.
-The available iSCSI gateways must be defined using the following commands::
-
- $ ceph dashboard iscsi-gateway-list
- $ ceph dashboard iscsi-gateway-add <gateway_name> <scheme>://<username>:<password>@<host>[:port]
- $ ceph dashboard iscsi-gateway-rm <gateway_name>
-
If ceph-iscsi REST API is configured in HTTPS mode and its using a self-signed
certificate, then we need to configure the dashboard to avoid SSL certificate
verification when accessing ceph-iscsi API.
To disable API SSL verification run the following commmand::
- $ ceph dashboard iscsi-set-api-ssl-verification false
+ $ ceph dashboard set-iscsi-api-ssl-verification false
+
+The available iSCSI gateways must be defined using the following commands::
+
+ $ ceph dashboard iscsi-gateway-list
+ $ ceph dashboard iscsi-gateway-add <scheme>://<username>:<password>@<host>[:port]
+ $ ceph dashboard iscsi-gateway-rm <gateway_name>
.. _dashboard-grafana:
import errno
import json
-try:
- from urlparse import urlparse
-except ImportError:
- from urllib.parse import urlparse
-
from mgr_module import CLIReadCommand, CLIWriteCommand
-from .orchestrator import OrchClient
-from .. import mgr
-
-
-class IscsiGatewayAlreadyExists(Exception):
- def __init__(self, gateway_name):
- super(IscsiGatewayAlreadyExists, self).__init__(
- "iSCSI gateway '{}' already exists".format(gateway_name))
-
-
-class IscsiGatewayDoesNotExist(Exception):
- def __init__(self, hostname):
- super(IscsiGatewayDoesNotExist, self).__init__(
- "iSCSI gateway '{}' does not exist".format(hostname))
-
-
-class InvalidServiceUrl(Exception):
- def __init__(self, service_url):
- super(InvalidServiceUrl, self).__init__(
- "Invalid service URL '{}'. "
- "Valid format: '<scheme>://<username>:<password>@<host>[:port]'.".format(service_url))
-
-
-class ManagedByOrchestratorException(Exception):
- def __init__(self):
- super(ManagedByOrchestratorException, self).__init__(
- "iSCSI configuration is managed by the orchestrator")
-
-
-_ISCSI_STORE_KEY = "_iscsi_config"
-
-
-class IscsiGatewaysConfig(object):
- @classmethod
- def _load_config(cls):
- if OrchClient.instance().available():
- raise ManagedByOrchestratorException()
- json_db = mgr.get_store(_ISCSI_STORE_KEY,
- '{"gateways": {}}')
- return json.loads(json_db)
-
- @classmethod
- def _save_config(cls, config):
- mgr.set_store(_ISCSI_STORE_KEY, json.dumps(config))
-
- @classmethod
- def add_gateway(cls, name, service_url):
- config = cls._load_config()
- if name in config:
- raise IscsiGatewayAlreadyExists(name)
- url = urlparse(service_url)
- if not url.scheme or not url.hostname or not url.username or not url.password:
- raise InvalidServiceUrl(service_url)
- config['gateways'][name] = {'service_url': service_url}
- cls._save_config(config)
-
- @classmethod
- def remove_gateway(cls, name):
- config = cls._load_config()
- if name not in config['gateways']:
- raise IscsiGatewayDoesNotExist(name)
-
- del config['gateways'][name]
- cls._save_config(config)
-
- @classmethod
- def get_gateways_config(cls):
- try:
- config = cls._load_config()
- except ManagedByOrchestratorException:
- config = {'gateways': {}}
- instances = OrchClient.instance().list_service_info("iscsi")
- for instance in instances:
- config['gateways'][instance.nodename] = {
- 'service_url': instance.service_url
- }
- return config
-
- @classmethod
- def get_gateway_config(cls, name):
- config = IscsiGatewaysConfig.get_gateways_config()
- if name not in config['gateways']:
- raise IscsiGatewayDoesNotExist(name)
- return config['gateways'][name]
+from .iscsi_client import IscsiClient
+from .iscsi_config import IscsiGatewaysConfig, IscsiGatewayAlreadyExists, InvalidServiceUrl, \
+ ManagedByOrchestratorException, IscsiGatewayDoesNotExist
+from ..rest_client import RequestException
@CLIReadCommand('dashboard iscsi-gateway-list', desc='List iSCSI gateways')
@CLIWriteCommand('dashboard iscsi-gateway-add',
- 'name=name,type=CephString '
'name=service_url,type=CephString',
'Add iSCSI gateway configuration')
-def add_iscsi_gateway(_, name, service_url):
+def add_iscsi_gateway(_, service_url):
try:
+ IscsiGatewaysConfig.validate_service_url(service_url)
+ name = IscsiClient.instance(service_url=service_url).get_hostname()['data']
IscsiGatewaysConfig.add_gateway(name, service_url)
return 0, 'Success', ''
except IscsiGatewayAlreadyExists as ex:
return -errno.EINVAL, '', str(ex)
except ManagedByOrchestratorException as ex:
return -errno.EINVAL, '', str(ex)
+ except RequestException as ex:
+ return -errno.EINVAL, '', str(ex)
@CLIWriteCommand('dashboard iscsi-gateway-rm',
except ImportError:
from urllib.parse import urlparse
-from .iscsi_cli import IscsiGatewaysConfig
+from .iscsi_config import IscsiGatewaysConfig
from .. import logger
from ..settings import Settings
from ..rest_client import RestClient
service_url = None
@classmethod
- def instance(cls, gateway_name=None):
- if not gateway_name:
- gateway_name = list(IscsiGatewaysConfig.get_gateways_config()['gateways'].keys())[0]
- gateways_config = IscsiGatewaysConfig.get_gateway_config(gateway_name)
- service_url = gateways_config['service_url']
+ def instance(cls, gateway_name=None, service_url=None):
+ if not service_url:
+ if not gateway_name:
+ gateway_name = list(IscsiGatewaysConfig.get_gateways_config()['gateways'].keys())[0]
+ gateways_config = IscsiGatewaysConfig.get_gateway_config(gateway_name)
+ service_url = gateways_config['service_url']
instance = cls._instances.get(gateway_name)
if not instance or service_url != instance.service_url or \
instance = IscsiClient(host, port, IscsiClient._CLIENT_NAME, ssl,
auth, Settings.ISCSI_API_SSL_VERIFICATION)
instance.service_url = service_url
- cls._instances[gateway_name] = instance
+ if gateway_name:
+ cls._instances[gateway_name] = instance
return instance
def get_ip_addresses(self, request=None):
return request()
+ @RestClient.api_get('/api/sysinfo/hostname')
+ def get_hostname(self, request=None):
+ return request()
+
@RestClient.api_get('/api/config')
def get_config(self, request=None):
return request({
--- /dev/null
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
+import json
+
+try:
+ from urlparse import urlparse
+except ImportError:
+ from urllib.parse import urlparse
+
+from .orchestrator import OrchClient
+from .. import mgr
+
+
+class IscsiGatewayAlreadyExists(Exception):
+ def __init__(self, gateway_name):
+ super(IscsiGatewayAlreadyExists, self).__init__(
+ "iSCSI gateway '{}' already exists".format(gateway_name))
+
+
+class IscsiGatewayDoesNotExist(Exception):
+ def __init__(self, hostname):
+ super(IscsiGatewayDoesNotExist, self).__init__(
+ "iSCSI gateway '{}' does not exist".format(hostname))
+
+
+class InvalidServiceUrl(Exception):
+ def __init__(self, service_url):
+ super(InvalidServiceUrl, self).__init__(
+ "Invalid service URL '{}'. "
+ "Valid format: '<scheme>://<username>:<password>@<host>[:port]'.".format(service_url))
+
+
+class ManagedByOrchestratorException(Exception):
+ def __init__(self):
+ super(ManagedByOrchestratorException, self).__init__(
+ "iSCSI configuration is managed by the orchestrator")
+
+
+_ISCSI_STORE_KEY = "_iscsi_config"
+
+
+class IscsiGatewaysConfig(object):
+ @classmethod
+ def _load_config(cls):
+ if OrchClient.instance().available():
+ raise ManagedByOrchestratorException()
+ json_db = mgr.get_store(_ISCSI_STORE_KEY,
+ '{"gateways": {}}')
+ return json.loads(json_db)
+
+ @classmethod
+ def _save_config(cls, config):
+ mgr.set_store(_ISCSI_STORE_KEY, json.dumps(config))
+
+ @classmethod
+ def validate_service_url(cls, service_url):
+ url = urlparse(service_url)
+ if not url.scheme or not url.hostname or not url.username or not url.password:
+ raise InvalidServiceUrl(service_url)
+
+ @classmethod
+ def add_gateway(cls, name, service_url):
+ config = cls._load_config()
+ if name in config:
+ raise IscsiGatewayAlreadyExists(name)
+ IscsiGatewaysConfig.validate_service_url(service_url)
+ config['gateways'][name] = {'service_url': service_url}
+ cls._save_config(config)
+
+ @classmethod
+ def remove_gateway(cls, name):
+ config = cls._load_config()
+ if name not in config['gateways']:
+ raise IscsiGatewayDoesNotExist(name)
+
+ del config['gateways'][name]
+ cls._save_config(config)
+
+ @classmethod
+ def get_gateways_config(cls):
+ try:
+ config = cls._load_config()
+ except ManagedByOrchestratorException:
+ config = {'gateways': {}}
+ instances = OrchClient.instance().list_service_info("iscsi")
+ for instance in instances:
+ config['gateways'][instance.nodename] = {
+ 'service_url': instance.service_url
+ }
+ return config
+
+ @classmethod
+ def get_gateway_config(cls, name):
+ config = IscsiGatewaysConfig.get_gateways_config()
+ if name not in config['gateways']:
+ raise IscsiGatewayDoesNotExist(name)
+ return config['gateways'][name]
from ..controllers.iscsi import Iscsi, IscsiTarget
from ..services.iscsi_client import IscsiClient
from ..services.orchestrator import OrchClient
+from ..rest_client import RequestException
class IscsiTest(ControllerTestCase, CLICommandTestMixin):
def __init__(self):
self.gateway_name = None
+ self.service_url = None
self.config = {
"created": "2019/01/17 08:57:16",
"discovery_auth": {
}
@classmethod
- def instance(cls, gateway_name=None):
+ def instance(cls, gateway_name=None, service_url=None):
cls._instance.gateway_name = gateway_name
+ cls._instance.service_url = service_url
# pylint: disable=unused-argument
return cls._instance
}
return {'data': ips[self.gateway_name]}
+ def get_hostname(self):
+ hostnames = {
+ 'https://admin:admin@10.17.5.1:5001': 'node1',
+ 'https://admin:admin@10.17.5.2:5001': 'node2',
+ 'https://admin:admin@10.17.5.3:5001': 'node3'
+ }
+ if self.service_url not in hostnames:
+ raise RequestException('No route to host')
+ return {'data': hostnames[self.service_url]}
+
def update_discoveryauth(self, user, password, mutual_user, mutual_password):
self.config['discovery_auth']['username'] = user
self.config['discovery_auth']['password'] = password