
Ranger errors are split out unecessarily in the code base and need to be refactored for python 3.6 best practice Change-Id: I06b1e2679ff2f0d7cadf7eab4ab0a7cc61e138ca
521 lines
17 KiB
Python
Executable File
521 lines
17 KiB
Python
Executable File
"""Image model module."""
|
|
from orm.common.orm_common.utils.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
|