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.
21 import tornado
.httputil
22 import tornado
.httpserver
23 import tornado
.platform
.asyncio
26 import tornadostreamform
.multipart_streamer
as multipart_streamer
29 gi
.require_version('RwDts', '1.0')
30 gi
.require_version('RwcalYang', '1.0')
31 gi
.require_version('RwTypes', '1.0')
32 gi
.require_version('rwlib', '1.0')
33 gi
.require_version('RwLaunchpadYang', '1.0')
35 from gi
.repository
import (
37 RwLaunchpadYang
as rwlaunchpad
,
42 import gi
.repository
.rwlib
as rwlib
43 from gi
.repository
.RwKeyspec
import quoted_key
46 import rift
.mano
.cloud
47 import rift
.mano
.ro_account
48 import rift
.mano
.config_agent
49 import rift
.downloader
as downloader
50 from rift
.mano
.utils
.project
import (
53 get_add_delete_update_cfgs
,
56 from rift
.package
import store
58 from . import uploader
64 MAX_BUFFER_SIZE
= 1 * MB
# Max. size loaded into memory!
65 MAX_BODY_SIZE
= 1 * MB
# Max. size loaded into memory!
67 TaskStatus
= RwPkgMgmtYang
.TaskStatus
69 class LaunchpadError(Exception):
72 class LpProjectNotFound(Exception):
75 class CatalogDtsHandler(object):
76 def __init__(self
, project
, app
):
79 self
.project
= project
83 return self
.project
.log
87 return self
.project
.dts
90 class NsdCatalogDtsHandler(CatalogDtsHandler
):
91 XPATH
= "C,/project-nsd:nsd-catalog/project-nsd:nsd"
93 def add_nsd(self
, nsd
):
94 self
.log
.debug('nsd-catalog-handler:add:{}'.format(nsd
.id))
95 if nsd
.id not in self
.project
.nsd_catalog
:
96 self
.project
.nsd_catalog
[nsd
.id] = nsd
98 self
.log
.error("nsd already in catalog: {}".format(nsd
.id))
100 def update_nsd(self
, nsd
):
101 self
.log
.debug('nsd-catalog-handler:update:{}'.format(nsd
.id))
102 if nsd
.id in self
.project
.nsd_catalog
:
103 self
.project
.nsd_catalog
[nsd
.id] = nsd
105 self
.log
.error("unrecognized NSD: {}".format(nsd
.id))
107 def delete_nsd(self
, nsd_id
):
108 self
.log
.debug('nsd-catalog-handler:delete:{}'.format(nsd_id
))
109 if nsd_id
in self
.project
.nsd_catalog
:
110 del self
.project
.nsd_catalog
[nsd_id
]
112 self
.log
.error("unrecognized NSD: {}".format(nsd_id
))
115 self
.project
.nsd_package_store
.delete_package(nsd_id
)
116 except store
.PackageStoreError
as e
:
117 self
.log
.warning("could not delete package from store: %s", str(e
))
121 def apply_config(dts
, acg
, xact
, action
, _
):
122 if xact
.xact
is None:
123 if action
== rwdts
.AppconfAction
.INSTALL
:
125 for element
in self
.reg
.elements
:
126 self
.log
.debug("Add NSD on restart: {}".format(element
.id))
127 self
.add_nsd(element
)
129 self
.log
.error("DTS handle is null for project {}".
130 format(self
.project
.name
))
132 self
.log
.debug("No xact handle. Skipping apply config")
135 add_cfgs
, delete_cfgs
, update_cfgs
= get_add_delete_update_cfgs(
136 dts_member_reg
=self
.reg
,
142 for cfg
in delete_cfgs
:
143 self
.delete_nsd(cfg
.id)
150 for cfg
in update_cfgs
:
153 self
.log
.debug("Registering for NSD catalog in project".
154 format(self
.project
.name
))
156 acg_handler
= rift
.tasklets
.AppConfGroup
.Handler(
157 on_apply
=apply_config
,
160 with self
.dts
.appconf_group_create(acg_handler
) as acg
:
161 xpath
= self
.project
.add_project(NsdCatalogDtsHandler
.XPATH
)
162 self
.reg
= acg
.register(
164 flags
=rwdts
.Flag
.SUBSCRIBER
,
167 def deregister(self
):
169 self
.reg
.deregister()
173 class VnfdCatalogDtsHandler(CatalogDtsHandler
):
174 XPATH
= "C,/project-vnfd:vnfd-catalog/project-vnfd:vnfd"
176 def add_vnfd(self
, vnfd
):
177 self
.log
.debug('vnfd-catalog-handler:add:{}'.format(vnfd
.id))
178 if vnfd
.id not in self
.project
.vnfd_catalog
:
179 self
.project
.vnfd_catalog
[vnfd
.id] = vnfd
182 self
.log
.error("VNFD already in catalog: {}".format(vnfd
.id))
184 def update_vnfd(self
, vnfd
):
185 self
.log
.debug('vnfd-catalog-handler:update:{}'.format(vnfd
.id))
187 if vnfd
.id in self
.project
.vnfd_catalog
:
188 self
.project
.vnfd_catalog
[vnfd
.id] = vnfd
191 self
.log
.error("unrecognized VNFD: {}".format(vnfd
.id))
193 def delete_vnfd(self
, vnfd_id
):
194 self
.log
.debug('vnfd-catalog-handler:delete:{}'.format(vnfd_id
))
195 if vnfd_id
in self
.project
.vnfd_catalog
:
196 del self
.project
.vnfd_catalog
[vnfd_id
]
198 self
.log
.error("unrecognized VNFD: {}".format(vnfd_id
))
201 self
.project
.vnfd_package_store
.delete_package(vnfd_id
)
202 except store
.PackageStoreError
as e
:
203 self
.log
.warning("could not delete package from store: %s", str(e
))
207 def apply_config(dts
, acg
, xact
, action
, _
):
208 if xact
.xact
is None:
209 if action
== rwdts
.AppconfAction
.INSTALL
:
211 for element
in self
.reg
.elements
:
212 self
.log
.error("Add VNFD on restart: {}".format(element
.id))
213 self
.add_vnfd(element
)
215 self
.log
.error("DTS handle is null for project {}".
216 format(self
.project
.name
))
218 self
.log
.debug("No xact handle. Skipping apply config")
221 add_cfgs
, delete_cfgs
, update_cfgs
= get_add_delete_update_cfgs(
222 dts_member_reg
=self
.reg
,
228 for cfg
in delete_cfgs
:
229 self
.delete_vnfd(cfg
.id)
236 for cfg
in update_cfgs
:
237 self
.update_vnfd(cfg
)
239 self
.log
.debug("Registering for VNFD catalog in project {}".
240 format(self
.project
.name
))
242 acg_handler
= rift
.tasklets
.AppConfGroup
.Handler(
243 on_apply
=apply_config
,
246 with self
.dts
.appconf_group_create(acg_handler
) as acg
:
247 xpath
= self
.project
.add_project(VnfdCatalogDtsHandler
.XPATH
)
248 self
.reg
= acg
.register(
250 flags
=rwdts
.Flag
.SUBSCRIBER
,
253 def deregister(self
):
255 self
.reg
.deregister()
258 class CfgAgentAccountHandlers(object):
259 def __init__(self
, dts
, log
, log_hdl
, loop
, project
):
262 self
._log
_hdl
= log_hdl
264 self
._project
= project
266 self
._log
.debug("creating config agent account config handler")
267 self
.cfg_agent_cfg_handler
= rift
.mano
.config_agent
.ConfigAgentSubscriber(
268 self
._dts
, self
._log
, self
._project
,
269 rift
.mano
.config_agent
.ConfigAgentCallbacks(
270 on_add_apply
=self
.on_cfg_agent_account_added
,
271 on_delete_apply
=self
.on_cfg_agent_account_deleted
,
275 self
._log
.debug("creating config agent account opdata handler")
276 self
.cfg_agent_operdata_handler
= rift
.mano
.config_agent
.CfgAgentDtsOperdataHandler(
277 self
._dts
, self
._log
, self
._loop
, self
._project
280 def on_cfg_agent_account_deleted(self
, account
):
281 self
._log
.debug("config agent account deleted")
282 self
.cfg_agent_operdata_handler
.delete_cfg_agent_account(account
.name
)
284 def on_cfg_agent_account_added(self
, account
):
285 self
._log
.debug("config agent account added")
286 self
.cfg_agent_operdata_handler
.add_cfg_agent_account(account
)
290 self
.cfg_agent_cfg_handler
.register()
291 yield from self
.cfg_agent_operdata_handler
.register()
293 def deregister(self
):
294 self
.cfg_agent_operdata_handler
.deregister()
295 self
.cfg_agent_cfg_handler
.deregister()
298 class CloudAccountHandlers(object):
299 def __init__(self
, dts
, log
, log_hdl
, loop
, app
, project
):
301 self
._log
_hdl
= log_hdl
305 self
._project
= project
307 self
._log
.debug("Creating cloud account config handler for project {}".
308 format(project
.name
))
309 self
.cloud_cfg_handler
= rift
.mano
.cloud
.CloudAccountConfigSubscriber(
310 self
._dts
, self
._log
, self
._log
_hdl
, self
._project
,
311 rift
.mano
.cloud
.CloudAccountConfigCallbacks(
312 on_add_apply
=self
.on_cloud_account_added
,
313 on_delete_apply
=self
.on_cloud_account_deleted
,
317 self
._log
.debug("creating cloud account opdata handler")
318 self
.cloud_operdata_handler
= rift
.mano
.cloud
.CloudAccountDtsOperdataHandler(
319 self
._dts
, self
._log
, self
._loop
, self
._project
,
322 def on_cloud_account_deleted(self
, account_name
):
323 self
._log
.debug("cloud account deleted")
324 self
._app
.accounts
[self
._project
.name
] = \
325 list(self
.cloud_cfg_handler
.accounts
.values())
326 self
.cloud_operdata_handler
.delete_cloud_account(account_name
)
328 def on_cloud_account_added(self
, account
):
329 self
._log
.debug("cloud account added")
330 self
._app
.accounts
[self
._project
.name
] = \
331 list(self
.cloud_cfg_handler
.accounts
.values())
332 self
._log
.debug("accounts: %s", self
._app
.accounts
)
333 self
.cloud_operdata_handler
.add_cloud_account(account
)
337 yield from self
.cloud_cfg_handler
.register()
338 yield from self
.cloud_operdata_handler
.register()
340 def deregister(self
):
341 self
.cloud_cfg_handler
.deregister()
342 self
.cloud_operdata_handler
.deregister()
344 class ROAccountHandlers(object):
345 def __init__(self
, dts
, log
, loop
, app
, project
):
350 self
._project
= project
352 self
._log
.debug("Creating RO account config handler for project {}".
353 format(project
.name
))
354 self
.ro_cfg_handler
= rift
.mano
.ro_account
.ROAccountConfigSubscriber(
355 self
._dts
, self
._log
, self
._loop
, self
._project
, None,
356 rift
.mano
.ro_account
.ROAccountConfigCallbacks(
357 on_add_apply
=self
.on_ro_account_added
,
358 on_delete_apply
=self
.on_ro_account_deleted
,
362 self
._log
.debug("Creating RO account opdata handler")
363 self
.ro_operdata_handler
= rift
.mano
.ro_account
.ROAccountDtsOperdataHandler(
364 self
._dts
, self
._log
, self
._loop
, self
._project
367 def on_ro_account_deleted(self
, account_name
):
368 self
._log
.debug(" launchpad tasklet RO account deleted")
369 self
._app
.ro_accounts
[self
._project
.name
] = \
370 list(self
.ro_cfg_handler
.accounts
.values())
371 self
.ro_operdata_handler
.delete_ro_account(account_name
)
373 def on_ro_account_added(self
, account
):
374 self
._log
.debug(" launchpad tasklet RO account added")
375 self
._app
.ro_accounts
[self
._project
.name
] = \
376 list(self
.ro_cfg_handler
.accounts
.values())
377 self
._log
.debug("Accounts: %s", self
._app
.ro_accounts
)
378 self
.ro_operdata_handler
.add_ro_account(account
)
382 yield from self
.ro_cfg_handler
.register()
383 yield from self
.ro_operdata_handler
.register()
385 def deregister(self
):
386 self
.ro_cfg_handler
.deregister()
387 self
.ro_operdata_handler
.deregister()
389 class StatusHandlers(object):
391 downloader
.DownloadStatus
.STARTED
: TaskStatus
.QUEUED
.value_nick
.upper(),
392 downloader
.DownloadStatus
.IN_PROGRESS
: TaskStatus
.IN_PROGRESS
.value_nick
.upper(),
393 downloader
.DownloadStatus
.COMPLETED
: TaskStatus
.COMPLETED
.value_nick
.upper(),
394 downloader
.DownloadStatus
.FAILED
: TaskStatus
.FAILED
.value_nick
.upper(),
395 downloader
.DownloadStatus
.CANCELLED
: TaskStatus
.CANCELLED
.value_nick
.upper()
398 def __init__(self
, dts
, log
, loop
, app
, project
):
403 self
.project
= project
406 def xpath(self
, transaction_id
=None):
411 self
.reg
= yield from self
.dts
.register(xpath
=self
.xpath(),
412 flags
=rwdts
.Flag
.PUBLISHER|rwdts
.Flag
.CACHE|rwdts
.Flag
.NO_PREP_READ
)
414 assert self
.reg
is not None
416 def deregister(self
):
418 self
.reg
.deregister()
422 class UploadStatusHandlers(StatusHandlers
):
423 """Publisher for status of onboarded packages.
425 def __init__(self
, dts
, log
, loop
, app
, project
):
426 super(UploadStatusHandlers
, self
).__init
__(dts
, log
, loop
, app
, project
)
428 self
.transaction_to_job_map
= {}
430 def xpath(self
, transaction_id
=None):
431 return self
.project
.add_project("D,/rw-pkg-mgmt:create-jobs/rw-pkg-mgmt:job" +
432 ("[transaction-id={}]".format(quoted_key(transaction_id
)) if transaction_id
else ""))
434 def create_job_xpath(self
):
435 return self
.project
.add_project("D,/rw-pkg-mgmt:create-jobs")
440 def on_prepare(xact_info
, action
, ks_path
, msg
):
441 """ prepare callback from dts """
443 if action
== rwdts
.QueryAction
.READ
:
444 xpath
= ks_path
.to_xpath(RwPkgMgmtYang
.get_schema())
445 path_entry
= RwPkgMgmtYang
.YangData_RwProject_Project_CreateJobs_Job().schema().keyspec_to_entry(ks_path
)
446 transaction_id
= path_entry
.key00
.transaction_id
448 create_job_msg
= msg
.as_dict()
450 if transaction_id
in self
.transaction_to_job_map
:
451 job
= self
.transaction_to_job_map
[transaction_id
]
452 xact_info
.respond_xpath(rsp_code
=rwdts
.XactRspCode
.ACK
,
457 jobs
= RwPkgMgmtYang
.YangData_RwProject_Project_CreateJobs()
458 for job
in self
.transaction_to_job_map
.values():
459 jb
= RwPkgMgmtYang
.YangData_RwProject_Project_CreateJobs_Job
.from_dict({
460 "transaction_id": job
.transaction_id
,
464 xact_info
.respond_xpath(rsp_code
=rwdts
.XactRspCode
.ACK
,
465 xpath
=self
.create_job_xpath(),
468 xact_info
.respond_xpath(rwdts
.XactRspCode
.ACK
)
470 hdl
= rift
.tasklets
.DTS
.RegistrationHandler(on_prepare
=on_prepare
,)
471 with self
.dts
.group_create() as group
:
472 self
.reg
= group
.register(xpath
=self
.xpath(),
474 flags
=rwdts
.Flag
.PUBLISHER
,
477 def upload_status(self
, job
, trans_id
):
479 create_job
= RwPkgMgmtYang
.YangData_RwProject_Project_CreateJobs_Job
.from_dict({
480 "transaction_id": trans_id
,
481 "status": StatusHandlers
.STATUS_MAP
[job
.status
]
483 self
.transaction_to_job_map
[trans_id
] = create_job
484 except Exception as e
:
485 self
.log
.error("Exception : {}".format(e
))
487 class UpdateStatusHandlers(StatusHandlers
):
488 """Publisher for status of updated packages.
490 def __init__(self
, dts
, log
, loop
, app
, project
):
491 super(UpdateStatusHandlers
, self
).__init
__(dts
, log
, loop
, app
, project
)
493 def xpath(self
, transaction_id
=None):
494 return self
.project
.add_project("D,/rw-pkg-mgmt:update-jobs/rw-pkg-mgmt:job" +
495 ("[transaction-id={}]".format(quoted_key(transaction_id
)) if transaction_id
else ""))
498 def schedule_dts_work(self
, job
, transaction_id
):
499 # Publish the download state
500 create_job
= RwPkgMgmtYang
.YangData_RwProject_Project_UpdateJobs_Job
.from_dict({
501 "transaction_id": transaction_id
,
502 "status": StatusHandlers
.STATUS_MAP
[job
.status
]
505 self
.reg
.update_element(
506 self
.xpath(transaction_id
=transaction_id
), create_job
)
508 def update_status(self
, job
, trans_id
):
509 self
.log
.debug("Download completed, writing status of task")
510 asyncio
.ensure_future(self
.schedule_dts_work(job
, trans_id
), loop
=self
.loop
)
512 class LaunchpadProject(ManoProject
):
514 def __init__(self
, name
, tasklet
, **kw
):
515 super(LaunchpadProject
, self
).__init
__(tasklet
.log
, name
)
517 self
._app
= kw
['app']
519 self
.config_handler
= None
520 self
.nsd_catalog_handler
= None
521 self
.vld_catalog_handler
= None
522 self
.vnfd_catalog_handler
= None
523 self
.cloud_handler
= None
524 self
.ro_handler
= None
525 self
.lp_config_handler
= None
526 self
.account_handler
= None
527 self
.upload_handlers
= None
528 self
.update_handlers
= None
530 self
.nsd_catalog
= dict()
531 self
.vld_catalog
= dict()
532 self
.vnfd_catalog
= dict()
533 self
.nsd_package_store
= rift
.package
.store
.NsdPackageFilesystemStore(tasklet
.log
,
535 self
.vnfd_package_store
= rift
.package
.store
.VnfdPackageFilesystemStore(tasklet
.log
,
547 def upload_status_handler(self
):
548 return self
.upload_handlers
551 def update_status_handler(self
):
552 return self
.update_handlers
556 self
.log
.debug("creating NSD catalog handler for project {}".format(self
.name
))
557 self
.nsd_catalog_handler
= NsdCatalogDtsHandler(self
, self
._app
)
558 yield from self
.nsd_catalog_handler
.register()
560 self
.log
.debug("creating VNFD catalog handler for project {}".format(self
.name
))
561 self
.vnfd_catalog_handler
= VnfdCatalogDtsHandler(self
, self
._app
)
562 yield from self
.vnfd_catalog_handler
.register()
564 self
.log
.debug("creating cloud account handler for project {}".format(self
.name
))
565 self
.cloud_handler
= CloudAccountHandlers(self
.dts
, self
.log
, self
.log_hdl
,
566 self
.loop
, self
._app
, self
)
567 yield from self
.cloud_handler
.register()
569 self
.log
.debug("creating RO account handler for project {}".format(self
.name
))
570 self
.ro_handler
= ROAccountHandlers(self
.dts
, self
.log
, self
.loop
, self
._app
, self
)
571 yield from self
.ro_handler
.register()
573 self
.log
.debug("creating config agent handler for project {}".format(self
.name
))
574 self
.config_handler
= CfgAgentAccountHandlers(self
.dts
, self
.log
, self
.log_hdl
,
576 yield from self
.config_handler
.register()
578 self
.log
.debug("creating upload handler for project {}".format(self
.name
))
579 self
.upload_handlers
= UploadStatusHandlers(self
.dts
, self
.log
, self
.loop
,
581 yield from self
.upload_handlers
.register()
583 self
.log
.debug("creating update handler for project {}".format(self
.name
))
584 self
.update_handlers
= UpdateStatusHandlers(self
.dts
, self
.log
, self
.loop
,
586 yield from self
.update_handlers
.register()
588 def deregister(self
):
589 self
.log
.debug("De-register handlers for project: {}".format(self
.name
))
590 self
.config_handler
.deregister()
591 self
.cloud_handler
.deregister()
592 self
.ro_handler
.deregister()
593 self
.vnfd_catalog_handler
.deregister()
594 self
.nsd_catalog_handler
.deregister()
595 self
.update_handlers
.deregister()
596 self
.upload_handlers
.deregister()
599 def cloud_accounts(self
):
600 if self
.cloud_handler
is None:
603 return list(self
.cloud_handler
.cloud_cfg_handler
.accounts
.values())
606 def ro_accounts(self
):
607 if self
.ro_handler
is None:
610 return list(self
.ro_handler
.ro_cfg_handler
.accounts
.values())
612 class LaunchpadTasklet(rift
.tasklets
.Tasklet
):
613 UPLOAD_MAX_BODY_SIZE
= MAX_BODY_SIZE
614 UPLOAD_MAX_BUFFER_SIZE
= MAX_BUFFER_SIZE
617 def __init__(self
, *args
, **kwargs
):
618 super(LaunchpadTasklet
, self
).__init
__(*args
, **kwargs
)
619 self
.rwlog
.set_category("rw-mano-log")
620 self
.rwlog
.set_subcategory("launchpad")
623 self
.project_handler
= None
629 def _get_project(self
, project
=None):
631 project
= DEFAULT_PROJECT
633 if project
in self
.projects
:
634 return self
.projects
[project
]
636 msg
= "Project {} not found".format(project
)
638 raise LpProjectNotFound(msg
)
640 def nsd_catalog_get(self
, project
=None):
641 return self
._get
_project
(project
=project
).nsd_catalog
643 def vnfd_catalog_get(self
, project
=None):
644 return self
._get
_project
(project
=project
).vnfd_catalog
646 def get_cloud_accounts(self
, project
=None):
647 return self
._get
_project
(project
=project
).cloud_accounts
650 super(LaunchpadTasklet
, self
).start()
651 self
.log
.info("Starting LaunchpadTasklet")
653 self
.log
.debug("Registering with dts")
654 self
.dts
= rift
.tasklets
.DTS(
656 rwlaunchpad
.get_schema(),
658 self
.on_dts_state_change
661 self
.log
.debug("Created DTS Api GI Object: %s", self
.dts
)
668 self
.log
.exception("Caught Exception in LP stop")
671 def get_vnfd_catalog(self
, project
):
672 return self
.projects
[project
].vnfd_catalog
674 def get_nsd_catalog(self
, project
):
675 return self
.projects
[project
].nsd_catalog
680 io_loop
= rift
.tasklets
.tornado
.TaskletAsyncIOLoop(asyncio_loop
=self
.loop
)
681 self
.app
= uploader
.UploaderApplication
.from_tasklet(self
)
682 yield from self
.app
.register()
684 manifest
= self
.tasklet_info
.get_pb_manifest()
685 ssl_cert
= manifest
.bootstrap_phase
.rwsecurity
.cert
686 ssl_key
= manifest
.bootstrap_phase
.rwsecurity
.key
688 "certfile": ssl_cert
,
692 if manifest
.bootstrap_phase
.rwsecurity
.use_ssl
:
693 self
.server
= tornado
.httpserver
.HTTPServer(
695 max_body_size
=LaunchpadTasklet
.UPLOAD_MAX_BODY_SIZE
,
697 ssl_options
=ssl_options
,
701 self
.server
= tornado
.httpserver
.HTTPServer(
703 max_body_size
=LaunchpadTasklet
.UPLOAD_MAX_BODY_SIZE
,
707 self
.log
.debug("Registering project handler")
708 self
.project_handler
= ProjectHandler(self
, LaunchpadProject
,
710 self
.project_handler
.register()
712 except Exception as e
:
713 self
.log
.error("Exception : {}".format(e
))
714 self
.log
.exception(e
)
718 address
= rwlib
.getenv("RWVM_INTERNAL_IPADDR")
719 if (address
is None):
721 self
.server
.listen(LaunchpadTasklet
.UPLOAD_PORT
, address
=address
)
722 self
.server
.listen(LaunchpadTasklet
.UPLOAD_PORT
, address
="127.0.0.1")
724 def on_instance_started(self
):
725 self
.log
.debug("Got instance started callback")
728 def on_dts_state_change(self
, state
):
729 """Handle DTS state change
731 Take action according to current DTS state to transition application
732 into the corresponding application state
735 state - current dts state
739 rwdts
.State
.INIT
: rwdts
.State
.REGN_COMPLETE
,
740 rwdts
.State
.CONFIG
: rwdts
.State
.RUN
,
744 rwdts
.State
.INIT
: self
.init
,
745 rwdts
.State
.RUN
: self
.run
,
748 # Transition application to next state
749 handler
= handlers
.get(state
, None)
750 if handler
is not None:
753 # Transition dts to next state
754 next_state
= switch
.get(state
, None)
755 if next_state
is not None:
756 self
.dts
.handle
.set_state(next_state
)