Skip to content

Commit

Permalink
Add validation to ensure unique capabilities when needed and device name
Browse files Browse the repository at this point in the history
Added a validation method `validate_capability_value` to the `ComputeHostExtraCapability` model to
enforce uniqueness of `ExtraCapability`'s `capability_name` when its `is_unique=True`.
This validation ensures that only one capability is allowed for each resource when is_unique is set to True.
If a duplicate entry is found, a ValueError is raised with details about the non-unique capability and the affected compute host.

Set Uniqueness for `name` in `Device` model

Change-Id: I523a133abe15797cfb5b0b0edc830918dbe26f15
  • Loading branch information
AnishReddyRavula committed Mar 18, 2024
1 parent b6c92ac commit 14d8182
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 4 deletions.
1 change: 1 addition & 0 deletions blazar/db/sqlalchemy/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2045,6 +2045,7 @@ def resource_properties_list(resource_type):
models.ExtraCapability.capability_name,
models.ExtraCapability.private,
resource_model.capability_value,
models.ExtraCapability.is_unique,
).join(resource_model), resource_model, deleted=False).distinct()

return query.all()
Expand Down
25 changes: 23 additions & 2 deletions blazar/db/sqlalchemy/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from blazar.db.sqlalchemy import model_base as mb
import sqlalchemy as sa
from sqlalchemy.dialects.mysql import MEDIUMTEXT
from sqlalchemy.orm import relationship
from sqlalchemy.orm import relationship, validates


# Helpers
Expand Down Expand Up @@ -198,6 +198,8 @@ class ExtraCapability(mb.BlazarBase, mb.SoftDeleteMixinWithUuid):
capability_name = sa.Column(sa.String(255), nullable=False)
private = sa.Column(sa.Boolean, nullable=False,
server_default=sa.false())
is_unique = sa.Column(sa.Boolean, nullable=False,
server_default=sa.false())

__table_args__ = (sa.UniqueConstraint('resource_type', 'capability_name'),)

Expand Down Expand Up @@ -312,6 +314,25 @@ class ComputeHostExtraCapability(mb.BlazarBase, mb.SoftDeleteMixinWithUuid):
def to_dict(self):
return super(ComputeHostExtraCapability, self).to_dict()

@validates('capability_value')
def validate_capability_value(self, key, capability_value):
from blazar.db.sqlalchemy import facade_wrapper
session = facade_wrapper.get_session()
extra_capability = session.query(ExtraCapability).filter_by(id=self.capability_id).first()
if extra_capability and extra_capability.is_unique:
existing_capability = (
session.query(ComputeHostExtraCapability).filter_by(computehost_id=self.computehost_id,
capability_id=self.capability_id).first()
)
if existing_capability:
raise ValueError(
f"{extra_capability.capability_name} must be unique. "
f"Please select unique {extra_capability.capability_name} for "
f"{self.computehost_id}"
)
return capability_value



# Floating IP
class FloatingIPReservation(mb.BlazarBase, mb.SoftDeleteMixinWithUuid):
Expand Down Expand Up @@ -467,7 +488,7 @@ class Device(mb.BlazarBase, mb.SoftDeleteMixinWithUuid):
__tablename__ = 'devices'

id = _id_column()
name = sa.Column(sa.String(255), nullable=False)
name = sa.Column(sa.String(255), unique=True, nullable=False)
device_type = sa.Column(sa.Enum('container', 'vm', 'shell',
name='allowed_device_types'),
nullable=False)
Expand Down
5 changes: 3 additions & 2 deletions blazar/plugins/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,15 +106,16 @@ def list_resource_properties(self, query):
detail = False if not query else query.get('detail', False)
resource_properties = collections.defaultdict(list)

for name, private, value in db_api.resource_properties_list(
for name, private, value, is_unique in db_api.resource_properties_list(
self.resource_type):

if not private:
resource_properties[name].append(value)
resource_properties[name].append(is_unique)

if detail:
return [
dict(property=k, private=False, values=v)
dict(property=k, private=False, values=v[0], is_unique=v[1])
for k, v in resource_properties.items()]
else:
return [dict(property=k) for k, v in resource_properties.items()]
Expand Down

0 comments on commit 14d8182

Please sign in to comment.