blob: 3032b677f93172e072d087cba860d89c3721bfd5 [file] [log] [blame]
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Cloudwatt driver.
"""
try:
import simplejson as json
except ImportError:
import json
from libcloud.utils.py3 import httplib
from libcloud.compute.types import Provider
from libcloud.compute.drivers.openstack import OpenStack_1_1_Connection
from libcloud.compute.drivers.openstack import OpenStack_1_1_NodeDriver
from libcloud.common.openstack_identity import OpenStackIdentityConnection
from libcloud.utils.iso8601 import parse_date
from libcloud.compute.types import InvalidCredsError, MalformedResponseError
__all__ = ["CloudwattNodeDriver"]
BASE_URL = "https://identity.fr1.cloudwatt.com/v2.0"
AUTH_URL = BASE_URL + "/tokens"
class CloudwattAuthConnection(OpenStackIdentityConnection):
"""
AuthConnection class for the Cloudwatt driver.
"""
name = "Cloudwatt Auth"
def __init__(self, *args, **kwargs):
self._ex_tenant_id = kwargs.pop("ex_tenant_id")
super(CloudwattAuthConnection, self).__init__(*args, **kwargs)
def morph_action_hook(self, action):
(_, _, _, request_path) = self._tuple_from_url(self.auth_url)
if request_path == "":
# No path is provided in the auth_url, use action passed to this
# method.
return action
return request_path
def authenticate(self, force=False):
reqbody = json.dumps(
{
"auth": {
"passwordCredentials": {
"username": self.user_id,
"password": self.key,
},
"tenantId": self._ex_tenant_id,
}
}
)
resp = self.request("/tokens", data=reqbody, headers={}, method="POST")
if resp.status == httplib.UNAUTHORIZED:
# HTTP UNAUTHORIZED (401): auth failed
raise InvalidCredsError()
elif resp.status != httplib.OK:
body = "code: %s body:%s" % (resp.status, resp.body)
raise MalformedResponseError(
"Malformed response", body=body, driver=self.driver
)
else:
try:
body = json.loads(resp.body)
except Exception as e:
raise MalformedResponseError("Failed to parse JSON", e)
try:
expires = body["access"]["token"]["expires"]
self.auth_token = body["access"]["token"]["id"]
self.auth_token_expires = parse_date(expires)
self.urls = body["access"]["serviceCatalog"]
self.auth_user_info = None
except KeyError as e:
raise MalformedResponseError(
"Auth JSON response is \
missing required elements",
e,
)
return self
class CloudwattConnection(OpenStack_1_1_Connection):
"""
Connection class for the Cloudwatt driver.
"""
auth_url = BASE_URL
service_region = "fr1"
service_type = "compute"
def __init__(self, *args, **kwargs):
self.ex_tenant_id = kwargs.pop("ex_tenant_id")
super(CloudwattConnection, self).__init__(*args, **kwargs)
osa = CloudwattAuthConnection(
auth_url=AUTH_URL,
user_id=self.user_id,
key=self.key,
tenant_name=self._ex_tenant_name,
timeout=self.timeout,
ex_tenant_id=self.ex_tenant_id,
parent_conn=self,
)
self._osa = osa
self._auth_version = "2.0"
class CloudwattNodeDriver(OpenStack_1_1_NodeDriver):
"""
Implements the :class:`NodeDriver`'s for Cloudwatt.
"""
name = "Cloudwatt"
website = "https://www.cloudwatt.com/"
connectionCls = CloudwattConnection
type = Provider.CLOUDWATT
def __init__(
self,
key,
secret,
tenant_id,
secure=True,
tenant_name=None,
host=None,
port=None,
**kwargs,
):
"""
@inherits: :class:`NodeDriver.__init__`
:param tenant_id: ID of tenant required for Cloudwatt auth
:type tenant_id: ``str``
"""
self.ex_tenant_id = tenant_id
self.extra = {}
super(CloudwattNodeDriver, self).__init__(
key=key, secret=secret, secure=secure, host=host, port=port, **kwargs
)
def attach_volume(self, node, volume, device=None):
return super(CloudwattNodeDriver, self).attach_volume(node, volume, device)
def _ex_connection_class_kwargs(self):
"""
Includes ``tenant_id`` in Connection.
"""
return {"ex_tenant_id": self.ex_tenant_id}