Change-Id: I091ab913606298812db3bcc0645755909fb5293d
This commit is contained in:
xiaodongwang 2014-08-18 14:43:05 -07:00
parent 5d321de688
commit 90ae66a7b5
7 changed files with 174 additions and 84 deletions

View File

@ -51,20 +51,20 @@ def _check_subnet(subnet):
@utils.supported_filters(optional_support_keys=SUPPORTED_FIELDS)
@database.run_in_session()
@user_api.check_user_permission_in_session(
permission.PERMISSION_LIST_NETWORKS
permission.PERMISSION_LIST_SUBNETS
)
@utils.wrap_to_dict(RESP_FIELDS)
def list_subnets(session, lister, **filters):
"""List subnets."""
return utils.list_db_objects(
session, models.Network, **filters
session, models.Subnet, **filters
)
@utils.supported_filters([])
@database.run_in_session()
@user_api.check_user_permission_in_session(
permission.PERMISSION_LIST_NETWORKS
permission.PERMISSION_LIST_SUBNETS
)
@utils.wrap_to_dict(RESP_FIELDS)
def get_subnet(
@ -73,7 +73,8 @@ def get_subnet(
):
"""Get subnet info."""
return utils.get_db_object(
session, models.Network, exception_when_missing, id=subnet_id
session, models.Subnet,
exception_when_missing, id=subnet_id
)
@ -84,7 +85,7 @@ def get_subnet(
@utils.input_validates(subnet=_check_subnet)
@database.run_in_session()
@user_api.check_user_permission_in_session(
permission.PERMISSION_ADD_NETWORK
permission.PERMISSION_ADD_SUBNET
)
@utils.wrap_to_dict(RESP_FIELDS)
def add_subnet(
@ -93,7 +94,7 @@ def add_subnet(
):
"""Create a subnet."""
return utils.add_db_object(
session, models.Network,
session, models.Subnet,
exception_when_existing, subnet, **kwargs
)
@ -105,26 +106,26 @@ def add_subnet(
@utils.input_validates(subnet=_check_subnet)
@database.run_in_session()
@user_api.check_user_permission_in_session(
permission.PERMISSION_ADD_NETWORK
permission.PERMISSION_ADD_SUBNET
)
@utils.wrap_to_dict(RESP_FIELDS)
def update_subnet(session, updater, subnet_id, **kwargs):
"""Update a subnet."""
network = utils.get_db_object(
session, models.Network, id=subnet_id
subnet = utils.get_db_object(
session, models.Subnet, id=subnet_id
)
return utils.update_db_object(session, network, **kwargs)
return utils.update_db_object(session, subnet, **kwargs)
@utils.supported_filters([])
@database.run_in_session()
@user_api.check_user_permission_in_session(
permission.PERMISSION_DEL_NETWORK
permission.PERMISSION_DEL_SUBNET
)
@utils.wrap_to_dict(RESP_FIELDS)
def del_subnet(session, deleter, subnet_id, **kwargs):
"""Delete a subnet."""
network = utils.get_db_object(
session, models.Network, id=subnet_id
subnet = utils.get_db_object(
session, models.Subnet, id=subnet_id
)
return utils.del_db_object(session, network)
return utils.del_db_object(session, subnet)

View File

@ -89,14 +89,14 @@ PERMISSION_LIST_ADAPTERS = PermissionWrapper(
PERMISSION_LIST_METADATAS = PermissionWrapper(
'list_metadatas', 'list metadatas', 'list metadatas'
)
PERMISSION_LIST_NETWORKS = PermissionWrapper(
'list_networks', 'list networks', 'list networks'
PERMISSION_LIST_SUBNETS = PermissionWrapper(
'list_subnets', 'list subnets', 'list subnets'
)
PERMISSION_ADD_NETWORK = PermissionWrapper(
'add_network', 'add network', 'add network'
PERMISSION_ADD_SUBNET = PermissionWrapper(
'add_subnet', 'add subnet', 'add subnet'
)
PERMISSION_DEL_NETWORK = PermissionWrapper(
'del_network', 'del network', 'del network'
PERMISSION_DEL_SUBNET = PermissionWrapper(
'del_subnet', 'del subnet', 'del subnet'
)
PERMISSION_LIST_CLUSTERS = PermissionWrapper(
'list_clusters', 'list clusters', 'list clusters'
@ -224,9 +224,9 @@ PERMISSIONS = [
PERMISSION_DEL_MACHINE,
PERMISSION_LIST_ADAPTERS,
PERMISSION_LIST_METADATAS,
PERMISSION_LIST_NETWORKS,
PERMISSION_ADD_NETWORK,
PERMISSION_DEL_NETWORK,
PERMISSION_LIST_SUBNETS,
PERMISSION_ADD_SUBNET,
PERMISSION_DEL_SUBNET,
PERMISSION_LIST_CLUSTERS,
PERMISSION_ADD_CLUSTER,
PERMISSION_DEL_CLUSTER,

View File

@ -151,12 +151,43 @@ def model_filter(query, model, **filters):
return query
def replace_output(**output_mapping):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
return _replace_output(
func(*args, **kwargs), **output_mapping
)
return wrapper
return decorator
def _replace_output(data, **output_mapping):
"""Helper to replace output data."""
if isinstance(data, list):
return [
_replace_output(item, **output_mapping)
for item in data
]
info = {}
for key, value in data.items():
if key in output_mapping:
output_key = output_mapping[key]
if isinstance(output_key, basestring):
info[output_key] = value
else:
info[key] = (
_replace_output(value, **output_key)
)
else:
info[key] = value
return info
def wrap_to_dict(support_keys=[], **filters):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
logging.info('wrap to dict: args: %s', str(args))
logging.info('wrap to dict: kwargs: %s', kwargs)
return _wrapper_dict(
func(*args, **kwargs), support_keys, **filters
)
@ -181,12 +212,36 @@ def _wrapper_dict(data, support_keys, **filters):
for key in support_keys:
if key in data:
if key in filters:
info[key] = _wrapper_dict(data[key], filters[key])
filter_keys = filters[key]
if isinstance(filter_keys, dict):
info[key] = _wrapper_dict(
data[key], filter_keys.keys(),
**filter_keys
)
else:
info[key] = _wrapper_dict(
data[key], filter_keys
)
else:
info[key] = data[key]
return info
def replace_input_types(**kwarg_mapping):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
replaced_kwargs = {}
for key, value in kwargs.items():
if key in kwarg_mapping:
replaced_kwargs[key] = kwarg_mapping[key](value)
else:
replaced_kwargs[key] = value
return func(*args, **replaced_kwargs)
return wrapper
return decorator
def replace_filters(**filter_mapping):
def decorator(func):
@functools.wraps(func)

View File

@ -74,8 +74,34 @@ class HelperMixin(object):
def update(self):
pass
@staticmethod
def type_compatible(value, column_type):
if value is None:
return True
if not hasattr(column_type, 'python_type'):
return True
column_python_type = column_type.python_type
if isinstance(value, column_python_type):
return True
if issubclass(column_python_type, basestring):
return isinstance(value, basestring)
if column_python_type in [int, long]:
return type(value) in [int, long]
if column_python_type in [float]:
return type(value) in [float]
if column_python_type in [bool]:
return type(value) in [bool]
return False
def validate(self):
pass
for key, column in self.__mapper__.columns.items():
value = getattr(self, key)
if not self.type_compatible(value, column.type):
raise exception.InvalidParameter(
'column %s value %r type is unexpected: %s' % (
key, value, column.type
)
)
def to_dict(self):
keys = self.__mapper__.columns.keys()
@ -259,11 +285,11 @@ class InstallerMixin(HelperMixin):
settings = Column(JSONEncoded, default={})
def validate(self):
super(InstallerMixin, self).validate()
if not self.name:
raise exception.InvalidParameter(
'name is not set in installer %s' % self.name
)
super(InstallerMixin, self).validate()
class StateMixin(TimestampMixin, HelperMixin):
@ -335,11 +361,11 @@ class HostNetwork(BASE, TimestampMixin, HelperMixin):
@hybrid_property
def subnet(self):
return self.network.subnet
return self.subnet.subnet
@subnet.expression
def subnet(cls):
return cls.network.subnet
return cls.subnet.subnet
@property
def netmask(self):
@ -349,7 +375,8 @@ class HostNetwork(BASE, TimestampMixin, HelperMixin):
self.host.config_validated = False
def validate(self):
if not self.network:
super(HostNetwork, self).validate()
if not self.subnet:
raise exception.InvalidParameter(
'subnet is not set in %s interface %s' % (
self.host_id, self.interface
@ -369,7 +396,6 @@ class HostNetwork(BASE, TimestampMixin, HelperMixin):
str(ip), str(subnet)
)
)
super(HostNetwork, self).validate()
def to_dict(self):
dict_info = super(HostNetwork, self).to_dict()
@ -758,6 +784,7 @@ class Host(BASE, TimestampMixin, HelperMixin):
super(Host, self).update()
def validate(self):
super(Host, self).validate()
creator = self.creator
if not creator:
raise exception.InvalidParameter(
@ -777,7 +804,6 @@ class Host(BASE, TimestampMixin, HelperMixin):
raise exception.InvalidParameter(
'os %s is not deployable in host %s' % (os.name, self.id)
)
super(Host, self).validate()
@property
def os_installed(self):
@ -981,6 +1007,7 @@ class Cluster(BASE, TimestampMixin, HelperMixin):
super(Cluster, self).update()
def validate(self):
super(Cluster, self).validate()
creator = self.creator
if not creator:
raise exception.InvalidParameter(
@ -1024,13 +1051,22 @@ class Cluster(BASE, TimestampMixin, HelperMixin):
raise exception.InvalidParameter(
'flavor is not set in cluster %s' % self.id
)
if flavor.adapter_id != self.adapter_id:
flavor_adapter_id = flavor.adapter_id
adapter_id = self.adapter_id
logging.info(
'flavor adapter type %s value %s',
type(flavor_adapter_id), flavor_adapter_id
)
logging.info(
'adapter type %s value %s',
type(adapter_id), adapter_id
)
if flavor_adapter_id != adapter_id:
raise exception.InvalidParameter(
'flavor adapter id %s does not match adapter id %s' % (
flavor.adapter_id, self.adapter_id
flavor_adapter_id, adapter_id
)
)
super(Cluster, self).validate()
@property
def patched_os_config(self):
@ -1164,11 +1200,11 @@ class UserToken(BASE, HelperMixin):
super(UserToken, self).__init__(**kwargs)
def validate(self):
super(UserToken, self).validate()
if not self.user:
raise exception.InvalidParameter(
'user is not set in token: %s' % self.token
)
super(UserToken, self).validate()
class UserLog(BASE, HelperMixin):
@ -1188,11 +1224,11 @@ class UserLog(BASE, HelperMixin):
return self.user.email
def validate(self):
super(UserLog, self).validate()
if not self.user:
raise exception.InvalidParameter(
'user is not set in user log: %s' % self.id
)
super(UserLog, self).validate()
class User(BASE, HelperMixin, TimestampMixin):
@ -1238,11 +1274,11 @@ class User(BASE, HelperMixin, TimestampMixin):
super(User, self).__init__(**kwargs)
def validate(self):
super(User, self).validate()
if not self.crypted_password:
raise exception.InvalidParameter(
'password is not set in user : %s' % self.email
)
super(User, self).validate()
@property
def password(self):
@ -1301,6 +1337,7 @@ class SwitchMachine(BASE, HelperMixin, TimestampMixin):
super(SwitchMachine, self).__init__(**kwargs)
def validate(self):
super(SwitchMachine, self).validate()
if not self.switch:
raise exception.InvalidParameter(
'switch is not set in %s' % self.id
@ -1429,13 +1466,13 @@ class Machine(BASE, HelperMixin, TimestampMixin):
super(Machine, self).__init__(**kwargs)
def validate(self):
super(Machine, self).validate()
try:
netaddr.EUI(self.mac)
except Exception:
raise exception.InvalidParameter(
'mac address %s format uncorrect' % self.mac
)
super(Machine, self).validate()
@property
def patched_ipmi_credentials(self):
@ -1586,11 +1623,11 @@ class OSConfigMetadata(BASE, MetadataMixin):
super(OSConfigMetadata, self).__init__(**kwargs)
def validate(self):
super(OSConfigMetadata, self).validate()
if not self.os:
raise exception.InvalidParameter(
'os is not set in os metadata %s' % self.id
)
super(OSConfigMetadata, self).validate()
class OSConfigField(BASE, FieldMixin):
@ -1725,6 +1762,7 @@ class AdapterFlavorRole(BASE, HelperMixin):
super(AdapterFlavorRole, self).__init__()
def validate(self):
super(AdapterFlavorRole, self).validate()
flavor_adapter_id = self.flavor.adapter_id
role_adapter_id = self.role.adapter_id
if flavor_adapter_id != role_adapter_id:
@ -1782,11 +1820,11 @@ class AdapterFlavor(BASE, HelperMixin):
super(AdapterFlavor, self).initialize()
def validate(self):
super(AdapterFlavor, self).validate()
if not self.template:
raise exception.InvalidParameter(
'template is not set in adapter flavor %s' % self.id
)
super(AdapterFlavor, self).validate()
def to_dict(self):
dict_info = super(AdapterFlavor, self).to_dict()
@ -1881,11 +1919,11 @@ class PackageConfigMetadata(BASE, MetadataMixin):
super(PackageConfigMetadata, self).__init__(**kwargs)
def validate(self):
super(PackageConfigMetadata, self).validate()
if not self.adapter:
raise exception.InvalidParameter(
'adapter is not set in package metadata %s' % self.id
)
super(PackageConfigMetadata, self).validate()
class PackageConfigField(BASE, FieldMixin):
@ -2117,7 +2155,7 @@ class DistributedSystem(BASE, HelperMixin):
nullable=True
)
name = Column(String(80), unique=True)
deployable = Column(String(80), default=False)
deployable = Column(Boolean, default=False)
adapters = relationship(
Adapter,
@ -2184,7 +2222,7 @@ class Subnet(BASE, TimestampMixin, HelperMixin):
name = Column(String(80), unique=True)
subnet = Column(String(80), unique=True)
host_interfaces = relationship(
host_networks = relationship(
HostNetwork,
passive_deletes=True, passive_updates=True,
cascade='all, delete-orphan',

View File

@ -30,9 +30,9 @@ METADATA = {
'http_proxy': {
'_self': {
'field': 'general',
'default_value': 'http://$ipaddr:3128',
'default_value': 'http://127.0.0.1:3128',
'options': [
'http://$ipaddr:3128'
'http://127.0.0.1:3128'
],
'mapping_to': 'http_proxy'
}
@ -40,9 +40,9 @@ METADATA = {
'https_proxy': {
'_self': {
'field': 'general',
'default_value': 'http://$ipaddr:3128',
'default_value': 'http://127.0.0.1:3128',
'options': [
'http://$ipaddr:3128'
'http://127.0.0.1:3128'
],
'mapping_to': 'https_proxy'
}
@ -52,13 +52,11 @@ METADATA = {
'field': 'general_list',
'default_value': [
'127.0.0.1',
'$hostname',
'$ipaddr'
'compass'
],
'options': [
'127.0.0.1',
'$hostname',
'$ipaddr'
'compass'
],
'mapping_to': 'no_proxy'
}
@ -67,9 +65,9 @@ METADATA = {
'_self': {
'is_required': True,
'field': 'general',
'default_value': '$ipaddr',
'default_value': '127.0.0.1',
'options': [
'$ipaddr'
'127.0.0.1'
],
'mapping_to': 'ntp_server'
}
@ -79,10 +77,10 @@ METADATA = {
'is_required': True,
'field': 'general_list',
'default_value': [
'$ipaddr',
'127.0.0.1',
],
'options': [
'$ipaddr'
'127.0.0.1'
],
'mapping_to': 'nameservers'
}
@ -91,17 +89,17 @@ METADATA = {
'_self': {
'field': 'general',
'is_required' : True,
'default_value': ['$domain'][0],
'options': ['$domain'],
'default_value': 'ods.com',
'options': ['ods.com'],
}
},
'search_path': {
'_self': {
'field': 'general_list',
'default_value': [
'$domain'
'ods.com'
],
'options': ['$domain'],
'options': ['ods.com'],
'mapping_to': 'search_path'
}
},
@ -109,7 +107,7 @@ METADATA = {
'_self': {
'is_required': True,
'field': 'ip',
'default_value': '$gateway',
'default_value': '127.0.0.1',
'mapping_to': 'gateway'
}
}

View File

@ -30,9 +30,9 @@ METADATA = {
'http_proxy': {
'_self': {
'field': 'general',
'default_value': 'http://$ipaddr:3128',
'default_value': 'http://127.0.0.1:3128',
'options': [
'http://$ipaddr:3128'
'http://127.0.0.1:3128'
],
'mapping_to': 'http_proxy'
}
@ -40,9 +40,9 @@ METADATA = {
'https_proxy': {
'_self': {
'field': 'general',
'default_value': 'http://$ipaddr:3128',
'default_value': 'http://127.0.0.1:3128',
'options': [
'http://$ipaddr:3128'
'http://127.0.0.1:3128'
],
'mapping_to': 'https_proxy'
}
@ -52,13 +52,11 @@ METADATA = {
'field': 'general_list',
'default_value': [
'127.0.0.1',
'$hostname',
'$ipaddr'
'compass'
],
'options': [
'127.0.0.1',
'$hostname',
'$ipaddr'
'compass'
],
'mapping_to': 'no_proxy'
}
@ -67,9 +65,9 @@ METADATA = {
'_self': {
'is_required': True,
'field': 'general',
'default_value': '$ipaddr',
'default_value': '127.0.0.1',
'options': [
'$ipaddr'
'127.0.0.1'
],
'mapping_to': 'ntp_server'
}
@ -79,10 +77,10 @@ METADATA = {
'is_required': True,
'field': 'general_list',
'default_value': [
'$ipaddr',
'127.0.0.1',
],
'options': [
'$ipaddr'
'127.0.0.1'
],
'mapping_to': 'nameservers'
}
@ -91,17 +89,17 @@ METADATA = {
'_self': {
'field': 'general',
'is_required' : True,
'default_value': ['$domain'][0],
'options': ['$domain'],
'default_value': 'ods.com',
'options': ['ods.com'],
}
},
'search_path': {
'_self': {
'field': 'general_list',
'default_value': [
'$domain'
'ods.com'
],
'options': ['$domain'],
'options': ['ods.com'],
'mapping_to': 'search_path'
}
},
@ -109,7 +107,7 @@ METADATA = {
'_self': {
'is_required': True,
'field': 'ip',
'default_value': '$gateway',
'default_value': '127.0.0.1',
'mapping_to': 'gateway'
}
}

View File

@ -68,7 +68,7 @@ class TestGetMachine(BaseTest):
self.user_object,
1,
mac='28:6e:d4:46:c4:25',
port=1
port='1'
)
get_machine = machine.get_machine(
self.user_object,
@ -91,7 +91,7 @@ class TestListMachines(BaseTest):
self.user_object,
1,
mac='28:6e:d4:46:c4:25',
port=1
port='1'
)
list_machine = machine.list_machines(self.user_object)
self.assertIsNotNone(list_machine)
@ -111,7 +111,7 @@ class TestUpdateMachine(BaseTest):
self.user_object,
1,
mac='28:6e:d4:46:c4:25',
port=1
port='1'
)
machine.update_machine(
self.user_object,
@ -139,7 +139,7 @@ class TestPatchMachine(BaseTest):
self.user_object,
1,
mac='28:6e:d4:46:c4:25',
port=1
port='1'
)
machine.patch_machine(
self.user_object,
@ -167,7 +167,7 @@ class TestDelMachine(BaseTest):
self.user_object,
1,
mac='28:6e:d4:46:c4:25',
port=1
port='1'
)
machine.del_machine(
self.user_object,