Support NFV Orchestration API v2.0
Support the latest NFV Orchestration API v2.0 listed below. * VNF LCM v2 * VNF FM v1 * VNF PM v2 In addition, to manage VNF packages for testing purposes, also support Orchestration API v1.0 listed below. * VNF packages Implements: blueprint v2-api-horizon Change-Id: I0284cba30154cf4cc5d496be157288e2c2614ccf
This commit is contained in:
parent
4709605bd5
commit
a1840d24ba
@ -0,0 +1,13 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Support the latest NFV Orchestration API v2.0 listed below.
|
||||||
|
|
||||||
|
* Virtualized Network Function Lifecycle Management Interface (VNF LCM) v2
|
||||||
|
* Virtualized Network Function Fault Management Interface (VNF FM) v1
|
||||||
|
* Virtualized Network Function Performance Management Interface (VNF PM) v2
|
||||||
|
|
||||||
|
In addition, to manage VNF packages for testing purposes, also support
|
||||||
|
Orchestration API v1.0 listed below.
|
||||||
|
|
||||||
|
* Virtualized Network Function Packages (VNF packages)
|
@ -44,10 +44,11 @@ CERT_VERIFY_TYPES = (
|
|||||||
|
|
||||||
|
|
||||||
@memoized
|
@memoized
|
||||||
def tackerclient(request):
|
def tackerclient(request, api_version="1"):
|
||||||
insecure = getattr(settings, 'OPENSTACK_SSL_NO_VERIFY', False)
|
insecure = getattr(settings, 'OPENSTACK_SSL_NO_VERIFY', False)
|
||||||
cacert = getattr(settings, 'OPENSTACK_SSL_CACERT', None)
|
cacert = getattr(settings, 'OPENSTACK_SSL_CACERT', None)
|
||||||
c = tacker_client.Client(
|
c = tacker_client.Client(
|
||||||
|
api_version=api_version,
|
||||||
token=request.user.token.id,
|
token=request.user.token.id,
|
||||||
auth_url=base.url_for(request, 'identity'),
|
auth_url=base.url_for(request, 'identity'),
|
||||||
endpoint_url=base.url_for(request, 'nfv-orchestration'),
|
endpoint_url=base.url_for(request, 'nfv-orchestration'),
|
||||||
@ -251,3 +252,370 @@ def create_ns(request, ns_arg, **params):
|
|||||||
LOG.debug("create_ns(): ns_arg=%s", str(ns_arg))
|
LOG.debug("create_ns(): ns_arg=%s", str(ns_arg))
|
||||||
ns_instance = tackerclient(request).create_ns(body=ns_arg)
|
ns_instance = tackerclient(request).create_ns(body=ns_arg)
|
||||||
return ns_instance
|
return ns_instance
|
||||||
|
|
||||||
|
|
||||||
|
# VNF Packages v1
|
||||||
|
@profiler.trace
|
||||||
|
def create_vnf_package(request, body):
|
||||||
|
LOG.debug("create_vnf_package(): body=%s", body)
|
||||||
|
vnf_package = tackerclient(request).create_vnf_package(body=body)
|
||||||
|
return vnf_package
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace
|
||||||
|
def list_vnf_packages(request, **params):
|
||||||
|
LOG.debug("list_vnf_packages(): params=%s", params)
|
||||||
|
vnf_packages = tackerclient(request).list_vnf_packages(**params).get(
|
||||||
|
'vnf_packages')
|
||||||
|
return vnf_packages
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace
|
||||||
|
def get_vnf_package(request, vnf_pkg_id):
|
||||||
|
LOG.debug("get_vnf_package(): vnf_pkg_id=%s", vnf_pkg_id)
|
||||||
|
vnf_package = tackerclient(request).show_vnf_package(vnf_pkg_id)
|
||||||
|
return vnf_package
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace
|
||||||
|
def delete_vnf_package(request, vnf_pkg_id):
|
||||||
|
LOG.debug("delete_vnf_package(): vnf_pkg_id=%s", vnf_pkg_id)
|
||||||
|
result = tackerclient(request).delete_vnf_package(vnf_pkg_id)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace
|
||||||
|
def upload_vnf_package(request, vnf_pkg_id, file_data=None, **params):
|
||||||
|
LOG.debug("upload_vnf_package(): vnf_pkg_id=%s, params=%s",
|
||||||
|
vnf_pkg_id, params)
|
||||||
|
vnf_package = tackerclient(request).upload_vnf_package(
|
||||||
|
vnf_pkg_id, file_data=file_data, **params)
|
||||||
|
return vnf_package
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace
|
||||||
|
def update_vnf_package(request, vnf_pkg_id, body):
|
||||||
|
LOG.debug("update_vnf_package(): vnf_pkg_id=%s, body=%s",
|
||||||
|
vnf_pkg_id, body)
|
||||||
|
updated_values = tackerclient(request).update_vnf_package(
|
||||||
|
vnf_pkg_id, body=body)
|
||||||
|
return updated_values
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace
|
||||||
|
def fetch_vnf_package(request, vnf_pkg_id):
|
||||||
|
LOG.debug("fetch_vnf_package(): vnf_pkg_id=%s", vnf_pkg_id)
|
||||||
|
vnf_package_file = tackerclient(request).download_vnf_package(vnf_pkg_id)
|
||||||
|
return vnf_package_file
|
||||||
|
|
||||||
|
|
||||||
|
# VNF LCM v2
|
||||||
|
@profiler.trace
|
||||||
|
def create_vnf_instance(request, body):
|
||||||
|
LOG.debug("create_vnf_instance(): body=%s", body)
|
||||||
|
vnf_instance = (tackerclient(request, api_version="2")
|
||||||
|
.create_vnf_instance(body=body))
|
||||||
|
return vnf_instance
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace
|
||||||
|
def get_vnf_instance(request, vnf_instance_id):
|
||||||
|
LOG.debug("get_vnf_instance(): vnf_instance_id=%s", vnf_instance_id)
|
||||||
|
vnf_instance = (tackerclient(request, api_version="2")
|
||||||
|
.show_vnf_instance(vnf_instance_id))
|
||||||
|
return vnf_instance
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace
|
||||||
|
def list_vnf_instances(request, **params):
|
||||||
|
LOG.debug("list_vnf_instances(): params=%s", params)
|
||||||
|
vnf_instances = (tackerclient(request, api_version="2")
|
||||||
|
.list_vnf_instances(**params))
|
||||||
|
return vnf_instances
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace
|
||||||
|
def delete_vnf_instance(request, vnf_instance_id):
|
||||||
|
LOG.debug("delete_vnf_instance(): vnf_instance_id=%s", vnf_instance_id)
|
||||||
|
result = (tackerclient(request, api_version="2")
|
||||||
|
.delete_vnf_instance(vnf_instance_id))
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace
|
||||||
|
def instantiate_vnf_instance(request, vnf_instance_id, body):
|
||||||
|
LOG.debug("instantiate_vnf_instance(): vnf_instance_id=%s, body=%s",
|
||||||
|
vnf_instance_id, body)
|
||||||
|
result = (tackerclient(request, api_version="2")
|
||||||
|
.instantiate_vnf_instance(vnf_instance_id, body=body))
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace
|
||||||
|
def terminate_vnf_instance(request, vnf_instance_id, body):
|
||||||
|
LOG.debug("terminate_vnf_instance(): vnf_instance_id=%s, body=%s",
|
||||||
|
vnf_instance_id, body)
|
||||||
|
result = (tackerclient(request, api_version="2")
|
||||||
|
.terminate_vnf_instance(vnf_instance_id, body=body))
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace
|
||||||
|
def heal_vnf_instance(request, vnf_instance_id, body):
|
||||||
|
LOG.debug("heal_vnf_instance(): vnf_instance_id=%s, body=%s",
|
||||||
|
vnf_instance_id, body)
|
||||||
|
result = (tackerclient(request, api_version="2")
|
||||||
|
.heal_vnf_instance(vnf_instance_id, body=body))
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace
|
||||||
|
def update_vnf_instance(request, vnf_instance_id, body):
|
||||||
|
LOG.debug("update_vnf_instance(): vnf_instance_id=%s, body=%s",
|
||||||
|
vnf_instance_id, body)
|
||||||
|
result = (tackerclient(request, api_version="2")
|
||||||
|
.update_vnf_instance(vnf_instance_id, body=body))
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace
|
||||||
|
def scale_vnf_instance(request, vnf_instance_id, body):
|
||||||
|
LOG.debug("scale_vnf_instance(): vnf_instance_id=%s, body=%s",
|
||||||
|
vnf_instance_id, body)
|
||||||
|
result = (tackerclient(request, api_version="2")
|
||||||
|
.scale_vnf_instance(vnf_instance_id, body=body))
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace
|
||||||
|
def change_ext_conn_vnf_instance(request, vnf_instance_id, body):
|
||||||
|
LOG.debug("change_ext_conn_vnf_instance(): vnf_instance_id=%s, body=%s",
|
||||||
|
vnf_instance_id, body)
|
||||||
|
result = (tackerclient(request, api_version="2")
|
||||||
|
.change_ext_conn_vnf_instance(vnf_instance_id, body=body))
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace
|
||||||
|
def change_vnfpkg_vnf_instance(request, vnf_instance_id, body):
|
||||||
|
LOG.debug("change_vnfpkg_vnf_instance(): vnf_instance_id=%s, body=%s",
|
||||||
|
vnf_instance_id, body)
|
||||||
|
result = (tackerclient(request, api_version="2")
|
||||||
|
.change_vnfpkg_vnf_instance(vnf_instance_id, body=body))
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace
|
||||||
|
def list_vnf_lcm_op_occs(request, **params):
|
||||||
|
LOG.debug("list_vnf_lcm_op_occs(): params=%s", params)
|
||||||
|
op_occs = (tackerclient(request, api_version="2")
|
||||||
|
.list_vnf_lcm_op_occs(**params))
|
||||||
|
return op_occs
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace
|
||||||
|
def get_vnf_lcm_op_occ(request, op_occ_id):
|
||||||
|
LOG.debug("get_vnf_lcm_op_occ(): op_occ_id=%s", op_occ_id)
|
||||||
|
op_occ = (tackerclient(request, api_version="2")
|
||||||
|
.show_vnf_lcm_op_occs(op_occ_id))
|
||||||
|
return op_occ
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace
|
||||||
|
def rollback_vnf_lcm_op_occ(request, op_occ_id):
|
||||||
|
LOG.debug("rollback_vnf_lcm_op_occ(): op_occ_id=%s", op_occ_id)
|
||||||
|
result = (tackerclient(request, api_version="2")
|
||||||
|
.rollback_vnf_instance(op_occ_id))
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace
|
||||||
|
def retry_vnf_lcm_op_occ(request, op_occ_id):
|
||||||
|
LOG.debug("retry_vnf_lcm_op_occ(): op_occ_id=%s", op_occ_id)
|
||||||
|
result = (tackerclient(request, api_version="2")
|
||||||
|
.retry_vnf_instance(op_occ_id))
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace
|
||||||
|
def fail_vnf_lcm_op_occ(request, op_occ_id):
|
||||||
|
LOG.debug("fail_vnf_lcm_op_occs(): op_occ_id=%s", op_occ_id)
|
||||||
|
result = (tackerclient(request, api_version="2")
|
||||||
|
.fail_vnf_instance(op_occ_id))
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace
|
||||||
|
def list_vnf_lcm_subscriptions(request, **params):
|
||||||
|
LOG.debug("list_vnf_lcm_subscriptions(): params=%s", params)
|
||||||
|
subscriptions = (tackerclient(request, api_version="2")
|
||||||
|
.list_lccn_subscriptions(**params))
|
||||||
|
return subscriptions
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace
|
||||||
|
def get_vnf_lcm_subscription(request, subsc_id):
|
||||||
|
LOG.debug("get_vnf_lcm_subscription(): subsc_id=%s", subsc_id)
|
||||||
|
subscription = (tackerclient(request, api_version="2")
|
||||||
|
.show_lccn_subscription(subsc_id))
|
||||||
|
return subscription
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace
|
||||||
|
def delete_vnf_lcm_subscription(request, subsc_id):
|
||||||
|
LOG.debug("delete_vnf_lcm_subscription(): subsc_id=%s", subsc_id)
|
||||||
|
result = (tackerclient(request, api_version="2")
|
||||||
|
.delete_lccn_subscription(subsc_id))
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace
|
||||||
|
def create_vnf_lcm_subscription(request, param):
|
||||||
|
LOG.debug("create_vnf_lcm_subscription(): param=%s", param)
|
||||||
|
subscription = (tackerclient(request, api_version="2")
|
||||||
|
.create_lccn_subscription(body=param))
|
||||||
|
return subscription
|
||||||
|
|
||||||
|
|
||||||
|
# VNF FM v1
|
||||||
|
@profiler.trace
|
||||||
|
def list_fm_alarms(request, **params):
|
||||||
|
LOG.debug("list_fm_alarms(): params=%s", params)
|
||||||
|
fm_alarms = tackerclient(request).list_vnf_fm_alarms(**params).get(
|
||||||
|
'vnf_fm_alarms')
|
||||||
|
return fm_alarms
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace
|
||||||
|
def get_fm_alarm(request, alarm_id):
|
||||||
|
LOG.debug("get_fm_alarm(): alarm_id=%s", alarm_id)
|
||||||
|
fm_alarm = tackerclient(request).show_vnf_fm_alarm(alarm_id)
|
||||||
|
return fm_alarm
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace
|
||||||
|
def update_fm_alarm(request, alarm_id, body):
|
||||||
|
LOG.debug("update_fm_alarm(): alarm_id=%s, body=%s", alarm_id, body)
|
||||||
|
updated_values = tackerclient(request).update_vnf_fm_alarm(
|
||||||
|
alarm_id, body=body)
|
||||||
|
return updated_values
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace
|
||||||
|
def create_fm_subscription(request, body):
|
||||||
|
LOG.debug("create_fm_subscription(): body=%s", body)
|
||||||
|
fm_subscription = tackerclient(request).create_vnf_fm_sub(body=body)
|
||||||
|
return fm_subscription
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace
|
||||||
|
def list_fm_subscriptions(request, **params):
|
||||||
|
LOG.debug("list_fm_subscriptions(): params=%s", params)
|
||||||
|
fm_subscriptions = tackerclient(request).list_vnf_fm_subs(**params).get(
|
||||||
|
'vnf_fm_subs')
|
||||||
|
return fm_subscriptions
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace
|
||||||
|
def get_fm_subscription(request, subsc_id):
|
||||||
|
LOG.debug("get_fm_subscription(): subsc_id=%s", subsc_id)
|
||||||
|
fm_subscription = tackerclient(request).show_vnf_fm_sub(subsc_id)
|
||||||
|
return fm_subscription
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace
|
||||||
|
def delete_fm_subscription(request, subsc_id):
|
||||||
|
LOG.debug("delete_fm_subscription(): subsc_id=%s", subsc_id)
|
||||||
|
result = tackerclient(request).delete_vnf_fm_sub(subsc_id)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
# VNF PM v2
|
||||||
|
@profiler.trace
|
||||||
|
def create_pm_job(request, body):
|
||||||
|
LOG.debug("create_pm_job(): body=%s", body)
|
||||||
|
pm_job = (tackerclient(request, api_version="2")
|
||||||
|
.create_vnf_pm_job(body=body))
|
||||||
|
return pm_job
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace
|
||||||
|
def list_pm_jobs(request, **params):
|
||||||
|
LOG.debug("list_pm_jobs(): params=%s", params)
|
||||||
|
pm_jobs = (tackerclient(request, api_version="2")
|
||||||
|
.list_vnf_pm_jobs(**params).get('vnf_pm_jobs'))
|
||||||
|
return pm_jobs
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace
|
||||||
|
def get_pm_job(request, pm_job_id):
|
||||||
|
LOG.debug("get_pm_job(): pm_job_id=%s", pm_job_id)
|
||||||
|
pm_job = tackerclient(request, api_version="2").show_vnf_pm_job(pm_job_id)
|
||||||
|
return pm_job
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace
|
||||||
|
def update_pm_job(request, pm_job_id, body):
|
||||||
|
LOG.debug("update_pm_job(): pm_job_id=%s, body=%s", pm_job_id, body)
|
||||||
|
updated_values = (tackerclient(request, api_version="2")
|
||||||
|
.update_vnf_pm_job(pm_job_id, body=body))
|
||||||
|
return updated_values
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace
|
||||||
|
def delete_pm_job(request, pm_job_id):
|
||||||
|
LOG.debug("delete_pm_job(): pm_job_id=%s", pm_job_id)
|
||||||
|
result = (tackerclient(request, api_version="2")
|
||||||
|
.delete_vnf_pm_job(pm_job_id))
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace
|
||||||
|
def get_pm_report(request, pm_job_id, pm_report_id):
|
||||||
|
LOG.debug("get_pm_report(): pm_job_id=%s, pm_report_id=%s",
|
||||||
|
pm_job_id, pm_report_id)
|
||||||
|
pm_report = (tackerclient(request, api_version="2")
|
||||||
|
.show_vnf_pm_report(pm_job_id, pm_report_id))
|
||||||
|
return pm_report
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace
|
||||||
|
def create_pm_threshold(request, body):
|
||||||
|
LOG.debug("create_pm_threshold(): body=%s", body)
|
||||||
|
pm_threshold = (tackerclient(request, api_version="2")
|
||||||
|
.create_vnf_pm_threshold(body=body))
|
||||||
|
return pm_threshold
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace
|
||||||
|
def list_pm_thresholds(request, **params):
|
||||||
|
LOG.debug("list_pm_thresholds(): params=%s", params)
|
||||||
|
pm_thresholds = (tackerclient(request, api_version="2")
|
||||||
|
.list_vnf_pm_thresholds(**params)
|
||||||
|
.get('vnf_pm_thresholds'))
|
||||||
|
return pm_thresholds
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace
|
||||||
|
def get_pm_threshold(request, pm_threshold_id):
|
||||||
|
LOG.debug("get_pm_threshold(): pm_threshold_id=%s", pm_threshold_id)
|
||||||
|
pm_threshold = (tackerclient(request, api_version="2")
|
||||||
|
.show_vnf_pm_threshold(pm_threshold_id))
|
||||||
|
return pm_threshold
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace
|
||||||
|
def update_pm_threshold(request, pm_threshold_id, body):
|
||||||
|
LOG.debug("update_pm_threshold(): pm_threshold_id=%s, body=%s",
|
||||||
|
pm_threshold_id, body)
|
||||||
|
updated_values = (tackerclient(request, api_version="2")
|
||||||
|
.update_vnf_pm_threshold(pm_threshold_id, body=body))
|
||||||
|
return updated_values
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace
|
||||||
|
def delete_pm_threshold(request, pm_threshold_id):
|
||||||
|
LOG.debug("delete_pm_threshold(): pm_threshold_id=%s", pm_threshold_id)
|
||||||
|
result = (tackerclient(request, api_version="2")
|
||||||
|
.delete_vnf_pm_threshold(pm_threshold_id))
|
||||||
|
return result
|
||||||
|
@ -20,21 +20,46 @@ import horizon
|
|||||||
|
|
||||||
class Vnfmgroup(horizon.PanelGroup):
|
class Vnfmgroup(horizon.PanelGroup):
|
||||||
slug = "nfvgroup"
|
slug = "nfvgroup"
|
||||||
name = _("VNF Management")
|
name = _("(Legacy)VNF Management")
|
||||||
panels = ('vnfcatalog', 'vnfmanager',)
|
panels = ('vnfcatalog', 'vnfmanager',)
|
||||||
|
|
||||||
|
|
||||||
class Nfvogroup(horizon.PanelGroup):
|
class Nfvogroup(horizon.PanelGroup):
|
||||||
slug = "nfvogroup"
|
slug = "nfvogroup"
|
||||||
name = _("NFV Orchestration")
|
name = _("(Legacy)NFV Orchestration")
|
||||||
panels = ('vim', 'vnffgcatalog', 'vnffgmanager',
|
panels = ('vim', 'vnffgcatalog', 'vnffgmanager',
|
||||||
'nscatalog', 'nsmanager')
|
'nscatalog', 'nsmanager')
|
||||||
|
|
||||||
|
|
||||||
|
class Vnfpkggroup(horizon.PanelGroup):
|
||||||
|
slug = "vnfpkggroup"
|
||||||
|
name = _("VNF Packages v1")
|
||||||
|
panels = ('vnfpackages',)
|
||||||
|
|
||||||
|
|
||||||
|
class Vnflcmgroup(horizon.PanelGroup):
|
||||||
|
slug = "vnflcmgroup"
|
||||||
|
name = _("VNF LCM v2")
|
||||||
|
panels = ('vnflcm', 'vnflcmopocc', 'lccnsubscription',)
|
||||||
|
|
||||||
|
|
||||||
|
class Vnffmgroup(horizon.PanelGroup):
|
||||||
|
slug = "vnffmgroup"
|
||||||
|
name = _("VNF FM v1")
|
||||||
|
panels = ('vnffmalarm', 'vnffmsubscription',)
|
||||||
|
|
||||||
|
|
||||||
|
class Vnfpmgroup(horizon.PanelGroup):
|
||||||
|
slug = "vnfpmgroup"
|
||||||
|
name = _("VNF PM v2")
|
||||||
|
panels = ('vnfpmjob', 'vnfpmthreshold',)
|
||||||
|
|
||||||
|
|
||||||
class Nfv(horizon.Dashboard):
|
class Nfv(horizon.Dashboard):
|
||||||
name = _("NFV")
|
name = _("NFV")
|
||||||
slug = "nfv"
|
slug = "nfv"
|
||||||
panels = (Vnfmgroup, Nfvogroup,) # Add your panels here.
|
panels = (Vnfmgroup, Nfvogroup, Vnfpkggroup, Vnflcmgroup, Vnffmgroup,
|
||||||
|
Vnfpmgroup,) # Add your panels here.
|
||||||
default_panel = 'vnfcatalog' # Specify the slug of the dashboard's
|
default_panel = 'vnfcatalog' # Specify the slug of the dashboard's
|
||||||
# default panel.
|
# default panel.
|
||||||
|
|
||||||
|
@ -0,0 +1,65 @@
|
|||||||
|
# Copyright (C) 2024 Fujitsu
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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 json
|
||||||
|
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from horizon import exceptions
|
||||||
|
from horizon import forms
|
||||||
|
from horizon import messages
|
||||||
|
|
||||||
|
from tacker_horizon.openstack_dashboard import api
|
||||||
|
|
||||||
|
|
||||||
|
class CreateLccnSubscription(forms.SelfHandlingForm):
|
||||||
|
param_file = forms.FileField(
|
||||||
|
label=_("Param File"),
|
||||||
|
widget=forms.FileInput(attrs={
|
||||||
|
'class': 'switched',
|
||||||
|
'data-switch-on': 'source',
|
||||||
|
'data-source-upload': _('Param File')}))
|
||||||
|
|
||||||
|
def __init__(self, request, *args, **kwargs):
|
||||||
|
super(CreateLccnSubscription, self).__init__(request, *args, **kwargs)
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
data = super(CreateLccnSubscription, self).clean()
|
||||||
|
|
||||||
|
try:
|
||||||
|
param_str = self.files['param_file'].read()
|
||||||
|
param = json.loads(param_str)
|
||||||
|
data['param_data'] = param
|
||||||
|
except Exception as e:
|
||||||
|
msg = _('Failed to read file: %s.') % e
|
||||||
|
raise forms.ValidationError(msg)
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
def handle(self, request, data):
|
||||||
|
try:
|
||||||
|
param = data['param_data']
|
||||||
|
subsc = api.tacker.create_vnf_lcm_subscription(request, param)
|
||||||
|
messages.success(
|
||||||
|
request,
|
||||||
|
_('Create LCCN Subscription. (id: %s)') % subsc['id'])
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
exceptions.handle(
|
||||||
|
request,
|
||||||
|
_('Failed to create LCCN Subscription.'))
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
@ -0,0 +1,29 @@
|
|||||||
|
# Copyright (C) 2024 Fujitsu
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
import horizon
|
||||||
|
|
||||||
|
from tacker_horizon.openstack_dashboard.dashboards.nfv import dashboard
|
||||||
|
|
||||||
|
|
||||||
|
class LccnSubscription(horizon.Panel):
|
||||||
|
name = _("LCCN Subscription")
|
||||||
|
slug = "lccnsubscription"
|
||||||
|
|
||||||
|
|
||||||
|
dashboard.Nfv.register(LccnSubscription)
|
@ -0,0 +1,69 @@
|
|||||||
|
# Copyright (C) 2024 Fujitsu
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from django.utils.translation import ngettext_lazy
|
||||||
|
|
||||||
|
from horizon import tables
|
||||||
|
from openstack_dashboard import policy
|
||||||
|
|
||||||
|
from tacker_horizon.openstack_dashboard import api
|
||||||
|
|
||||||
|
|
||||||
|
class DeleteLccnSubscription(policy.PolicyTargetMixin, tables.DeleteAction):
|
||||||
|
@staticmethod
|
||||||
|
def action_present(count):
|
||||||
|
return ngettext_lazy(
|
||||||
|
"Delete Lccn Subscription",
|
||||||
|
"Delete Lccn Subscriptions",
|
||||||
|
count
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def action_past(count):
|
||||||
|
return ngettext_lazy(
|
||||||
|
"Delete Lccn Subscription",
|
||||||
|
"Delete Lccn Subscriptions",
|
||||||
|
count
|
||||||
|
)
|
||||||
|
|
||||||
|
def action(self, request, obj_id):
|
||||||
|
api.tacker.delete_vnf_lcm_subscription(request, obj_id)
|
||||||
|
|
||||||
|
|
||||||
|
class CreateLccnSubscription(tables.LinkAction):
|
||||||
|
name = "create_lccnsubsc"
|
||||||
|
verbose_name = _("Create Lccn Subscription")
|
||||||
|
classes = ("ajax-modal",)
|
||||||
|
icon = "plus"
|
||||||
|
url = "horizon:nfv:lccnsubscription:createlccnsubscription"
|
||||||
|
|
||||||
|
|
||||||
|
class LccnSubscriptionTable(tables.DataTable):
|
||||||
|
id = tables.Column('id', verbose_name=_("ID"),
|
||||||
|
link="horizon:nfv:lccnsubscription:detail",)
|
||||||
|
callback_uri = tables.Column('callback_uri',
|
||||||
|
verbose_name=_("Callback URI"))
|
||||||
|
|
||||||
|
class Meta(object):
|
||||||
|
name = "lccnsubsc"
|
||||||
|
verbose_name = _("LCCN Subscription")
|
||||||
|
pagination_param = 'subsc_marker'
|
||||||
|
prev_pagination_param = 'prev_subsc_marker'
|
||||||
|
table_actions = (CreateLccnSubscription, DeleteLccnSubscription,
|
||||||
|
tables.FilterAction)
|
||||||
|
row_actions = (DeleteLccnSubscription,)
|
||||||
|
multi_select = True
|
@ -0,0 +1,109 @@
|
|||||||
|
# Copyright (C) 2024 Fujitsu
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from horizon import exceptions
|
||||||
|
from horizon import tabs
|
||||||
|
from horizon import utils as horizon_utils
|
||||||
|
|
||||||
|
from tacker_horizon.openstack_dashboard import api
|
||||||
|
from tacker_horizon.openstack_dashboard.dashboards.nfv.lccnsubscription \
|
||||||
|
import tables
|
||||||
|
|
||||||
|
|
||||||
|
class LccnSubscItem(object):
|
||||||
|
def __init__(self, subsc_id, callback_uri):
|
||||||
|
self.id = subsc_id
|
||||||
|
self.name = subsc_id
|
||||||
|
self.callback_uri = callback_uri
|
||||||
|
|
||||||
|
|
||||||
|
class LccnSubscriptionTab(tabs.TableTab):
|
||||||
|
name = _("LCCN Subscription tab")
|
||||||
|
slug = "lccnsubsc_tab"
|
||||||
|
table_classes = (tables.LccnSubscriptionTable,)
|
||||||
|
template_name = ("horizon/common/_detail_table.html")
|
||||||
|
preload = False
|
||||||
|
|
||||||
|
def has_prev_data(self, table):
|
||||||
|
return self._has_prev
|
||||||
|
|
||||||
|
def has_more_data(self, table):
|
||||||
|
return self._has_more
|
||||||
|
|
||||||
|
def get_lccnsubsc_data(self):
|
||||||
|
try:
|
||||||
|
self._has_prev = False
|
||||||
|
page_size = horizon_utils.functions.get_page_size(self.request)
|
||||||
|
marker = self.request.GET.get(
|
||||||
|
"subsc_marker", None)
|
||||||
|
prev_marker = self.request.GET.get(
|
||||||
|
"prev_subsc_marker", None)
|
||||||
|
subscs = api.tacker.list_vnf_lcm_subscriptions(
|
||||||
|
self.request)
|
||||||
|
if marker is not None or prev_marker is not None:
|
||||||
|
for i, subsc in enumerate(subscs):
|
||||||
|
if subsc["id"] == marker and i < len(subscs) - 1:
|
||||||
|
subscs = subscs[i + 1:]
|
||||||
|
self._has_prev = True
|
||||||
|
break
|
||||||
|
if subsc["id"] == prev_marker and i > page_size:
|
||||||
|
subscs = subscs[i - page_size:]
|
||||||
|
self._has_prev = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if len(subscs) > page_size:
|
||||||
|
self._has_more = True
|
||||||
|
else:
|
||||||
|
self._has_more = False
|
||||||
|
|
||||||
|
rows = []
|
||||||
|
for i, subsc in enumerate(subscs):
|
||||||
|
if i >= page_size:
|
||||||
|
break
|
||||||
|
item = LccnSubscItem(
|
||||||
|
subsc_id=subsc.get('id', ''),
|
||||||
|
callback_uri=subsc.get('callbackUri', ''))
|
||||||
|
rows.append(item)
|
||||||
|
return rows
|
||||||
|
except Exception:
|
||||||
|
self._has_more = False
|
||||||
|
error_message = _('Failed to get LCCN Subscriptions.')
|
||||||
|
exceptions.handle(self.request, error_message)
|
||||||
|
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
class LccnSubscriptionTabs(tabs.TabGroup):
|
||||||
|
slug = "lccnsubsc_tabs"
|
||||||
|
tabs = (LccnSubscriptionTab,)
|
||||||
|
sticky = True
|
||||||
|
|
||||||
|
|
||||||
|
class LccnSubscDetailTab(tabs.Tab):
|
||||||
|
name = _("LCCN Subscription Detail Tab")
|
||||||
|
slug = "lccnsubsc_detail_tab"
|
||||||
|
template_name = "nfv/lccnsubscription/lccnsubsc_detail.html"
|
||||||
|
|
||||||
|
def get_context_data(self, request):
|
||||||
|
return {'lccnsubscription': self.tab_group.kwargs['lccnsubscription']}
|
||||||
|
|
||||||
|
|
||||||
|
class LccnSubscDetailTabs(tabs.TabGroup):
|
||||||
|
slug = "lccnsubsc_detail_tabs"
|
||||||
|
tabs = (LccnSubscDetailTab,)
|
||||||
|
sticky = True
|
@ -0,0 +1,9 @@
|
|||||||
|
{% extends "horizon/common/_modal_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block form_attrs %}enctype="multipart/form-data"{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-body-right %}
|
||||||
|
<h3>{% trans "Description:" %}</h3>
|
||||||
|
<p>{% trans "Create a Lccn Subscription." %}</p>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,11 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "create_lccn_subscription" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=_("create_lccn_subscription") %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include 'nfv/lccnsubscription/_create_lccn_subscription.html' %}
|
||||||
|
{% endblock %}
|
@ -0,0 +1,15 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Lccn Subscription Detail" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=page_title %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
{{ tab_group.render }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,15 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "LCCN Subscription" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=_("LCCN Subscription") %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
{{ tab_group.render }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,14 @@
|
|||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
<div class="detail">
|
||||||
|
<dl class="dl-horizontal">
|
||||||
|
<dt>{% trans "Callback URI" %}</dt>
|
||||||
|
<dd>{{ lccnsubscription.callbackUri }}</dd>
|
||||||
|
<dt>{% trans "Filter" %}</dt>
|
||||||
|
<dd>{{ lccnsubscription.filter }}</dd>
|
||||||
|
<dt>{% trans "ID" %}</dt>
|
||||||
|
<dd>{{ lccnsubscription.id }}</dd>
|
||||||
|
<dt>{% trans "Links" %}</dt>
|
||||||
|
<dd>{{ lccnsubscription.links }}</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
@ -0,0 +1,29 @@
|
|||||||
|
# Copyright (C) 2024 Fujitsu
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
|
from django.urls import re_path
|
||||||
|
|
||||||
|
from tacker_horizon.openstack_dashboard.dashboards.nfv.lccnsubscription \
|
||||||
|
import views
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
re_path(r'^$', views.IndexView.as_view(), name='index'),
|
||||||
|
re_path(r'^(?P<id>[^/]+)/$', views.DetailView.as_view(),
|
||||||
|
name='detail'),
|
||||||
|
re_path(r'^createlccnsubscription$',
|
||||||
|
views.CreateLccnSubscriptionView.as_view(),
|
||||||
|
name='createlccnsubscription'),
|
||||||
|
]
|
@ -0,0 +1,88 @@
|
|||||||
|
# Copyright (C) 2024 Fujitsu
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
|
from django.urls import reverse
|
||||||
|
from django.urls import reverse_lazy
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from horizon import exceptions
|
||||||
|
from horizon import forms
|
||||||
|
from horizon import tabs
|
||||||
|
from horizon.utils import memoized
|
||||||
|
|
||||||
|
from tacker_horizon.openstack_dashboard import api as tacker_api
|
||||||
|
from tacker_horizon.openstack_dashboard.dashboards.nfv.lccnsubscription \
|
||||||
|
import forms as project_forms
|
||||||
|
from tacker_horizon.openstack_dashboard.dashboards.nfv.lccnsubscription \
|
||||||
|
import tabs as lccnsubsctabs
|
||||||
|
|
||||||
|
|
||||||
|
class IndexView(tabs.TabbedTableView):
|
||||||
|
tab_group_class = lccnsubsctabs.LccnSubscriptionTabs
|
||||||
|
template_name = 'nfv/lccnsubscription/index.html'
|
||||||
|
|
||||||
|
|
||||||
|
class CreateLccnSubscriptionView(forms.ModalFormView):
|
||||||
|
form_class = project_forms.CreateLccnSubscription
|
||||||
|
template_name = 'nfv/lccnsubscription/create_lccn_subscription.html'
|
||||||
|
success_url = reverse_lazy("horizon:nfv:lccnsubscription:index")
|
||||||
|
modal_id = "add_service_modal"
|
||||||
|
modal_header = _("Create Lccn Subscription")
|
||||||
|
submit_label = _("Create Lccn Subscription")
|
||||||
|
submit_url = "horizon:nfv:lccnsubscription:createlccnsubscription"
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(
|
||||||
|
CreateLccnSubscriptionView, self).get_context_data(**kwargs)
|
||||||
|
context['submit_url'] = reverse(self.submit_url)
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class DetailView(tabs.TabView):
|
||||||
|
tab_group_class = lccnsubsctabs.LccnSubscDetailTabs
|
||||||
|
template_name = 'nfv/lccnsubscription/detail.html'
|
||||||
|
redirect_url = 'horizon:nfv:lccnsubscription:index'
|
||||||
|
page_title = _("LCCN Subscription Detail")
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(DetailView, self).get_context_data(**kwargs)
|
||||||
|
lccnsubscription = self.get_data()
|
||||||
|
context['lccnsubscription'] = lccnsubscription
|
||||||
|
context['id'] = kwargs['id']
|
||||||
|
context['url'] = reverse(self.redirect_url)
|
||||||
|
return context
|
||||||
|
|
||||||
|
@memoized.memoized_method
|
||||||
|
def get_data(self):
|
||||||
|
subsc_id = self.kwargs.get('id', None)
|
||||||
|
|
||||||
|
try:
|
||||||
|
lccnsubscription = tacker_api.tacker.get_vnf_lcm_subscription(
|
||||||
|
self.request, subsc_id)
|
||||||
|
lccnsubscription['links'] = lccnsubscription.get('_links', '')
|
||||||
|
return lccnsubscription
|
||||||
|
except Exception as e:
|
||||||
|
redirect = reverse(self.redirect_url)
|
||||||
|
exceptions.handle(
|
||||||
|
self.request,
|
||||||
|
_('Failed to get LCCN Subscription. (id: %s)') % subsc_id,
|
||||||
|
redirect=redirect)
|
||||||
|
raise exceptions.Http302(redirect) from e
|
||||||
|
|
||||||
|
def get_tabs(self, request, *args, **kwargs):
|
||||||
|
lccnsubscription = self.get_data()
|
||||||
|
return self.tab_group_class(
|
||||||
|
request, lccnsubscription=lccnsubscription, **kwargs)
|
@ -0,0 +1,52 @@
|
|||||||
|
# Copyright (C) 2024 Fujitsu
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from horizon import exceptions
|
||||||
|
from horizon import forms
|
||||||
|
from horizon import messages
|
||||||
|
|
||||||
|
from tacker_horizon.openstack_dashboard import api
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateVnfFmAlarm(forms.SelfHandlingForm):
|
||||||
|
ack_state = forms.ChoiceField(
|
||||||
|
label=_('ACK State'),
|
||||||
|
choices=[('ACKNOWLEDGED', _('ACKNOWLEDGED')),
|
||||||
|
('UNACKNOWLEDGED', _('UNACKNOWLEDGED'))])
|
||||||
|
|
||||||
|
def __init__(self, request, *args, **kwargs):
|
||||||
|
super(UpdateVnfFmAlarm, self).__init__(request, *args, **kwargs)
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
data = super(UpdateVnfFmAlarm, self).clean()
|
||||||
|
return data
|
||||||
|
|
||||||
|
def handle(self, request, data):
|
||||||
|
try:
|
||||||
|
ack_state = data.get('ack_state', None)
|
||||||
|
|
||||||
|
body = {}
|
||||||
|
body['ackState'] = ack_state
|
||||||
|
alarm_id = request.resolver_match.kwargs['id']
|
||||||
|
api.tacker.update_fm_alarm(request, alarm_id, body)
|
||||||
|
messages.success(request,
|
||||||
|
_('Update FM Alarm. (id: %s)') % alarm_id)
|
||||||
|
return True
|
||||||
|
except Exception:
|
||||||
|
msg = _('Failed to update FM Alarm. (id: %s)') % alarm_id
|
||||||
|
exceptions.handle(request, msg)
|
||||||
|
return False
|
@ -0,0 +1,29 @@
|
|||||||
|
# Copyright (C) 2024 Fujitsu
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
import horizon
|
||||||
|
|
||||||
|
from tacker_horizon.openstack_dashboard.dashboards.nfv import dashboard
|
||||||
|
|
||||||
|
|
||||||
|
class VnfFmAlarm(horizon.Panel):
|
||||||
|
name = _("Alarm")
|
||||||
|
slug = "vnffmalarm"
|
||||||
|
|
||||||
|
|
||||||
|
dashboard.Nfv.register(VnfFmAlarm)
|
@ -0,0 +1,48 @@
|
|||||||
|
# Copyright (C) 2024 Fujitsu
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from horizon import tables
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateVnfFmAlarm(tables.LinkAction):
|
||||||
|
name = "updatealarm"
|
||||||
|
verbose_name = _("Update Alarm")
|
||||||
|
url = "horizon:nfv:vnffmalarm:updatealarm"
|
||||||
|
classes = ("ajax-modal",)
|
||||||
|
|
||||||
|
|
||||||
|
class VnfFmAlarmTable(tables.DataTable):
|
||||||
|
id = tables.Column('id', link="horizon:nfv:vnffmalarm:detail",
|
||||||
|
verbose_name=_("ID"))
|
||||||
|
|
||||||
|
managed_object_id = tables.Column('managed_object_id',
|
||||||
|
verbose_name=_("Managed Object ID"))
|
||||||
|
ack_state = tables.Column('ack_state', verbose_name=_("Ack State"))
|
||||||
|
event_type = tables.Column('event_type', verbose_name=_("Event Type"))
|
||||||
|
perceived_severity = tables.Column('perceived_severity',
|
||||||
|
verbose_name=_("Perceived Severity"))
|
||||||
|
probable_cause = tables.Column('probable_cause',
|
||||||
|
verbose_name=_("Probable Cause"))
|
||||||
|
|
||||||
|
class Meta(object):
|
||||||
|
name = "alarm"
|
||||||
|
verbose_name = _("Alarm")
|
||||||
|
pagination_param = 'vnffmalarm_marker'
|
||||||
|
prev_pagination_param = 'prev_vnffmalarm_marker'
|
||||||
|
table_actions = (tables.FilterAction,)
|
||||||
|
row_actions = (UpdateVnfFmAlarm,)
|
@ -0,0 +1,114 @@
|
|||||||
|
# Copyright (C) 2024 Fujitsu
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from horizon import exceptions
|
||||||
|
from horizon import tabs
|
||||||
|
from horizon import utils as horizon_utils
|
||||||
|
|
||||||
|
from tacker_horizon.openstack_dashboard import api
|
||||||
|
from tacker_horizon.openstack_dashboard.dashboards.nfv.vnffmalarm \
|
||||||
|
import tables
|
||||||
|
|
||||||
|
|
||||||
|
class VnfFmAlarmItem(object):
|
||||||
|
def __init__(self, alarm_id, managed_object_id, ack_state, event_type,
|
||||||
|
perceived_severity, probable_cause):
|
||||||
|
self.id = alarm_id
|
||||||
|
self.name = alarm_id
|
||||||
|
self.managed_object_id = managed_object_id
|
||||||
|
self.ack_state = ack_state
|
||||||
|
self.event_type = event_type
|
||||||
|
self.perceived_severity = perceived_severity
|
||||||
|
self.probable_cause = probable_cause
|
||||||
|
|
||||||
|
|
||||||
|
class VnfFmAlarmTab(tabs.TableTab):
|
||||||
|
name = _("VNFFMAlarm Tab")
|
||||||
|
slug = "vnffmalarm_tab"
|
||||||
|
table_classes = (tables.VnfFmAlarmTable,)
|
||||||
|
template_name = "horizon/common/_detail_table.html"
|
||||||
|
preload = False
|
||||||
|
|
||||||
|
def has_prev_data(self, table):
|
||||||
|
return self._has_prev
|
||||||
|
|
||||||
|
def has_more_data(self, table):
|
||||||
|
return self._has_more
|
||||||
|
|
||||||
|
def get_alarm_data(self):
|
||||||
|
try:
|
||||||
|
self._has_prev = False
|
||||||
|
page_size = horizon_utils.functions.get_page_size(self.request)
|
||||||
|
marker = self.request.GET.get("vnffmalarm_marker", None)
|
||||||
|
prev_marker = self.request.GET.get("prev_vnffmalarm_marker", None)
|
||||||
|
alarms = api.tacker.list_fm_alarms(self.request)
|
||||||
|
|
||||||
|
if marker is not None or prev_marker is not None:
|
||||||
|
for i, alarm in enumerate(alarms):
|
||||||
|
if alarm["id"] == marker and i < len(alarms) - 1:
|
||||||
|
alarms = alarms[i + 1:]
|
||||||
|
self._has_prev = True
|
||||||
|
break
|
||||||
|
if alarm["id"] == prev_marker and i > page_size:
|
||||||
|
alarms = alarms[i - page_size:]
|
||||||
|
self._has_prev = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if len(alarms) > page_size:
|
||||||
|
self._has_more = True
|
||||||
|
else:
|
||||||
|
self._has_more = False
|
||||||
|
|
||||||
|
rows = []
|
||||||
|
for i, alarm in enumerate(alarms):
|
||||||
|
if i >= page_size:
|
||||||
|
break
|
||||||
|
item = VnfFmAlarmItem(alarm['id'],
|
||||||
|
alarm['managedObjectId'],
|
||||||
|
alarm['ackState'],
|
||||||
|
alarm['eventType'],
|
||||||
|
alarm['perceivedSeverity'],
|
||||||
|
alarm['probableCause'])
|
||||||
|
rows.append(item)
|
||||||
|
return rows
|
||||||
|
except Exception:
|
||||||
|
self._has_more = False
|
||||||
|
error_message = _('Failed to get FM Alarms.')
|
||||||
|
exceptions.handle(self.request, error_message)
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
class VnfFmAlarmTabs(tabs.TabGroup):
|
||||||
|
slug = "vnffmalarm_tabs"
|
||||||
|
tabs = (VnfFmAlarmTab,)
|
||||||
|
sticky = True
|
||||||
|
|
||||||
|
|
||||||
|
class VnfFmAlarmDetailTab(tabs.Tab):
|
||||||
|
name = _("VNF FM Alarm")
|
||||||
|
slug = "vnffmalarm_detail_tab"
|
||||||
|
template_name = "nfv/vnffmalarm/alarm_detail.html"
|
||||||
|
|
||||||
|
def get_context_data(self, request):
|
||||||
|
return {'alarm': self.tab_group.kwargs['alarm']}
|
||||||
|
|
||||||
|
|
||||||
|
class VnfFmAlarmDetailTabs(tabs.TabGroup):
|
||||||
|
slug = "vnffmalarm_detail_tabs"
|
||||||
|
tabs = (VnfFmAlarmDetailTab,)
|
||||||
|
sticky = True
|
@ -0,0 +1,9 @@
|
|||||||
|
{% extends "horizon/common/_modal_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block form_attrs %}enctype="multipart/form-data"{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-body-right %}
|
||||||
|
<h3>{% trans "Description:" %}</h3>
|
||||||
|
<p>{% trans "Update a Alarm." %}</p>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,42 @@
|
|||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
<div class="detail">
|
||||||
|
<dl class="dl-horizontal">
|
||||||
|
<dt>{% trans "Ack State" %}</dt>
|
||||||
|
<dd>{{ alarm.ackState }}</dd>
|
||||||
|
<dt title="Alarm Acknowledged Time">{% trans "Alarm Acknowledged Time" %}</dt>
|
||||||
|
<dd>{{ alarm.alarmAcknowledgedTime }}</dd>
|
||||||
|
<dt>{% trans "Alarm Changed Time" %}</dt>
|
||||||
|
<dd>{{ alarm.alarmChangedTime }}</dd>
|
||||||
|
<dt>{% trans "Alarm Cleared Time" %}</dt>
|
||||||
|
<dd>{{ alarm.alarmClearedTime }}</dd>
|
||||||
|
<dt>{% trans "Alarm Raised Time" %}</dt>
|
||||||
|
<dd>{{ alarm.alarmRaisedTime }}</dd>
|
||||||
|
<dt>{% trans "Correlated Alarm IDs" %}</dt>
|
||||||
|
<dd>{{ alarm.correlatedAlarmIds }}</dd>
|
||||||
|
<dt>{% trans "Event Time" %}</dt>
|
||||||
|
<dd>{{ alarm.eventTime }}</dd>
|
||||||
|
<dt>{% trans "Event Type" %}</dt>
|
||||||
|
<dd>{{ alarm.eventType }}</dd>
|
||||||
|
<dt>{% trans "Fault Details" %}</dt>
|
||||||
|
<dd>{{ alarm.faultDetails }}</dd>
|
||||||
|
<dt>{% trans "Fault Type" %}</dt>
|
||||||
|
<dd>{{ alarm.faultType }}</dd>
|
||||||
|
<dt>{% trans "ID" %}</dt>
|
||||||
|
<dd>{{ alarm.id }}</dd>
|
||||||
|
<dt>{% trans "Is Root Cause" %}</dt>
|
||||||
|
<dd>{{ alarm.isRootCause }}</dd>
|
||||||
|
<dt>{% trans "Links" %}</dt>
|
||||||
|
<dd>{{ alarm.links }}</dd>
|
||||||
|
<dt>{% trans "Managed Object ID" %}</dt>
|
||||||
|
<dd>{{ alarm.managedObjectId }}</dd>
|
||||||
|
<dt>{% trans "Perceived Severity" %}</dt>
|
||||||
|
<dd>{{ alarm.perceivedSeverity }}</dd>
|
||||||
|
<dt>{% trans "Probable Cause" %}</dt>
|
||||||
|
<dd>{{ alarm.probableCause }}</dd>
|
||||||
|
<dt title="Root Cause Faulty Resource">{% trans "Root Cause Faulty Resource" %}</dt>
|
||||||
|
<dd>{{ alarm.rootCauseFaultyResource }}</dd>
|
||||||
|
<dt>{% trans "VNFC Instance IDs" %}</dt>
|
||||||
|
<dd>{{ alarm.vnfcInstanceIds }}</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
@ -0,0 +1,15 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Alarm Detail" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=page_title %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
{{ tab_group.render }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,15 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Alarm" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=_("Alarm") %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
{{ tab_group.render }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,11 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Update Alarm" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=_("Update Alarm") %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include 'nfv/vnffmalarm/_update_alarm.html' %}
|
||||||
|
{% endblock %}
|
@ -0,0 +1,29 @@
|
|||||||
|
# Copyright (C) 2024 Fujitsu
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
|
from django.urls import re_path
|
||||||
|
|
||||||
|
from tacker_horizon.openstack_dashboard.dashboards.nfv.vnffmalarm \
|
||||||
|
import views
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
re_path(r'^$', views.IndexView.as_view(), name='index'),
|
||||||
|
re_path(r'^(?P<id>[^/]+)/updatealarm$',
|
||||||
|
views.UpdateVnfFmAlarmView.as_view(),
|
||||||
|
name='updatealarm'),
|
||||||
|
re_path(r'^(?P<id>[^/]+)/$', views.DetailView.as_view(),
|
||||||
|
name='detail'),
|
||||||
|
]
|
@ -0,0 +1,90 @@
|
|||||||
|
# Copyright (C) 2024 Fujitsu
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
|
from django.urls import reverse
|
||||||
|
from django.urls import reverse_lazy
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from horizon import exceptions
|
||||||
|
from horizon import forms
|
||||||
|
from horizon import tabs
|
||||||
|
from horizon.utils import memoized
|
||||||
|
|
||||||
|
from tacker_horizon.openstack_dashboard import api as tacker_api
|
||||||
|
from tacker_horizon.openstack_dashboard.dashboards.nfv.vnffmalarm \
|
||||||
|
import forms as project_forms
|
||||||
|
from tacker_horizon.openstack_dashboard.dashboards.nfv.vnffmalarm \
|
||||||
|
import tabs as alarm_tabs
|
||||||
|
|
||||||
|
|
||||||
|
class IndexView(tabs.TabbedTableView):
|
||||||
|
# A very simple class-based view...
|
||||||
|
tab_group_class = alarm_tabs.VnfFmAlarmTabs
|
||||||
|
template_name = 'nfv/vnffmalarm/index.html'
|
||||||
|
|
||||||
|
def get_data(self, request, context, *args, **kwargs):
|
||||||
|
# Add data to the context here...
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateVnfFmAlarmView(forms.ModalFormView):
|
||||||
|
form_class = project_forms.UpdateVnfFmAlarm
|
||||||
|
template_name = 'nfv/vnffmalarm/update_alarm.html'
|
||||||
|
success_url = reverse_lazy("horizon:nfv:vnffmalarm:index")
|
||||||
|
modal_id = "update_alarm_modal"
|
||||||
|
modal_header = _("Update Alarm")
|
||||||
|
submit_label = _("Update Alarm")
|
||||||
|
submit_url = "horizon:nfv:vnffmalarm:updatealarm"
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(UpdateVnfFmAlarmView, self).get_context_data(**kwargs)
|
||||||
|
context['submit_url'] = reverse(self.submit_url,
|
||||||
|
kwargs={'id': self.kwargs['id']})
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class DetailView(tabs.TabView):
|
||||||
|
tab_group_class = alarm_tabs.VnfFmAlarmDetailTabs
|
||||||
|
template_name = 'nfv/vnffmalarm/detail.html'
|
||||||
|
redirect_url = 'horizon:nfv:vnffmalarm:index'
|
||||||
|
page_title = _("Alarm Detail: {{ id }}")
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(DetailView, self).get_context_data(**kwargs)
|
||||||
|
alarm = self.get_data()
|
||||||
|
context['alarm'] = alarm
|
||||||
|
context['id'] = kwargs['id']
|
||||||
|
context['url'] = reverse(self.redirect_url)
|
||||||
|
return context
|
||||||
|
|
||||||
|
@memoized.memoized_method
|
||||||
|
def get_data(self):
|
||||||
|
alarm_id = self.kwargs['id']
|
||||||
|
|
||||||
|
try:
|
||||||
|
alarm = tacker_api.tacker.get_fm_alarm(self.request, alarm_id)
|
||||||
|
alarm['links'] = alarm.get('_links', '')
|
||||||
|
return alarm
|
||||||
|
except Exception:
|
||||||
|
redirect = reverse(self.redirect_url)
|
||||||
|
exceptions.handle(self.request,
|
||||||
|
_('Failed to get FM Alarm. (id: %s)') % alarm_id,
|
||||||
|
redirect=redirect)
|
||||||
|
raise exceptions.Http302(redirect)
|
||||||
|
|
||||||
|
def get_tabs(self, request, *args, **kwargs):
|
||||||
|
alarm = self.get_data()
|
||||||
|
return self.tab_group_class(request, alarm=alarm, **kwargs)
|
@ -0,0 +1,64 @@
|
|||||||
|
# Copyright (C) 2024 Fujitsu
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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 json
|
||||||
|
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from horizon import exceptions
|
||||||
|
from horizon import forms
|
||||||
|
from horizon import messages
|
||||||
|
|
||||||
|
from tacker_horizon.openstack_dashboard import api
|
||||||
|
|
||||||
|
|
||||||
|
class CreateVnfFmSubscription(forms.SelfHandlingForm):
|
||||||
|
param_file = forms.FileField(
|
||||||
|
label=_("Param File"),
|
||||||
|
help_text=_("parameter file to upload."),
|
||||||
|
widget=forms.FileInput(
|
||||||
|
attrs={'class': 'switched',
|
||||||
|
'data-switch-on': 'source',
|
||||||
|
'data-source-file': _('Param File')}))
|
||||||
|
|
||||||
|
def __init__(self, request, *args, **kwargs):
|
||||||
|
super(CreateVnfFmSubscription, self).__init__(request, *args, **kwargs)
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
data = super(CreateVnfFmSubscription, self).clean()
|
||||||
|
|
||||||
|
try:
|
||||||
|
param_str = self.files['param_file'].read()
|
||||||
|
param = json.loads(param_str)
|
||||||
|
data['param'] = param
|
||||||
|
except Exception as e:
|
||||||
|
msg = _('Failed to read file: %s.') % e
|
||||||
|
raise forms.ValidationError(msg)
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
def handle(self, request, data):
|
||||||
|
try:
|
||||||
|
param = data['param']
|
||||||
|
subscription_instance = api.tacker.create_fm_subscription(
|
||||||
|
request, param)
|
||||||
|
messages.success(request,
|
||||||
|
_('Create FM Subscription. (id: %s)') %
|
||||||
|
subscription_instance['id'])
|
||||||
|
return True
|
||||||
|
except Exception:
|
||||||
|
msg = _('Failed to create FM Subscription.')
|
||||||
|
exceptions.handle(request, msg)
|
||||||
|
return False
|
@ -0,0 +1,29 @@
|
|||||||
|
# Copyright (C) 2024 Fujitsu
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
import horizon
|
||||||
|
|
||||||
|
from tacker_horizon.openstack_dashboard.dashboards.nfv import dashboard
|
||||||
|
|
||||||
|
|
||||||
|
class VnfFmSubscription(horizon.Panel):
|
||||||
|
name = _("Subscription")
|
||||||
|
slug = "vnffmsubscription"
|
||||||
|
|
||||||
|
|
||||||
|
dashboard.Nfv.register(VnfFmSubscription)
|
@ -0,0 +1,68 @@
|
|||||||
|
# Copyright (C) 2024 Fujitsu
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from django.utils.translation import ngettext_lazy
|
||||||
|
|
||||||
|
from horizon import tables
|
||||||
|
from openstack_dashboard import policy
|
||||||
|
|
||||||
|
from tacker_horizon.openstack_dashboard import api
|
||||||
|
|
||||||
|
|
||||||
|
class DeleteVnfFmSubscription(policy.PolicyTargetMixin, tables.DeleteAction):
|
||||||
|
@staticmethod
|
||||||
|
def action_present(count):
|
||||||
|
return ngettext_lazy(
|
||||||
|
"Delete Subscription",
|
||||||
|
"Delete Subscriptions",
|
||||||
|
count
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def action_past(count):
|
||||||
|
return ngettext_lazy(
|
||||||
|
"Delete Subscription",
|
||||||
|
"Delete Subscriptions",
|
||||||
|
count
|
||||||
|
)
|
||||||
|
|
||||||
|
def action(self, request, obj_id):
|
||||||
|
api.tacker.delete_fm_subscription(request, obj_id)
|
||||||
|
|
||||||
|
|
||||||
|
class CreateVnfFmSubscription(tables.LinkAction):
|
||||||
|
name = "createsubscription"
|
||||||
|
verbose_name = _("Create Subscription")
|
||||||
|
classes = ("ajax-modal",)
|
||||||
|
icon = "plus"
|
||||||
|
url = "horizon:nfv:vnffmsubscription:createsubscription"
|
||||||
|
|
||||||
|
|
||||||
|
class VnfFmSubscriptionTable(tables.DataTable):
|
||||||
|
id = tables.Column('id', link="horizon:nfv:vnffmsubscription:detail",
|
||||||
|
verbose_name=_("ID"))
|
||||||
|
callback_uri = tables.Column('callback_uri',
|
||||||
|
verbose_name=_("Callback Uri"))
|
||||||
|
|
||||||
|
class Meta(object):
|
||||||
|
name = "subscription"
|
||||||
|
verbose_name = _("Subscription")
|
||||||
|
pagination_param = 'vnffmsubscription_marker'
|
||||||
|
prev_pagination_param = 'prev_vnffmsubscription_marker'
|
||||||
|
table_actions = (CreateVnfFmSubscription, DeleteVnfFmSubscription,
|
||||||
|
tables.FilterAction,)
|
||||||
|
row_actions = (DeleteVnfFmSubscription,)
|
@ -0,0 +1,106 @@
|
|||||||
|
# Copyright (C) 2024 Fujitsu
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from horizon import exceptions
|
||||||
|
from horizon import tabs
|
||||||
|
from horizon import utils as horizon_utils
|
||||||
|
|
||||||
|
from tacker_horizon.openstack_dashboard import api
|
||||||
|
from tacker_horizon.openstack_dashboard.dashboards.nfv.vnffmsubscription \
|
||||||
|
import tables
|
||||||
|
|
||||||
|
|
||||||
|
class VnfFmSubscriptionItem(object):
|
||||||
|
def __init__(self, subscription_id, callback_uri):
|
||||||
|
self.id = subscription_id
|
||||||
|
self.name = subscription_id
|
||||||
|
self.callback_uri = callback_uri
|
||||||
|
|
||||||
|
|
||||||
|
class VnfFmSubscriptionTab(tabs.TableTab):
|
||||||
|
name = _("VNFFMSubscription Tab")
|
||||||
|
slug = "vnffmsubscription_tab"
|
||||||
|
table_classes = (tables.VnfFmSubscriptionTable,)
|
||||||
|
template_name = "horizon/common/_detail_table.html"
|
||||||
|
preload = False
|
||||||
|
|
||||||
|
def has_prev_data(self, table):
|
||||||
|
return self._has_prev
|
||||||
|
|
||||||
|
def has_more_data(self, table):
|
||||||
|
return self._has_more
|
||||||
|
|
||||||
|
def get_subscription_data(self):
|
||||||
|
try:
|
||||||
|
self._has_prev = False
|
||||||
|
page_size = horizon_utils.functions.get_page_size(self.request)
|
||||||
|
marker = self.request.GET.get("vnffmsubscription_marker", None)
|
||||||
|
prev_marker = self.request.GET.get(
|
||||||
|
"prev_vnffmsubscription_marker", None)
|
||||||
|
subscriptions = api.tacker.list_fm_subscriptions(self.request)
|
||||||
|
|
||||||
|
if marker is not None or prev_marker is not None:
|
||||||
|
for i, subsc in enumerate(subscriptions):
|
||||||
|
if subsc["id"] == marker and i < len(subscriptions) - 1:
|
||||||
|
subscriptions = subscriptions[i + 1:]
|
||||||
|
self._has_prev = True
|
||||||
|
break
|
||||||
|
if subsc["id"] == prev_marker and i > page_size:
|
||||||
|
subscriptions = subscriptions[i - page_size:]
|
||||||
|
self._has_prev = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if len(subscriptions) > page_size:
|
||||||
|
self._has_more = True
|
||||||
|
else:
|
||||||
|
self._has_more = False
|
||||||
|
|
||||||
|
rows = []
|
||||||
|
for i, subsc in enumerate(subscriptions):
|
||||||
|
if i >= page_size:
|
||||||
|
break
|
||||||
|
item = VnfFmSubscriptionItem(subsc['id'],
|
||||||
|
subsc['callbackUri'])
|
||||||
|
rows.append(item)
|
||||||
|
return rows
|
||||||
|
except Exception:
|
||||||
|
self._has_more = False
|
||||||
|
error_message = _('Failed to get FM Subscriptions.')
|
||||||
|
exceptions.handle(self.request, error_message)
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
class VnfFmSubscriptionTabs(tabs.TabGroup):
|
||||||
|
slug = "vnffmsubscription_tabs"
|
||||||
|
tabs = (VnfFmSubscriptionTab,)
|
||||||
|
sticky = True
|
||||||
|
|
||||||
|
|
||||||
|
class VnfFmSubscriptionDetailTab(tabs.Tab):
|
||||||
|
name = _("VNF FM Subscription")
|
||||||
|
slug = "vnffmsubscription_detail_tab"
|
||||||
|
template_name = "nfv/vnffmsubscription/subscription_detail.html"
|
||||||
|
|
||||||
|
def get_context_data(self, request):
|
||||||
|
return {'subscription': self.tab_group.kwargs['subscription']}
|
||||||
|
|
||||||
|
|
||||||
|
class VnfFmSubscriptionDetailTabs(tabs.TabGroup):
|
||||||
|
slug = "vnffmsubscription_detail_tabs"
|
||||||
|
tabs = (VnfFmSubscriptionDetailTab,)
|
||||||
|
sticky = True
|
@ -0,0 +1,9 @@
|
|||||||
|
{% extends "horizon/common/_modal_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block form_attrs %}enctype="multipart/form-data"{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-body-right %}
|
||||||
|
<h3>{% trans "Description:" %}</h3>
|
||||||
|
<p>{% trans "Create a Subscription." %}</p>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,11 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Create Subscription" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=_("Create Subscription") %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include 'nfv/vnffmsubscription/_create_subscription.html' %}
|
||||||
|
{% endblock %}
|
@ -0,0 +1,15 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Subscription Detail" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=page_title %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
{{ tab_group.render }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,15 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Subscription" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=_("Subscription") %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
{{ tab_group.render }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,14 @@
|
|||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
<div class="detail">
|
||||||
|
<dl class="dl-horizontal">
|
||||||
|
<dt>{% trans "ID" %}</dt>
|
||||||
|
<dd>{{ subscription.id }}</dd>
|
||||||
|
<dt>{% trans "Links" %}</dt>
|
||||||
|
<dd>{{ subscription.links }}</dd>
|
||||||
|
<dt>{% trans "Callback Uri" %}</dt>
|
||||||
|
<dd>{{ subscription.callback_uri }}</dd>
|
||||||
|
<dt>{% trans "Filter" %}</dt>
|
||||||
|
<dd>{{ subscription.filter }}</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
@ -0,0 +1,29 @@
|
|||||||
|
# Copyright (C) 2024 Fujitsu
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
|
from django.urls import re_path
|
||||||
|
|
||||||
|
from tacker_horizon.openstack_dashboard.dashboards.nfv.vnffmsubscription \
|
||||||
|
import views
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
re_path(r'^$', views.IndexView.as_view(), name='index'),
|
||||||
|
re_path(r'^createsubscription',
|
||||||
|
views.CreateVnfFmSubscriptionView.as_view(),
|
||||||
|
name='createsubscription'),
|
||||||
|
re_path(r'^(?P<id>[^/]+)/$', views.DetailView.as_view(),
|
||||||
|
name='detail'),
|
||||||
|
]
|
@ -0,0 +1,94 @@
|
|||||||
|
# Copyright (C) 2024 Fujitsu
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
|
from django.urls import reverse
|
||||||
|
from django.urls import reverse_lazy
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from horizon import exceptions
|
||||||
|
from horizon import forms
|
||||||
|
from horizon import tabs
|
||||||
|
from horizon.utils import memoized
|
||||||
|
|
||||||
|
from tacker_horizon.openstack_dashboard import api as tacker_api
|
||||||
|
from tacker_horizon.openstack_dashboard.dashboards.nfv.vnffmsubscription \
|
||||||
|
import forms as project_forms
|
||||||
|
from tacker_horizon.openstack_dashboard.dashboards.nfv.vnffmsubscription \
|
||||||
|
import tabs as subscription_tabs
|
||||||
|
|
||||||
|
|
||||||
|
class IndexView(tabs.TabbedTableView):
|
||||||
|
# A very simple class-based view...
|
||||||
|
tab_group_class = subscription_tabs.VnfFmSubscriptionTabs
|
||||||
|
template_name = 'nfv/vnffmsubscription/index.html'
|
||||||
|
|
||||||
|
def get_data(self, request, context, *args, **kwargs):
|
||||||
|
# Add data to the context here...
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class CreateVnfFmSubscriptionView(forms.ModalFormView):
|
||||||
|
form_class = project_forms.CreateVnfFmSubscription
|
||||||
|
template_name = 'nfv/vnffmsubscription/create_subscription.html'
|
||||||
|
success_url = reverse_lazy("horizon:nfv:vnffmsubscription:index")
|
||||||
|
modal_id = "create_subscription_modal"
|
||||||
|
modal_header = _("Create Subscription")
|
||||||
|
submit_label = _("Create Subscription")
|
||||||
|
submit_url = "horizon:nfv:vnffmsubscription:createsubscription"
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(CreateVnfFmSubscriptionView,
|
||||||
|
self).get_context_data(**kwargs)
|
||||||
|
context['submit_url'] = reverse(self.submit_url)
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class DetailView(tabs.TabView):
|
||||||
|
tab_group_class = subscription_tabs.VnfFmSubscriptionDetailTabs
|
||||||
|
template_name = 'nfv/vnffmsubscription/detail.html'
|
||||||
|
redirect_url = 'horizon:nfv:vnffmsubscription:index'
|
||||||
|
page_title = _("Subscription Detail: {{ id }}")
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(DetailView, self).get_context_data(**kwargs)
|
||||||
|
subscription = self.get_data()
|
||||||
|
context['subscription'] = subscription
|
||||||
|
context['id'] = kwargs['id']
|
||||||
|
context['url'] = reverse(self.redirect_url)
|
||||||
|
return context
|
||||||
|
|
||||||
|
@memoized.memoized_method
|
||||||
|
def get_data(self):
|
||||||
|
subscription_id = self.kwargs['id']
|
||||||
|
|
||||||
|
try:
|
||||||
|
subscription = tacker_api.tacker.get_fm_subscription(
|
||||||
|
self.request, subscription_id)
|
||||||
|
subscription['links'] = subscription.get('_links', '')
|
||||||
|
subscription['callback_uri'] = subscription.get('callbackUri', '')
|
||||||
|
subscription['filter'] = subscription.get('filter', '')
|
||||||
|
return subscription
|
||||||
|
except Exception:
|
||||||
|
redirect = reverse(self.redirect_url)
|
||||||
|
exceptions.handle(self.request,
|
||||||
|
_('Failed to get FM Subscription. (id: %s)') %
|
||||||
|
subscription_id, redirect=redirect)
|
||||||
|
raise exceptions.Http302(redirect)
|
||||||
|
|
||||||
|
def get_tabs(self, request, *args, **kwargs):
|
||||||
|
subscription = self.get_data()
|
||||||
|
return self.tab_group_class(request,
|
||||||
|
subscription=subscription, **kwargs)
|
@ -0,0 +1,425 @@
|
|||||||
|
# Copyright (C) 2024 Fujitsu
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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 json
|
||||||
|
import time
|
||||||
|
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from horizon import exceptions
|
||||||
|
from horizon import forms
|
||||||
|
from horizon import messages
|
||||||
|
|
||||||
|
from tacker_horizon.openstack_dashboard import api
|
||||||
|
|
||||||
|
|
||||||
|
class CreateVnfIdentifier(forms.SelfHandlingForm):
|
||||||
|
vnfd_id = forms.CharField(label=_("VNFD ID"))
|
||||||
|
param_file = forms.FileField(
|
||||||
|
label=_("Param File"),
|
||||||
|
widget=forms.FileInput(attrs={
|
||||||
|
'class': 'switched',
|
||||||
|
'data-switch-on': 'source',
|
||||||
|
'data-source-upload': _('Param File')}),
|
||||||
|
required=False)
|
||||||
|
name = forms.CharField(label=_("Name"), required=False)
|
||||||
|
description = forms.CharField(label=_("Description"), required=False)
|
||||||
|
|
||||||
|
def __init__(self, request, *args, **kwargs):
|
||||||
|
super(CreateVnfIdentifier, self).__init__(request, *args, **kwargs)
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
data = super(CreateVnfIdentifier, self).clean()
|
||||||
|
|
||||||
|
param_file = data.get('param_file', None)
|
||||||
|
|
||||||
|
try:
|
||||||
|
if param_file:
|
||||||
|
metadata = self.files['param_file'].read()
|
||||||
|
data['metadata'] = json.loads(metadata)
|
||||||
|
except Exception as e:
|
||||||
|
msg = _('Failed to read file: %s.') % e
|
||||||
|
raise forms.ValidationError(msg)
|
||||||
|
return data
|
||||||
|
|
||||||
|
def handle(self, request, data):
|
||||||
|
try:
|
||||||
|
vnfd_id = data.get('vnfd_id', None)
|
||||||
|
metadata = data.get('metadata', None)
|
||||||
|
name = data.get('name', None)
|
||||||
|
description = data.get('description', None)
|
||||||
|
|
||||||
|
body = {}
|
||||||
|
body['vnfdId'] = vnfd_id
|
||||||
|
if metadata:
|
||||||
|
body['metadata'] = metadata
|
||||||
|
if name:
|
||||||
|
body['vnfInstanceName'] = name
|
||||||
|
if description:
|
||||||
|
body['vnfInstanceDescription'] = description
|
||||||
|
|
||||||
|
response = api.tacker.create_vnf_instance(request, body)
|
||||||
|
messages.success(request,
|
||||||
|
_('Create VNF Identifier. (id: %s)') %
|
||||||
|
response['id'])
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
exceptions.handle(request, _('Failed to create VNF Identifier.'))
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class InstantiateVnf(forms.SelfHandlingForm):
|
||||||
|
param_file = forms.FileField(
|
||||||
|
label=_("Param File"),
|
||||||
|
widget=forms.FileInput(attrs={
|
||||||
|
'class': 'switched',
|
||||||
|
'data-switch-on': 'source',
|
||||||
|
'data-source-upload': _('Param File')}))
|
||||||
|
|
||||||
|
def __init__(self, request, *args, **kwargs):
|
||||||
|
super(InstantiateVnf, self).__init__(request, *args, **kwargs)
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
data = super(InstantiateVnf, self).clean()
|
||||||
|
|
||||||
|
try:
|
||||||
|
param_str = self.files['param_file'].read()
|
||||||
|
param = json.loads(param_str)
|
||||||
|
data['param_data'] = param
|
||||||
|
except Exception as e:
|
||||||
|
msg = _('Failed to read file: %s.') % e
|
||||||
|
raise forms.ValidationError(msg)
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
def handle(self, request, data):
|
||||||
|
try:
|
||||||
|
vnf_id = request.resolver_match.kwargs.get('id', None)
|
||||||
|
param = data['param_data']
|
||||||
|
api.tacker.instantiate_vnf_instance(request, vnf_id, param)
|
||||||
|
messages.success(request,
|
||||||
|
_('Accepted to instantiate VNF Instance. '
|
||||||
|
'(id: %s)') % vnf_id)
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
exceptions.handle(request,
|
||||||
|
_('Failed to instantiate VNF Instance. '
|
||||||
|
'(id: %s)') % vnf_id)
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class TerminateVnf(forms.SelfHandlingForm):
|
||||||
|
termination_type = forms.ChoiceField(
|
||||||
|
label=_('Termination Type'),
|
||||||
|
required=True,
|
||||||
|
choices=[('GRACEFUL', _('GRACEFUL')),
|
||||||
|
('FORCEFUL', _('FORCEFUL'))],
|
||||||
|
widget=forms.Select(
|
||||||
|
attrs={'class': 'switchable', 'data-slug': 'source'}))
|
||||||
|
termination_timeout = forms.IntegerField(
|
||||||
|
min_value=0,
|
||||||
|
required=False,
|
||||||
|
label=_('Graceful Termination Timeout'))
|
||||||
|
is_delete = forms.BooleanField(
|
||||||
|
label=_('Delete VNF Instance'),
|
||||||
|
required=False)
|
||||||
|
|
||||||
|
def __init__(self, request, *args, **kwargs):
|
||||||
|
super(TerminateVnf, self).__init__(request, *args, **kwargs)
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
data = super(TerminateVnf, self).clean()
|
||||||
|
return data
|
||||||
|
|
||||||
|
def handle(self, request, data):
|
||||||
|
try:
|
||||||
|
is_delete = data.get('is_delete', False)
|
||||||
|
vnf_id = request.resolver_match.kwargs.get('id', None)
|
||||||
|
body = {}
|
||||||
|
termination_type = data.get('termination_type', None)
|
||||||
|
body['terminationType'] = termination_type
|
||||||
|
termination_timeout = data.get('terminationTimeout', None)
|
||||||
|
if termination_timeout:
|
||||||
|
body['gracefulTerminationTimeout'] = termination_timeout
|
||||||
|
api.tacker.terminate_vnf_instance(request, vnf_id, body)
|
||||||
|
if not is_delete:
|
||||||
|
messages.success(request,
|
||||||
|
_('Accepted to terminate VNF Instance. '
|
||||||
|
'(id: %s)') % vnf_id)
|
||||||
|
except Exception:
|
||||||
|
exceptions.handle(request,
|
||||||
|
_('Failed to terminate VNF Instance. '
|
||||||
|
'(id: %s)') % vnf_id)
|
||||||
|
return False
|
||||||
|
|
||||||
|
if is_delete:
|
||||||
|
retry = 0
|
||||||
|
retry_limit = 12
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
time.sleep(10)
|
||||||
|
api.tacker.delete_vnf_instance(request, vnf_id)
|
||||||
|
messages.success(request,
|
||||||
|
_('Delete VNF Identifier. (id: %s)') %
|
||||||
|
vnf_id)
|
||||||
|
break
|
||||||
|
except Exception as exc:
|
||||||
|
if 'is in progress' in str(exc):
|
||||||
|
# Conflict error occurs even if delete
|
||||||
|
# is executed immediately after terminate
|
||||||
|
retry = retry + 1
|
||||||
|
if retry >= retry_limit:
|
||||||
|
exceptions.handle(
|
||||||
|
request,
|
||||||
|
_('Delete VNF Identifier retry out. (id: %s)')
|
||||||
|
% vnf_id)
|
||||||
|
break
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
exceptions.handle(
|
||||||
|
request,
|
||||||
|
_('Failed to delete VNF Identifer. (id: %s)') %
|
||||||
|
vnf_id)
|
||||||
|
break
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class HealVnf(forms.SelfHandlingForm):
|
||||||
|
cause = forms.CharField(label=_("Cause"),
|
||||||
|
required=False)
|
||||||
|
vnfc_instances = forms.CharField(
|
||||||
|
label=_('VNFC Instance'), required=False, widget=forms.Textarea,
|
||||||
|
help_text=_('Enter VNFC instance IDs in comma-separated list format.'))
|
||||||
|
|
||||||
|
def __init__(self, request, *args, **kwargs):
|
||||||
|
super(HealVnf, self).__init__(request, *args, **kwargs)
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
data = super(HealVnf, self).clean()
|
||||||
|
return data
|
||||||
|
|
||||||
|
def handle(self, request, data):
|
||||||
|
try:
|
||||||
|
vnf_id = request.resolver_match.kwargs.get('id', None)
|
||||||
|
body = {}
|
||||||
|
cause = data.get('cause', None)
|
||||||
|
if cause:
|
||||||
|
body['cause'] = cause
|
||||||
|
array_str = data.get('vnfc_instances', None)
|
||||||
|
if array_str:
|
||||||
|
array_str.replace('\n', '')
|
||||||
|
vnfc_instance_ids = [s.strip() for s in array_str.split(',')]
|
||||||
|
body['vnfcInstanceId'] = vnfc_instance_ids
|
||||||
|
api.tacker.heal_vnf_instance(request, vnf_id, body)
|
||||||
|
messages.success(request,
|
||||||
|
_('Accepted to heal VNF Instance. (id: %s)') %
|
||||||
|
vnf_id)
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
exceptions.handle(request,
|
||||||
|
_('Failed to heal VNF Instance. (id: %s)') %
|
||||||
|
vnf_id)
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateVnf(forms.SelfHandlingForm):
|
||||||
|
param_file = forms.FileField(
|
||||||
|
label=_("Param File"),
|
||||||
|
widget=forms.FileInput(attrs={
|
||||||
|
'class': 'switched',
|
||||||
|
'data-switch-on': 'source',
|
||||||
|
'data-source-upload': _('Param File')}))
|
||||||
|
|
||||||
|
def __init__(self, request, *args, **kwargs):
|
||||||
|
super(UpdateVnf, self).__init__(request, *args, **kwargs)
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
data = super(UpdateVnf, self).clean()
|
||||||
|
try:
|
||||||
|
param_str = self.files['param_file'].read()
|
||||||
|
param = json.loads(param_str)
|
||||||
|
data['param_data'] = param
|
||||||
|
except Exception as e:
|
||||||
|
msg = _('Failed to read file: %s.') % e
|
||||||
|
raise forms.ValidationError(msg)
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
def handle(self, request, data):
|
||||||
|
try:
|
||||||
|
vnf_id = request.resolver_match.kwargs.get('id', None)
|
||||||
|
param = data['param_data']
|
||||||
|
api.tacker.update_vnf_instance(request, vnf_id, param)
|
||||||
|
messages.success(request,
|
||||||
|
_('Accepted to update VNF Instance. '
|
||||||
|
'(id: %s)') % vnf_id)
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
exceptions.handle(request,
|
||||||
|
_('Failed to update VNF Instance. '
|
||||||
|
'(id: %s)') % vnf_id)
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class ScaleVnf(forms.SelfHandlingForm):
|
||||||
|
scale_type = forms.ChoiceField(
|
||||||
|
label=_('Type'),
|
||||||
|
choices=[('SCALE_IN', _('SCALE_IN')),
|
||||||
|
('SCALE_OUT', _('SCALE_OUT'))])
|
||||||
|
aspect_id = forms.CharField(label=_("Aspect ID"))
|
||||||
|
num_of_steps = forms.IntegerField(
|
||||||
|
label=_("Number of Steps"), min_value=1, required=False)
|
||||||
|
param_file = forms.FileField(
|
||||||
|
label=_("Param File"),
|
||||||
|
widget=forms.FileInput(attrs={
|
||||||
|
'class': 'switched',
|
||||||
|
'data-switch-on': 'source',
|
||||||
|
'data-source-upload': _('Param File')}),
|
||||||
|
required=False)
|
||||||
|
|
||||||
|
def __init__(self, request, *args, **kwargs):
|
||||||
|
super(ScaleVnf, self).__init__(request, *args, **kwargs)
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
data = super(ScaleVnf, self).clean()
|
||||||
|
|
||||||
|
param_file = data.get('param_file', None)
|
||||||
|
|
||||||
|
try:
|
||||||
|
if param_file:
|
||||||
|
additional_params = self.files['param_file'].read()
|
||||||
|
data['additional_params'] = json.loads(additional_params)
|
||||||
|
except Exception as e:
|
||||||
|
msg = _('Failed to read file: %s.') % e
|
||||||
|
raise forms.ValidationError(msg)
|
||||||
|
return data
|
||||||
|
|
||||||
|
def handle(self, request, data):
|
||||||
|
try:
|
||||||
|
vnf_id = request.resolver_match.kwargs.get('id', None)
|
||||||
|
scale_type = data.get('scale_type', None)
|
||||||
|
aspect_id = data.get('aspect_id', None)
|
||||||
|
num_of_steps = data.get('num_of_steps', None)
|
||||||
|
additional_params = data.get('additional_params', None)
|
||||||
|
|
||||||
|
body = {}
|
||||||
|
body['type'] = scale_type
|
||||||
|
body['aspectId'] = aspect_id
|
||||||
|
if num_of_steps:
|
||||||
|
body['numberOfSteps'] = num_of_steps
|
||||||
|
if additional_params:
|
||||||
|
body['additionalParams'] = additional_params
|
||||||
|
|
||||||
|
api.tacker.scale_vnf_instance(request, vnf_id, body)
|
||||||
|
messages.success(request,
|
||||||
|
_('Accepted to scale VNF Instance. '
|
||||||
|
'(id: %s)') % vnf_id)
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
exceptions.handle(request,
|
||||||
|
_('Failed to scale VNF Instance. '
|
||||||
|
'(id: %s)') % vnf_id)
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class ChangeExternalVnfConnectivity(forms.SelfHandlingForm):
|
||||||
|
param_file = forms.FileField(
|
||||||
|
label=_("Param File"),
|
||||||
|
widget=forms.FileInput(attrs={
|
||||||
|
'class': 'switched',
|
||||||
|
'data-switch-on': 'source',
|
||||||
|
'data-source-upload': _('Param File')}))
|
||||||
|
|
||||||
|
def __init__(self, request, *args, **kwargs):
|
||||||
|
super(ChangeExternalVnfConnectivity,
|
||||||
|
self).__init__(request, *args, **kwargs)
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
data = super(ChangeExternalVnfConnectivity, self).clean()
|
||||||
|
try:
|
||||||
|
param_str = self.files['param_file'].read()
|
||||||
|
param = json.loads(param_str)
|
||||||
|
data['param_data'] = param
|
||||||
|
except Exception as e:
|
||||||
|
msg = _('Failed to read file: %s.') % e
|
||||||
|
raise forms.ValidationError(msg)
|
||||||
|
return data
|
||||||
|
|
||||||
|
def handle(self, request, data):
|
||||||
|
try:
|
||||||
|
vnf_id = request.resolver_match.kwargs.get('id', None)
|
||||||
|
param = data['param_data']
|
||||||
|
api.tacker.change_ext_conn_vnf_instance(request, vnf_id, param)
|
||||||
|
messages.success(request,
|
||||||
|
_('Accepted to change External VNF Connectivity. '
|
||||||
|
'(id: %s)') % vnf_id)
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
exceptions.handle(request,
|
||||||
|
_('Failed to change External VNF Connectivity. '
|
||||||
|
'(id: %s)') % vnf_id)
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class ChangeCurrentVnfPackage(forms.SelfHandlingForm):
|
||||||
|
param_file = forms.FileField(
|
||||||
|
label=_("Param File"),
|
||||||
|
widget=forms.FileInput(attrs={
|
||||||
|
'class': 'switched',
|
||||||
|
'data-switch-on': 'source',
|
||||||
|
'data-source-upload': _('Param File')}))
|
||||||
|
|
||||||
|
def __init__(self, request, *args, **kwargs):
|
||||||
|
super(ChangeCurrentVnfPackage, self).__init__(request, *args, **kwargs)
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
data = super(ChangeCurrentVnfPackage, self).clean()
|
||||||
|
try:
|
||||||
|
param_str = self.files['param_file'].read()
|
||||||
|
param = json.loads(param_str)
|
||||||
|
data['param_data'] = param
|
||||||
|
except Exception as e:
|
||||||
|
msg = _('Failed to read file: %s.') % e
|
||||||
|
raise forms.ValidationError(msg)
|
||||||
|
return data
|
||||||
|
|
||||||
|
def handle(self, request, data):
|
||||||
|
try:
|
||||||
|
vnf_id = request.resolver_match.kwargs.get('id', None)
|
||||||
|
param = data['param_data']
|
||||||
|
api.tacker.change_vnfpkg_vnf_instance(request, vnf_id, param)
|
||||||
|
messages.success(request,
|
||||||
|
_('Accepted to change Current VNF Package. '
|
||||||
|
'(id: %s)') % vnf_id)
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
exceptions.handle(request,
|
||||||
|
_('Failed to change Current VNF Package. '
|
||||||
|
'(id: %s)') % vnf_id)
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
@ -0,0 +1,29 @@
|
|||||||
|
# Copyright (C) 2024 Fujitsu
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
import horizon
|
||||||
|
|
||||||
|
from tacker_horizon.openstack_dashboard.dashboards.nfv import dashboard
|
||||||
|
|
||||||
|
|
||||||
|
class VnfLcm(horizon.Panel):
|
||||||
|
name = _("VNF LCM")
|
||||||
|
slug = "vnflcm"
|
||||||
|
|
||||||
|
|
||||||
|
dashboard.Nfv.register(VnfLcm)
|
@ -0,0 +1,129 @@
|
|||||||
|
# Copyright (C) 2024 Fujitsu
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from django.utils.translation import ngettext_lazy
|
||||||
|
|
||||||
|
from horizon import tables
|
||||||
|
from openstack_dashboard import policy
|
||||||
|
|
||||||
|
from tacker_horizon.openstack_dashboard import api
|
||||||
|
|
||||||
|
|
||||||
|
class DeleteVnfIdentifier(policy.PolicyTargetMixin, tables.DeleteAction):
|
||||||
|
@staticmethod
|
||||||
|
def action_present(count):
|
||||||
|
return ngettext_lazy(
|
||||||
|
"Delete VNF Identifier",
|
||||||
|
"Delete VNF Identifiers",
|
||||||
|
count
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def action_past(count):
|
||||||
|
return ngettext_lazy(
|
||||||
|
"Delete VNF Identifier",
|
||||||
|
"Delete VNF Identifiers",
|
||||||
|
count
|
||||||
|
)
|
||||||
|
|
||||||
|
def action(self, request, obj_id):
|
||||||
|
api.tacker.delete_vnf_instance(request, obj_id)
|
||||||
|
|
||||||
|
|
||||||
|
class CreateVnfIdentifier(tables.LinkAction):
|
||||||
|
name = "createvnfid"
|
||||||
|
verbose_name = _("Create VNF Identifier")
|
||||||
|
url = "horizon:nfv:vnflcm:createvnfidentifier"
|
||||||
|
classes = ("ajax-modal",)
|
||||||
|
icon = "plus"
|
||||||
|
|
||||||
|
|
||||||
|
class InstantiateVnf(tables.LinkAction):
|
||||||
|
name = "instantiatevnf"
|
||||||
|
verbose_name = _("Instantiate VNF")
|
||||||
|
url = "horizon:nfv:vnflcm:instantiatevnf"
|
||||||
|
classes = ("ajax-modal",)
|
||||||
|
|
||||||
|
|
||||||
|
class TerminateVnf(tables.LinkAction):
|
||||||
|
name = "terminate_vnf"
|
||||||
|
verbose_name = _("Terminate VNF")
|
||||||
|
url = "horizon:nfv:vnflcm:terminatevnf"
|
||||||
|
classes = ("ajax-modal",)
|
||||||
|
|
||||||
|
|
||||||
|
class HealVnf(tables.LinkAction):
|
||||||
|
name = "heal_vnf"
|
||||||
|
verbose_name = _("Heal VNF")
|
||||||
|
url = "horizon:nfv:vnflcm:healvnf"
|
||||||
|
classes = ("ajax-modal",)
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateVnf(tables.LinkAction):
|
||||||
|
name = "update_Vnf"
|
||||||
|
verbose_name = _("Update VNF")
|
||||||
|
url = "horizon:nfv:vnflcm:updatevnf"
|
||||||
|
classes = ("ajax-modal",)
|
||||||
|
|
||||||
|
|
||||||
|
class ScaleVnf(tables.LinkAction):
|
||||||
|
name = "scale_vnf"
|
||||||
|
verbose_name = _("Scale VNF")
|
||||||
|
url = "horizon:nfv:vnflcm:scalevnf"
|
||||||
|
classes = ("ajax-modal",)
|
||||||
|
|
||||||
|
|
||||||
|
class ChangeExternalVnfConnectivity(tables.LinkAction):
|
||||||
|
name = "change_external_vnf_connectivity"
|
||||||
|
verbose_name = _("Change External VNF Connectivity")
|
||||||
|
url = "horizon:nfv:vnflcm:changeconnectivity"
|
||||||
|
classes = ("ajax-modal",)
|
||||||
|
|
||||||
|
|
||||||
|
class ChangeCurrentVnfPackage(tables.LinkAction):
|
||||||
|
name = "change_current_vnf_package"
|
||||||
|
verbose_name = _("Change Current VNF Package")
|
||||||
|
url = "horizon:nfv:vnflcm:changevnfpkg"
|
||||||
|
classes = ("ajax-modal",)
|
||||||
|
|
||||||
|
|
||||||
|
class VnfLcmTable(tables.DataTable):
|
||||||
|
id = tables.Column('id', verbose_name=_("ID"),
|
||||||
|
link="horizon:nfv:vnflcm:detail",)
|
||||||
|
vnf_instance_name = tables.Column('vnf_instance_name',
|
||||||
|
verbose_name=_("VNF Instance Name"))
|
||||||
|
instantiation_state = tables.Column('instantiation_state',
|
||||||
|
verbose_name=_("Instantiation State"))
|
||||||
|
vnf_provider = tables.Column('vnf_provider',
|
||||||
|
verbose_name=_("VNF Provider"))
|
||||||
|
vnf_software_version = tables.Column(
|
||||||
|
'vnf_software_version',
|
||||||
|
verbose_name=_("VNF Software Version"))
|
||||||
|
vnf_product_name = tables.Column('vnf_product_name',
|
||||||
|
verbose_name=_("VNF Product Name"))
|
||||||
|
vnfd_id = tables.Column('vnfd_id', verbose_name=_("VNFD ID"))
|
||||||
|
|
||||||
|
class Meta(object):
|
||||||
|
name = "vnflcm"
|
||||||
|
verbose_name = _("VNF LCM")
|
||||||
|
pagination_param = 'vnflcm_marker'
|
||||||
|
prev_pagination_param = 'prev_vnflcm_marker'
|
||||||
|
table_actions = (CreateVnfIdentifier, DeleteVnfIdentifier,
|
||||||
|
tables.FilterAction,)
|
||||||
|
row_actions = (InstantiateVnf, TerminateVnf, DeleteVnfIdentifier,
|
||||||
|
HealVnf, UpdateVnf, ScaleVnf,
|
||||||
|
ChangeExternalVnfConnectivity, ChangeCurrentVnfPackage,)
|
131
tacker_horizon/openstack_dashboard/dashboards/nfv/vnflcm/tabs.py
Normal file
131
tacker_horizon/openstack_dashboard/dashboards/nfv/vnflcm/tabs.py
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
# Copyright (C) 2024 Fujitsu
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from horizon import exceptions
|
||||||
|
from horizon import tabs
|
||||||
|
from horizon import utils as horizon_utils
|
||||||
|
|
||||||
|
from tacker_horizon.openstack_dashboard import api
|
||||||
|
from tacker_horizon.openstack_dashboard.dashboards.nfv.vnflcm import tables
|
||||||
|
from tacker_horizon.openstack_dashboard.dashboards.nfv.vnflcmopocc \
|
||||||
|
import tabs as opocc_tab
|
||||||
|
|
||||||
|
|
||||||
|
class VnfLcmItem(object):
|
||||||
|
def __init__(self, vnf_id, vnf_instance_name, instantiation_state,
|
||||||
|
vnf_provider, vnf_software_version, vnf_product_name,
|
||||||
|
vnfd_id):
|
||||||
|
self.id = vnf_id
|
||||||
|
self.name = vnf_id
|
||||||
|
self.vnf_instance_name = vnf_instance_name
|
||||||
|
self.instantiation_state = instantiation_state
|
||||||
|
self.vnf_provider = vnf_provider
|
||||||
|
self.vnf_software_version = vnf_software_version
|
||||||
|
self.vnf_product_name = vnf_product_name
|
||||||
|
self.vnfd_id = vnfd_id
|
||||||
|
|
||||||
|
|
||||||
|
class VnfLcmTab(tabs.TableTab):
|
||||||
|
name = _("VNFLCM tab")
|
||||||
|
slug = "vnflcm_tab"
|
||||||
|
table_classes = (tables.VnfLcmTable,)
|
||||||
|
template_name = ("horizon/common/_detail_table.html")
|
||||||
|
preload = False
|
||||||
|
|
||||||
|
def has_prev_data(self, table):
|
||||||
|
return self._has_prev
|
||||||
|
|
||||||
|
def has_more_data(self, table):
|
||||||
|
return self._has_more
|
||||||
|
|
||||||
|
def get_vnflcm_data(self):
|
||||||
|
try:
|
||||||
|
self._has_prev = False
|
||||||
|
page_size = horizon_utils.functions.get_page_size(self.request)
|
||||||
|
marker = self.request.GET.get(
|
||||||
|
"vnflcm_marker", None)
|
||||||
|
prev_marker = self.request.GET.get(
|
||||||
|
"prev_vnflcm_marker", None)
|
||||||
|
vnf_instances = api.tacker.list_vnf_instances(self.request)
|
||||||
|
if marker is not None or prev_marker is not None:
|
||||||
|
for i, instance in enumerate(vnf_instances):
|
||||||
|
if instance["id"] == marker and i < len(vnf_instances) - 1:
|
||||||
|
vnf_instances = vnf_instances[i + 1:]
|
||||||
|
self._has_prev = True
|
||||||
|
break
|
||||||
|
if instance["id"] == prev_marker and i > page_size:
|
||||||
|
vnf_instances = vnf_instances[i - page_size:]
|
||||||
|
self._has_prev = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if len(vnf_instances) > page_size:
|
||||||
|
self._has_more = True
|
||||||
|
else:
|
||||||
|
self._has_more = False
|
||||||
|
|
||||||
|
rows = []
|
||||||
|
for i, instance in enumerate(vnf_instances):
|
||||||
|
if i >= page_size:
|
||||||
|
break
|
||||||
|
item = VnfLcmItem(
|
||||||
|
vnf_id=instance.get('id', ''),
|
||||||
|
vnf_instance_name=instance.get('vnfInstanceName', ''),
|
||||||
|
instantiation_state=instance.get(
|
||||||
|
'instantiationState', ''),
|
||||||
|
vnf_provider=instance.get('vnfProvider', ''),
|
||||||
|
vnf_software_version=instance.get(
|
||||||
|
'vnfSoftwareVersion', ''),
|
||||||
|
vnf_product_name=instance.get('vnfProductName', ''),
|
||||||
|
vnfd_id=instance.get('vnfdId', ''))
|
||||||
|
rows.append(item)
|
||||||
|
return rows
|
||||||
|
except Exception:
|
||||||
|
self._has_more = False
|
||||||
|
error_message = _('Failed to get VNF Instances.')
|
||||||
|
exceptions.handle(self.request, error_message)
|
||||||
|
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
class VnfLcmTabs(tabs.TabGroup):
|
||||||
|
slug = "vnflcm_tabs"
|
||||||
|
tabs = (VnfLcmTab,)
|
||||||
|
sticky = True
|
||||||
|
|
||||||
|
|
||||||
|
class VnfLcmOpOccItem(object):
|
||||||
|
def __init__(self, id, operation_state, vnf_instance_id, operation):
|
||||||
|
self.id = id
|
||||||
|
self.operation_state = operation_state
|
||||||
|
self.vnf_instance_id = vnf_instance_id
|
||||||
|
self.operation = operation
|
||||||
|
|
||||||
|
|
||||||
|
class VnfLcmDetailTab(tabs.Tab):
|
||||||
|
name = _("VNF Instance Detail Tab")
|
||||||
|
slug = "vnflcm_detail_tab"
|
||||||
|
template_name = "nfv/vnflcm/vnflcm_detail.html"
|
||||||
|
|
||||||
|
def get_context_data(self, request):
|
||||||
|
return {'vnflcm': self.tab_group.kwargs['vnflcm']}
|
||||||
|
|
||||||
|
|
||||||
|
class VnfLcmDetailTabs(tabs.TabGroup):
|
||||||
|
slug = "vnflcm_detail_tabs"
|
||||||
|
tabs = (VnfLcmDetailTab, opocc_tab.VnfLcmOpOccTab,)
|
||||||
|
sticky = True
|
@ -0,0 +1,9 @@
|
|||||||
|
{% extends "horizon/common/_modal_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block form_attrs %}enctype="multipart/form-data"{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-body-right %}
|
||||||
|
<h3>{% trans "Description:" %}</h3>
|
||||||
|
<p>{% trans "Change a External VNF Connectivity." %}</p>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,9 @@
|
|||||||
|
{% extends "horizon/common/_modal_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block form_attrs %}enctype="multipart/form-data"{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-body-right %}
|
||||||
|
<h3>{% trans "Description:" %}</h3>
|
||||||
|
<p>{% trans "Change a Current VNF Package." %}</p>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,9 @@
|
|||||||
|
{% extends "horizon/common/_modal_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block form_attrs %}enctype="multipart/form-data"{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-body-right %}
|
||||||
|
<h3>{% trans "Description:" %}</h3>
|
||||||
|
<p>{% trans "Create a VNF Identifier." %}</p>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,9 @@
|
|||||||
|
{% extends "horizon/common/_modal_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block form_attrs %}enctype="multipart/form-data"{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-body-right %}
|
||||||
|
<h3>{% trans "Description:" %}</h3>
|
||||||
|
<p>{% trans "Heal a VNF instance." %}</p>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,9 @@
|
|||||||
|
{% extends "horizon/common/_modal_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block form_attrs %}enctype="multipart/form-data"{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-body-right %}
|
||||||
|
<h3>{% trans "Description:" %}</h3>
|
||||||
|
<p>{% trans "Instantiate a VNF instance." %}</p>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,9 @@
|
|||||||
|
{% extends "horizon/common/_modal_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block form_attrs %}enctype="multipart/form-data"{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-body-right %}
|
||||||
|
<h3>{% trans "Description:" %}</h3>
|
||||||
|
<p>{% trans "Scale a VNF instance." %}</p>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,9 @@
|
|||||||
|
{% extends "horizon/common/_modal_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block form_attrs %}enctype="multipart/form-data"{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-body-right %}
|
||||||
|
<h3>{% trans "Description:" %}</h3>
|
||||||
|
<p>{% trans "Terminate a VNF instance." %}</p>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,9 @@
|
|||||||
|
{% extends "horizon/common/_modal_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block form_attrs %}enctype="multipart/form-data"{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-body-right %}
|
||||||
|
<h3>{% trans "Description:" %}</h3>
|
||||||
|
<p>{% trans "Update a VNF instance." %}</p>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,11 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Change External VNF Connectivity" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=_("Change External VNF Connectivity") %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include 'nfv/vnflcm/_change_connectivity.html' %}
|
||||||
|
{% endblock %}
|
@ -0,0 +1,11 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Change Current VNF Package" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=_("Change Current VNF Package") %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include 'nfv/vnflcm/_change_vnfpkg.html' %}
|
||||||
|
{% endblock %}
|
@ -0,0 +1,11 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "create_vnf_id" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=_("Create VNF Identifier") %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include 'nfv/vnflcm/_create_vnf_identifier.html' %}
|
||||||
|
{% endblock %}
|
@ -0,0 +1,15 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "VNF LCM Detail" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=page_title %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
{{ tab_group.render }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,11 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Heal VNF" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=_("Heal VNF") %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include 'nfv/vnflcm/_heal_vnf.html' %}
|
||||||
|
{% endblock %}
|
@ -0,0 +1,15 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "VNF LCM" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=_("VNF LCM") %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
{{ tab_group.render }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,11 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Instantiate VNF" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=_("Instantiate VNF") %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include 'nfv/vnflcm/_instantiate_vnf.html' %}
|
||||||
|
{% endblock %}
|
@ -0,0 +1,11 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Scale VNF" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=_("Scale VNF") %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include 'nfv/vnflcm/_scale_vnf.html' %}
|
||||||
|
{% endblock %}
|
@ -0,0 +1,11 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Terminate VNF" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=_("Terminate VNF") %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include 'nfv/vnflcm/_terminate_vnf.html' %}
|
||||||
|
{% endblock %}
|
@ -0,0 +1,11 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Update VNF" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=_("Update VNF") %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include 'nfv/vnflcm/_update_vnf.html' %}
|
||||||
|
{% endblock %}
|
@ -0,0 +1,30 @@
|
|||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
<div class="detail">
|
||||||
|
<dl class="dl-horizontal">
|
||||||
|
<dt>{% trans "ID" %}</dt>
|
||||||
|
<dd>{{ vnflcm.id }}</dd>
|
||||||
|
<dt>{% trans "Instantiated Vnf Info" %}</dt>
|
||||||
|
<dd>{{ vnflcm.instantiatedVnfInfo }}</dd>
|
||||||
|
<dt>{% trans "Instantiation State" %}</dt>
|
||||||
|
<dd>{{ vnflcm.instantiationState }}</dd>
|
||||||
|
<dt>{% trans "Links" %}</dt>
|
||||||
|
<dd>{{ vnflcm.links }}</dd>
|
||||||
|
<dt>{% trans "VIM Connection Info" %}</dt>
|
||||||
|
<dd>{{ vnflcm.vimConnectionInfo }}</dd>
|
||||||
|
<dt>{% trans "VNF Instance Description" %}</dt>
|
||||||
|
<dd>{{ vnflcm.vnfInstanceDescription }}</dd>
|
||||||
|
<dt>{% trans "VNF Instance Name" %}</dt>
|
||||||
|
<dd>{{ vnflcm.vnfInstanceName }}</dd>
|
||||||
|
<dt>{% trans "VNF Product Name" %}</dt>
|
||||||
|
<dd>{{ vnflcm.vnfProductName }}</dd>
|
||||||
|
<dt>{% trans "VNF Provider" %}</dt>
|
||||||
|
<dd>{{ vnflcm.vnfProvider }}</dd>
|
||||||
|
<dt>{% trans "VNF Software Version" %}</dt>
|
||||||
|
<dd>{{ vnflcm.vnfSoftwareVersion }}</dd>
|
||||||
|
<dt>{% trans "VNFD ID" %}</dt>
|
||||||
|
<dd>{{ vnflcm.vnfdId }}</dd>
|
||||||
|
<dt>{% trans "VNFD Version" %}</dt>
|
||||||
|
<dd>{{ vnflcm.vnfdVersion }}</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
@ -0,0 +1,44 @@
|
|||||||
|
# Copyright (C) 2024 Fujitsu
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
|
from django.urls import re_path
|
||||||
|
|
||||||
|
from tacker_horizon.openstack_dashboard.dashboards.nfv.vnflcm \
|
||||||
|
import views
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
re_path(r'^$', views.IndexView.as_view(), name='index'),
|
||||||
|
re_path(r'^(?P<id>[^/]+)/$', views.DetailView.as_view(), name='detail'),
|
||||||
|
re_path(r'^createvnfidentifier$', views.CreateVnfIdentifierView.as_view(),
|
||||||
|
name='createvnfidentifier'),
|
||||||
|
re_path(r'^(?P<id>[^/]+)/instantiatevnf/$',
|
||||||
|
views.InstantiateVnfView.as_view(),
|
||||||
|
name='instantiatevnf'),
|
||||||
|
re_path(r'^(?P<id>[^/]+)/terminatevnf/$', views.TerminateVnfView.as_view(),
|
||||||
|
name='terminatevnf'),
|
||||||
|
re_path(r'^(?P<id>[^/]+)/healvnf/$', views.HealVnfView.as_view(),
|
||||||
|
name='healvnf'),
|
||||||
|
re_path(r'^(?P<id>[^/]+)/updatevnf/$', views.UpdateVnfView.as_view(),
|
||||||
|
name='updatevnf'),
|
||||||
|
re_path(r'^(?P<id>[^/]+)/scalevnf/$', views.ScaleVnfView.as_view(),
|
||||||
|
name='scalevnf'),
|
||||||
|
re_path(r'^(?P<id>[^/]+)/changeconnectivity/$',
|
||||||
|
views.ChangeExternalVnfConnectivityView.as_view(),
|
||||||
|
name='changeconnectivity'),
|
||||||
|
re_path(r'^(?P<id>[^/]+)/changevnfpkg/$',
|
||||||
|
views.ChangeCurrentVnfPackageView.as_view(),
|
||||||
|
name='changevnfpkg'),
|
||||||
|
]
|
@ -0,0 +1,200 @@
|
|||||||
|
# Copyright (C) 2024 Fujitsu
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
|
from django.urls import reverse
|
||||||
|
from django.urls import reverse_lazy
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from horizon import exceptions
|
||||||
|
from horizon import forms
|
||||||
|
from horizon import tabs
|
||||||
|
from horizon.utils import memoized
|
||||||
|
|
||||||
|
from tacker_horizon.openstack_dashboard import api as tacker_api
|
||||||
|
from tacker_horizon.openstack_dashboard.dashboards.nfv.vnflcm \
|
||||||
|
import forms as project_forms
|
||||||
|
from tacker_horizon.openstack_dashboard.dashboards.nfv.vnflcm \
|
||||||
|
import tabs as vnflcm_tabs
|
||||||
|
|
||||||
|
|
||||||
|
class IndexView(tabs.TabbedTableView):
|
||||||
|
tab_group_class = vnflcm_tabs.VnfLcmTabs
|
||||||
|
template_name = 'nfv/vnflcm/index.html'
|
||||||
|
|
||||||
|
|
||||||
|
class CreateVnfIdentifierView(forms.ModalFormView):
|
||||||
|
form_class = project_forms.CreateVnfIdentifier
|
||||||
|
template_name = 'nfv/vnflcm/create_vnf_identifier.html'
|
||||||
|
success_url = reverse_lazy("horizon:nfv:vnflcm:index")
|
||||||
|
modal_id = "add_service_modal"
|
||||||
|
modal_header = _("Create VNF Identifier")
|
||||||
|
submit_label = _("Create VNF Identifier")
|
||||||
|
submit_url = "horizon:nfv:vnflcm:createvnfidentifier"
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(
|
||||||
|
CreateVnfIdentifierView, self).get_context_data(**kwargs)
|
||||||
|
context['submit_url'] = reverse(self.submit_url)
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class InstantiateVnfView(forms.ModalFormView):
|
||||||
|
form_class = project_forms.InstantiateVnf
|
||||||
|
template_name = 'nfv/vnflcm/instantiate_vnf.html'
|
||||||
|
success_url = reverse_lazy("horizon:nfv:vnflcm:index")
|
||||||
|
modal_id = "add_service_modal"
|
||||||
|
modal_header = _("Instantiate VNF")
|
||||||
|
submit_label = _("Instantiate VNF")
|
||||||
|
submit_url = "horizon:nfv:vnflcm:instantiatevnf"
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(InstantiateVnfView, self).get_context_data(**kwargs)
|
||||||
|
context['submit_url'] = reverse(self.submit_url,
|
||||||
|
kwargs={'id': self.kwargs['id']})
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class TerminateVnfView(forms.ModalFormView):
|
||||||
|
form_class = project_forms.TerminateVnf
|
||||||
|
template_name = 'nfv/vnflcm/terminate_vnf.html'
|
||||||
|
success_url = reverse_lazy("horizon:nfv:vnflcm:index")
|
||||||
|
modal_id = "add_service_modal"
|
||||||
|
modal_header = _("Terminate VNF")
|
||||||
|
submit_label = _("Terminate VNF")
|
||||||
|
submit_url = "horizon:nfv:vnflcm:terminatevnf"
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(TerminateVnfView, self).get_context_data(**kwargs)
|
||||||
|
context['submit_url'] = reverse(self.submit_url,
|
||||||
|
kwargs={'id': self.kwargs['id']})
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class HealVnfView(forms.ModalFormView):
|
||||||
|
form_class = project_forms.HealVnf
|
||||||
|
template_name = 'nfv/vnflcm/heal_vnf.html'
|
||||||
|
success_url = reverse_lazy("horizon:nfv:vnflcm:index")
|
||||||
|
modal_id = "add_service_modal"
|
||||||
|
modal_header = _("Heal VNF")
|
||||||
|
submit_label = _("Heal VNF")
|
||||||
|
submit_url = "horizon:nfv:vnflcm:healvnf"
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(HealVnfView, self).get_context_data(**kwargs)
|
||||||
|
context['submit_url'] = reverse(self.submit_url,
|
||||||
|
kwargs={'id': self.kwargs['id']})
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateVnfView(forms.ModalFormView):
|
||||||
|
form_class = project_forms.UpdateVnf
|
||||||
|
template_name = 'nfv/vnflcm/update_vnf.html'
|
||||||
|
success_url = reverse_lazy("horizon:nfv:vnflcm:index")
|
||||||
|
modal_id = "add_service_modal"
|
||||||
|
modal_header = _("Update VNF")
|
||||||
|
submit_label = _("Update VNF")
|
||||||
|
submit_url = "horizon:nfv:vnflcm:updatevnf"
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(UpdateVnfView, self).get_context_data(**kwargs)
|
||||||
|
context['submit_url'] = reverse(self.submit_url,
|
||||||
|
kwargs={'id': self.kwargs['id']})
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class ScaleVnfView(forms.ModalFormView):
|
||||||
|
form_class = project_forms.ScaleVnf
|
||||||
|
template_name = 'nfv/vnflcm/scale_vnf.html'
|
||||||
|
success_url = reverse_lazy("horizon:nfv:vnflcm:index")
|
||||||
|
modal_id = "add_service_modal"
|
||||||
|
modal_header = _("Scale VNF")
|
||||||
|
submit_label = _("Scale VNF")
|
||||||
|
submit_url = "horizon:nfv:vnflcm:scalevnf"
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(ScaleVnfView, self).get_context_data(**kwargs)
|
||||||
|
context['submit_url'] = reverse(self.submit_url,
|
||||||
|
kwargs={'id': self.kwargs['id']})
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class ChangeExternalVnfConnectivityView(forms.ModalFormView):
|
||||||
|
form_class = project_forms.ChangeExternalVnfConnectivity
|
||||||
|
template_name = 'nfv/vnflcm/change_connectivity.html'
|
||||||
|
success_url = reverse_lazy("horizon:nfv:vnflcm:index")
|
||||||
|
modal_id = "add_service_modal"
|
||||||
|
modal_header = _("Change External VNF Connectivity")
|
||||||
|
submit_label = _("Change External VNF Connectivity")
|
||||||
|
submit_url = "horizon:nfv:vnflcm:changeconnectivity"
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(
|
||||||
|
ChangeExternalVnfConnectivityView, self).get_context_data(**kwargs)
|
||||||
|
context['submit_url'] = reverse(self.submit_url,
|
||||||
|
kwargs={'id': self.kwargs['id']})
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class ChangeCurrentVnfPackageView(forms.ModalFormView):
|
||||||
|
form_class = project_forms.ChangeCurrentVnfPackage
|
||||||
|
template_name = 'nfv/vnflcm/change_vnfpkg.html'
|
||||||
|
success_url = reverse_lazy("horizon:nfv:vnflcm:index")
|
||||||
|
modal_id = "add_service_modal"
|
||||||
|
modal_header = _("Change Current VNF Package")
|
||||||
|
submit_label = _("Change Current VNF Package")
|
||||||
|
submit_url = "horizon:nfv:vnflcm:changevnfpkg"
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(
|
||||||
|
ChangeCurrentVnfPackageView, self).get_context_data(**kwargs)
|
||||||
|
context['submit_url'] = reverse(self.submit_url,
|
||||||
|
kwargs={'id': self.kwargs['id']})
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class DetailView(tabs.TabbedTableView):
|
||||||
|
tab_group_class = vnflcm_tabs.VnfLcmDetailTabs
|
||||||
|
template_name = 'nfv/vnflcm/detail.html'
|
||||||
|
redirect_url = 'horizon:nfv:vnflcm:index'
|
||||||
|
page_title = _("VNF Instance Detail: {{ id }}")
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(DetailView, self).get_context_data(**kwargs)
|
||||||
|
vnflcm = self.get_data()
|
||||||
|
context['vnflcm'] = vnflcm
|
||||||
|
context['id'] = kwargs['id']
|
||||||
|
context['url'] = reverse(self.redirect_url)
|
||||||
|
return context
|
||||||
|
|
||||||
|
@memoized.memoized_method
|
||||||
|
def get_data(self):
|
||||||
|
vnf_id = self.kwargs['id']
|
||||||
|
|
||||||
|
try:
|
||||||
|
vnflcm = tacker_api.tacker.get_vnf_instance(self.request, vnf_id)
|
||||||
|
vnflcm['links'] = vnflcm.get('_links', '')
|
||||||
|
return vnflcm
|
||||||
|
except Exception:
|
||||||
|
redirect = reverse(self.redirect_url)
|
||||||
|
exceptions.handle(
|
||||||
|
self.request,
|
||||||
|
_('Failed to get VNF instance. (id: %s)') % vnf_id,
|
||||||
|
redirect=redirect)
|
||||||
|
raise exceptions.Http302(redirect)
|
||||||
|
|
||||||
|
def get_tabs(self, request, *args, **kwargs):
|
||||||
|
vnflcm = self.get_data()
|
||||||
|
return self.tab_group_class(request, vnflcm=vnflcm, **kwargs)
|
@ -0,0 +1,29 @@
|
|||||||
|
# Copyright (C) 2024 Fujitsu
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
import horizon
|
||||||
|
|
||||||
|
from tacker_horizon.openstack_dashboard.dashboards.nfv import dashboard
|
||||||
|
|
||||||
|
|
||||||
|
class VnfOpOcc(horizon.Panel):
|
||||||
|
name = _("VNF OP OCC")
|
||||||
|
slug = "vnflcmopocc"
|
||||||
|
|
||||||
|
|
||||||
|
dashboard.Nfv.register(VnfOpOcc)
|
@ -0,0 +1,114 @@
|
|||||||
|
# Copyright (C) 2024 Fujitsu
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from django.utils.translation import ngettext_lazy
|
||||||
|
|
||||||
|
from horizon import tables
|
||||||
|
|
||||||
|
from tacker_horizon.openstack_dashboard import api
|
||||||
|
|
||||||
|
|
||||||
|
class VnfLcmRollback(tables.BatchAction):
|
||||||
|
name = "vnflcmrollback"
|
||||||
|
verbose_name = _("Rollback VNF Lifecycle Management Operation")
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def action_present(count):
|
||||||
|
return ngettext_lazy(
|
||||||
|
"Rollback VNF Lifecycle Management Operation",
|
||||||
|
"Rollback VNF Lifecycle Management Operation",
|
||||||
|
count
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def action_past(count):
|
||||||
|
return ngettext_lazy(
|
||||||
|
"Rollback VNF Lifecycle Management Operation",
|
||||||
|
"Rollback VNF Lifecycle Management Operation",
|
||||||
|
count
|
||||||
|
)
|
||||||
|
|
||||||
|
def action(self, request, obj_id):
|
||||||
|
api.tacker.rollback_vnf_lcm_op_occ(request, obj_id)
|
||||||
|
|
||||||
|
|
||||||
|
class VnfLcmRetry(tables.BatchAction):
|
||||||
|
name = "vnflcmretry"
|
||||||
|
verbose_name = _("Retry")
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def action_present(count):
|
||||||
|
return ngettext_lazy(
|
||||||
|
"Retry",
|
||||||
|
"Retry",
|
||||||
|
count
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def action_past(count):
|
||||||
|
return ngettext_lazy(
|
||||||
|
"Retry",
|
||||||
|
"Retry",
|
||||||
|
count
|
||||||
|
)
|
||||||
|
|
||||||
|
def action(self, request, obj_id):
|
||||||
|
api.tacker.retry_vnf_lcm_op_occ(request, obj_id)
|
||||||
|
|
||||||
|
|
||||||
|
class VnfLcmFail(tables.BatchAction):
|
||||||
|
name = "vnflcmfail"
|
||||||
|
verbose_name = _("Fail")
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def action_present(count):
|
||||||
|
return ngettext_lazy(
|
||||||
|
"Fail",
|
||||||
|
"Fail",
|
||||||
|
count
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def action_past(count):
|
||||||
|
return ngettext_lazy(
|
||||||
|
"Fail",
|
||||||
|
"Fail",
|
||||||
|
count
|
||||||
|
)
|
||||||
|
|
||||||
|
def action(self, request, obj_id):
|
||||||
|
api.tacker.fail_vnf_lcm_op_occ(request, obj_id)
|
||||||
|
|
||||||
|
|
||||||
|
class VnfLcmOpOccTable(tables.DataTable):
|
||||||
|
id = tables.Column('id', verbose_name=_("ID"),
|
||||||
|
link="horizon:nfv:vnflcmopocc:detail",)
|
||||||
|
operation_state = tables.Column('operation_state',
|
||||||
|
verbose_name=_("OperationState"))
|
||||||
|
vnf_instance_id = tables.Column('vnf_instance_id',
|
||||||
|
verbose_name=_("VNFInstanceID"))
|
||||||
|
operation = tables.Column('operation', verbose_name=_("Operation"))
|
||||||
|
|
||||||
|
class Meta(object):
|
||||||
|
name = "vnflcmopocc"
|
||||||
|
verbose_name = _("VNF LCM OP OCC")
|
||||||
|
pagination_param = 'opocc_marker'
|
||||||
|
prev_pagination_param = 'prev_opocc_marker'
|
||||||
|
table_actions = (VnfLcmRollback, VnfLcmRetry, VnfLcmFail,
|
||||||
|
tables.FilterAction,)
|
||||||
|
row_actions = (VnfLcmRollback, VnfLcmRetry, VnfLcmFail,)
|
||||||
|
multi_select = True
|
@ -0,0 +1,118 @@
|
|||||||
|
# Copyright (C) 2024 Fujitsu
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from horizon import exceptions
|
||||||
|
from horizon import tabs
|
||||||
|
from horizon import utils as horizon_utils
|
||||||
|
|
||||||
|
from tacker_horizon.openstack_dashboard import api
|
||||||
|
from tacker_horizon.openstack_dashboard.dashboards.nfv.vnflcmopocc \
|
||||||
|
import tables
|
||||||
|
|
||||||
|
|
||||||
|
class VnfLcmOpOccItem(object):
|
||||||
|
def __init__(self, opocc_id, operation_state, vnf_instance_id,
|
||||||
|
operation):
|
||||||
|
self.id = opocc_id
|
||||||
|
self.name = opocc_id
|
||||||
|
self.operation_state = operation_state
|
||||||
|
self.vnf_instance_id = vnf_instance_id
|
||||||
|
self.operation = operation
|
||||||
|
|
||||||
|
|
||||||
|
class VnfLcmOpOccTab(tabs.TableTab):
|
||||||
|
name = _("List LCM Operation Occurrences")
|
||||||
|
slug = "vnflcmopocc_tab"
|
||||||
|
table_classes = (tables.VnfLcmOpOccTable,)
|
||||||
|
template_name = ("horizon/common/_detail_table.html")
|
||||||
|
preload = False
|
||||||
|
|
||||||
|
def has_prev_data(self, table):
|
||||||
|
return self._has_prev
|
||||||
|
|
||||||
|
def has_more_data(self, table):
|
||||||
|
return self._has_more
|
||||||
|
|
||||||
|
def get_vnflcmopocc_data(self):
|
||||||
|
try:
|
||||||
|
opoccs = []
|
||||||
|
self._has_prev = False
|
||||||
|
page_size = horizon_utils.functions.get_page_size(self.request)
|
||||||
|
marker = self.request.GET.get(
|
||||||
|
"opocc_marker", None)
|
||||||
|
prev_marker = self.request.GET.get(
|
||||||
|
"prev_opocc_marker", None)
|
||||||
|
params = {}
|
||||||
|
opocc_id = self.request.resolver_match.kwargs.get("id", None)
|
||||||
|
if opocc_id:
|
||||||
|
params["filter"] = "(eq,vnfInstanceId,{0})".format(opocc_id)
|
||||||
|
opoccs = api.tacker.list_vnf_lcm_op_occs(self.request, **params)
|
||||||
|
if marker is not None or prev_marker is not None:
|
||||||
|
for i, opocc in enumerate(opoccs):
|
||||||
|
if opocc["id"] == marker and i < len(opoccs) - 1:
|
||||||
|
opoccs = opoccs[i + 1:]
|
||||||
|
self._has_prev = True
|
||||||
|
break
|
||||||
|
if opocc["id"] == prev_marker and i > page_size:
|
||||||
|
opoccs = opoccs[i - page_size:]
|
||||||
|
self._has_prev = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if len(opoccs) > page_size:
|
||||||
|
self._has_more = True
|
||||||
|
else:
|
||||||
|
self._has_more = False
|
||||||
|
|
||||||
|
rows = []
|
||||||
|
for i, opocc in enumerate(opoccs):
|
||||||
|
if i >= page_size:
|
||||||
|
break
|
||||||
|
item = VnfLcmOpOccItem(
|
||||||
|
opocc_id=opocc.get('id', ''),
|
||||||
|
operation_state=opocc.get('operationState', ''),
|
||||||
|
vnf_instance_id=opocc.get('vnfInstanceId', ''),
|
||||||
|
operation=opocc.get('operation', ''))
|
||||||
|
rows.append(item)
|
||||||
|
return rows
|
||||||
|
except Exception:
|
||||||
|
self._has_more = False
|
||||||
|
error_message = _('Failed to get VNF LCM operation occurrences.')
|
||||||
|
exceptions.handle(self.request, error_message)
|
||||||
|
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
class VnfLcmOpOccTabs(tabs.TabGroup):
|
||||||
|
slug = "vnflcmopocc_tabs"
|
||||||
|
tabs = (VnfLcmOpOccTab,)
|
||||||
|
sticky = True
|
||||||
|
|
||||||
|
|
||||||
|
class VnfOpOccDetailTab(tabs.Tab):
|
||||||
|
name = _("LCM OP OCC Detail")
|
||||||
|
slug = "vnflcmopocc_detail_tab"
|
||||||
|
template_name = "nfv/vnflcmopocc/vnflcmopocc_detail.html"
|
||||||
|
|
||||||
|
def get_context_data(self, request):
|
||||||
|
return {'vnflcmopocc': self.tab_group.kwargs['vnflcmopocc']}
|
||||||
|
|
||||||
|
|
||||||
|
class VnfOpOccDetailTabs(tabs.TabGroup):
|
||||||
|
slug = "vnflcmopocc_detail_tabs"
|
||||||
|
tabs = (VnfOpOccDetailTab,)
|
||||||
|
sticky = True
|
@ -0,0 +1,15 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "VNF LCM OP OCC" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=page_title %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
{{ tab_group.render }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,15 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "VNF LCM OP OCC" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=_("VNF LCM OP OCC") %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
{{ tab_group.render }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,38 @@
|
|||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
<div class="detail">
|
||||||
|
<dl class="dl-horizontal">
|
||||||
|
<dt>{% trans "CancelMode" %}</dt>
|
||||||
|
<dd>{{ vnflcmopocc.cancelMode }}</dd>
|
||||||
|
<dt>{% trans "ChangedExtConnectivity" %}</dt>
|
||||||
|
<dd>{{ vnflcmopocc.changedExtConnectivity }}</dd>
|
||||||
|
<dt>{% trans "ChangedInfo" %}</dt>
|
||||||
|
<dd>{{ vnflcmopocc.changedInfo }}</dd>
|
||||||
|
<dt>{% trans "Error" %}</dt>
|
||||||
|
<dd>{{ vnflcmopocc.error }}</dd>
|
||||||
|
<dt>{% trans "GrantID" %}</dt>
|
||||||
|
<dd>{{ vnflcmopocc.grantId }}</dd>
|
||||||
|
<dt>{% trans "ID" %}</dt>
|
||||||
|
<dd>{{ vnflcmopocc.id }}</dd>
|
||||||
|
<dt>{% trans "IsAutomaticInvocation" %}</dt>
|
||||||
|
<dd>{{ vnflcmopocc.isAutomaticInvocation }}</dd>
|
||||||
|
<dt>{% trans "IsCancelPending" %}</dt>
|
||||||
|
<dd>{{ vnflcmopocc.isCancelPending }}</dd>
|
||||||
|
<dt>{% trans "Links" %}</dt>
|
||||||
|
<dd>{{ vnflcmopocc.links }}</dd>
|
||||||
|
<dt>{% trans "Operation" %}</dt>
|
||||||
|
<dd>{{ vnflcmopocc.operation }}</dd>
|
||||||
|
<dt>{% trans "OperationParams" %}</dt>
|
||||||
|
<dd>{{ vnflcmopocc.operationParams }}</dd>
|
||||||
|
<dt>{% trans "OperationState" %}</dt>
|
||||||
|
<dd>{{ vnflcmopocc.operationState }}</dd>
|
||||||
|
<dt>{% trans "ResourceChanges" %}</dt>
|
||||||
|
<dd>{{ vnflcmopocc.resourceChanges }}</dd>
|
||||||
|
<dt>{% trans "StartTime" %}</dt>
|
||||||
|
<dd>{{ vnflcmopocc.startTime }}</dd>
|
||||||
|
<dt>{% trans "StateEnteredTime" %}</dt>
|
||||||
|
<dd>{{ vnflcmopocc.stateEnteredTime }}</dd>
|
||||||
|
<dt>{% trans "VnfInstanceID" %}</dt>
|
||||||
|
<dd>{{ vnflcmopocc.vnfInstanceId }}</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
@ -0,0 +1,25 @@
|
|||||||
|
# Copyright (C) 2024 Fujitsu
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
|
from django.urls import re_path
|
||||||
|
|
||||||
|
from tacker_horizon.openstack_dashboard.dashboards.nfv.vnflcmopocc \
|
||||||
|
import views
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
re_path(r'^$', views.IndexView.as_view(), name='index'),
|
||||||
|
re_path(r'^(?P<id>[^/]+)/$', views.DetailView.as_view(), name='detail'),
|
||||||
|
]
|
@ -0,0 +1,73 @@
|
|||||||
|
# Copyright (C) 2024 Fujitsu
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
|
from django.urls import reverse
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from horizon import exceptions
|
||||||
|
from horizon import tabs
|
||||||
|
from horizon.utils import memoized
|
||||||
|
|
||||||
|
from tacker_horizon.openstack_dashboard import api as tacker_api
|
||||||
|
from tacker_horizon.openstack_dashboard.dashboards.nfv.vnflcmopocc \
|
||||||
|
import tabs as vnflcmopocc_tabs
|
||||||
|
|
||||||
|
|
||||||
|
class IndexView(tabs.TabbedTableView):
|
||||||
|
# A very simple class-based view...
|
||||||
|
tab_group_class = vnflcmopocc_tabs.VnfLcmOpOccTabs
|
||||||
|
template_name = 'nfv/vnflcmopocc/index.html'
|
||||||
|
|
||||||
|
def get_data(self, request, context, *args, **kwargs):
|
||||||
|
# Add data to the context here...
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class DetailView(tabs.TabView):
|
||||||
|
tab_group_class = vnflcmopocc_tabs.VnfOpOccDetailTabs
|
||||||
|
template_name = 'nfv/vnflcmopocc/detail.html'
|
||||||
|
redirect_url = 'horizon:nfv:vnflcmopocc:index'
|
||||||
|
page_title = _("LCM OP OCC Details: {{ id }}")
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(DetailView, self).get_context_data(**kwargs)
|
||||||
|
vnflcmopocc = self.get_data()
|
||||||
|
context['vnflcmopocc'] = vnflcmopocc
|
||||||
|
context['id'] = kwargs['id']
|
||||||
|
context['url'] = reverse(self.redirect_url)
|
||||||
|
return context
|
||||||
|
|
||||||
|
@memoized.memoized_method
|
||||||
|
def get_data(self):
|
||||||
|
opocc_id = self.kwargs['id']
|
||||||
|
|
||||||
|
try:
|
||||||
|
vnflcmopocc = tacker_api.tacker.get_vnf_lcm_op_occ(self.request,
|
||||||
|
opocc_id)
|
||||||
|
vnflcmopocc['links'] = vnflcmopocc.get('_links', '')
|
||||||
|
return vnflcmopocc
|
||||||
|
except Exception:
|
||||||
|
redirect = reverse(self.redirect_url)
|
||||||
|
exceptions.handle(
|
||||||
|
self.request,
|
||||||
|
_('Failed to get VNF LCM operation occurrence. (id: %s)') %
|
||||||
|
opocc_id,
|
||||||
|
redirect=redirect)
|
||||||
|
raise exceptions.Http302(redirect)
|
||||||
|
|
||||||
|
def get_tabs(self, request, *args, **kwargs):
|
||||||
|
vnflcmopocc = self.get_data()
|
||||||
|
return self.tab_group_class(request, vnflcmopocc=vnflcmopocc, **kwargs)
|
@ -0,0 +1,189 @@
|
|||||||
|
# Copyright (C) 2024 Fujitsu
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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 os
|
||||||
|
|
||||||
|
from django.core.files.uploadedfile import InMemoryUploadedFile
|
||||||
|
from django.core.files.uploadedfile import SimpleUploadedFile
|
||||||
|
from django.core.files.uploadedfile import TemporaryUploadedFile
|
||||||
|
from django.forms import ValidationError
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from horizon import exceptions
|
||||||
|
from horizon import forms
|
||||||
|
from horizon import messages
|
||||||
|
from oslo_log import log as logging
|
||||||
|
|
||||||
|
from tacker_horizon.openstack_dashboard import api
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class UploadVnfPackage(forms.SelfHandlingForm):
|
||||||
|
user_data = forms.JSONField(
|
||||||
|
label=_("User Data"), required=False)
|
||||||
|
source_type = forms.ChoiceField(
|
||||||
|
label=_('VNF Package Source'),
|
||||||
|
choices=[('url', _('URL')), ('file', _('File'))],
|
||||||
|
widget=forms.Select(
|
||||||
|
attrs={'class': 'switchable', 'data-slug': 'source'}))
|
||||||
|
url = forms.URLField(
|
||||||
|
widget=forms.TextInput(attrs={
|
||||||
|
'class': 'switched',
|
||||||
|
'data-switch-on': 'source',
|
||||||
|
'data-source-url': _('URL')}),
|
||||||
|
required=False)
|
||||||
|
user_name = forms.CharField(
|
||||||
|
widget=forms.TextInput(attrs={
|
||||||
|
'class': 'switched',
|
||||||
|
'data-switch-on': 'source',
|
||||||
|
'data-source-url': _('User Name')}),
|
||||||
|
required=False)
|
||||||
|
password = forms.CharField(
|
||||||
|
widget=forms.PasswordInput(attrs={
|
||||||
|
'class': 'switched',
|
||||||
|
'data-switch-on': 'source',
|
||||||
|
'data-source-url': _('Password')}),
|
||||||
|
required=False)
|
||||||
|
vnf_package = forms.FileField(
|
||||||
|
widget=forms.FileInput(attrs={
|
||||||
|
'class': 'switched',
|
||||||
|
'data-switch-on': 'source',
|
||||||
|
'data-source-file': _('VNF Package')}),
|
||||||
|
required=False)
|
||||||
|
|
||||||
|
def __init__(self, request, *args, **kwargs):
|
||||||
|
super(UploadVnfPackage, self).__init__(request, *args, **kwargs)
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
data = super(UploadVnfPackage, self).clean()
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
def handle(self, request, data):
|
||||||
|
try:
|
||||||
|
body = {}
|
||||||
|
user_data = data.get('user_data', None)
|
||||||
|
if user_data:
|
||||||
|
body['userDefinedData'] = user_data
|
||||||
|
response = api.tacker.create_vnf_package(request, body)
|
||||||
|
except Exception:
|
||||||
|
exceptions.handle(request,
|
||||||
|
_('Failed to create VNF Package.'))
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
params = {}
|
||||||
|
source_type = data.get('source_type', None)
|
||||||
|
if source_type == 'url':
|
||||||
|
params['url'] = data.get('url', None)
|
||||||
|
user_name = data.get('user_name', None)
|
||||||
|
password = data.get('password', None)
|
||||||
|
if user_name:
|
||||||
|
params['userName'] = user_name
|
||||||
|
params['password'] = password
|
||||||
|
api.tacker.upload_vnf_package(
|
||||||
|
request, response['id'], **params)
|
||||||
|
messages.success(
|
||||||
|
request,
|
||||||
|
_('Accepted to upload VNF Package. '
|
||||||
|
'(id: %s)') % response['id'])
|
||||||
|
else:
|
||||||
|
file = request.FILES['vnf_package']
|
||||||
|
if isinstance(file, TemporaryUploadedFile):
|
||||||
|
# Hack to fool Django, so we can keep file open.
|
||||||
|
file.file._closer.close_called = True
|
||||||
|
elif isinstance(file, InMemoryUploadedFile):
|
||||||
|
# Clone a new file for InMemoryUploadedFile.
|
||||||
|
# Because the old one will be closed by Django.
|
||||||
|
file = SimpleUploadedFile(
|
||||||
|
file.name, file.read(), file.content_type)
|
||||||
|
try:
|
||||||
|
api.tacker.upload_vnf_package(
|
||||||
|
request, response['id'], file, **params)
|
||||||
|
messages.success(
|
||||||
|
request,
|
||||||
|
_('Accepted to upload VNF Package. '
|
||||||
|
'(id: %s)') % response['id'])
|
||||||
|
finally:
|
||||||
|
try:
|
||||||
|
filename = str(file.file.name)
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
os.remove(filename)
|
||||||
|
except OSError as e:
|
||||||
|
LOG.warning(
|
||||||
|
'Failed to remove temporary file '
|
||||||
|
'%(file)s (%(e)s)',
|
||||||
|
{'file': filename, 'e': e})
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
exceptions.handle(request,
|
||||||
|
_('Failed to upload VNF Package. (id: %s)') %
|
||||||
|
response['id'])
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateVnfPackage(forms.SelfHandlingForm):
|
||||||
|
operationalState = forms.ChoiceField(
|
||||||
|
label=_('Operational State'),
|
||||||
|
required=False,
|
||||||
|
choices=[(None, _(' ')),
|
||||||
|
('ENABLED', _('ENABLED')),
|
||||||
|
('DISABLED', _('DISABLED'))],
|
||||||
|
widget=forms.Select(
|
||||||
|
attrs={'class': 'switchable', 'data-slug': 'source'}))
|
||||||
|
userData = forms.JSONField(label=_('User Data'),
|
||||||
|
required=False)
|
||||||
|
|
||||||
|
def __init__(self, request, *args, **kwargs):
|
||||||
|
super(UpdateVnfPackage, self).__init__(request, *args, **kwargs)
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
data = super(UpdateVnfPackage, self).clean()
|
||||||
|
operationalState = data.get('operationalState', None)
|
||||||
|
userData = data.get('userData', None)
|
||||||
|
if operationalState is None and userData is None:
|
||||||
|
raise ValidationError(
|
||||||
|
_("At least one of the \"operationalState\" or \
|
||||||
|
\"userDefinedData\" parameters shall be present."))
|
||||||
|
return data
|
||||||
|
|
||||||
|
def handle(self, request, data):
|
||||||
|
try:
|
||||||
|
vnfpkg_id = request.resolver_match.kwargs.get('id', None)
|
||||||
|
body = {}
|
||||||
|
operationalState = data.get('operationalState', None)
|
||||||
|
if operationalState:
|
||||||
|
body['operationalState'] = operationalState
|
||||||
|
|
||||||
|
userDefinedData = data.get('userData', None)
|
||||||
|
if userDefinedData:
|
||||||
|
body['userDefinedData'] = userDefinedData
|
||||||
|
api.tacker.update_vnf_package(request, vnfpkg_id, body)
|
||||||
|
messages.success(request,
|
||||||
|
_('Update VNF Package. (id: %s)') % vnfpkg_id)
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
exceptions.handle(request,
|
||||||
|
_('Failed to update VNF Package. (id: %s)') %
|
||||||
|
vnfpkg_id)
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
@ -0,0 +1,29 @@
|
|||||||
|
# Copyright (C) 2024 Fujitsu
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
import horizon
|
||||||
|
|
||||||
|
from tacker_horizon.openstack_dashboard.dashboards.nfv import dashboard
|
||||||
|
|
||||||
|
|
||||||
|
class VnfPackages(horizon.Panel):
|
||||||
|
name = _("VNF Packages")
|
||||||
|
slug = "vnfpackages"
|
||||||
|
|
||||||
|
|
||||||
|
dashboard.Nfv.register(VnfPackages)
|
@ -0,0 +1,116 @@
|
|||||||
|
# Copyright (C) 2024 Fujitsu
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from django.utils.translation import ngettext_lazy
|
||||||
|
|
||||||
|
from horizon import exceptions
|
||||||
|
from horizon import messages
|
||||||
|
from horizon import tables
|
||||||
|
from openstack_dashboard import policy
|
||||||
|
|
||||||
|
from tacker_horizon.openstack_dashboard import api
|
||||||
|
|
||||||
|
|
||||||
|
class DeleteVnfPackage(policy.PolicyTargetMixin, tables.DeleteAction):
|
||||||
|
@staticmethod
|
||||||
|
def action_present(count):
|
||||||
|
return ngettext_lazy(
|
||||||
|
"Delete VNF Package",
|
||||||
|
"Delete VNF Packages",
|
||||||
|
count
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def action_past(count):
|
||||||
|
return ngettext_lazy(
|
||||||
|
"Delete VNF Package",
|
||||||
|
"Delete VNF Packages",
|
||||||
|
count
|
||||||
|
)
|
||||||
|
|
||||||
|
def action(self, request, obj_id):
|
||||||
|
api.tacker.delete_vnf_package(request, obj_id)
|
||||||
|
|
||||||
|
|
||||||
|
class UploadVnfPackage(tables.LinkAction):
|
||||||
|
name = "uploadvnfpkg"
|
||||||
|
verbose_name = _("Upload VNF Package")
|
||||||
|
classes = ("ajax-modal",)
|
||||||
|
icon = "plus"
|
||||||
|
url = "horizon:nfv:vnfpackages:uploadvnfpkg"
|
||||||
|
|
||||||
|
|
||||||
|
class FetchVnfPackage(tables.LinkAction):
|
||||||
|
name = "fetchvnfpkg"
|
||||||
|
verbose_name = _("Fetch VNF Package")
|
||||||
|
verbose_name_plural = _("Fetch VNF Package")
|
||||||
|
icon = "download"
|
||||||
|
url = "horizon:nfv:vnfpackages:fetch"
|
||||||
|
|
||||||
|
def allowed(self, request, datum=None):
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateVnfPackageInfo(tables.LinkAction):
|
||||||
|
name = "updatevnfpkginfo"
|
||||||
|
verbose_name = _("Update VNF Package Info")
|
||||||
|
url = "horizon:nfv:vnfpackages:updatevnfpkg"
|
||||||
|
classes = ("ajax-modal",)
|
||||||
|
|
||||||
|
|
||||||
|
class CreateVnfIdentifier(tables.Action):
|
||||||
|
name = "createvnfid"
|
||||||
|
verbose_name = _("Create VNF Identifier")
|
||||||
|
|
||||||
|
def single(self, table, request, obj_id): # pylint: disable=E0202
|
||||||
|
try:
|
||||||
|
vnf_pkg = api.tacker.get_vnf_package(request, obj_id)
|
||||||
|
vnfd_id = vnf_pkg.get('vnfdId', None)
|
||||||
|
if not vnfd_id:
|
||||||
|
msg = _('Failed to get VNFD ID')
|
||||||
|
raise Exception(msg)
|
||||||
|
req_body = {}
|
||||||
|
req_body['vnfdId'] = vnfd_id
|
||||||
|
response = api.tacker.create_vnf_instance(request, req_body)
|
||||||
|
messages.success(request,
|
||||||
|
_('Create VNF Identifier. (id: %s)') %
|
||||||
|
response['id'])
|
||||||
|
except Exception:
|
||||||
|
exceptions.handle(request,
|
||||||
|
_('Failed to create VNF Identifier.'))
|
||||||
|
|
||||||
|
|
||||||
|
class VnfPackageTable(tables.DataTable):
|
||||||
|
id = tables.Column('id', verbose_name=_("ID"),
|
||||||
|
link="horizon:nfv:vnfpackages:detail",)
|
||||||
|
name = tables.Column('vnf_product_name',
|
||||||
|
verbose_name=_("VNF Product Name"))
|
||||||
|
onboarding_state = tables.Column('onboarding_state',
|
||||||
|
verbose_name=_("Onboarding State"))
|
||||||
|
usage_state = tables.Column('usage_state', verbose_name=_("Usage State"))
|
||||||
|
operational_state = tables.Column('operational_state',
|
||||||
|
verbose_name=_("Operational State"))
|
||||||
|
|
||||||
|
class Meta(object):
|
||||||
|
name = "vnfpackage"
|
||||||
|
verbose_name = _("VNF Package")
|
||||||
|
pagination_param = 'package_marker'
|
||||||
|
prev_pagination_param = 'prev_package_marker'
|
||||||
|
table_actions = (UploadVnfPackage, DeleteVnfPackage,
|
||||||
|
tables.FilterAction,)
|
||||||
|
row_actions = (FetchVnfPackage, UpdateVnfPackageInfo, DeleteVnfPackage,
|
||||||
|
CreateVnfIdentifier,)
|
@ -0,0 +1,118 @@
|
|||||||
|
# Copyright (C) 2024 Fujitsu
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from horizon import exceptions
|
||||||
|
from horizon import tabs
|
||||||
|
from horizon import utils as horizon_utils
|
||||||
|
|
||||||
|
from tacker_horizon.openstack_dashboard import api
|
||||||
|
from tacker_horizon.openstack_dashboard.dashboards.nfv import utils # noqa
|
||||||
|
from tacker_horizon.openstack_dashboard.dashboards.nfv.vnfpackages \
|
||||||
|
import tables
|
||||||
|
|
||||||
|
|
||||||
|
class VnfPackageItem(object):
|
||||||
|
def __init__(self, vnfpkg_id, vnf_product_name, onboarding_state,
|
||||||
|
usage_state, operational_state, vnfd_id,):
|
||||||
|
self.id = vnfpkg_id
|
||||||
|
self.name = vnfpkg_id
|
||||||
|
self.vnf_product_name = vnf_product_name
|
||||||
|
self.onboarding_state = onboarding_state
|
||||||
|
self.usage_state = usage_state
|
||||||
|
self.operational_state = operational_state
|
||||||
|
self.vnfd_id = vnfd_id
|
||||||
|
|
||||||
|
|
||||||
|
class VnfPackageTab(tabs.TableTab):
|
||||||
|
name = _("VNFP tab")
|
||||||
|
slug = "vnfpkg_tab"
|
||||||
|
table_classes = (tables.VnfPackageTable,)
|
||||||
|
template_name = ("horizon/common/_detail_table.html")
|
||||||
|
preload = False
|
||||||
|
|
||||||
|
def has_prev_data(self, table):
|
||||||
|
return self._has_prev
|
||||||
|
|
||||||
|
def has_more_data(self, table):
|
||||||
|
return self._has_more
|
||||||
|
|
||||||
|
def get_vnfpackage_data(self):
|
||||||
|
try:
|
||||||
|
self._has_prev = False
|
||||||
|
page_size = horizon_utils.functions.get_page_size(self.request)
|
||||||
|
marker = self.request.GET.get(
|
||||||
|
"package_marker", None)
|
||||||
|
prev_marker = self.request.GET.get(
|
||||||
|
"prev_package_marker", None)
|
||||||
|
packages = api.tacker.list_vnf_packages(self.request)
|
||||||
|
if marker is not None or prev_marker is not None:
|
||||||
|
for i, package in enumerate(packages):
|
||||||
|
if package["id"] == marker and i < len(packages) - 1:
|
||||||
|
packages = packages[i + 1:]
|
||||||
|
self._has_prev = True
|
||||||
|
break
|
||||||
|
if package["id"] == prev_marker and i > page_size:
|
||||||
|
packages = packages[i - page_size:]
|
||||||
|
self._has_prev = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if len(packages) > page_size:
|
||||||
|
self._has_more = True
|
||||||
|
else:
|
||||||
|
self._has_more = False
|
||||||
|
|
||||||
|
rows = []
|
||||||
|
for i, package in enumerate(packages):
|
||||||
|
if i >= page_size:
|
||||||
|
break
|
||||||
|
item = VnfPackageItem(
|
||||||
|
vnfpkg_id=package.get('id', ''),
|
||||||
|
vnf_product_name=package.get('vnfProductName', ''),
|
||||||
|
onboarding_state=package.get('onboardingState', ''),
|
||||||
|
usage_state=package.get('usageState', ''),
|
||||||
|
operational_state=package.get('operationalState', ''),
|
||||||
|
vnfd_id=package.get('vnfdId', ''),)
|
||||||
|
rows.append(item)
|
||||||
|
return rows
|
||||||
|
except Exception:
|
||||||
|
self._has_more = False
|
||||||
|
error_message = _('Failed to get VNF Packages.')
|
||||||
|
exceptions.handle(self.request, error_message)
|
||||||
|
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
class VnfPackageTabs(tabs.TabGroup):
|
||||||
|
slug = "vnfpkg_tabs"
|
||||||
|
tabs = (VnfPackageTab,)
|
||||||
|
sticky = True
|
||||||
|
|
||||||
|
|
||||||
|
class VnfPackageDetailTab(tabs.Tab):
|
||||||
|
name = _("VNFPkg Detail")
|
||||||
|
slug = "vnfpkg_detail_tab"
|
||||||
|
template_name = "nfv/vnfpackages/vnfpkg_detail.html"
|
||||||
|
|
||||||
|
def get_context_data(self, request):
|
||||||
|
return {'vnfpkg': self.tab_group.kwargs['vnfpkg']}
|
||||||
|
|
||||||
|
|
||||||
|
class VnfPackageDetailTabs(tabs.TabGroup):
|
||||||
|
slug = "vnfpkg_detail_tabs"
|
||||||
|
tabs = (VnfPackageDetailTab,)
|
||||||
|
sticky = True
|
@ -0,0 +1,9 @@
|
|||||||
|
{% extends "horizon/common/_modal_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block form_attrs %}enctype="multipart/form-data"{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-body-right %}
|
||||||
|
<h3>{% trans "Description:" %}</h3>
|
||||||
|
<p>{% trans "Update a VNF Package information." %}</p>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,9 @@
|
|||||||
|
{% extends "horizon/common/_modal_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block form_attrs %}enctype="multipart/form-data"{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-body-right %}
|
||||||
|
<h3>{% trans "Description:" %}</h3>
|
||||||
|
<p>{% trans "Upload a VNF Package." %}</p>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,15 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "VNF Package Details" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=page_title %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
{{ tab_group.render }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,15 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "VNF Packages" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=_("VNF Packages") %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
{{ tab_group.render }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,11 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Update VNF Package" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=_("Update VNF Package") %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include 'nfv/vnfpackages/_update_vnfpkg.html' %}
|
||||||
|
{% endblock %}
|
@ -0,0 +1,11 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Upload VNF Package" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=_("Upload VNF Package") %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include 'nfv/vnfpackages/_upload_vnfpkg.html' %}
|
||||||
|
{% endblock %}
|
@ -0,0 +1,34 @@
|
|||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
<div class="detail">
|
||||||
|
<dl class="dl-horizontal">
|
||||||
|
<dt>{% trans "Additional Artifacts" %}</dt>
|
||||||
|
<dd>{{ vnfpkg.additionalArtifacts }}</dd>
|
||||||
|
<dt>{% trans "Checksum" %}</dt>
|
||||||
|
<dd>{{ vnfpkg.checksum }}</dd>
|
||||||
|
<dt>{% trans "ID" %}</dt>
|
||||||
|
<dd>{{ vnfpkg.id }}</dd>
|
||||||
|
<dt>{% trans "Links" %}</dt>
|
||||||
|
<dd>{{ vnfpkg.links }}</dd>
|
||||||
|
<dt>{% trans "Onboarding State" %}</dt>
|
||||||
|
<dd>{{ vnfpkg.onboardingState }}</dd>
|
||||||
|
<dt>{% trans "Operational State" %}</dt>
|
||||||
|
<dd>{{ vnfpkg.operationalState }}</dd>
|
||||||
|
<dt>{% trans "Software Images" %}</dt>
|
||||||
|
<dd>{{ vnfpkg.softwareImages }}</dd>
|
||||||
|
<dt>{% trans "Usage State" %}</dt>
|
||||||
|
<dd>{{ vnfpkg.usageState }}</dd>
|
||||||
|
<dt>{% trans "User Defined Data" %}</dt>
|
||||||
|
<dd>{{ vnfpkg.userDefinedData }}</dd>
|
||||||
|
<dt>{% trans "VNF Product Name" %}</dt>
|
||||||
|
<dd>{{ vnfpkg.vnfProductName }}</dd>
|
||||||
|
<dt>{% trans "VNF Provider" %}</dt>
|
||||||
|
<dd>{{ vnfpkg.vnfProvider }}</dd>
|
||||||
|
<dt>{% trans "VNF Software Version" %}</dt>
|
||||||
|
<dd>{{ vnfpkg.vnfSoftwareVersion }}</dd>
|
||||||
|
<dt>{% trans "VNFD ID" %}</dt>
|
||||||
|
<dd>{{ vnfpkg.vnfdId }}</dd>
|
||||||
|
<dt>{% trans "VNFD Version" %}</dt>
|
||||||
|
<dd>{{ vnfpkg.vnfdVersion }}</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
@ -0,0 +1,31 @@
|
|||||||
|
# Copyright (C) 2024 Fujitsu
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
|
from django.urls import re_path
|
||||||
|
|
||||||
|
from tacker_horizon.openstack_dashboard.dashboards.nfv.vnfpackages \
|
||||||
|
import views
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
re_path(r'^$', views.IndexView.as_view(), name='index'),
|
||||||
|
re_path(r'^(?P<id>[^/]+)/fetch/$', views.fetch_vnf_package,
|
||||||
|
name='fetch'),
|
||||||
|
re_path(r'^uploadvnfpkg$', views.UploadVnfPackageView.as_view(),
|
||||||
|
name='uploadvnfpkg'),
|
||||||
|
re_path(r'^(?P<id>[^/]+)/$', views.DetailView.as_view(), name='detail'),
|
||||||
|
re_path(r'^(?P<id>[^/]+)/updatevnfpkg/$',
|
||||||
|
views.UpdateVnfPackageView.as_view(), name='updatevnfpkg'),
|
||||||
|
]
|
@ -0,0 +1,121 @@
|
|||||||
|
# Copyright (C) 2024 Fujitsu
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
|
from django import http
|
||||||
|
from django.urls import reverse
|
||||||
|
from django.urls import reverse_lazy
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from horizon import exceptions
|
||||||
|
from horizon import forms
|
||||||
|
from horizon import tabs
|
||||||
|
from horizon.utils import memoized
|
||||||
|
|
||||||
|
from tacker_horizon.openstack_dashboard import api as tacker_api
|
||||||
|
from tacker_horizon.openstack_dashboard.dashboards.nfv.vnfpackages \
|
||||||
|
import forms as project_forms
|
||||||
|
from tacker_horizon.openstack_dashboard.dashboards.nfv.vnfpackages \
|
||||||
|
import tabs as vnfpkg_tabs
|
||||||
|
|
||||||
|
|
||||||
|
def fetch_vnf_package(request, id):
|
||||||
|
try:
|
||||||
|
file = tacker_api.tacker.fetch_vnf_package(request, id)
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
exceptions.handle(request,
|
||||||
|
_('Failed to fetch VNF Package. (id: %s)') % id,
|
||||||
|
redirect="horizon:nfv:vnfpackages:index")
|
||||||
|
response = http.HttpResponse(content_type='application/zip')
|
||||||
|
response.write(file)
|
||||||
|
response['Content-Disposition'] = (
|
||||||
|
'attachment; filename="package-%s.zip"' % id)
|
||||||
|
response['Content-Length'] = len(file)
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
class IndexView(tabs.TabbedTableView):
|
||||||
|
tab_group_class = vnfpkg_tabs.VnfPackageTabs
|
||||||
|
template_name = 'nfv/vnfpackages/index.html'
|
||||||
|
|
||||||
|
|
||||||
|
class UploadVnfPackageView(forms.ModalFormView):
|
||||||
|
form_class = project_forms.UploadVnfPackage
|
||||||
|
template_name = 'nfv/vnfpackages/upload_vnfpkg.html'
|
||||||
|
success_url = reverse_lazy("horizon:nfv:vnfpackages:index")
|
||||||
|
modal_id = "add_service_modal"
|
||||||
|
modal_header = _("Upload VNF Package")
|
||||||
|
submit_label = _("Upload VNF Package")
|
||||||
|
submit_url = "horizon:nfv:vnfpackages:uploadvnfpkg"
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(UploadVnfPackageView, self).get_context_data(**kwargs)
|
||||||
|
context['submit_url'] = reverse(self.submit_url)
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateVnfPackageView(forms.ModalFormView):
|
||||||
|
form_class = project_forms.UpdateVnfPackage
|
||||||
|
template_name = 'nfv/vnfpackages/update_vnfpkg.html'
|
||||||
|
success_url = reverse_lazy("horizon:nfv:vnfpackages:index")
|
||||||
|
modal_id = "add_service_modal"
|
||||||
|
modal_header = _("Update VNF Package Info")
|
||||||
|
submit_label = _("Update VNF Package Info")
|
||||||
|
submit_url = "horizon:nfv:vnfpackages:updatevnfpkg"
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(UpdateVnfPackageView, self).get_context_data(**kwargs)
|
||||||
|
context['id'] = self.kwargs['id']
|
||||||
|
context['submit_url'] = reverse(self.submit_url,
|
||||||
|
kwargs={'id': self.kwargs['id']})
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class DetailView(tabs.TabView):
|
||||||
|
tab_group_class = vnfpkg_tabs.VnfPackageDetailTabs
|
||||||
|
template_name = 'nfv/vnfpackages/detail.html'
|
||||||
|
redirect_url = 'horizon:nfv:vnfpackages:index'
|
||||||
|
page_title = _("VNF Package Details: {{ id }}")
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(DetailView, self).get_context_data(**kwargs)
|
||||||
|
vnfpkg = self.get_data()
|
||||||
|
context['vnfpkg'] = vnfpkg
|
||||||
|
context['id'] = kwargs['id']
|
||||||
|
context['url'] = reverse(self.redirect_url)
|
||||||
|
|
||||||
|
return context
|
||||||
|
|
||||||
|
@memoized.memoized_method
|
||||||
|
def get_data(self):
|
||||||
|
vnfpkg_id = self.kwargs.get('id', None)
|
||||||
|
|
||||||
|
try:
|
||||||
|
vnfpkg = tacker_api.tacker.get_vnf_package(self.request, vnfpkg_id)
|
||||||
|
vnfpkg['links'] = vnfpkg.get('_links', '')
|
||||||
|
return vnfpkg
|
||||||
|
except Exception:
|
||||||
|
redirect = reverse(self.redirect_url)
|
||||||
|
exceptions.handle(
|
||||||
|
self.request,
|
||||||
|
_('Failed to get VNF Package. (id: %s)') % vnfpkg_id,
|
||||||
|
redirect=redirect)
|
||||||
|
raise exceptions.Http302(redirect)
|
||||||
|
|
||||||
|
def get_tabs(self, request, *args, **kwargs):
|
||||||
|
vnfpkg = self.get_data()
|
||||||
|
return self.tab_group_class(request, vnfpkg=vnfpkg, **kwargs)
|
@ -0,0 +1,102 @@
|
|||||||
|
# Copyright (C) 2024 Fujitsu
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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 json
|
||||||
|
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from horizon import exceptions
|
||||||
|
from horizon import forms
|
||||||
|
from horizon import messages
|
||||||
|
|
||||||
|
from tacker_horizon.openstack_dashboard import api
|
||||||
|
|
||||||
|
|
||||||
|
class CreatePmJob(forms.SelfHandlingForm):
|
||||||
|
param_file = forms.FileField(
|
||||||
|
label=_("Param File"),
|
||||||
|
help_text=_("parameter file to upload."),
|
||||||
|
widget=forms.FileInput(
|
||||||
|
attrs={'class': 'switched',
|
||||||
|
'data-switch-on': 'source',
|
||||||
|
'data-source-file': _('Param File')}))
|
||||||
|
|
||||||
|
def __init__(self, request, *args, **kwargs):
|
||||||
|
super(CreatePmJob, self).__init__(request, *args, **kwargs)
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
data = super(CreatePmJob, self).clean()
|
||||||
|
|
||||||
|
try:
|
||||||
|
param_str = self.files['param_file'].read()
|
||||||
|
param = json.loads(param_str)
|
||||||
|
data['param'] = param
|
||||||
|
except Exception as e:
|
||||||
|
msg = _('Failed to read file: %s.') % e
|
||||||
|
raise forms.ValidationError(msg)
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
def handle(self, request, data):
|
||||||
|
try:
|
||||||
|
param = data['param']
|
||||||
|
pmjob = api.tacker.create_pm_job(request, param)
|
||||||
|
messages.success(request,
|
||||||
|
_('Create PM Job. (id: %s)') %
|
||||||
|
pmjob['id'])
|
||||||
|
return True
|
||||||
|
except Exception:
|
||||||
|
msg = _('Failed to create PM Job.')
|
||||||
|
exceptions.handle(request, msg)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class UpdatePmJob(forms.SelfHandlingForm):
|
||||||
|
param_file = forms.FileField(
|
||||||
|
label=_("Param File"),
|
||||||
|
help_text=_("parameter file to upload."),
|
||||||
|
widget=forms.FileInput(
|
||||||
|
attrs={'class': 'switched',
|
||||||
|
'data-switch-on': 'source',
|
||||||
|
'data-source-file': _('Param File')}))
|
||||||
|
|
||||||
|
def __init__(self, request, *args, **kwargs):
|
||||||
|
super(UpdatePmJob, self).__init__(request, *args, **kwargs)
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
data = super(UpdatePmJob, self).clean()
|
||||||
|
|
||||||
|
try:
|
||||||
|
param_str = self.files['param_file'].read()
|
||||||
|
param = json.loads(param_str)
|
||||||
|
data['param'] = param
|
||||||
|
except Exception as e:
|
||||||
|
msg = _('Failed to read file: %s.') % e
|
||||||
|
raise forms.ValidationError(msg)
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
def handle(self, request, data):
|
||||||
|
try:
|
||||||
|
param = data['param']
|
||||||
|
job_id = request.resolver_match.kwargs['id']
|
||||||
|
api.tacker.update_pm_job(request, job_id, param)
|
||||||
|
messages.success(request,
|
||||||
|
_('Update PM Job. (id: %s)') % job_id)
|
||||||
|
return True
|
||||||
|
except Exception:
|
||||||
|
msg = _('Failed to update PM Job. (id: %s)') % job_id
|
||||||
|
exceptions.handle(request, msg)
|
||||||
|
return False
|
@ -0,0 +1,29 @@
|
|||||||
|
# Copyright (C) 2024 Fujitsu
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
import horizon
|
||||||
|
|
||||||
|
from tacker_horizon.openstack_dashboard.dashboards.nfv import dashboard
|
||||||
|
|
||||||
|
|
||||||
|
class VnfPmJob(horizon.Panel):
|
||||||
|
name = _("PM Job")
|
||||||
|
slug = "vnfpmjob"
|
||||||
|
|
||||||
|
|
||||||
|
dashboard.Nfv.register(VnfPmJob)
|
@ -0,0 +1,74 @@
|
|||||||
|
# Copyright (C) 2024 Fujitsu
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from django.utils.translation import ngettext_lazy
|
||||||
|
|
||||||
|
from horizon import tables
|
||||||
|
from openstack_dashboard import policy
|
||||||
|
|
||||||
|
from tacker_horizon.openstack_dashboard import api
|
||||||
|
|
||||||
|
|
||||||
|
class DeletePmJob(policy.PolicyTargetMixin, tables.DeleteAction):
|
||||||
|
@staticmethod
|
||||||
|
def action_present(count):
|
||||||
|
return ngettext_lazy(
|
||||||
|
"Delete PM Job",
|
||||||
|
"Delete PM Jobs",
|
||||||
|
count
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def action_past(count):
|
||||||
|
return ngettext_lazy(
|
||||||
|
"Delete PM Job",
|
||||||
|
"Delete PM Jobs",
|
||||||
|
count
|
||||||
|
)
|
||||||
|
|
||||||
|
def action(self, request, obj_id):
|
||||||
|
api.tacker.delete_pm_job(request, obj_id)
|
||||||
|
|
||||||
|
|
||||||
|
class CreatePmJob(tables.LinkAction):
|
||||||
|
name = "createpmjob"
|
||||||
|
verbose_name = _("Create PM Job")
|
||||||
|
classes = ("ajax-modal",)
|
||||||
|
icon = "plus"
|
||||||
|
url = "horizon:nfv:vnfpmjob:createpmjob"
|
||||||
|
|
||||||
|
|
||||||
|
class UpdatePmJob(tables.LinkAction):
|
||||||
|
name = "updatepmjob"
|
||||||
|
verbose_name = _("Update PM Job")
|
||||||
|
url = "horizon:nfv:vnfpmjob:updatepmjob"
|
||||||
|
classes = ("ajax-modal",)
|
||||||
|
|
||||||
|
|
||||||
|
class VnfPmJobTable(tables.DataTable):
|
||||||
|
id = tables.Column('id', link="horizon:nfv:vnfpmjob:detail",
|
||||||
|
verbose_name=_("ID"))
|
||||||
|
object_type = tables.Column('object_type', verbose_name=_("Object Type"))
|
||||||
|
links = tables.Column('links', verbose_name=_("Links"))
|
||||||
|
|
||||||
|
class Meta(object):
|
||||||
|
name = "pmjob"
|
||||||
|
verbose_name = _("PM Job")
|
||||||
|
pagination_param = 'vnfpmjob_marker'
|
||||||
|
prev_pagination_param = 'prev_vnfpmjob_marker'
|
||||||
|
table_actions = (CreatePmJob, DeletePmJob, tables.FilterAction,)
|
||||||
|
row_actions = (UpdatePmJob, DeletePmJob,)
|
@ -0,0 +1,122 @@
|
|||||||
|
# Copyright (C) 2024 Fujitsu
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from horizon import exceptions
|
||||||
|
from horizon import tabs
|
||||||
|
from horizon import utils as horizon_utils
|
||||||
|
|
||||||
|
from tacker_horizon.openstack_dashboard import api
|
||||||
|
from tacker_horizon.openstack_dashboard.dashboards.nfv.vnfpmjob \
|
||||||
|
import tables
|
||||||
|
|
||||||
|
|
||||||
|
class VnfPmJobItem(object):
|
||||||
|
def __init__(self, job_id, links, object_type):
|
||||||
|
self.id = job_id
|
||||||
|
self.name = job_id
|
||||||
|
self.links = links
|
||||||
|
self.object_type = object_type
|
||||||
|
|
||||||
|
|
||||||
|
class VnfPmJobTab(tabs.TableTab):
|
||||||
|
name = _("VNFPMJob Tab")
|
||||||
|
slug = "vnfpmjob_tab"
|
||||||
|
table_classes = (tables.VnfPmJobTable,)
|
||||||
|
template_name = "horizon/common/_detail_table.html"
|
||||||
|
preload = False
|
||||||
|
|
||||||
|
def has_prev_data(self, table):
|
||||||
|
return self._has_prev
|
||||||
|
|
||||||
|
def has_more_data(self, table):
|
||||||
|
return self._has_more
|
||||||
|
|
||||||
|
def get_pmjob_data(self):
|
||||||
|
try:
|
||||||
|
self._has_prev = False
|
||||||
|
page_size = horizon_utils.functions.get_page_size(self.request)
|
||||||
|
marker = self.request.GET.get("vnfpmjob_marker", None)
|
||||||
|
prev_marker = self.request.GET.get("prev_vnfpmjob_marker", None)
|
||||||
|
pmjobs = api.tacker.list_pm_jobs(self.request)
|
||||||
|
|
||||||
|
if marker is not None or prev_marker is not None:
|
||||||
|
for i, pmjob in enumerate(pmjobs):
|
||||||
|
if pmjob["id"] == marker and i < len(pmjobs) - 1:
|
||||||
|
pmjobs = pmjobs[i + 1:]
|
||||||
|
self._has_prev = True
|
||||||
|
break
|
||||||
|
if pmjob["id"] == prev_marker and i > page_size:
|
||||||
|
pmjobs = pmjobs[i - page_size:]
|
||||||
|
self._has_prev = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if len(pmjobs) > page_size:
|
||||||
|
self._has_more = True
|
||||||
|
else:
|
||||||
|
self._has_more = False
|
||||||
|
|
||||||
|
rows = []
|
||||||
|
for i, pmjob in enumerate(pmjobs):
|
||||||
|
if i >= page_size:
|
||||||
|
break
|
||||||
|
item = VnfPmJobItem(pmjob['id'],
|
||||||
|
pmjob['_links'],
|
||||||
|
pmjob['objectType'])
|
||||||
|
rows.append(item)
|
||||||
|
return rows
|
||||||
|
except Exception:
|
||||||
|
self._has_more = False
|
||||||
|
error_message = _('Failed to get PM Jobs.')
|
||||||
|
exceptions.handle(self.request, error_message)
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
class VnfPmJobTabs(tabs.TabGroup):
|
||||||
|
slug = "vnfpmjob_tabs"
|
||||||
|
tabs = (VnfPmJobTab,)
|
||||||
|
sticky = True
|
||||||
|
|
||||||
|
|
||||||
|
class VnfPmJobDetailTab(tabs.Tab):
|
||||||
|
name = _("VNF PM Job")
|
||||||
|
slug = "vnfpmjob_detail_tab"
|
||||||
|
template_name = "nfv/vnfpmjob/pmjob_detail.html"
|
||||||
|
|
||||||
|
def get_context_data(self, request):
|
||||||
|
return {'pmjob': self.tab_group.kwargs['pmjob']}
|
||||||
|
|
||||||
|
|
||||||
|
class VnfPmJobDetailTabs(tabs.TabGroup):
|
||||||
|
slug = "vnfpmjob_detail_tabs"
|
||||||
|
tabs = (VnfPmJobDetailTab,)
|
||||||
|
sticky = True
|
||||||
|
|
||||||
|
|
||||||
|
class VnfPmJobReportDetailTab(tabs.Tab):
|
||||||
|
name = _("PM Job Reports")
|
||||||
|
slug = "vnfpmjob_report_detail_tab"
|
||||||
|
template_name = "nfv/vnfpmjob/report_detail.html"
|
||||||
|
|
||||||
|
def get_context_data(self, request):
|
||||||
|
return {'report': self.tab_group.kwargs['report']}
|
||||||
|
|
||||||
|
|
||||||
|
class VnfPmJobReportDetailTabs(tabs.TabGroup):
|
||||||
|
slug = "vnfpmjob_report_detail_tabs"
|
||||||
|
tabs = (VnfPmJobReportDetailTab,)
|
||||||
|
sticky = True
|
@ -0,0 +1,9 @@
|
|||||||
|
{% extends "horizon/common/_modal_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block form_attrs %}enctype="multipart/form-data"{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-body-right %}
|
||||||
|
<h3>{% trans "Description:" %}</h3>
|
||||||
|
<p>{% trans "Create a PM Job." %}</p>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,9 @@
|
|||||||
|
{% extends "horizon/common/_modal_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block form_attrs %}enctype="multipart/form-data"{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-body-right %}
|
||||||
|
<h3>{% trans "Description:" %}</h3>
|
||||||
|
<p>{% trans "Update a PM Job." %}</p>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,11 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Create PM Job" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=_("Create PM Job") %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include 'nfv/vnfpmjob/_create_pmjob.html' %}
|
||||||
|
{% endblock %}
|
@ -0,0 +1,15 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "PM Job Detail" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=page_title %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
{{ tab_group.render }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,15 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "PM Job" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=_("PM Job") %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
{{ tab_group.render }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,57 @@
|
|||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
th, td {
|
||||||
|
padding: 8px;
|
||||||
|
text-align: left;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="detail">
|
||||||
|
<dl class="dl-horizontal">
|
||||||
|
<dt>{% trans "ID" %}</dt>
|
||||||
|
<dd>{{ pmjob.id }}</dd>
|
||||||
|
<dt>{% trans "Links" %}</dt>
|
||||||
|
<dd>{{ pmjob.links }}</dd>
|
||||||
|
<dt>{% trans "Callback Uri" %}</dt>
|
||||||
|
<dd>{{ pmjob.callback_uri }}</dd>
|
||||||
|
<dt>{% trans "Criteria" %}</dt>
|
||||||
|
<dd>{{ pmjob.criteria }}</dd>
|
||||||
|
<dt>{% trans "Object Instance IDs" %}</dt>
|
||||||
|
<dd>{{ pmjob.object_instance_ids }}</dd>
|
||||||
|
<dt>{% trans "Object Type" %}</dt>
|
||||||
|
<dd>{{ pmjob.object_type }}</dd>
|
||||||
|
<dt>{% trans "Sub Object Instance IDs" %}</dt>
|
||||||
|
<dd>{{ pmjob.sub_object_instance_ids }}</dd>
|
||||||
|
<dt>{% trans "Reports" %}</dt>
|
||||||
|
<dd>
|
||||||
|
<table style="width:100%">
|
||||||
|
<tr>
|
||||||
|
<th><b>{% trans "readyTime" %}<br/></b></th>
|
||||||
|
<th><b>{% trans "href" %}<br/></b></th>
|
||||||
|
</tr>
|
||||||
|
{% for report in pmjob.reports %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ report.readyTime }}</td>
|
||||||
|
<td>
|
||||||
|
{% if report.href %}
|
||||||
|
{% if report.id and report.reportId %}
|
||||||
|
<a href="{% url 'horizon:nfv:vnfpmjob:reportdetail' report.id report.reportId %}">{{ report.href }}</a>
|
||||||
|
{% else %}
|
||||||
|
{% trans report.href %}
|
||||||
|
{% endif %}
|
||||||
|
{% else %}
|
||||||
|
{% trans "-" %}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
@ -0,0 +1,39 @@
|
|||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
th, td {
|
||||||
|
padding: 8px;
|
||||||
|
text-align: left;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="detail">
|
||||||
|
<dl class="dl-horizontal">
|
||||||
|
<dt>{% trans "Entries" %}</dt>
|
||||||
|
<dd>
|
||||||
|
<table style="width:100%">
|
||||||
|
<tr>
|
||||||
|
<th><b>{% trans "objectType" %}<br/></b></th>
|
||||||
|
<th><b>{% trans "objectInstanceId" %}<br/></b></th>
|
||||||
|
<th><b>{% trans "subObjectInstanceId" %}<br/></b></th>
|
||||||
|
<th><b>{% trans "performanceMetric" %}<br/></b></th>
|
||||||
|
<th><b>{% trans "performanceValues" %}<br/></b></th>
|
||||||
|
</tr>
|
||||||
|
{% for entrie in report.entries %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ entrie.objectType }}</td>
|
||||||
|
<td>{{ entrie.objectInstanceId }}</td>
|
||||||
|
<td>{{ entrie.subObjectInstanceId }}</td>
|
||||||
|
<td>{{ entrie.performanceMetric }}</td>
|
||||||
|
<td>{{ entrie.performanceValues }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user