blob: 13af56ad5b0e67fb97b5bbc5612e67943b909de7 [file] [log] [blame]
Jeremy Mordkoff6f07e6f2016-09-07 18:56:51 -04001
Jeremy Mordkoff4870d0e2017-09-30 20:28:33 -04002#
Jeremy Mordkoff6f07e6f2016-09-07 18:56:51 -04003# Copyright 2016 RIFT.IO Inc
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17
18import sys
19import asyncio
20from gi import require_version
Jeremy Mordkoff4870d0e2017-09-30 20:28:33 -040021require_version('RwCal', '1.0')
Jeremy Mordkoff6f07e6f2016-09-07 18:56:51 -040022require_version('RwcalYang', '1.0')
23require_version('RwTypes', '1.0')
24require_version('RwCloudYang', '1.0')
Ananda Baitharu9a6c5922016-11-16 09:20:16 -050025require_version('RwCal', '1.0')
Jeremy Mordkoff6f07e6f2016-09-07 18:56:51 -040026
27from gi.repository import (
28 RwTypes,
29 RwcalYang,
30 RwCloudYang,
31 )
32import rw_peas
33
34if sys.version_info < (3, 4, 4):
35 asyncio.ensure_future = asyncio.async
36
37
38class PluginLoadingError(Exception):
39 pass
40
41
42class CloudAccountCalError(Exception):
43 pass
44
45
46class CloudAccount(object):
47 def __init__(self, log, rwlog_hdl, account_msg):
48 self._log = log
49 self._account_msg = account_msg.deep_copy()
50
51 self._cal_plugin = None
52 self._engine = None
53
54 self._cal = self.plugin.get_interface("Cloud")
55 self._cal.init(rwlog_hdl)
Jeremy Mordkoff4870d0e2017-09-30 20:28:33 -040056
57 self._status = RwCloudYang.YangData_RwProject_Project_Cloud_Account_ConnectionStatus(
Jeremy Mordkoff6f07e6f2016-09-07 18:56:51 -040058 status="unknown",
59 details="Connection status lookup not started"
60 )
61
62 self._validate_task = None
63
64 @property
65 def plugin(self):
66 if self._cal_plugin is None:
67 try:
68 self._cal_plugin = rw_peas.PeasPlugin(
69 getattr(self._account_msg, self.account_type).plugin_name,
70 'RwCal-1.0',
71 )
72
73 except AttributeError as e:
74 raise PluginLoadingError(str(e))
75
76 self._engine, _, _ = self._cal_plugin()
77
78 return self._cal_plugin
79
80 def _wrap_status_fn(self, fn, *args, **kwargs):
81 ret = fn(*args, **kwargs)
82 rw_status = ret[0]
83 if rw_status != RwTypes.RwStatus.SUCCESS:
84 msg = "%s returned %s" % (fn.__name__, str(rw_status))
85 self._log.error(msg)
86 raise CloudAccountCalError(msg)
87
88 # If there was only one other return value besides rw_status, then just
89 # return that element. Otherwise return the rest of the return values
90 # as a list.
91 return ret[1] if len(ret) == 2 else ret[1:]
92
93 @property
94 def cal(self):
95 return self._cal
96
97 @property
98 def name(self):
99 return self._account_msg.name
100
101 @property
102 def account_msg(self):
103 return self._account_msg
104
105 @property
106 def cal_account_msg(self):
Jeremy Mordkoff4870d0e2017-09-30 20:28:33 -0400107 return RwcalYang.YangData_RwProject_Project_CloudAccounts_CloudAccountList.from_dict(
Jeremy Mordkoff6f07e6f2016-09-07 18:56:51 -0400108 self.account_msg.as_dict(),
109 ignore_missing_keys=True,
110 )
111
112 def cloud_account_msg(self, account_dict):
Jeremy Mordkoff4870d0e2017-09-30 20:28:33 -0400113 self._account_msg = RwCloudYang.YangData_RwProject_Project_CloudAccounts_CloudAccountList.from_dict(account_dict)
Jeremy Mordkoff6f07e6f2016-09-07 18:56:51 -0400114
115 @property
116 def account_type(self):
117 return self._account_msg.account_type
118
119 @property
120 def connection_status(self):
121 return self._status
122
123 def update_from_cfg(self, cfg):
124 self._log.debug("Updating parent CloudAccount to %s", cfg)
125
126 # Hack to catch updates triggered from apply_callback when a sdn-account is removed
127 # from a cloud-account. To be fixed properly when updates are handled
128 if (self.account_msg.name == cfg.name
129 and self.account_msg.account_type == cfg.account_type):
130 return
131
132 if cfg.has_field("sdn_account"):
133 self.account_msg.sdn_account = cfg.sdn_account
134 else:
135 raise NotImplementedError("Update cloud account not yet supported")
136
137 def create_image(self, image_info_msg):
138 image_id = self._wrap_status_fn(
139 self.cal.create_image, self.cal_account_msg, image_info_msg
140 )
141
142 return image_id
143
144 def get_image_list(self):
145 self._log.debug("Getting image list from account: %s", self.name)
146 resources = self._wrap_status_fn(
147 self.cal.get_image_list, self.cal_account_msg
148 )
149
150 return resources.imageinfo_list
151
152 @asyncio.coroutine
153 def validate_cloud_account_credentials(self, loop):
Jeremy Mordkoff4870d0e2017-09-30 20:28:33 -0400154 self._log.debug("Validating Cloud Account credentials for account %s",
155 self.name)
156 self._status = RwCloudYang.YangData_RwProject_Project_Cloud_Account_ConnectionStatus(
Jeremy Mordkoff6f07e6f2016-09-07 18:56:51 -0400157 status="validating",
158 details="Cloud account connection validation in progress"
159 )
160 rwstatus, status = yield from loop.run_in_executor(
161 None,
162 self._cal.validate_cloud_creds,
163 self.cal_account_msg,
164 )
165 if rwstatus == RwTypes.RwStatus.SUCCESS:
Jeremy Mordkoff4870d0e2017-09-30 20:28:33 -0400166 self._status = RwCloudYang.YangData_RwProject_Project_Cloud_Account_ConnectionStatus.from_dict(status.as_dict())
Jeremy Mordkoff6f07e6f2016-09-07 18:56:51 -0400167 else:
Jeremy Mordkoff4870d0e2017-09-30 20:28:33 -0400168 self._status = RwCloudYang.YangData_RwProject_Project_Cloud_Account_ConnectionStatus(
Jeremy Mordkoff6f07e6f2016-09-07 18:56:51 -0400169 status="failure",
170 details="Error when calling CAL validate cloud creds"
171 )
172
Jeremy Mordkoff4870d0e2017-09-30 20:28:33 -0400173 if self._status.status == 'failure':
174 self._log.error("Cloud account validation failed. Acct: %s, response: %s",
175 self.name, self._status)
Jeremy Mordkoff6f07e6f2016-09-07 18:56:51 -0400176
Jeremy Mordkoff4870d0e2017-09-30 20:28:33 -0400177 @asyncio.coroutine
Jeremy Mordkoff6f07e6f2016-09-07 18:56:51 -0400178 def start_validate_credentials(self, loop):
179 if self._validate_task is not None:
180 self._validate_task.cancel()
181 self._validate_task = None
182
Jeremy Mordkoff4870d0e2017-09-30 20:28:33 -0400183 self._validate_task = yield from asyncio.ensure_future(
Jeremy Mordkoff6f07e6f2016-09-07 18:56:51 -0400184 self.validate_cloud_account_credentials(loop),
185 loop=loop
186 )