Add Kosmos Objects lib
Change-Id: I3a188e6e326f61695e549ba99c8ff82bcbe2e215
This commit is contained in:
parent
8cc34a7d45
commit
5f61bbd440
|
@ -28,7 +28,7 @@ pip-log.txt
|
|||
nosetests.xml
|
||||
.testrepository
|
||||
.venv
|
||||
|
||||
cover/*
|
||||
# Translations
|
||||
*.mo
|
||||
|
||||
|
@ -52,3 +52,9 @@ ChangeLog
|
|||
*~
|
||||
.*.swp
|
||||
.*sw?
|
||||
.idea
|
||||
*.ipynb
|
||||
.ipynb_checkpoints/*
|
||||
*.sublime-*
|
||||
# Flake8 Results
|
||||
flake8_results.html
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
# Copyright 2015 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
def register_all():
|
||||
__import__('kosmos.objects.pool_member_parameter')
|
||||
__import__('kosmos.objects.pool_member')
|
||||
__import__('kosmos.objects.pool')
|
||||
__import__('kosmos.objects.monitor_parameter')
|
||||
__import__('kosmos.objects.monitor')
|
||||
__import__('kosmos.objects.base')
|
||||
__import__('kosmos.objects.load_balancer')
|
|
@ -0,0 +1,63 @@
|
|||
# Copyright 2015 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from oslo_log import log as logging
|
||||
from oslo_versionedobjects import base as ovoo_base
|
||||
|
||||
from kosmos.objects import fields
|
||||
from kosmos import objects
|
||||
|
||||
LOG = logging.getLogger('kosmos')
|
||||
|
||||
|
||||
class VersionedObjectRegistry(ovoo_base.VersionedObjectRegistry):
|
||||
def registration_hook(self, cls, index):
|
||||
setattr(objects, cls.obj_name(), cls)
|
||||
|
||||
|
||||
class KosmosObject(ovoo_base.VersionedObject):
|
||||
"""Base class and object factory.
|
||||
This forms the base of all objects that can be remoted or instantiated
|
||||
via RPC. Simply defining a class that inherits from this base class
|
||||
will make it remotely instantiatable. Objects should implement the
|
||||
necessary "get" classmethod routines as well as "save" object methods
|
||||
as appropriate.
|
||||
"""
|
||||
|
||||
OBJ_PROJECT_NAMESPACE = 'kosmos'
|
||||
|
||||
DB_TABLE = ''
|
||||
|
||||
|
||||
class KosmosOwnedObject(object):
|
||||
"""Mixin class for objects owned by users.
|
||||
This adds the fields that we use in common for most object ownership.
|
||||
"""
|
||||
fields = {
|
||||
'project_id': fields.StringField(),
|
||||
'domain_id': fields.StringField(),
|
||||
}
|
||||
|
||||
|
||||
class KosmosPersistentObject(object):
|
||||
"""Mixin class for Persistent objects.
|
||||
This adds the fields that we use in common for most persistent objects.
|
||||
"""
|
||||
fields = {
|
||||
'id': fields.UUIDField(read_only=True),
|
||||
'version': fields.IntegerField(read_only=True),
|
||||
'created_at': fields.DateTimeField(nullable=True),
|
||||
'updated_at': fields.DateTimeField(nullable=True),
|
||||
'deleted_at': fields.DateTimeField(nullable=True)
|
||||
}
|
|
@ -0,0 +1,194 @@
|
|||
# Copyright 2015 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from kosmos._i18n import _
|
||||
import re
|
||||
import uuid as uuid_tools
|
||||
from oslo_versionedobjects import fields
|
||||
|
||||
|
||||
# Import field errors from oslo.versionedobjects
|
||||
KeyTypeError = fields.KeyTypeError
|
||||
ElementTypeError = fields.ElementTypeError
|
||||
|
||||
# Import fields from oslo.versionedobjects
|
||||
BooleanField = fields.BooleanField
|
||||
UnspecifiedDefault = fields.UnspecifiedDefault
|
||||
IntegerField = fields.IntegerField
|
||||
FloatField = fields.FloatField
|
||||
StringField = fields.StringField
|
||||
EnumField = fields.EnumField
|
||||
DateTimeField = fields.DateTimeField
|
||||
DictOfStringsField = fields.DictOfStringsField
|
||||
DictOfNullableStringsField = fields.DictOfNullableStringsField
|
||||
DictOfIntegersField = fields.DictOfIntegersField
|
||||
ListOfStringsField = fields.ListOfStringsField
|
||||
SetOfIntegersField = fields.SetOfIntegersField
|
||||
ListOfSetsOfIntegersField = fields.ListOfSetsOfIntegersField
|
||||
ListOfDictOfNullableStringsField = fields.ListOfDictOfNullableStringsField
|
||||
DictProxyField = fields.DictProxyField
|
||||
ObjectField = fields.ObjectField
|
||||
ListOfObjectsField = fields.ListOfObjectsField
|
||||
|
||||
# Ripped from designate/schema/format.py
|
||||
RE_ZONENAME = r'^(?!.{255,})(?:(?!\-)[A-Za-z0-9_\-]{1,63}(?<!\-)\.)+\Z'
|
||||
RE_HOSTNAME = r'^(?!.{255,})(?:(?:^\*|(?!\-)[A-Za-z0-9_\-]{1,63})(?<!\-)\.)+\Z'
|
||||
|
||||
|
||||
# TODO(graham): Remove this when https://review.openstack.org/#/c/250493
|
||||
# merges
|
||||
class UUID(fields.FieldType):
|
||||
|
||||
def coerce(self, obj, attr, value):
|
||||
|
||||
msg = _("%(value)s is not a valid UUID for %(attr)s") % {
|
||||
'attr': attr,
|
||||
'value': value
|
||||
}
|
||||
try:
|
||||
uuid_tools.UUID(value)
|
||||
except ValueError:
|
||||
raise ValueError(msg)
|
||||
|
||||
return str(value)
|
||||
|
||||
|
||||
class UUIDField(fields.AutoTypedField):
|
||||
AUTO_TYPE = UUID()
|
||||
|
||||
|
||||
class DNSZoneName(StringField):
|
||||
|
||||
def coerce(self, obj, attr, value):
|
||||
|
||||
if not re.match(RE_ZONENAME, value):
|
||||
msg = _("'%s' is not a valid DNS Zone name") % value
|
||||
raise ValueError(msg)
|
||||
|
||||
return super(DNSZoneName, self).coerce(obj, attr, value)
|
||||
|
||||
|
||||
class DNSFQDN(StringField):
|
||||
|
||||
def coerce(self, obj, attr, value):
|
||||
if not re.match(RE_HOSTNAME, value):
|
||||
msg = _("'%s' is not valid a valid DNS FQDN") % value
|
||||
raise ValueError(msg)
|
||||
|
||||
return super(DNSFQDN, self).coerce(obj, attr, value)
|
||||
|
||||
|
||||
class PreDefinedEnumType(EnumField):
|
||||
|
||||
_TYPES = ()
|
||||
_msg = _("%(value)s is not a valid choice, choose from %(options)r")
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super(PreDefinedEnumType, self).__init__(self._TYPES, **kwargs)
|
||||
|
||||
def coerce(self, obj, attr, value):
|
||||
try:
|
||||
return super(PreDefinedEnumType, self).coerce(obj, attr, value)
|
||||
except ValueError:
|
||||
msg = self._msg % {"value": value, "options": self._TYPES}
|
||||
raise ValueError(msg)
|
||||
|
||||
|
||||
class PoolMemberType(PreDefinedEnumType):
|
||||
|
||||
IP = 'IP'
|
||||
NEUTRON_LBAAS_V2 = 'NEUTRON_LBAAS_V2'
|
||||
NEUTRON_PORT = 'NEUTRON_PORT'
|
||||
|
||||
# TODO(graham): Dynamically Load this list of types from config + plugins
|
||||
_TYPES = (IP, NEUTRON_LBAAS_V2, NEUTRON_PORT)
|
||||
|
||||
|
||||
class MonitorType(PreDefinedEnumType):
|
||||
|
||||
TCP = 'TCP'
|
||||
UDP = 'UDP'
|
||||
ICMP = 'ICMP'
|
||||
HTTP = 'HTTP'
|
||||
HTTPS = 'HTTPS'
|
||||
SSH = 'SSH'
|
||||
|
||||
# TODO(graham): Dynamically Load this list of types from config + plugins
|
||||
_TYPES = (TCP, UDP, ICMP, HTTP, HTTPS, SSH)
|
||||
|
||||
_msg = _("%(value)s is not a valid Monitor Type, choose from %(options)r")
|
||||
|
||||
|
||||
class StateMachineEnforce(object):
|
||||
|
||||
# This is dict of states, that have dicts of states an object is
|
||||
# allowed to transition to
|
||||
|
||||
ALLOWED_TRANSITIONS = {}
|
||||
|
||||
def coerce(self, obj, attr, value):
|
||||
super(StateMachineEnforce, self).coerce(obj, attr, value)
|
||||
msg = _("%(object)s's are not allowed transition out of %(value)s "
|
||||
"state")
|
||||
# olso.versionedobjects do not create the field until it is first used
|
||||
try:
|
||||
current_value = getattr(obj, attr)
|
||||
except NotImplementedError:
|
||||
return value
|
||||
|
||||
if current_value in self.ALLOWED_TRANSITIONS:
|
||||
|
||||
if value in self.ALLOWED_TRANSITIONS[current_value]:
|
||||
return value
|
||||
else:
|
||||
msg = _(
|
||||
"%(object)s's are not allowed transition out of "
|
||||
"'%(current_value)s' state to '%(value)s' state, choose "
|
||||
"from %(options)r")
|
||||
msg = msg % {
|
||||
'object': obj.obj_name(),
|
||||
'current_value': current_value,
|
||||
'value': value,
|
||||
'options': [x for x in self.ALLOWED_TRANSITIONS[current_value]]
|
||||
}
|
||||
raise ValueError(msg)
|
||||
|
||||
|
||||
class KosmosActions(StateMachineEnforce, PreDefinedEnumType):
|
||||
|
||||
CREATE = 'create'
|
||||
UPDATE = 'update'
|
||||
DELETE = 'delete'
|
||||
NONE = 'none'
|
||||
|
||||
ALLOWED_TRANSITIONS = {
|
||||
CREATE: {
|
||||
NONE,
|
||||
UPDATE
|
||||
},
|
||||
UPDATE: {
|
||||
NONE
|
||||
},
|
||||
NONE: {
|
||||
UPDATE,
|
||||
DELETE
|
||||
},
|
||||
DELETE: {
|
||||
NONE
|
||||
}
|
||||
}
|
||||
|
||||
_TYPES = (CREATE, UPDATE, DELETE, NONE)
|
||||
|
||||
_msg = _("%(value)s is not a valid Action, choose from %(options)r")
|
|
@ -0,0 +1,68 @@
|
|||
# Copyright 2015 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from kosmos._i18n import _
|
||||
from kosmos.objects import base
|
||||
from kosmos.objects import fields
|
||||
|
||||
|
||||
class LoadBalancerStatus(fields.StateMachineEnforce,
|
||||
fields.PreDefinedEnumType):
|
||||
|
||||
ACTIVE = 'active'
|
||||
PENDING = 'pending'
|
||||
ERROR = 'error'
|
||||
DELETED = 'deleted'
|
||||
|
||||
ALLOWED_TRANSITIONS = {
|
||||
ACTIVE: {
|
||||
ERROR,
|
||||
PENDING,
|
||||
DELETED
|
||||
},
|
||||
PENDING: {
|
||||
ACTIVE,
|
||||
ERROR,
|
||||
DELETED
|
||||
},
|
||||
ERROR: {
|
||||
PENDING,
|
||||
ACTIVE,
|
||||
DELETED
|
||||
},
|
||||
DELETED: {}
|
||||
}
|
||||
|
||||
_TYPES = (ACTIVE, PENDING, ERROR, DELETED)
|
||||
|
||||
_msg = _("'%(value)s' is not a valid status, choose from %(options)r")
|
||||
|
||||
|
||||
@base.VersionedObjectRegistry.register
|
||||
class LoadBalancer(base.KosmosObject, base.KosmosOwnedObject,
|
||||
base.KosmosPersistentObject):
|
||||
|
||||
VERSION = '1.0'
|
||||
|
||||
fields = {
|
||||
'name': fields.StringField(),
|
||||
'description': fields.StringField(nullable=True),
|
||||
'fqdn': fields.DNSFQDN(),
|
||||
'zone_name': fields.DNSZoneName(),
|
||||
'flavor': fields.UUIDField(),
|
||||
'appliance_id': fields.StringField(),
|
||||
'pool': fields.ObjectField('Pool'),
|
||||
'status': LoadBalancerStatus(),
|
||||
'action': fields.KosmosActions(),
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
# Copyright 2015 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from kosmos._i18n import _
|
||||
from kosmos.objects import base
|
||||
from kosmos.objects import fields
|
||||
|
||||
|
||||
class MonitorStatus(fields.StateMachineEnforce, fields.PreDefinedEnumType):
|
||||
|
||||
ACTIVE = 'active'
|
||||
PENDING = 'pending'
|
||||
ERROR = 'error'
|
||||
DELETED = 'deleted'
|
||||
|
||||
ALLOWED_TRANSITIONS = {
|
||||
ACTIVE: {
|
||||
ERROR,
|
||||
PENDING,
|
||||
DELETED
|
||||
},
|
||||
PENDING: {
|
||||
ACTIVE,
|
||||
ERROR,
|
||||
DELETED
|
||||
},
|
||||
ERROR: {
|
||||
PENDING,
|
||||
ACTIVE,
|
||||
DELETED
|
||||
},
|
||||
DELETED: {}
|
||||
}
|
||||
|
||||
_TYPES = (ACTIVE, PENDING, ERROR, DELETED)
|
||||
|
||||
_msg = _("'%(value)s' is not a valid status, choose from %(options)r")
|
||||
|
||||
|
||||
@base.VersionedObjectRegistry.register
|
||||
class Monitor(base.KosmosObject, base.KosmosOwnedObject,
|
||||
base.KosmosPersistentObject):
|
||||
|
||||
VERSION = '1.0'
|
||||
|
||||
fields = {
|
||||
'name': fields.StringField(),
|
||||
'description': fields.StringField(nullable=True),
|
||||
'type': fields.MonitorType(),
|
||||
'target': fields.StringField(),
|
||||
'auth': fields.BooleanField(),
|
||||
'parameters': fields.ListOfObjectsField(
|
||||
'MonitorParameter', default=[]),
|
||||
'status': MonitorStatus(),
|
||||
'action': fields.KosmosActions(),
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
# Copyright 2015 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from kosmos.objects import base
|
||||
from kosmos.objects import fields
|
||||
|
||||
|
||||
@base.VersionedObjectRegistry.register
|
||||
class MonitorParameter(base.KosmosObject, base.KosmosOwnedObject,
|
||||
base.KosmosPersistentObject):
|
||||
|
||||
VERSION = '1.0'
|
||||
|
||||
fields = {
|
||||
'key': fields.StringField(nullable=False),
|
||||
'value': fields.StringField(nullable=True),
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
# Copyright 2015 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from kosmos._i18n import _
|
||||
from kosmos.objects import base
|
||||
from kosmos.objects import fields
|
||||
|
||||
|
||||
class PoolStatus(fields.StateMachineEnforce, fields.PreDefinedEnumType):
|
||||
|
||||
ACTIVE = 'active'
|
||||
PENDING = 'pending'
|
||||
DEGRADED = 'degraded'
|
||||
DOWN = 'down'
|
||||
ERROR = 'error'
|
||||
DELETED = 'deleted'
|
||||
|
||||
ALLOWED_TRANSITIONS = {
|
||||
ACTIVE: {
|
||||
DEGRADED,
|
||||
DOWN,
|
||||
ERROR,
|
||||
PENDING,
|
||||
DELETED
|
||||
},
|
||||
PENDING: {
|
||||
ACTIVE,
|
||||
ERROR,
|
||||
DELETED
|
||||
},
|
||||
DEGRADED: {
|
||||
ERROR,
|
||||
ACTIVE,
|
||||
DELETED
|
||||
},
|
||||
DOWN: {
|
||||
ACTIVE,
|
||||
ERROR,
|
||||
DELETED
|
||||
},
|
||||
ERROR: {
|
||||
PENDING,
|
||||
ACTIVE,
|
||||
DELETED
|
||||
},
|
||||
DELETED: {}
|
||||
}
|
||||
|
||||
_TYPES = (ACTIVE, PENDING, DEGRADED, DOWN, ERROR, DELETED)
|
||||
|
||||
_msg = _("'%(value)s' is not a valid status, choose from %(options)r")
|
||||
|
||||
|
||||
@base.VersionedObjectRegistry.register
|
||||
class Pool(base.KosmosObject, base.KosmosOwnedObject,
|
||||
base.KosmosPersistentObject):
|
||||
|
||||
VERSION = '1.0'
|
||||
|
||||
fields = {
|
||||
'name': fields.StringField(),
|
||||
'description': fields.StringField(nullable=True),
|
||||
'members': fields.ListOfObjectsField(
|
||||
'PoolMember',
|
||||
default=[]),
|
||||
'status': PoolStatus(),
|
||||
'action': fields.KosmosActions(),
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
# Copyright 2015 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from kosmos._i18n import _
|
||||
from kosmos.objects import base
|
||||
from kosmos.objects import fields
|
||||
|
||||
|
||||
class PoolMemberStatus(fields.StateMachineEnforce, fields.PreDefinedEnumType):
|
||||
|
||||
ACTIVE = 'active'
|
||||
PENDING = 'pending'
|
||||
DEGRADED = 'degraded'
|
||||
DOWN = 'down'
|
||||
ERROR = 'error'
|
||||
DELETED = 'deleted'
|
||||
|
||||
ALLOWED_TRANSITIONS = {
|
||||
ACTIVE: {
|
||||
DEGRADED,
|
||||
DOWN,
|
||||
ERROR,
|
||||
PENDING,
|
||||
DELETED
|
||||
},
|
||||
PENDING: {
|
||||
ACTIVE,
|
||||
ERROR,
|
||||
DELETED
|
||||
},
|
||||
DEGRADED: {
|
||||
ERROR,
|
||||
ACTIVE,
|
||||
DELETED
|
||||
},
|
||||
DOWN: {
|
||||
ACTIVE,
|
||||
ERROR,
|
||||
DELETED
|
||||
},
|
||||
ERROR: {
|
||||
PENDING,
|
||||
ACTIVE,
|
||||
DELETED
|
||||
},
|
||||
DELETED: {}
|
||||
}
|
||||
|
||||
_TYPES = (ACTIVE, PENDING, DEGRADED, DOWN, ERROR, DELETED)
|
||||
_msg = _("'%(value)s' is not a valid status, choose from %(options)r")
|
||||
|
||||
|
||||
@base.VersionedObjectRegistry.register
|
||||
class PoolMember(base.KosmosObject, base.KosmosOwnedObject,
|
||||
base.KosmosPersistentObject):
|
||||
|
||||
VERSION = '1.0'
|
||||
|
||||
fields = {
|
||||
'name': fields.StringField(),
|
||||
'description': fields.StringField(nullable=True),
|
||||
'type': fields.PoolMemberType(nullable=False),
|
||||
'parameters': fields.ListOfObjectsField(
|
||||
'PoolMemberParameter',
|
||||
default=[]),
|
||||
'status': PoolMemberStatus(),
|
||||
'action': fields.KosmosActions(),
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
# Copyright 2015 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from oslo_versionedobjects.base import VersionedObjectRegistry
|
||||
|
||||
from kosmos.objects import base
|
||||
from kosmos.objects import fields
|
||||
|
||||
|
||||
@VersionedObjectRegistry.register
|
||||
class PoolMemberParameter(base.KosmosObject, base.KosmosOwnedObject,
|
||||
base.KosmosPersistentObject):
|
||||
|
||||
VERSION = '1.0'
|
||||
|
||||
fields = {
|
||||
'key': fields.StringField(nullable=False),
|
||||
'value': fields.StringField(nullable=True),
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2010-2011 OpenStack Foundation
|
||||
# Copyright 2015-2016 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
from kosmos.tests.unit import base as test
|
||||
from kosmos import objects
|
||||
|
||||
|
||||
class TestCase(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
objects.register_all()
|
||||
super(TestCase, self).setUp()
|
||||
|
||||
"""Test case base class for all unit tests."""
|
||||
@staticmethod
|
||||
def compare_objects(test_case, obj_1, obj_2):
|
||||
for field, value in obj_1.items():
|
||||
test.assertEqual(getattr(obj_1, field), getattr(obj_2, field))
|
|
@ -0,0 +1,40 @@
|
|||
# Copyright 2015 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
from oslo_versionedobjects import fixture
|
||||
from kosmos.tests.unit.objects import base as test
|
||||
from kosmos.objects import base
|
||||
|
||||
|
||||
# NOTE: The hashes in this list should only be changed if they come with a
|
||||
# corresponding version bump in the affected objects.
|
||||
object_data = {
|
||||
'LoadBalancer': '1.0-06538794c851e034ece73694cc4737ad',
|
||||
'Monitor': '1.0-1e3dd244093ce14b4b8079ae4deea343',
|
||||
'MonitorParameter': '1.0-5fae2adca64543db6c854f6418de7089',
|
||||
'Pool': '1.0-fb284fb3826c2c984494a319f91d04b1',
|
||||
'PoolMember': '1.0-0586ac99722f74080988aa49113452de',
|
||||
'PoolMemberParameter': '1.0-5fae2adca64543db6c854f6418de7089'
|
||||
}
|
||||
|
||||
|
||||
class TestObjectVersions(test.TestCase):
|
||||
|
||||
def test_versions(self):
|
||||
checker = fixture.ObjectVersionChecker(
|
||||
base.VersionedObjectRegistry.obj_classes())
|
||||
expected, actual = checker.test_hashes(object_data)
|
||||
self.assertEqual(expected, actual,
|
||||
'Some objects have changed; please make sure the '
|
||||
'versions have been bumped, and then update their '
|
||||
'hashes in the object_data map in this test module.')
|
|
@ -0,0 +1,226 @@
|
|||
# Copyright 2015 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""
|
||||
test_kosmos
|
||||
----------------------------------
|
||||
|
||||
Tests for `objects` module.
|
||||
"""
|
||||
import uuid
|
||||
import testtools
|
||||
from oslo_versionedobjects import exception
|
||||
from kosmos.tests.unit.objects import base as test
|
||||
from kosmos import objects
|
||||
import kosmos.objects.fields as kosmos_fields
|
||||
|
||||
|
||||
class TestPreDefinedEnumType(kosmos_fields.PreDefinedEnumType):
|
||||
|
||||
_TYPES = (
|
||||
'Galactica',
|
||||
'Pegasus',
|
||||
'Athena',
|
||||
'Atlantia',
|
||||
'Columbia',
|
||||
'Erasmus',
|
||||
'Night Flight',
|
||||
'Solaria',
|
||||
'Triton',
|
||||
'Uned',
|
||||
'Universal',
|
||||
'Valkyrie',
|
||||
'Yashuman',
|
||||
)
|
||||
|
||||
|
||||
@objects.base.VersionedObjectRegistry.register_if(False)
|
||||
class TestObject(objects.base.KosmosObject):
|
||||
|
||||
fields = {
|
||||
'text': kosmos_fields.StringField(),
|
||||
'uuid': kosmos_fields.UUIDField(),
|
||||
'int': kosmos_fields.IntegerField(),
|
||||
'read_only': kosmos_fields.StringField(read_only=True),
|
||||
'dns_zone_name': kosmos_fields.DNSZoneName(),
|
||||
'dns_fqdn': kosmos_fields.DNSFQDN(),
|
||||
'pool_member_type': kosmos_fields.PoolMemberType(),
|
||||
'monitor_type': kosmos_fields.MonitorType(),
|
||||
'enum': TestPreDefinedEnumType()
|
||||
}
|
||||
|
||||
|
||||
@objects.base.VersionedObjectRegistry.register_if(False)
|
||||
class TestOwnedObject(objects.base.KosmosObject,
|
||||
objects.base.KosmosOwnedObject):
|
||||
|
||||
pass
|
||||
|
||||
|
||||
@objects.base.VersionedObjectRegistry.register_if(False)
|
||||
class TestPersistentObject(objects.base.KosmosObject,
|
||||
objects.base.KosmosPersistentObject):
|
||||
pass
|
||||
|
||||
|
||||
@objects.base.VersionedObjectRegistry.register_if(False)
|
||||
class TestPersistentOwnedObject(objects.base.KosmosObject,
|
||||
objects.base.KosmosPersistentObject,
|
||||
objects.base.KosmosOwnedObject):
|
||||
pass
|
||||
|
||||
|
||||
class TestKosmosObjectsBase(test.TestCase):
|
||||
|
||||
def test_basic(self):
|
||||
test_object = TestObject()
|
||||
|
||||
self.assertEqual(test_object.OBJ_PROJECT_NAMESPACE, 'kosmos')
|
||||
|
||||
def test_owned_mixin(self):
|
||||
test_object = TestOwnedObject()
|
||||
|
||||
set_fields = [x for x in test_object.fields.keys()]
|
||||
|
||||
required_fields = [
|
||||
'project_id',
|
||||
'domain_id'
|
||||
]
|
||||
|
||||
set_fields.sort()
|
||||
required_fields.sort()
|
||||
self.assertEqual(required_fields, set_fields)
|
||||
|
||||
def test_persistant_mixin(self):
|
||||
test_object = TestPersistentObject()
|
||||
|
||||
set_fields = [x for x in test_object.fields.keys()]
|
||||
|
||||
required_fields = [
|
||||
'id',
|
||||
'version',
|
||||
'created_at',
|
||||
'updated_at',
|
||||
'deleted_at'
|
||||
]
|
||||
|
||||
set_fields.sort()
|
||||
required_fields.sort()
|
||||
self.assertEqual(required_fields, set_fields)
|
||||
|
||||
def test_persistant_owned_mixin(self):
|
||||
test_object = TestPersistentOwnedObject()
|
||||
|
||||
set_fields = [x for x in test_object.fields.keys()]
|
||||
|
||||
required_fields = [
|
||||
'id',
|
||||
'version',
|
||||
'created_at',
|
||||
'updated_at',
|
||||
'deleted_at',
|
||||
'project_id',
|
||||
'domain_id'
|
||||
]
|
||||
|
||||
set_fields.sort()
|
||||
required_fields.sort()
|
||||
self.assertEqual(required_fields, set_fields)
|
||||
|
||||
def test_to_dict(self):
|
||||
test_object = TestPersistentOwnedObject()
|
||||
|
||||
test_object = TestObject()
|
||||
test_object.text = 'test_text'
|
||||
test_object.uuid = '77c1e75d-ba52-4ec9-a0a8-9d61bfb85407'
|
||||
test_object.int = 42
|
||||
test_object.dns_zone_name = 'dns.zone.tld.'
|
||||
test_object.dns_fqdn = '*.dns.zone.tld.'
|
||||
test_object.enum = 'Galactica'
|
||||
test_object.pool_member_type = 'IP'
|
||||
test_object.monitor_type = 'HTTP'
|
||||
|
||||
test_object.obj_reset_changes()
|
||||
|
||||
expected_output = {
|
||||
'versioned_object.name': 'TestObject',
|
||||
'versioned_object.namespace': 'kosmos',
|
||||
'versioned_object.data': {
|
||||
'int': 42,
|
||||
'dns_fqdn': '*.dns.zone.tld.',
|
||||
'dns_zone_name': 'dns.zone.tld.',
|
||||
'text': 'test_text',
|
||||
'uuid': '77c1e75d-ba52-4ec9-a0a8-9d61bfb85407',
|
||||
'monitor_type': 'HTTP',
|
||||
'enum': 'Galactica',
|
||||
'pool_member_type': 'IP'
|
||||
},
|
||||
'versioned_object.version': '1.0'
|
||||
}
|
||||
|
||||
self.assertDictEqual(test_object.obj_to_primitive(), expected_output)
|
||||
|
||||
|
||||
class TestKosmosObjectsFields(test.TestCase):
|
||||
|
||||
def test_basic(self):
|
||||
test_object = TestObject()
|
||||
test_object.text = 'test_text'
|
||||
test_object.uuid = str(uuid.uuid4())
|
||||
test_object.int = 42
|
||||
test_object.dns_zone_name = 'dns.zone.tld.'
|
||||
test_object.dns_fqdn = '*.dns.zone.tld.'
|
||||
|
||||
def test_invalid_data(self):
|
||||
test_object = TestObject()
|
||||
|
||||
with testtools.ExpectedException(ValueError):
|
||||
test_object.text = TestOwnedObject()
|
||||
with testtools.ExpectedException(ValueError):
|
||||
test_object.uuid = 'fake_uuid'
|
||||
with testtools.ExpectedException(ValueError):
|
||||
test_object.int = 'one'
|
||||
with testtools.ExpectedException(ValueError):
|
||||
test_object.dns_zone_name = 'dns.zone.tld'
|
||||
with testtools.ExpectedException(ValueError):
|
||||
test_object.dns_fqdn = 'name'
|
||||
|
||||
def test_read_only(self):
|
||||
test_object = TestObject()
|
||||
# Set initial value - 'read_only' is write once, then read only
|
||||
test_object.read_only = 'Initial Value'
|
||||
with testtools.ExpectedException(exception.ReadOnlyFieldError):
|
||||
test_object.read_only = 'Updated Value'
|
||||
self.assertEqual(test_object.read_only, 'Initial Value')
|
||||
|
||||
def test_enums_base(self):
|
||||
test_object = TestObject()
|
||||
test_object.enum = 'Galactica'
|
||||
test_object.enum = 'Athena'
|
||||
with testtools.ExpectedException(ValueError):
|
||||
test_object.enum = 'Enterprise'
|
||||
|
||||
def test_enums_pool_member(self):
|
||||
test_object = TestObject()
|
||||
test_object.pool_member_type = 'IP'
|
||||
test_object.pool_member_type = 'NEUTRON_PORT'
|
||||
with testtools.ExpectedException(ValueError):
|
||||
test_object.pool_member_type = 'AMAZON_ELB'
|
||||
|
||||
def test_enums_monitor_type(self):
|
||||
test_object = TestObject()
|
||||
test_object.monitor_type = 'TCP'
|
||||
test_object.monitor_type = 'HTTP'
|
||||
with testtools.ExpectedException(ValueError):
|
||||
test_object.monitor_type = 'XMPP'
|
|
@ -0,0 +1,94 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2015 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""
|
||||
test_kosmos
|
||||
----------------------------------
|
||||
|
||||
Tests for `kosmos_objects` `Pool` class.
|
||||
"""
|
||||
from kosmos.tests.unit.objects import base as test
|
||||
from kosmos import objects
|
||||
import kosmos.objects.fields as kosmos_fields
|
||||
|
||||
|
||||
class TestKosmosObjectsPool(test.TestCase):
|
||||
|
||||
def test_basic(self):
|
||||
test_object = objects.pool.Pool()
|
||||
|
||||
test_object = objects.pool.Pool()
|
||||
test_object.id = '568004ac-e41c-43bc-8a42-c284a7eaea25'
|
||||
test_object.name = "Pool Name"
|
||||
test_object.description = "Pool Description"
|
||||
test_object.members = [
|
||||
objects.base.KosmosObject.obj_class_from_name(
|
||||
'PoolMember', '1.0')()
|
||||
]
|
||||
test_object.members[0].id = 'b47d8499-de07-4344-a9e1-9773375a66e0'
|
||||
test_object.members[0].name = "Pool Member Name"
|
||||
test_object.members[0].description = "Pool Member Description"
|
||||
test_object.members[0].type = kosmos_fields.PoolMemberType.IP
|
||||
test_object.members[0].parameters = [
|
||||
objects.base.KosmosObject.obj_class_from_name(
|
||||
'PoolMemberParameter', '1.0'
|
||||
)()
|
||||
]
|
||||
test_object.members[0].parameters[0].key = 'address'
|
||||
test_object.members[0].parameters[0].value = '10.0.0.1'
|
||||
|
||||
test_object.obj_reset_changes()
|
||||
|
||||
self.assertEqual(test_object.OBJ_PROJECT_NAMESPACE, 'kosmos')
|
||||
|
||||
def test_from_dict(self):
|
||||
|
||||
test_input = {
|
||||
'versioned_object.namespace': 'kosmos',
|
||||
'versioned_object.data': {
|
||||
'id': '568004ac-e41c-43bc-8a42-c284a7eaea25',
|
||||
'name': 'Pool Name',
|
||||
'description': 'Pool Description',
|
||||
'members': [
|
||||
{
|
||||
'versioned_object.namespace': 'kosmos',
|
||||
'versioned_object.data': {
|
||||
'id': 'b47d8499-de07-4344-a9e1-9773375a66e0',
|
||||
'type': 'IP',
|
||||
'name': 'Pool Member Name',
|
||||
'description': 'Pool Member Description',
|
||||
'parameters': [
|
||||
{
|
||||
'versioned_object.namespace': 'kosmos',
|
||||
'versioned_object.data': {
|
||||
'key': 'address',
|
||||
'value': '10.0.0.1'
|
||||
},
|
||||
'versioned_object.version': '1.0',
|
||||
'versioned_object.name':
|
||||
'PoolMemberParameter',
|
||||
}
|
||||
]
|
||||
},
|
||||
'versioned_object.version': '1.0',
|
||||
'versioned_object.name': 'PoolMember',
|
||||
}
|
||||
]
|
||||
},
|
||||
'versioned_object.version': '1.0',
|
||||
'versioned_object.name': 'Pool',
|
||||
}
|
||||
|
||||
objects.base.KosmosObject.obj_from_primitive(test_input)
|
|
@ -0,0 +1,103 @@
|
|||
# Copyright 2015 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import testtools
|
||||
from kosmos.tests.unit.objects import base as test
|
||||
from kosmos import objects
|
||||
import kosmos.objects.fields as kosmos_fields
|
||||
|
||||
|
||||
class TestStateMachineField(kosmos_fields.StateMachineEnforce,
|
||||
kosmos_fields.PreDefinedEnumType):
|
||||
|
||||
ACTIVE = 'active'
|
||||
PENDING = 'pending'
|
||||
DEGRADED = 'degraded'
|
||||
DOWN = 'down'
|
||||
ERROR = 'error'
|
||||
|
||||
ALLOWED_TRANSITIONS = {
|
||||
# This is dict of states, that have dicts of states an object is
|
||||
# allowed to transition to
|
||||
ACTIVE: {
|
||||
DEGRADED,
|
||||
DOWN,
|
||||
ERROR,
|
||||
PENDING
|
||||
},
|
||||
PENDING: {
|
||||
ACTIVE,
|
||||
ERROR
|
||||
},
|
||||
DEGRADED: {
|
||||
ERROR,
|
||||
DOWN,
|
||||
ACTIVE
|
||||
},
|
||||
DOWN: {
|
||||
ACTIVE,
|
||||
ERROR
|
||||
},
|
||||
ERROR: {
|
||||
PENDING,
|
||||
ACTIVE
|
||||
}
|
||||
}
|
||||
|
||||
_TYPES = (
|
||||
ACTIVE,
|
||||
PENDING,
|
||||
DEGRADED,
|
||||
DOWN,
|
||||
ERROR
|
||||
)
|
||||
|
||||
|
||||
@objects.base.VersionedObjectRegistry.register_if(False)
|
||||
class StateMachineTestObject(objects.base.KosmosObject):
|
||||
|
||||
VERSION = '1.0'
|
||||
|
||||
fields = {
|
||||
'status': TestStateMachineField()
|
||||
}
|
||||
|
||||
|
||||
class TestKosmosObjectsFields(test.TestCase):
|
||||
|
||||
def test_non_existant_states(self):
|
||||
test_object = StateMachineTestObject()
|
||||
with testtools.ExpectedException(
|
||||
ValueError,
|
||||
msg="missing is not a valid choice, choose from ('active', "
|
||||
"'pending', 'degraded', 'down', 'error')"):
|
||||
test_object.status = 'missing'
|
||||
|
||||
def test_allow_transitions(self):
|
||||
test_object = StateMachineTestObject()
|
||||
test_object.status = TestStateMachineField.PENDING
|
||||
test_object.status = TestStateMachineField.ACTIVE
|
||||
test_object.status = TestStateMachineField.DOWN
|
||||
test_object.status = TestStateMachineField.ERROR
|
||||
test_object.status = 'pending'
|
||||
|
||||
def test_disallow_transitions(self):
|
||||
test_object = StateMachineTestObject()
|
||||
test_object.status = TestStateMachineField.PENDING
|
||||
with testtools.ExpectedException(
|
||||
ValueError,
|
||||
msg="StateMachineTestObject's are not allowed transition out "
|
||||
"of 'pending' state to 'down' state, choose from "
|
||||
"['error', 'active']"):
|
||||
test_object.status = TestStateMachineField.DOWN
|
|
@ -0,0 +1,91 @@
|
|||
# Copyright 2015 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
from __future__ import print_function
|
||||
|
||||
import re
|
||||
import sys
|
||||
import linecache
|
||||
|
||||
from prettytable import PrettyTable
|
||||
|
||||
PEP8_LINE = r'^((?P<file>.*):(?P<line>\d*):(?P<col>\d*):) ' \
|
||||
'(?P<error>(?P<error_code>\w\d{1,3})(?P<error_desc>.*$))'
|
||||
|
||||
HTML = True
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
raw_errors = []
|
||||
|
||||
max_filename_len = 0
|
||||
for line in sys.stdin:
|
||||
m = re.match(PEP8_LINE, line)
|
||||
if m:
|
||||
m = m.groupdict()
|
||||
raw_errors.append(m)
|
||||
if len(m['file']) > max_filename_len:
|
||||
max_filename_len = len(m['file'])
|
||||
else:
|
||||
print(line)
|
||||
|
||||
if len(raw_errors) > 0:
|
||||
|
||||
print('Flake8 Results')
|
||||
|
||||
ct = PrettyTable([
|
||||
"File",
|
||||
"Line",
|
||||
"Column",
|
||||
"Error Code",
|
||||
"Error Message",
|
||||
"Code"
|
||||
])
|
||||
|
||||
ct.align["File"] = "l"
|
||||
ct.align["Error Message"] = "l"
|
||||
ct.align["Code"] = "l"
|
||||
|
||||
for line in raw_errors:
|
||||
ct.add_row(format_dict(line))
|
||||
|
||||
print(ct)
|
||||
|
||||
with open('flake8_results.html', 'w') as f:
|
||||
f.write('<html><head><style type="text/css">table a:link{color:#666;font-weight:700;text-decoration:none}table a:visited{color:#999;font-weight:700;text-decoration:none}table a:active,table a:hover{color:#bd5a35;text-decoration:underline}table{font-family:Arial,Helvetica,sans-serif;color:#666;font-size:12px;text-shadow:1px 1px 0 #fff;background:#eaebec;margin:20px;border:1px solid #ccc;-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;-moz-box-shadow:0 1px 2px #d1d1d1;-webkit-box-shadow:0 1px 2px #d1d1d1;box-shadow:0 1px 2px #d1d1d1}table th{padding:21px 25px 22px;border-top:1px solid #fafafa;border-bottom:1px solid #e0e0e0;background:#ededed;background:-webkit-gradient(linear,left top,left bottom,from(#ededed),to(#ebebeb));background:-moz-linear-gradient(top,#ededed,#ebebeb)}table th:first-child{text-align:left;padding-left:20px}table tr:first-child th:first-child{-moz-border-radius-topleft:3px;-webkit-border-top-left-radius:3px;border-top-left-radius:3px}table tr:first-child th:last-child{-moz-border-radius-topright:3px;-webkit-border-top-right-radius:3px;border-top-right-radius:3px}table tr{text-align:left;padding-left:20px}table td:first-child{text-align:left;padding-left:20px;border-left:0}table td{padding:18px;border-top:1px solid #fff;border-bottom:1px solid #e0e0e0;border-left:1px solid #e0e0e0;background:#fafafa;background:-webkit-gradient(linear,left top,left bottom,from(#fbfbfb),to(#fafafa));background:-moz-linear-gradient(top,#fbfbfb,#fafafa)}table tr.even td{background:#f6f6f6;background:-webkit-gradient(linear,left top,left bottom,from(#f8f8f8),to(#f6f6f6));background:-moz-linear-gradient(top,#f8f8f8,#f6f6f6)}table tr:last-child td{border-bottom:0}table tr:last-child td:first-child{-moz-border-radius-bottomleft:3px;-webkit-border-bottom-left-radius:3px;border-bottom-left-radius:3px}table tr:last-child td:last-child{-moz-border-radius-bottomright:3px;-webkit-border-bottom-right-radius:3px;border-bottom-right-radius:3px}table tr:hover td{background:#f2f2f2;background:-webkit-gradient(linear,left top,left bottom,from(#f2f2f2),to(#f0f0f0));background:-moz-linear-gradient(top,#f2f2f2,#f0f0f0)}</style></head><body>%s</body</html>' % ct.get_html_string(attributes = {"cellspacing": 0})) # noqa
|
||||
|
||||
|
||||
def format_dict(raw):
|
||||
output = []
|
||||
if raw['file'].startswith('./'):
|
||||
output.append(raw['file'][2:])
|
||||
else:
|
||||
output.append(raw['file'])
|
||||
|
||||
output.append(raw['line'])
|
||||
output.append(raw['col'])
|
||||
output.append(raw['error_code'])
|
||||
|
||||
output.append(raw['error_desc'].lstrip())
|
||||
|
||||
code_string = linecache.getline(
|
||||
output[0],
|
||||
int(raw['line'])).lstrip().rstrip()
|
||||
|
||||
output.append(code_string)
|
||||
|
||||
return output
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -0,0 +1,6 @@
|
|||
#!/bin/sh
|
||||
|
||||
TESTARGS=$1
|
||||
|
||||
exec 3>&1
|
||||
status=$(exec 4>&1 >&3; ( flake8 ; echo $? >&4 ) | python tools/pretty_flake8.py) && exit $status
|
14
tox.ini
14
tox.ini
|
@ -10,9 +10,11 @@ setenv =
|
|||
VIRTUAL_ENV={envdir}
|
||||
deps = -r{toxinidir}/test-requirements.txt
|
||||
commands = python setup.py test --slowest --testr-args='{posargs}'
|
||||
whitelist_externals = sh
|
||||
|
||||
[testenv:pep8]
|
||||
commands = flake8
|
||||
commands = sh tools/pretty_flake8.sh
|
||||
|
||||
|
||||
[testenv:venv]
|
||||
commands = {posargs}
|
||||
|
@ -26,13 +28,13 @@ commands = python setup.py build_sphinx
|
|||
[testenv:debug]
|
||||
commands = oslo_debug_helper {posargs}
|
||||
|
||||
[hacking]
|
||||
import_exceptions = kosmos._i18n
|
||||
|
||||
[flake8]
|
||||
# E123, E125 skipped as they are invalid PEP-8.
|
||||
|
||||
show-source = True
|
||||
ignore = E123,E125
|
||||
ignore = E123,E125,H302,H306,H402,H404,H405,H904
|
||||
builtins = _
|
||||
exclude=.venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build
|
||||
|
||||
[hacking]
|
||||
import_exceptions = kosmos._i18n
|
||||
exclude=.venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build,tools
|
||||
|
|
Loading…
Reference in New Issue