Chi Lo 84c23a4781 Associate tenants as memeber list to shared image
Change-Id: I297c9a9ec77a64b07b3ad6a8c59121c7381bfd97
2020-09-24 17:05:04 +00:00

521 lines
17 KiB
Python
Executable File

"""Image model module."""
from orm.services.image_manager.ims.logic.error_base import ErrorStatus
from orm.services.image_manager.ims.persistency.sql_alchemy import db_models
from orm.services.image_manager.ims.persistency.wsme.base import Model
from orm.common.orm_common.utils.cross_api_utils import (get_regions_of_group,
set_utils_conf)
from pecan import conf
import wsme
class Metadata(Model):
"""region metadata model
"""
checksum = wsme.wsattr(wsme.types.text, mandatory=False)
size = wsme.wsattr(wsme.types.text, mandatory=False)
virtual_size = wsme.wsattr(wsme.types.text, mandatory=False)
def __init__(self, checksum='', size='', virtual_size=''):
"""region metadata model
:param checksum: image checksum
:param size: image size
:param virtual_size: image virtual size in lcp
"""
self.checksum = checksum
self.size = size
self.virtual_size = virtual_size
class MetadataWrapper(Model):
"""region metadata model
"""
metadata = wsme.wsattr(Metadata, mandatory=False)
def __init__(self, metadata=Metadata()):
"""region metadata model
:param metadata: metadata class
"""
self.metadata = metadata
class Region(Model):
name = wsme.wsattr(str, mandatory=True)
type = wsme.wsattr(str, default="single", mandatory=False)
# Output-only fields
status = wsme.wsattr(str, mandatory=False)
checksum = wsme.wsattr(wsme.types.text, mandatory=False)
size = wsme.wsattr(wsme.types.text, mandatory=False)
virtual_size = wsme.wsattr(wsme.types.text, mandatory=False)
error_message = wsme.wsattr(wsme.types.text, mandatory=False)
def __init__(self, name="", type="single", status="", checksum='',
size='', virtual_size=''):
"""region array
:param name: region names
:param type: region type single/group
:param status: region creation status
:param checksum: image checksum
:param size: image size
:param virtual_size: image virtual size in lcp
"""
self.name = name
self.type = type
self.status = status
self.checksum = checksum
self.size = size
self.virtual_size = virtual_size
def to_db_model(self):
region_rec = db_models.ImageRegion()
region_rec.region_name = self.name
region_rec.region_type = self.type
region_rec.checksum = self.checksum
region_rec.size = self.size
region_rec.virtual_size = self.virtual_size
return region_rec
def set_error_message(self, error_message):
self.error_message = error_message
class RegionWrapper(Model): # pragma: no cover
"""regions model
"""
regions = wsme.wsattr([Region], mandatory=False)
def __init__(self, regions=[]):
"""init
:param regions: array of regions
"""
self.regions = regions
class CustomerWrapper(Model): # pragma: no cover
"""customers model
"""
customers = wsme.wsattr(wsme.types.ArrayType(str), mandatory=False)
def __init__(self, customers=[]):
"""init
:param regions: array of regions
"""
self.customers = customers
class Image(Model):
"""Image entity with all its related data."""
default_min_ram = 1024
default_min_disk = 1
default_protected = False
name = wsme.wsattr(wsme.types.text, mandatory=True)
enabled = wsme.wsattr(bool, mandatory=False)
url = wsme.wsattr(wsme.types.text, mandatory=True)
visibility = wsme.wsattr(wsme.types.text, mandatory=True)
disk_format = wsme.wsattr(wsme.types.text, mandatory=True,
name='disk-format')
container_format = wsme.wsattr(wsme.types.text, mandatory=True,
name='container-format')
min_disk = wsme.wsattr(wsme.types.IntegerType(minimum=0), mandatory=False,
default=default_min_disk, name='min-disk')
min_ram = wsme.wsattr(wsme.types.IntegerType(minimum=0), mandatory=False,
default=default_min_ram, name='min-ram')
tags = wsme.wsattr(wsme.types.ArrayType(str), mandatory=False)
properties = wsme.wsattr(wsme.types.DictType(str, str), mandatory=False)
regions = wsme.wsattr(wsme.types.ArrayType(Region), mandatory=False)
customers = wsme.wsattr(wsme.types.ArrayType(str), mandatory=False)
owner = wsme.wsattr(wsme.types.text, mandatory=False)
schema = wsme.wsattr(wsme.types.text, mandatory=False)
protected = wsme.wsattr(bool, mandatory=False, default=default_protected)
id = wsme.wsattr(wsme.types.text, mandatory=False, name='id')
# Output-only fields
status = wsme.wsattr(wsme.types.text, mandatory=False)
created_at = wsme.wsattr(wsme.types.text,
mandatory=False, name='created-at')
updated_at = wsme.wsattr(wsme.types.text,
mandatory=False, name='updated-at')
locations = wsme.wsattr(wsme.types.ArrayType(str), mandatory=False)
self_link = wsme.wsattr(wsme.types.text, mandatory=False, name='self')
file = wsme.wsattr(wsme.types.text, mandatory=False)
links = wsme.wsattr(wsme.types.DictType(str, str), mandatory=False)
def __init__(self,
id='',
name='',
enabled=True,
url='',
visibility='',
disk_format='',
container_format='',
min_disk=default_min_disk,
min_ram=default_min_ram,
tags=[],
properties={},
regions=[],
customers=[],
status='',
created_at='',
updated_at='',
locations=[],
self_link='',
protected=default_protected,
file='',
owner='',
schema='',
links={}):
"""Create a new Image.
:param id: Image UUID
:param name: Image name
:param url: Image URL
:param visibility: Image visibility (public | private)
:param disk_format: Image file format
:param container_format: Image container format
:param min_disk: Minimum disk size required
:param min_ram: Minimum RAM required
:param tags: Image tags
:param properties: Image properties
:param regions: Regions to use the image
:param customers: Customers to use the image
:param owner: Image owner
:param schema: Image schema
:param protected: Is the image protected from deletion
"""
self.id = id
self.name = name
self.enabled = enabled
self.url = url
self.visibility = visibility
self.disk_format = disk_format
self.container_format = container_format
self.min_disk = min_disk
self.min_ram = min_ram
self.tags = tags
self.properties = properties
self.regions = regions
self.customers = customers
self.status = status
self.created_at = created_at
self.updated_at = updated_at
self.locations = locations
self.self_link = self_link
self.protected = protected
self.file = file
self.owner = owner
self.schema = schema
self.links = links
def validate_model(self, context=None):
if self.name.strip() == '':
raise ErrorStatus(400, 'Image name is required.')
if self.url.strip() == '':
raise ErrorStatus(400, 'Image location URL is required.')
# Validate visibility
if self.visibility not in ["private", "public", "community", "shared"]:
raise ErrorStatus(400,
'Image visibility can only be public, private,'
' community, or shared')
elif self.customers and self.visibility != "shared":
raise ErrorStatus(400,
'Customers can only be specified with shared'
' image!')
# Validate disk format
valid_disk_formats = ('ami', 'ari', 'aki', 'vhd', 'vmdk', 'raw',
'qcow2', 'vdi', 'iso',)
if self.disk_format not in valid_disk_formats:
raise ErrorStatus(400, 'Invalid disk format!')
# validate customer input unique
customer_input = set()
for customer in self.customers:
if customer in customer_input:
raise ErrorStatus(
400, "customer {} exist more than one".format(customer))
customer_input.add(customer)
# Validate container format
valid_container_formats = ('ami', 'ari', 'aki', 'bare', 'ovf', 'ova',
'docker')
if self.container_format not in valid_container_formats:
raise ErrorStatus(
400,
'Invalid container format! {}'.format(self.container_format))
if int(self.min_ram) not in list(range(0, self.min_ram + 1, 1024)):
raise ErrorStatus(
400, 'mininum RAM value must be a multiple of 1024')
if context == "update":
for region in self.regions:
if region.type == "group":
raise ErrorStatus(
400,
'region {} type is invalid for update, \'group\' can'
' be only in create'.format(region.name))
def to_db_model(self):
image = db_models.Image()
tags = []
properties = []
customers = []
regions = []
for tag in self.tags:
tag_rec = db_models.ImageTag()
tag_rec.tag = tag
tags.append(tag_rec)
for key, value in self.properties.items():
prop = db_models.ImageProperty()
prop.key_name = key
prop.key_value = value
properties.append(prop)
for region in self.regions:
regions.append(region.to_db_model())
for customer in self.customers:
customer_rec = db_models.ImageCustomer()
customer_rec.customer_id = customer
customers.append(customer_rec)
image.id = self.id
image.name = self.name
image.enabled = self.enabled
image.url = self.url
image.visibility = self.visibility
image.disk_format = self.disk_format
image.container_format = self.container_format
image.min_disk = self.min_disk
image.min_ram = self.min_ram
image.status = self.status
image.created_at = self.created_at
image.updated_at = self.updated_at
image.locations = self.locations
image.self_link = self.self_link
image.protected = self.protected
image.file = self.file
image.owner = self.owner
image.schema = self.schema
image.links = self.links
image.tags = tags
image.properties = properties
image.regions = regions
image.customers = customers
return image
@staticmethod
def from_db_model(sql_image):
image = Image()
image.id = sql_image.id
image.name = sql_image.name
image.enabled = sql_image.enabled == 1
image.url = sql_image.url
image.visibility = sql_image.visibility
image.disk_format = sql_image.disk_format
image.container_format = sql_image.container_format
image.min_disk = sql_image.min_disk
image.min_ram = sql_image.min_ram
image.protected = sql_image.protected == 1
image.owner = sql_image.owner
image.schema = sql_image.schema
image.created_at = str(sql_image.created_at)
image.updated_at = str(sql_image.updated_at)
for attribute in ('status', 'self_link', 'file'):
setattr(image, attribute, getattr(sql_image, attribute, ''))
for attribute in ('created_at', 'updated_at'):
setattr(image, attribute, str(getattr(sql_image, attribute, '')))
setattr(image, 'locations', getattr(sql_image, 'locations', []))
setattr(image, 'links', getattr(sql_image, 'links', {}))
image.customers = []
for customer in sql_image.customers:
image.customers.append(customer.customer_id)
image.regions = []
for sql_region in sql_image.regions:
region = Region()
region.name = sql_region.region_name
region.type = sql_region.region_type
region.checksum = sql_region.checksum
region.size = sql_region.size
region.virtual_size = sql_region.virtual_size
image.regions.append(region)
image.tags = []
for tag in sql_image.tags:
image.tags.append(tag.tag)
image.properties = {}
for prop in sql_image.properties:
image.properties[prop.key_name] = prop.key_value
return image
def handle_region_group(self):
regions_to_add = []
# get copy of it to be able to delete from the origin
for region in self.regions[:]:
if region.type == "group":
group_regions = self.get_regions_for_group(region.name)
if group_regions is None:
raise ErrorStatus(
404, "Group {} does not exist".format(region.name))
for group_region in group_regions:
regions_to_add.append(
Region(name=group_region, type='single'))
self.regions.remove(region)
# remove duplicates if exist
self.regions.extend(set(regions_to_add))
def get_regions_for_group(self, group_name):
set_utils_conf(conf)
regions = get_regions_of_group(group_name)
return regions
class ImageWrapper(Model):
"""image model
"""
image = wsme.wsattr(Image, mandatory=True, name='image')
def __init__(self, image=Image()):
"""init
:param image: image dict
"""
self.image = image
def to_db_model(self):
return self.image.to_db_model()
def validate_model(self, context=None):
return self.image.validate_model(context)
def validate_update(self, sql_image=None, new_image=None):
if sql_image and new_image:
if sql_image.name != new_image.name:
raise ErrorStatus(400, "Cannot change name of existing image")
if sql_image.container_format != new_image.container_format:
raise ErrorStatus(400, "Cannot change container format of "
"existing image")
if sql_image.disk_format != new_image.disk_format:
raise ErrorStatus(
400,
"Cannot change disk format of existing image")
if sql_image.min_ram != new_image.min_ram:
raise ErrorStatus(400,
"Cannot change min_ram of existing image")
if sql_image.min_disk != new_image.min_disk:
raise ErrorStatus(400,
"Cannot change min_disk of existing image")
if sql_image.url != new_image.url:
raise ErrorStatus(400, "Cannot change source data URL of "
"existing image")
def handle_region_group(self):
return self.image.handle_region_group()
def get_extra_spec_needed(self):
return self.image.get_extra_spec_needed()
@staticmethod
def from_db_model(sql_image):
image = ImageWrapper()
image.image = Image.from_db_model(sql_image)
return image
'''
' ImageSummary a DataObject contains all the fields defined in ImageSummary.
'''
class ImageSummary(Model):
name = wsme.wsattr(wsme.types.text)
id = wsme.wsattr(wsme.types.text)
visibility = wsme.wsattr(wsme.types.text)
status = wsme.wsattr(wsme.types.text, mandatory=True)
regions = wsme.wsattr([str], mandatory=True)
def __init__(self, name='', id='', visibility='', status='', regions=[]):
Model.__init__(self)
self.name = name
self.id = id
self.visibility = visibility
self.status = status
self.regions = regions
@staticmethod
def from_db_model(sql_image):
image = ImageSummary()
image.id = sql_image.id
image.name = sql_image.name
image.visibility = sql_image.visibility
image.regions = []
for sql_region in sql_image.regions:
region = Region()
region.name = sql_region.region_name
image.regions.append(region.name)
return image
@staticmethod
def from_wsme(wsme_image):
image = ImageSummary()
image.status = wsme_image.image.status
image.id = wsme_image.image.id
image.name = wsme_image.image.name
image.visibility = wsme_image.image.visibility
image.regions = []
for wsme_region in wsme_image.image.regions:
image.regions.append(wsme_region.name)
return image
class ImageSummaryResponse(Model):
images = wsme.wsattr([ImageSummary], mandatory=True)
def __init__(self): # pragma: no cover
Model.__init__(self)
self.images = []
class Enabled(Model):
enabled = wsme.wsattr(bool, mandatory=True)
def __init__(self, enabled=None): # pragma: no cover
Model.__init__(self)
self.enabled = enabled