Merge from OSM SO master
[osm/SO.git] / rwcm / plugins / rwconman / rift / tasklets / rwconmantasklet / rwconman_conagent.py
1 #
2 # Copyright 2016 RIFT.IO Inc
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 #
16
17 import asyncio
18 import rift.tasklets
19
20 from gi.repository import (
21 RwConfigAgentYang as rwcfg_agent,
22 )
23
24 from .riftcm_config_plugin import DEFAULT_CAP_TYPE
25 from . import RiftCA
26 from . import jujuconf
27 import rift.mano.config_agent
28
29
30 class ConfigAgentError(Exception):
31 pass
32
33
34 class ConfigAgentExistsError(ConfigAgentError):
35 pass
36
37
38 class UnknownAgentTypeError(Exception):
39 pass
40
41
42 class ConfigAgentVnfrAddError(Exception):
43 pass
44
45
46 class ConfigAgentVnfrTypeError(Exception):
47 pass
48
49
50 class ConfigAccountHandler(object):
51 def __init__(self, dts, log, loop, project, on_add_config_agent, on_delete_config_agent):
52 self._log = log
53 self._dts = dts
54 self._loop = loop
55 self._project = project
56 self._on_add_config_agent = on_add_config_agent
57 self._on_delete_config_agent = on_delete_config_agent
58
59 self._log.debug("creating config account handler")
60 self.cloud_cfg_handler = rift.mano.config_agent.ConfigAgentSubscriber(
61 self._dts, self._log, self._project,
62 rift.mano.config_agent.ConfigAgentCallbacks(
63 on_add_apply=self.on_config_account_added,
64 on_delete_apply=self.on_config_account_deleted,
65 )
66 )
67
68 def on_config_account_deleted(self, account):
69 self._log.debug("config account deleted: %s", account.name)
70 self._on_delete_config_agent(account)
71
72 def on_config_account_added(self, account):
73 self._log.debug("config account added")
74 self._log.debug(account.as_dict())
75 self._on_add_config_agent(account)
76
77 @asyncio.coroutine
78 def register(self):
79 self.cloud_cfg_handler.register()
80
81 def deregister(self):
82 self.cloud_cfg_handler.deregister()
83
84
85 class RiftCMConfigPlugins(object):
86 """ NSM Config Agent Plugins """
87 def __init__(self):
88 self._plugin_classes = {
89 "juju": jujuconf.JujuConfigPlugin,
90 "riftca": RiftCA.RiftCAConfigPlugin,
91 }
92
93 @property
94 def plugins(self):
95 """ Plugin info """
96 return self._plugin_classes
97
98 def __getitem__(self, name):
99 """ Get item """
100 return self._plugin_classes[name]
101
102 def register(self, plugin_name, plugin_class, *args):
103 """ Register a plugin to this Nsm"""
104 self._plugin_classes[plugin_name] = plugin_class
105
106 def deregister(self, plugin_name, plugin_class, *args):
107 """ Deregister a plugin to this Nsm"""
108 if plugin_name in self._plugin_classes:
109 del self._plugin_classes[plugin_name]
110
111 def class_by_plugin_name(self, name):
112 """ Get class by plugin name """
113 return self._plugin_classes[name]
114
115
116 class RiftCMConfigAgent(object):
117 def __init__(self, dts, log, loop, parent):
118 self._dts = dts
119 self._log = log
120 self._loop = loop
121 self._ConfigManagerConfig = parent
122
123 self._config_plugins = RiftCMConfigPlugins()
124 self._config_handler = ConfigAccountHandler(
125 self._dts, self._log, self._loop, parent._project,
126 self._on_config_agent, self._on_config_agent_delete)
127 self._plugin_instances = {}
128 self._default_account_added = False
129
130 @asyncio.coroutine
131 def invoke_config_agent_plugins(self, method, nsr, vnfr, *args):
132 # Invoke the methods on all config agent plugins registered
133 rc = False
134 for agent in self._plugin_instances.values():
135 if not agent.is_vnfr_managed(vnfr.id):
136 continue
137 try:
138 self._log.debug("Invoke {} on {}".format(method, agent.name))
139 rc = yield from agent.invoke(method, nsr, vnfr, *args)
140 break
141 except Exception as e:
142 self._log.error("Error invoking {} on {} : {}".
143 format(method, agent.name, e))
144 raise
145
146 self._log.info("vnfr({}), method={}, return rc={}"
147 .format(vnfr.name, method, rc))
148 return rc
149
150 def get_vnfr_config_agent(self, vnfr):
151 # if (not vnfr.has_field('netconf') and
152 # not vnfr.has_field('juju') and
153 # not vnfr.has_field('script')):
154 # return False
155
156 for agent in self._plugin_instances.values():
157 try:
158 if agent.is_vnfr_managed(vnfr.id):
159 return agent
160 except Exception as e:
161 self._log.debug("Check if VNFR {} is config agent managed: {}".
162 format(vnfr.name, e))
163
164 def is_vnfr_config_agent_managed(self, vnfr):
165 if self.get_vnfr_config_agent(vnfr):
166 return True
167 return False
168
169 def _on_config_agent(self, config_agent):
170 self._log.debug("Got nsm plugin config agent account: %s", config_agent)
171 try:
172 cap_name = config_agent.name
173 cap_inst = self._config_plugins.class_by_plugin_name(
174 config_agent.account_type)
175 except KeyError as e:
176 msg = "Config agent nsm plugin type not found: {}". \
177 format(config_agent.account_type)
178 self._log.error(msg)
179 raise UnknownAgentTypeError(msg)
180
181 # Check to see if the plugin was already instantiated
182 if cap_name in self._plugin_instances:
183 self._log.debug("Config agent nsm plugin {} already instantiated. " \
184 "Using existing.". format(cap_name))
185 else:
186 # Otherwise, instantiate a new plugin using the config agent account
187 self._log.debug("Instantiting new config agent using class: %s", cap_inst)
188 new_instance = cap_inst(self._dts, self._log, self._loop,
189 self._ConfigManagerConfig._project, config_agent)
190 self._plugin_instances[cap_name] = new_instance
191
192 # TODO (pjoseph): See why this was added, as this deletes the
193 # Rift plugin account when Juju account is added
194 # if self._default_account_added:
195 # # If the user has provided a config account, chuck the default one.
196 # if self.DEFAULT_CAP_TYPE in self._plugin_instances:
197 # del self._plugin_instances[self.DEFAULT_CAP_TYPE]
198
199 def _on_config_agent_delete(self, config_agent):
200 self._log.debug("Got nsm plugin config agent delete, account: %s, type: %s",
201 config_agent.name, config_agent.account_type)
202 cap_name = config_agent.account_type
203 if cap_name in self._plugin_instances:
204 self._log.debug("Config agent nsm plugin exists, deleting it.")
205 del self._plugin_instances[cap_name]
206 else:
207 self._log.error("Error deleting - Config Agent nsm plugin %s does not exist.", cap_name)
208
209
210 @asyncio.coroutine
211 def register(self):
212 self._log.debug("Registering for config agent nsm plugin manager")
213 yield from self._config_handler.register()
214
215 account = rwcfg_agent.ConfigAgentAccount()
216 account.account_type = DEFAULT_CAP_TYPE
217 account.name = "RiftCA"
218 self._on_config_agent(account)
219 self._default_account_added = True
220
221 # Also grab any account already configured
222 config_agents = yield from self._ConfigManagerConfig.cmdts_obj.get_config_agents(name=None)
223 for account in config_agents:
224 self._on_config_agent(account)
225
226 def deregister(self):
227 self._log.debug("De-registering config agent nsm plugin manager".
228 format(self._ConfigManagerConfig._project))
229 self._config_handler.deregister()
230
231 def set_config_agent(self, nsr, vnfr, method):
232 if method == 'juju':
233 agent_type = 'juju'
234 elif method in ['netconf', 'script']:
235 agent_type = DEFAULT_CAP_TYPE
236 else:
237 msg = "Unsupported configuration method ({}) for VNF:{}/{}". \
238 format(method, nsr.name, vnfr.name)
239 self._log.error(msg)
240 raise UnknownAgentTypeError(msg)
241
242 try:
243 acc_map = nsr.nsr_cfg_msg.vnf_cloud_account_map
244 except AttributeError:
245 self._log.debug("Did not find cloud account map for NS {}".
246 format(nsr.name))
247 acc_map = []
248
249 for vnfd in acc_map:
250 if vnfd.config_agent_account is not None:
251 if vnfd.member_vnf_index_ref == vnfr.vnfr_msg.member_index:
252 for agent in self._plugin_instances:
253 # Find the plugin with the same name
254 if agent == vnfd.config_agent_account:
255 # Check if the types are same
256 if self._plugin_instances[agent].agent_type != agent_type:
257 msg = "VNF {} specified config agent {} is not of type {}". \
258 format(vnfr.name, agent, agent_type)
259 self._log.error(msg)
260 raise ConfigAgentVnfrTypeError(msg)
261
262 self._plugin_instances[agent].add_vnfr_managed(vnfr)
263 self._log.debug("Added vnfr {} as config plugin {} managed".
264 format(vnfr.name, agent))
265 return
266
267 # If no config agent specified for the VNF, use the
268 # first available of the same type
269 for agent in self._plugin_instances:
270 if self._plugin_instances[agent].agent_type == agent_type:
271 self._plugin_instances[agent].add_vnfr_managed(vnfr)
272 self._log.debug("Added vnfr {} as config plugin {} managed".
273 format(vnfr.name, agent))
274 return
275
276 msg = "Error finding config agent of type {} for VNF {}". \
277 format(agent_type, vnfr.name)
278 self._log.error(msg)
279 raise ConfigAgentVnfrAddError(msg)