1 # -*- coding: utf-8 -*-
2 from __future__
import absolute_import
6 from orchestrator
import OrchestratorError
9 from urlparse
import urlparse
11 from urllib
.parse
import urlparse
13 from mgr_util
import merge_dicts
14 from .orchestrator
import OrchClient
18 class IscsiGatewayAlreadyExists(Exception):
19 def __init__(self
, gateway_name
):
20 super(IscsiGatewayAlreadyExists
, self
).__init
__(
21 "iSCSI gateway '{}' already exists".format(gateway_name
))
24 class IscsiGatewayDoesNotExist(Exception):
25 def __init__(self
, hostname
):
26 super(IscsiGatewayDoesNotExist
, self
).__init
__(
27 "iSCSI gateway '{}' does not exist".format(hostname
))
30 class InvalidServiceUrl(Exception):
31 def __init__(self
, service_url
):
32 super(InvalidServiceUrl
, self
).__init
__(
33 "Invalid service URL '{}'. "
34 "Valid format: '<scheme>://<username>:<password>@<host>[:port]'.".format(service_url
))
37 class ManagedByOrchestratorException(Exception):
39 super(ManagedByOrchestratorException
, self
).__init
__(
40 "iSCSI configuration is managed by the orchestrator")
43 _ISCSI_STORE_KEY
= "_iscsi_config"
46 class IscsiGatewaysConfig(object):
48 def _load_config_from_store(cls
):
49 json_db
= mgr
.get_store(_ISCSI_STORE_KEY
,
51 config
= json
.loads(json_db
)
52 cls
.update_iscsi_config(config
)
56 def update_iscsi_config(cls
, config
):
58 Since `ceph-iscsi` config v10, gateway names were renamed from host short name to FQDN.
59 If Ceph Dashboard were configured before v10, we try to update our internal gateways
60 database automatically.
62 for gateway_name
, gateway_config
in config
['gateways'].items():
63 if '.' not in gateway_name
:
64 from .iscsi_client
import IscsiClient
65 from ..rest_client
import RequestException
67 service_url
= gateway_config
['service_url']
68 new_gateway_name
= IscsiClient
.instance(
69 service_url
=service_url
).get_hostname()['data']
70 if gateway_name
!= new_gateway_name
:
71 config
['gateways'][new_gateway_name
] = gateway_config
72 del config
['gateways'][gateway_name
]
73 cls
._save
_config
(config
)
74 except RequestException
:
75 # If gateway is not acessible, it should be removed manually
76 # or we will try to update automatically next time
80 def _load_config_from_orchestrator():
81 config
= {'gateways': {}}
83 instances
= OrchClient().list_service_info("iscsi")
84 for instance
in instances
:
85 config
['gateways'][instance
.nodename
] = {
86 'service_url': instance
.service_url
88 except (RuntimeError, OrchestratorError
, ImportError):
93 def _save_config(cls
, config
):
94 mgr
.set_store(_ISCSI_STORE_KEY
, json
.dumps(config
))
97 def validate_service_url(cls
, service_url
):
98 url
= urlparse(service_url
)
99 if not url
.scheme
or not url
.hostname
or not url
.username
or not url
.password
:
100 raise InvalidServiceUrl(service_url
)
103 def add_gateway(cls
, name
, service_url
):
104 config
= cls
.get_gateways_config()
106 raise IscsiGatewayAlreadyExists(name
)
107 IscsiGatewaysConfig
.validate_service_url(service_url
)
108 config
['gateways'][name
] = {'service_url': service_url
}
109 cls
._save
_config
(config
)
112 def remove_gateway(cls
, name
):
113 if name
in cls
._load
_config
_from
_orchestrator
()['gateways']:
114 raise ManagedByOrchestratorException()
116 config
= cls
._load
_config
_from
_store
()
117 if name
not in config
['gateways']:
118 raise IscsiGatewayDoesNotExist(name
)
120 del config
['gateways'][name
]
121 cls
._save
_config
(config
)
124 def get_gateways_config(cls
):
125 orch_config
= cls
._load
_config
_from
_orchestrator
()
126 local_config
= cls
._load
_config
_from
_store
()
128 return {'gateways': merge_dicts(orch_config
['gateways'], local_config
['gateways'])}
131 def get_gateway_config(cls
, name
):
132 config
= IscsiGatewaysConfig
.get_gateways_config()
133 if name
not in config
['gateways']:
134 raise IscsiGatewayDoesNotExist(name
)
135 return config
['gateways'][name
]