blob: 13af56ad5b0e67fb97b5bbc5612e67943b909de7 [file] [log] [blame]
#
# Copyright 2016 RIFT.IO Inc
#
# Licensed 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.
#
import sys
import asyncio
from gi import require_version
require_version('RwCal', '1.0')
require_version('RwcalYang', '1.0')
require_version('RwTypes', '1.0')
require_version('RwCloudYang', '1.0')
require_version('RwCal', '1.0')
from gi.repository import (
RwTypes,
RwcalYang,
RwCloudYang,
)
import rw_peas
if sys.version_info < (3, 4, 4):
asyncio.ensure_future = asyncio.async
class PluginLoadingError(Exception):
pass
class CloudAccountCalError(Exception):
pass
class CloudAccount(object):
def __init__(self, log, rwlog_hdl, account_msg):
self._log = log
self._account_msg = account_msg.deep_copy()
self._cal_plugin = None
self._engine = None
self._cal = self.plugin.get_interface("Cloud")
self._cal.init(rwlog_hdl)
self._status = RwCloudYang.YangData_RwProject_Project_Cloud_Account_ConnectionStatus(
status="unknown",
details="Connection status lookup not started"
)
self._validate_task = None
@property
def plugin(self):
if self._cal_plugin is None:
try:
self._cal_plugin = rw_peas.PeasPlugin(
getattr(self._account_msg, self.account_type).plugin_name,
'RwCal-1.0',
)
except AttributeError as e:
raise PluginLoadingError(str(e))
self._engine, _, _ = self._cal_plugin()
return self._cal_plugin
def _wrap_status_fn(self, fn, *args, **kwargs):
ret = fn(*args, **kwargs)
rw_status = ret[0]
if rw_status != RwTypes.RwStatus.SUCCESS:
msg = "%s returned %s" % (fn.__name__, str(rw_status))
self._log.error(msg)
raise CloudAccountCalError(msg)
# If there was only one other return value besides rw_status, then just
# return that element. Otherwise return the rest of the return values
# as a list.
return ret[1] if len(ret) == 2 else ret[1:]
@property
def cal(self):
return self._cal
@property
def name(self):
return self._account_msg.name
@property
def account_msg(self):
return self._account_msg
@property
def cal_account_msg(self):
return RwcalYang.YangData_RwProject_Project_CloudAccounts_CloudAccountList.from_dict(
self.account_msg.as_dict(),
ignore_missing_keys=True,
)
def cloud_account_msg(self, account_dict):
self._account_msg = RwCloudYang.YangData_RwProject_Project_CloudAccounts_CloudAccountList.from_dict(account_dict)
@property
def account_type(self):
return self._account_msg.account_type
@property
def connection_status(self):
return self._status
def update_from_cfg(self, cfg):
self._log.debug("Updating parent CloudAccount to %s", cfg)
# Hack to catch updates triggered from apply_callback when a sdn-account is removed
# from a cloud-account. To be fixed properly when updates are handled
if (self.account_msg.name == cfg.name
and self.account_msg.account_type == cfg.account_type):
return
if cfg.has_field("sdn_account"):
self.account_msg.sdn_account = cfg.sdn_account
else:
raise NotImplementedError("Update cloud account not yet supported")
def create_image(self, image_info_msg):
image_id = self._wrap_status_fn(
self.cal.create_image, self.cal_account_msg, image_info_msg
)
return image_id
def get_image_list(self):
self._log.debug("Getting image list from account: %s", self.name)
resources = self._wrap_status_fn(
self.cal.get_image_list, self.cal_account_msg
)
return resources.imageinfo_list
@asyncio.coroutine
def validate_cloud_account_credentials(self, loop):
self._log.debug("Validating Cloud Account credentials for account %s",
self.name)
self._status = RwCloudYang.YangData_RwProject_Project_Cloud_Account_ConnectionStatus(
status="validating",
details="Cloud account connection validation in progress"
)
rwstatus, status = yield from loop.run_in_executor(
None,
self._cal.validate_cloud_creds,
self.cal_account_msg,
)
if rwstatus == RwTypes.RwStatus.SUCCESS:
self._status = RwCloudYang.YangData_RwProject_Project_Cloud_Account_ConnectionStatus.from_dict(status.as_dict())
else:
self._status = RwCloudYang.YangData_RwProject_Project_Cloud_Account_ConnectionStatus(
status="failure",
details="Error when calling CAL validate cloud creds"
)
if self._status.status == 'failure':
self._log.error("Cloud account validation failed. Acct: %s, response: %s",
self.name, self._status)
@asyncio.coroutine
def start_validate_credentials(self, loop):
if self._validate_task is not None:
self._validate_task.cancel()
self._validate_task = None
self._validate_task = yield from asyncio.ensure_future(
self.validate_cloud_account_credentials(loop),
loop=loop
)