3 # Copyright 2016 RIFT.IO Inc
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
9 # http://www.apache.org/licenses/LICENSE-2.0
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.
24 gi
.require_version('RwVnsYang', '1.0')
25 gi
.require_version('RwDts', '1.0')
26 from gi
.repository
import (
36 from rift
.vlmgr
import (
42 from rift
.topmgr
import (
43 NwtopStaticDtsHandler
,
44 NwtopDiscoveryDtsHandler
,
50 class SdnInterfaceError(Exception):
51 """ SDN interface creation Error """
55 class SdnPluginError(Exception):
56 """ SDN plugin creation Error """
60 class VlRecordError(Exception):
61 """ Vlr Record creation Error """
65 class VlRecordNotFound(Exception):
66 """ Vlr Record not found"""
69 class SdnAccountError(Exception):
70 """ Error while creating/deleting/updating SDN Account"""
73 class SdnAccountNotFound(Exception):
76 class SDNAccountDtsOperdataHandler(object):
77 def __init__(self
, dts
, log
, loop
, parent
):
83 def _register_show_status(self
):
84 def get_xpath(sdn_name
=None):
85 return "D,/rw-sdn:sdn/rw-sdn:account{}/rw-sdn:connection-status".format(
86 "[name='%s']" % sdn_name
if sdn_name
is not None else ''
90 def on_prepare(xact_info
, action
, ks_path
, msg
):
91 path_entry
= RwSdnYang
.SDNAccountConfig
.schema().keyspec_to_entry(ks_path
)
92 sdn_account_name
= path_entry
.key00
.name
93 self
._log
.debug("Got show sdn connection status request: %s", ks_path
.create_string())
96 saved_accounts
= self
._parent
._acctmgr
.get_saved_sdn_accounts(sdn_account_name
)
97 for account
in saved_accounts
:
98 sdn_acct
= RwSdnYang
.SDNAccountConfig()
99 sdn_acct
.from_dict(account
.as_dict())
101 self
._log
.debug("Responding to sdn connection status request: %s", sdn_acct
.connection_status
)
102 xact_info
.respond_xpath(
103 rwdts
.XactRspCode
.MORE
,
104 xpath
=get_xpath(account
.name
),
105 msg
=sdn_acct
.connection_status
,
107 except KeyError as e
:
108 self
._log
.warning(str(e
))
109 xact_info
.respond_xpath(rwdts
.XactRspCode
.NA
)
112 xact_info
.respond_xpath(rwdts
.XactRspCode
.ACK
)
114 yield from self
._dts
.register(
116 handler
=rift
.tasklets
.DTS
.RegistrationHandler(
117 on_prepare
=on_prepare
),
118 flags
=rwdts
.Flag
.PUBLISHER
,
121 def _register_validate_rpc(self
):
123 return "/rw-sdn:update-sdn-status"
126 def on_prepare(xact_info
, action
, ks_path
, msg
):
127 if not msg
.has_field("sdn_account"):
128 raise SdnAccountNotFound("SDN account name not provided")
130 sdn_account_name
= msg
.sdn_account
131 account
= self
._parent
._acctmgr
.get_sdn_account(sdn_account_name
)
133 self
._log
.warning("SDN account %s does not exist", sdn_account_name
)
134 xact_info
.respond_xpath(rwdts
.XactRspCode
.NA
)
137 self
._parent
._acctmgr
.start_validate_credentials(self
._loop
, sdn_account_name
)
139 xact_info
.respond_xpath(rwdts
.XactRspCode
.ACK
)
141 yield from self
._dts
.register(
143 handler
=rift
.tasklets
.DTS
.RegistrationHandler(
144 on_prepare
=on_prepare
146 flags
=rwdts
.Flag
.PUBLISHER
,
151 yield from self
._register
_show
_status
()
152 yield from self
._register
_validate
_rpc
()
154 class SDNAccountDtsHandler(object):
155 XPATH
= "C,/rw-sdn:sdn/rw-sdn:account"
157 def __init__(self
, dts
, log
, parent
):
160 self
._parent
= parent
162 self
._sdn
_account
= {}
164 def _set_sdn_account(self
, account
):
165 self
._log
.info("Setting sdn account: {}".format(account
))
166 if account
.name
in self
._sdn
_account
:
167 self
._log
.error("SDN Account with name %s already exists. Ignoring config", account
.name
);
168 self
._sdn
_account
[account
.name
] = account
169 self
._parent
._acctmgr
.set_sdn_account(account
)
171 def _del_sdn_account(self
, account_name
):
172 self
._log
.info("Deleting sdn account: {}".format(account_name
))
173 del self
._sdn
_account
[account_name
]
175 self
._parent
._acctmgr
.del_sdn_account(account_name
)
177 def _update_sdn_account(self
, account
):
178 self
._log
.info("Updating sdn account: {}".format(account
))
179 # No need to update locally saved sdn_account's updated fields, as they
180 # are not used anywhere. Call the parent's update callback.
181 self
._parent
._acctmgr
.update_sdn_account(account
)
185 def apply_config(dts
, acg
, xact
, action
, _
):
186 self
._log
.debug("Got sdn account apply config (xact: %s) (action: %s)", xact
, action
)
187 if action
== rwdts
.AppconfAction
.INSTALL
and xact
.id is None:
188 self
._log
.debug("No xact handle. Skipping apply config")
189 return RwTypes
.RwStatus
.SUCCESS
191 return RwTypes
.RwStatus
.SUCCESS
194 def on_prepare(dts
, acg
, xact
, xact_info
, ks_path
, msg
, scratch
):
195 """ Prepare callback from DTS for SDN Account config """
197 self
._log
.info("SDN Cloud account config received: %s", msg
)
199 fref
= ProtobufC
.FieldReference
.alloc()
200 fref
.goto_whole_message(msg
.to_pbcm())
202 if fref
.is_field_deleted():
203 # Delete the sdn account record
204 self
._del
_sdn
_account
(msg
.name
)
206 # If the account already exists, then this is an update.
207 if msg
.name
in self
._sdn
_account
:
208 self
._log
.debug("SDN account already exists. Invoking on_prepare update request")
209 if msg
.has_field("account_type"):
210 errmsg
= "Cannot update SDN account's account-type."
211 self
._log
.error(errmsg
)
212 xact_info
.send_error_xpath(RwTypes
.RwStatus
.FAILURE
,
213 SDNAccountDtsHandler
.XPATH
,
215 raise SdnAccountError(errmsg
)
217 # Update the sdn account record
218 self
._update
_sdn
_account
(msg
)
220 self
._log
.debug("SDN account does not already exist. Invoking on_prepare add request")
221 if not msg
.has_field('account_type'):
222 errmsg
= "New SDN account must contain account-type field."
223 self
._log
.error(errmsg
)
224 xact_info
.send_error_xpath(RwTypes
.RwStatus
.FAILURE
,
225 SDNAccountDtsHandler
.XPATH
,
227 raise SdnAccountError(errmsg
)
229 # Set the sdn account record
230 self
._set
_sdn
_account
(msg
)
232 xact_info
.respond_xpath(rwdts
.XactRspCode
.ACK
)
235 self
._log
.debug("Registering for Sdn Account config using xpath: %s",
236 SDNAccountDtsHandler
.XPATH
,
239 acg_handler
= rift
.tasklets
.AppConfGroup
.Handler(
240 on_apply
=apply_config
,
243 with self
._dts
.appconf_group_create(acg_handler
) as acg
:
245 xpath
=SDNAccountDtsHandler
.XPATH
,
246 flags
=rwdts
.Flag
.SUBSCRIBER | rwdts
.Flag
.DELTA_READY
,
247 on_prepare
=on_prepare
251 class VnsManager(object):
252 """ The Virtual Network Service Manager """
253 def __init__(self
, dts
, log
, log_hdl
, loop
):
256 self
._log
_hdl
= log_hdl
258 self
._vlr
_handler
= VlrDtsHandler(dts
, log
, loop
, self
)
259 self
._vld
_handler
= VldDtsHandler(dts
, log
, loop
, self
)
260 self
._sdn
_handler
= SDNAccountDtsHandler(dts
,log
,self
)
261 self
._sdn
_opdata
_handler
= SDNAccountDtsOperdataHandler(dts
,log
, loop
, self
)
262 self
._acctmgr
= SdnAccountMgr(self
._log
, self
._log
_hdl
, self
._loop
)
263 self
._nwtopdata
_store
= NwtopDataStore(log
)
264 self
._nwtopdiscovery
_handler
= NwtopDiscoveryDtsHandler(dts
, log
, loop
, self
._acctmgr
, self
._nwtopdata
_store
)
265 self
._nwtopstatic
_handler
= NwtopStaticDtsHandler(dts
, log
, loop
, self
._acctmgr
, self
._nwtopdata
_store
)
269 def register_vlr_handler(self
):
270 """ Register vlr DTS handler """
271 self
._log
.debug("Registering DTS VLR handler")
272 yield from self
._vlr
_handler
.register()
275 def register_vld_handler(self
):
276 """ Register vlr DTS handler """
277 self
._log
.debug("Registering DTS VLD handler")
278 yield from self
._vld
_handler
.register()
281 def register_sdn_handler(self
):
282 """ Register vlr DTS handler """
283 self
._log
.debug("Registering SDN Account config handler")
284 yield from self
._sdn
_handler
.register()
285 yield from self
._sdn
_opdata
_handler
.register()
288 def register_nwtopstatic_handler(self
):
289 """ Register static NW topology DTS handler """
290 self
._log
.debug("Registering static DTS NW topology handler")
291 yield from self
._nwtopstatic
_handler
.register()
294 def register_nwtopdiscovery_handler(self
):
295 """ Register discovery-based NW topology DTS handler """
296 self
._log
.debug("Registering discovery-based DTS NW topology handler")
297 yield from self
._nwtopdiscovery
_handler
.register()
301 """ Register all static DTS handlers"""
302 yield from self
.register_sdn_handler()
303 yield from self
.register_vlr_handler()
304 yield from self
.register_vld_handler()
305 yield from self
.register_nwtopstatic_handler()
307 yield from self
.register_nwtopdiscovery_handler()
309 def create_vlr(self
, msg
):
311 if msg
.id in self
._vlrs
:
312 err
= "Vlr id %s already exists" % msg
.id
314 # raise VlRecordError(err)
315 return self
._vlrs
[msg
.id]
317 self
._log
.info("Creating VirtualLinkRecord %s", msg
.id)
318 self
._vlrs
[msg
.id] = VirtualLinkRecord(self
._dts
,
325 return self
._vlrs
[msg
.id]
327 def get_vlr(self
, vlr_id
):
328 """ Get VLR by vlr id """
329 return self
._vlrs
[vlr_id
]
332 def delete_vlr(self
, vlr_id
, xact
):
333 """ Delete VLR with the passed id"""
334 if vlr_id
not in self
._vlrs
:
335 err
= "Delete Failed - Vlr id %s not found" % vlr_id
337 raise VlRecordNotFound(err
)
339 self
._log
.info("Deleting virtual link id %s", vlr_id
)
340 yield from self
._vlrs
[vlr_id
].terminate(xact
)
341 del self
._vlrs
[vlr_id
]
342 self
._log
.info("Deleted virtual link id %s", vlr_id
)
344 def find_vlr_by_vld_id(self
, vld_id
):
345 """ Find a VLR matching the VLD Id """
346 for vlr
in self
._vlrs
.values():
347 if vlr
.vld_id
== vld_id
:
353 """ Run this VNSM instance """
354 self
._log
.debug("Run VNSManager - registering static DTS handlers")
355 yield from self
.register()
357 def vld_in_use(self
, vld_id
):
358 """ Is this VLD in use """
362 def publish_vlr(self
, xact
, path
, msg
):
363 """ Publish a VLR """
364 self
._log
.debug("Publish vlr called with path %s, msg %s",
366 yield from self
._vlr
_handler
.update(xact
, path
, msg
)
369 def unpublish_vlr(self
, xact
, path
):
370 """ Publish a VLR """
371 self
._log
.debug("Unpublish vlr called with path %s", path
)
372 yield from self
._vlr
_handler
.delete(xact
, path
)
375 class VnsTasklet(rift
.tasklets
.Tasklet
):
376 """ The VNS tasklet class """
377 def __init__(self
, *args
, **kwargs
):
378 super(VnsTasklet
, self
).__init
__(*args
, **kwargs
)
379 self
.rwlog
.set_category("rw-mano-log")
380 self
.rwlog
.set_subcategory("vns")
383 self
._vlr
_handler
= None
386 # A mapping of instantiated vlr_id's to VirtualLinkRecord objects
390 super(VnsTasklet
, self
).start()
391 self
.log
.info("Starting VnsTasklet")
393 self
.log
.debug("Registering with dts")
394 self
._dts
= rift
.tasklets
.DTS(self
.tasklet_info
,
395 RwVnsYang
.get_schema(),
397 self
.on_dts_state_change
)
399 self
.log
.debug("Created DTS Api GI Object: %s", self
._dts
)
401 def on_instance_started(self
):
402 """ The task instance started callback"""
403 self
.log
.debug("Got instance started callback")
409 print("Caught Exception in VNS stop:", sys
.exc_info()[0])
414 """ task init callback"""
415 self
._vnsm
= VnsManager(dts
=self
._dts
,
417 log_hdl
=self
.log_hdl
,
419 yield from self
._vnsm
.run()
421 # NSM needs to detect VLD deletion that has active VLR
422 # self._vld_handler = VldDescriptorConfigDtsHandler(
423 # self._dts, self.log, self.loop, self._vlrs,
425 # yield from self._vld_handler.register()
429 """ tasklet run callback """
433 def on_dts_state_change(self
, state
):
434 """Take action according to current dts state to transition
435 application into the corresponding application state
438 state - current dts state
441 rwdts
.State
.INIT
: rwdts
.State
.REGN_COMPLETE
,
442 rwdts
.State
.CONFIG
: rwdts
.State
.RUN
,
446 rwdts
.State
.INIT
: self
.init
,
447 rwdts
.State
.RUN
: self
.run
,
450 # Transition application to next state
451 handler
= handlers
.get(state
, None)
452 if handler
is not None:
455 # Transition dts to next state
456 next_state
= switch
.get(state
, None)
457 if next_state
is not None:
458 self
._dts
.handle
.set_state(next_state
)