| 2025-12-08 06:23:50 |
Hitomi Koba |
description |
When there are two projects (for example, Project A and Project B),
if both try to onboard a VNF Package that contains the same vnfdId,
the onboarding of the second project fails.
Currently, the vnfdId duplication check is performed globally across all projects,
instead of being scoped per tenant/project.
As a result, multi-tenancy is not properly supported in VNF Package onboarding.
Project A:
```
$ openstack vnf p list
+--------------------------------------+------------------+------------------+-------------+-------------------+-------------------------------------------------------------------------------------------------+
| Id | Vnf Product Name | Onboarding State | Usage State | Operational State | Links |
+--------------------------------------+------------------+------------------+-------------+-------------------+-------------------------------------------------------------------------------------------------+
| a1cf34b0-ab73-4d36-8b32-0aac4f0c0c08 | Sample | ONBOARDED | NOT_IN_USE | ENABLED | { |
| | | | | | "self": { |
| | | | | | "href": "/vnfpkgm/v1/vnf_packages/a1cf34b0-ab73-4d36-8b32-0aac4f0c0c08" |
| | | | | | }, |
| | | | | | "packageContent": { |
| | | | | | "href": "/vnfpkgm/v1/vnf_packages/a1cf34b0-ab73-4d36-8b32-0aac4f0c0c08/package_content" |
| | | | | | } |
| | | | | | } |
+--------------------------------------+------------------+------------------+-------------+-------------------+-------------------------------------------------------------------------------------------------+
$ openstack vnf p show a1cf34b0-ab73-4d36-8b32-0aac4f0c0c08 -c 'VNFD ID'
+---------+--------------------------------------+
| Field | Value |
+---------+--------------------------------------+
| VNFD ID | c922dbf4-ee96-4e4b-af0e-85d233504d48 |
+---------+--------------------------------------+
```
Project B:
The status remains `CREATED` instead of changing to `ONBOARDED`.
```
$ openstack vnf p list
+--------------------------------------+------------------+------------------+-------------+-------------------+-------------------------------------------------------------------------------------------------+
| Id | Vnf Product Name | Onboarding State | Usage State | Operational State | Links |
+--------------------------------------+------------------+------------------+-------------+-------------------+-------------------------------------------------------------------------------------------------+
| 390b0bc9-90a3-4f3c-b510-c99f652f3679 | | CREATED | NOT_IN_USE | DISABLED | { |
| | | | | | "self": { |
| | | | | | "href": "/vnfpkgm/v1/vnf_packages/390b0bc9-90a3-4f3c-b510-c99f652f3679" |
| | | | | | }, |
| | | | | | "packageContent": { |
| | | | | | "href": "/vnfpkgm/v1/vnf_packages/390b0bc9-90a3-4f3c-b510-c99f652f3679/package_content" |
| | | | | | } |
| | | | | | } |
+--------------------------------------+------------------+------------------+-------------+-------------------+-------------------------------------------------------------------------------------------------+
```
Tacker error log
```
Traceback (most recent call last):
File "/usr/local/lib/python3.8/dist-packages/oslo_messaging/rpc/server.py", line 165, in _process_incoming
res = self.dispatcher.dispatch(message)
File "/usr/local/lib/python3.8/dist-packages/oslo_messaging/rpc/dispatcher.py", line 309, in dispatch
return self._do_dispatch(endpoint, method, ctxt, args)
File "/usr/local/lib/python3.8/dist-packages/oslo_messaging/rpc/dispatcher.py", line 229, in _do_dispatch
result = func(ctxt, **new_args)
File "/opt/stack/tacker/tacker/conductor/conductor_server.py", line 164, in decorated_function
vnf_package.save()
File "/usr/local/lib/python3.8/dist-packages/oslo_utils/excutils.py", line 227, in __exit__
self.force_reraise()
File "/usr/local/lib/python3.8/dist-packages/oslo_utils/excutils.py", line 200, in force_reraise
raise self.value
File "/opt/stack/tacker/tacker/conductor/conductor_server.py", line 127, in decorated_function
return function(self, context, *args, **kwargs)
File "/opt/stack/tacker/tacker/conductor/conductor_server.py", line 507, in load_csar_data
self._onboard_vnf_package(
File "/opt/stack/tacker/tacker/conductor/conductor_server.py", line 456, in _onboard_vnf_package
package_vnfd.create()
File "/usr/local/lib/python3.8/dist-packages/oslo_versionedobjects/base.py", line 226, in wrapper
return fn(self, *args, **kwargs)
File "/opt/stack/tacker/tacker/objects/vnf_package_vnfd.py", line 204, in create
db_vnf_package_vnfd = _vnf_package_vnfd_create(
File "/usr/local/lib/python3.8/dist-packages/oslo_db/sqlalchemy/enginefacade.py", line 1022, in wrapper
return fn(*args, **kwargs)
File "/opt/stack/tacker/tacker/objects/vnf_package_vnfd.py", line 39, in _vnf_package_vnfd_create
raise exceptions.VnfPackageVnfdIdDuplicate(
tacker.common.exceptions.VnfPackageVnfdIdDuplicate: Vnf package with vnfd id c922dbf4-ee96-4e4b-af0e-85d233504d48 already exists.
``` |
## Summary
In the current Tacker implementation, a VNFD ID is treated as globally unique across all projects.
As a result, it is not possible for multiple projects to onboard VNF packages that contain the same vnfdId,
even if those projects are logically separated tenants.
This behavior is inconsistent with the expected multi-tenant model, where each tenant should be able
to onboard and use the same VNF package independently.
## Current behavior
When there are two projects (for example, Project A and Project B),
and both try to onboard a VNF package that contains the same vnfdId:
- Project A can successfully onboard the VNF package.
- Project B tries to onboard a different VNF package that contains the same vnfdId.
- The onboarding for Project B fails with VnfPackageVnfdIdDuplicate, and the onboarding state
remains in CREATED instead of changing to ONBOARDED.
Project A:
```
$ openstack vnf p list
+--------------------------------------+------------------+------------------+-------------+-------------------+-------------------------------------------------------------------------------------------------+
| Id | Vnf Product Name | Onboarding State | Usage State | Operational State | Links |
+--------------------------------------+------------------+------------------+-------------+-------------------+-------------------------------------------------------------------------------------------------+
| a1cf34b0-ab73-4d36-8b32-0aac4f0c0c08 | Sample | ONBOARDED | NOT_IN_USE | ENABLED | { |
| | | | | | "self": { |
| | | | | | "href": "/vnfpkgm/v1/vnf_packages/a1cf34b0-ab73-4d36-8b32-0aac4f0c0c08" |
| | | | | | }, |
| | | | | | "packageContent": { |
| | | | | | "href": "/vnfpkgm/v1/vnf_packages/a1cf34b0-ab73-4d36-8b32-0aac4f0c0c08/package_content" |
| | | | | | } |
| | | | | | } |
+--------------------------------------+------------------+------------------+-------------+-------------------+-------------------------------------------------------------------------------------------------+
$ openstack vnf p show a1cf34b0-ab73-4d36-8b32-0aac4f0c0c08 -c 'VNFD ID'
+---------+--------------------------------------+
| Field | Value |
+---------+--------------------------------------+
| VNFD ID | c922dbf4-ee96-4e4b-af0e-85d233504d48 |
+---------+--------------------------------------+
```
Project B:
The status remains `CREATED` instead of changing to `ONBOARDED`.
```
$ openstack vnf p list
+--------------------------------------+------------------+------------------+-------------+-------------------+-------------------------------------------------------------------------------------------------+
| Id | Vnf Product Name | Onboarding State | Usage State | Operational State | Links |
+--------------------------------------+------------------+------------------+-------------+-------------------+-------------------------------------------------------------------------------------------------+
| 390b0bc9-90a3-4f3c-b510-c99f652f3679 | | CREATED | NOT_IN_USE | DISABLED | { |
| | | | | | "self": { |
| | | | | | "href": "/vnfpkgm/v1/vnf_packages/390b0bc9-90a3-4f3c-b510-c99f652f3679" |
| | | | | | }, |
| | | | | | "packageContent": { |
| | | | | | "href": "/vnfpkgm/v1/vnf_packages/390b0bc9-90a3-4f3c-b510-c99f652f3679/package_content" |
| | | | | | } |
| | | | | | } |
+--------------------------------------+------------------+------------------+-------------+-------------------+-------------------------------------------------------------------------------------------------+
```
Tacker error log
```
Traceback (most recent call last):
File "/usr/local/lib/python3.8/dist-packages/oslo_messaging/rpc/server.py", line 165, in _process_incoming
res = self.dispatcher.dispatch(message)
File "/usr/local/lib/python3.8/dist-packages/oslo_messaging/rpc/dispatcher.py", line 309, in dispatch
return self._do_dispatch(endpoint, method, ctxt, args)
File "/usr/local/lib/python3.8/dist-packages/oslo_messaging/rpc/dispatcher.py", line 229, in _do_dispatch
result = func(ctxt, **new_args)
File "/opt/stack/tacker/tacker/conductor/conductor_server.py", line 164, in decorated_function
vnf_package.save()
File "/usr/local/lib/python3.8/dist-packages/oslo_utils/excutils.py", line 227, in __exit__
self.force_reraise()
File "/usr/local/lib/python3.8/dist-packages/oslo_utils/excutils.py", line 200, in force_reraise
raise self.value
File "/opt/stack/tacker/tacker/conductor/conductor_server.py", line 127, in decorated_function
return function(self, context, *args, **kwargs)
File "/opt/stack/tacker/tacker/conductor/conductor_server.py", line 507, in load_csar_data
self._onboard_vnf_package(
File "/opt/stack/tacker/tacker/conductor/conductor_server.py", line 456, in _onboard_vnf_package
package_vnfd.create()
File "/usr/local/lib/python3.8/dist-packages/oslo_versionedobjects/base.py", line 226, in wrapper
return fn(self, *args, **kwargs)
File "/opt/stack/tacker/tacker/objects/vnf_package_vnfd.py", line 204, in create
db_vnf_package_vnfd = _vnf_package_vnfd_create(
File "/usr/local/lib/python3.8/dist-packages/oslo_db/sqlalchemy/enginefacade.py", line 1022, in wrapper
return fn(*args, **kwargs)
File "/opt/stack/tacker/tacker/objects/vnf_package_vnfd.py", line 39, in _vnf_package_vnfd_create
raise exceptions.VnfPackageVnfdIdDuplicate(
tacker.common.exceptions.VnfPackageVnfdIdDuplicate: Vnf package with vnfd id c922dbf4-ee96-4e4b-af0e-85d233504d48 already exists.
```
## Expected behavior
From a data-model perspective, tenant-scoped resources in Tacker should behave
consistently.
Resources such as:
- VNF Package (e.g. `vnf_packages` table),
- VNF Instance (e.g. `vnf_instances` table),
- VIMs (e.g. `vims` table) ...
all have a `tenant_id` column and are treated as **tenant-scoped**. Their
ownership and uniqueness are evaluated within the scope of a single
tenant/project.
By contrast, the VNFD metadata table (e.g. `vnf_package_vnfd`) does not have
a `tenant_id` column, and `vnfdId` is enforced as **globally unique** across
the whole deployment. This effectively makes VNFD a **global** resource.
In a real multi-tenant NFV deployment, however:
- The same VNFD (the same VNF product and VNFD content) may need to be used
by different projects/tenants.
- The choice of “which project owns this VNF package?” is an operational and
design decision, and should not be constrained by a globally unique `vnfdId`.
Therefore, VNFD should be aligned with other resources and become
**tenant-scoped** as well, by introducing `tenant_id` into the VNFD metadata
and scoping uniqueness per tenant.
VNFD metadata (vnf_package_vnfd) – expected
- id (PK)
- package_uuid (FK → vnf_packages.id)
- tenant_id (same value as the owning VNF package)
- vnfd_id
- ... other fields ...
- Uniqueness constraint:
UNIQUE (tenant_id, vnfd_id) |
|