Improvement to oslo.versionedobject support
This patch contains several improvements to oslo.versionedobject implementation: - Added VersionedObjectRegistry - Fixed usage of DictOfStringsField which is only limited to string values by introducing JsonField - Added 'isotime' function to be compatible with oslo.versionedobject - Fixed nullability of some fields - Fixed test cases where non-nullable fields are not assigned - Fixed backref problems when using cluster_policy object - Fixed datetime data type problems Change-Id: I306657b3c3e69c63e0a534baa22ce8a4db16858f
This commit is contained in:
parent
2a064c72af
commit
1def001fce
|
@ -51,9 +51,8 @@ class ServiceManageCommand(object):
|
|||
return
|
||||
|
||||
status = 'down'
|
||||
seconds_since_update = (timeutils.utcnow() -
|
||||
service.updated_at).total_seconds()
|
||||
if seconds_since_update <= 2 * CONF.periodic_interval:
|
||||
max_interval = 2 * CONF.periodic_interval
|
||||
if timeutils.is_older_than(service.updated_at, max_interval):
|
||||
status = 'up'
|
||||
|
||||
result = {
|
||||
|
|
|
@ -32,6 +32,7 @@ from senlin.common.i18n import _LI
|
|||
|
||||
cfg.CONF.import_opt('max_response_size', 'senlin.common.config')
|
||||
LOG = logging.getLogger(__name__)
|
||||
_ISO8601_TIME_FORMAT = '%Y-%m-%dT%H:%M:%S'
|
||||
|
||||
|
||||
class URLFetchError(exception.Error, IOError):
|
||||
|
@ -173,3 +174,17 @@ def format_time(value):
|
|||
value = value.replace(microsecond=0)
|
||||
value = value.isoformat()
|
||||
return value
|
||||
|
||||
|
||||
def isotime(at):
|
||||
"""Stringify time in ISO 8601 format.
|
||||
|
||||
oslo.versionedobject is using this function for datetime formatting.
|
||||
"""
|
||||
if at is None:
|
||||
return None
|
||||
|
||||
st = at.strftime(_ISO8601_TIME_FORMAT)
|
||||
tz = at.tzinfo.tzname(None) if at.tzinfo else 'UTC'
|
||||
st += ('Z' if tz == 'UTC' else tz)
|
||||
return st
|
||||
|
|
|
@ -1157,7 +1157,7 @@ def receiver_delete(context, receiver_id):
|
|||
def service_create(context, service_id, host=None, binary=None,
|
||||
topic=None):
|
||||
with session_for_write() as session:
|
||||
time_now = timeutils.utcnow()
|
||||
time_now = timeutils.utcnow(True)
|
||||
svc = models.Service(id=service_id, host=host, binary=binary,
|
||||
topic=topic, created_at=time_now,
|
||||
updated_at=time_now)
|
||||
|
@ -1174,7 +1174,7 @@ def service_update(context, service_id, values=None):
|
|||
if values is None:
|
||||
values = {}
|
||||
|
||||
values.update({'updated_at': timeutils.utcnow()})
|
||||
values.update({'updated_at': timeutils.utcnow(True)})
|
||||
service.update(values)
|
||||
service.save(session)
|
||||
return service
|
||||
|
|
|
@ -16,7 +16,7 @@ SQLAlchemy models for Senlin data.
|
|||
|
||||
from oslo_db.sqlalchemy import models
|
||||
from oslo_utils import uuidutils
|
||||
from sqlalchemy import Boolean, Column, DateTime, Float, ForeignKey, Integer
|
||||
from sqlalchemy import Boolean, Column, Float, ForeignKey, Integer
|
||||
from sqlalchemy import String, Text
|
||||
from sqlalchemy.ext import declarative
|
||||
from sqlalchemy.orm import backref
|
||||
|
@ -29,8 +29,8 @@ UUID4 = uuidutils.generate_uuid
|
|||
|
||||
|
||||
class TimestampMixin(object):
|
||||
created_at = Column(DateTime)
|
||||
updated_at = Column(DateTime)
|
||||
created_at = Column(types.TZAwareDateTime)
|
||||
updated_at = Column(types.TZAwareDateTime)
|
||||
|
||||
|
||||
class Profile(BASE, TimestampMixin, models.ModelBase):
|
||||
|
@ -80,7 +80,7 @@ class Cluster(BASE, TimestampMixin, models.ModelBase):
|
|||
domain = Column(String(32))
|
||||
parent = Column(String(36))
|
||||
|
||||
init_at = Column(DateTime)
|
||||
init_at = Column(types.TZAwareDateTime)
|
||||
|
||||
min_size = Column(Integer)
|
||||
max_size = Column(Integer)
|
||||
|
@ -111,7 +111,7 @@ class Node(BASE, TimestampMixin, models.ModelBase):
|
|||
index = Column(Integer)
|
||||
role = Column(String(64))
|
||||
|
||||
init_at = Column(DateTime)
|
||||
init_at = Column(types.TZAwareDateTime)
|
||||
|
||||
status = Column(String(255))
|
||||
status_reason = Column(Text)
|
||||
|
@ -151,7 +151,7 @@ class ClusterPolicies(BASE, models.ModelBase):
|
|||
enabled = Column(Boolean)
|
||||
priority = Column(Integer)
|
||||
data = Column(types.Dict)
|
||||
last_op = Column(DateTime)
|
||||
last_op = Column(types.TZAwareDateTime)
|
||||
|
||||
|
||||
class HealthRegistry(BASE, models.ModelBase):
|
||||
|
@ -244,7 +244,7 @@ class Event(BASE, models.ModelBase):
|
|||
__tablename__ = 'event'
|
||||
|
||||
id = Column('id', String(36), primary_key=True, default=lambda: UUID4())
|
||||
timestamp = Column(DateTime)
|
||||
timestamp = Column(types.TZAwareDateTime)
|
||||
oid = Column(String(36))
|
||||
oname = Column(String(255))
|
||||
otype = Column(String(36))
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
# under the License.
|
||||
|
||||
from oslo_serialization import jsonutils
|
||||
import pytz
|
||||
|
||||
from sqlalchemy.dialects import mysql
|
||||
from sqlalchemy.ext import mutable
|
||||
|
@ -108,5 +109,15 @@ class List(types.TypeDecorator):
|
|||
return jsonutils.loads(value)
|
||||
|
||||
|
||||
class TZAwareDateTime(types.TypeDecorator):
|
||||
"""A DB type that is time zone aware."""
|
||||
impl = types.DateTime
|
||||
|
||||
def process_result_value(self, value, dialect):
|
||||
if value is None:
|
||||
return None
|
||||
return value.replace(tzinfo=pytz.utc)
|
||||
|
||||
|
||||
mutable.MutableDict.associate_with(Dict)
|
||||
MutableList.associate_with(List)
|
||||
|
|
|
@ -21,6 +21,7 @@ from senlin.common import context as req_context
|
|||
from senlin.common import exception
|
||||
from senlin.common.i18n import _
|
||||
from senlin.common.i18n import _LE
|
||||
from senlin.common import utils
|
||||
from senlin.engine import cluster_policy as cp_mod
|
||||
from senlin.engine import event as EVENT
|
||||
from senlin.objects import action as ao
|
||||
|
@ -151,7 +152,7 @@ class Action(object):
|
|||
:return: The ID of the stored object.
|
||||
"""
|
||||
|
||||
timestamp = timeutils.utcnow()
|
||||
timestamp = timeutils.utcnow(True)
|
||||
|
||||
values = {
|
||||
'name': self.name,
|
||||
|
@ -492,8 +493,8 @@ class Action(object):
|
|||
'outputs': self.outputs,
|
||||
'depends_on': dep_on,
|
||||
'depended_by': dep_by,
|
||||
'created_at': self.created_at,
|
||||
'updated_at': self.updated_at,
|
||||
'created_at': utils.isotime(self.created_at),
|
||||
'updated_at': utils.isotime(self.updated_at),
|
||||
'data': self.data,
|
||||
}
|
||||
return action_dict
|
||||
|
|
|
@ -120,7 +120,7 @@ class ClusterAction(base.Action):
|
|||
nodes = []
|
||||
child = []
|
||||
for m in range(count):
|
||||
index = co.Cluster.next_index(self.context, self.cluster.id)
|
||||
index = co.Cluster.get_next_index(self.context, self.cluster.id)
|
||||
kwargs = {
|
||||
'index': index,
|
||||
'metadata': {},
|
||||
|
|
|
@ -135,7 +135,7 @@ class Cluster(object):
|
|||
'data': self.data,
|
||||
}
|
||||
|
||||
timestamp = timeutils.utcnow()
|
||||
timestamp = timeutils.utcnow(True)
|
||||
if self.id:
|
||||
values['updated_at'] = timestamp
|
||||
co.Cluster.update(context, self.id, values)
|
||||
|
@ -241,7 +241,7 @@ class Cluster(object):
|
|||
"""
|
||||
|
||||
values = {}
|
||||
now = timeutils.utcnow()
|
||||
now = timeutils.utcnow(True)
|
||||
if status == self.ACTIVE and self.status == self.CREATING:
|
||||
self.created_at = now
|
||||
values['created_at'] = now
|
||||
|
|
|
@ -108,7 +108,7 @@ class ClusterPolicy(object):
|
|||
return False
|
||||
|
||||
def record_last_op(self, context):
|
||||
self.last_op = timeutils.utcnow()
|
||||
self.last_op = timeutils.utcnow(True)
|
||||
self.store(context)
|
||||
|
||||
def to_dict(self):
|
||||
|
|
|
@ -82,6 +82,11 @@ class Event(object):
|
|||
self.cluster_id = entity.node.cluster_id
|
||||
self.oname = entity.node.name
|
||||
self.otype = 'NODE'
|
||||
else:
|
||||
self.oid = entity.target
|
||||
self.cluster_id = ''
|
||||
self.oname = ''
|
||||
self.otype = ''
|
||||
|
||||
def store(self, context):
|
||||
'''Store the event into database and return its ID.'''
|
||||
|
@ -108,7 +113,7 @@ class Event(object):
|
|||
|
||||
def critical(context, entity, action, status=None, status_reason=None,
|
||||
timestamp=None):
|
||||
timestamp = timestamp or timeutils.utcnow()
|
||||
timestamp = timestamp or timeutils.utcnow(True)
|
||||
event = Event(timestamp, logging.CRITICAL, entity,
|
||||
action=action, status=status, status_reason=status_reason,
|
||||
user=context.user, project=context.project)
|
||||
|
@ -122,7 +127,7 @@ def critical(context, entity, action, status=None, status_reason=None,
|
|||
|
||||
def error(context, entity, action, status=None, status_reason=None,
|
||||
timestamp=None):
|
||||
timestamp = timestamp or timeutils.utcnow()
|
||||
timestamp = timestamp or timeutils.utcnow(True)
|
||||
event = Event(timestamp, logging.ERROR, entity,
|
||||
action=action, status=status, status_reason=status_reason,
|
||||
user=context.user, project=context.project)
|
||||
|
@ -137,7 +142,7 @@ def error(context, entity, action, status=None, status_reason=None,
|
|||
|
||||
def warning(context, entity, action, status=None, status_reason=None,
|
||||
timestamp=None):
|
||||
timestamp = timestamp or timeutils.utcnow()
|
||||
timestamp = timestamp or timeutils.utcnow(True)
|
||||
event = Event(timestamp, logging.WARNING, entity,
|
||||
action=action, status=status, status_reason=status_reason,
|
||||
user=context.user, project=context.project)
|
||||
|
@ -152,7 +157,7 @@ def warning(context, entity, action, status=None, status_reason=None,
|
|||
|
||||
def info(context, entity, action, status=None, status_reason=None,
|
||||
timestamp=None):
|
||||
timestamp = timestamp or timeutils.utcnow()
|
||||
timestamp = timestamp or timeutils.utcnow(True)
|
||||
event = Event(timestamp, logging.INFO, entity,
|
||||
action=action, status=status, status_reason=status_reason,
|
||||
user=context.user, project=context.project)
|
||||
|
@ -167,7 +172,7 @@ def info(context, entity, action, status=None, status_reason=None,
|
|||
|
||||
def debug(context, entity, action, status=None, status_reason=None,
|
||||
timestamp=None):
|
||||
timestamp = timestamp or timeutils.utcnow()
|
||||
timestamp = timestamp or timeutils.utcnow(True)
|
||||
event = Event(timestamp, logging.DEBUG, entity,
|
||||
action=action, status=status, status_reason=status_reason,
|
||||
user=context.user, project=context.project)
|
||||
|
|
|
@ -124,7 +124,7 @@ class Node(object):
|
|||
if self.id:
|
||||
no.Node.update(context, self.id, values)
|
||||
else:
|
||||
init_at = timeutils.utcnow()
|
||||
init_at = timeutils.utcnow(True)
|
||||
self.init_at = init_at
|
||||
values['init_at'] = init_at
|
||||
node = no.Node.create(context, values)
|
||||
|
@ -212,7 +212,7 @@ class Node(object):
|
|||
'''Set status of the node.'''
|
||||
|
||||
values = {}
|
||||
now = timeutils.utcnow()
|
||||
now = timeutils.utcnow(True)
|
||||
if status == self.ACTIVE and self.status == self.CREATING:
|
||||
self.created_at = values['created_at'] = now
|
||||
elif status == self.ACTIVE and self.status == self.UPDATING:
|
||||
|
@ -329,7 +329,7 @@ class Node(object):
|
|||
return True
|
||||
res = profile_base.Profile.join_cluster(context, self, cluster_id)
|
||||
if res:
|
||||
timestamp = timeutils.utcnow()
|
||||
timestamp = timeutils.utcnow(True)
|
||||
db_node = no.Node.migrate(context, self.id, cluster_id, timestamp)
|
||||
self.cluster_id = cluster_id
|
||||
self.updated_at = timestamp
|
||||
|
@ -344,7 +344,7 @@ class Node(object):
|
|||
|
||||
res = profile_base.Profile.leave_cluster(context, self)
|
||||
if res:
|
||||
timestamp = timeutils.utcnow()
|
||||
timestamp = timeutils.utcnow(True)
|
||||
no.Node.migrate(context, self.id, None, timestamp)
|
||||
self.cluster_id = ''
|
||||
self.updated_at = timestamp
|
||||
|
|
|
@ -66,7 +66,7 @@ class Receiver(object):
|
|||
|
||||
:param context: Context for DB operations.
|
||||
"""
|
||||
self.created_at = timeutils.utcnow()
|
||||
self.created_at = timeutils.utcnow(True)
|
||||
values = {
|
||||
'id': self.id,
|
||||
'name': self.name,
|
||||
|
|
|
@ -46,7 +46,7 @@ def is_engine_dead(ctx, engine_id, period_time=None):
|
|||
eng = service_obj.Service.get(ctx, engine_id)
|
||||
if not eng:
|
||||
return True
|
||||
if (timeutils.utcnow() - eng.updated_at).total_seconds() > period_time:
|
||||
if timeutils.is_older_than(eng.updated_at, period_time):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
# under the License.
|
||||
|
||||
import copy
|
||||
import datetime
|
||||
import functools
|
||||
import uuid
|
||||
|
||||
|
@ -173,14 +172,13 @@ class EngineService(service.Service):
|
|||
|
||||
def service_manage_cleanup(self):
|
||||
ctx = senlin_context.get_admin_context()
|
||||
last_updated_window = (2 * cfg.CONF.periodic_interval)
|
||||
time_line = timeutils.utcnow() - datetime.timedelta(
|
||||
seconds=last_updated_window)
|
||||
time_window = (2 * cfg.CONF.periodic_interval)
|
||||
svcs = service_obj.Service.get_all(ctx)
|
||||
for svc in svcs:
|
||||
if svc['id'] == self.engine_id:
|
||||
continue
|
||||
if svc['updated_at'] < time_line:
|
||||
if timeutils.is_older_than(svc['updated_at'], time_window):
|
||||
# < time_line:
|
||||
# hasn't been updated, assuming it's died.
|
||||
LOG.info(_LI('Service %s was aborted'), svc['id'])
|
||||
service_obj.Service.delete(ctx, svc['id'])
|
||||
|
@ -1427,7 +1425,7 @@ class EngineService(service.Service):
|
|||
'operation aborted.')
|
||||
LOG.error(msg)
|
||||
raise exception.ProfileTypeNotMatch(message=msg)
|
||||
index = cluster_obj.Cluster.next_index(context, cluster_id)
|
||||
index = cluster_obj.Cluster.get_next_index(context, cluster_id)
|
||||
|
||||
# Create a node instance
|
||||
kwargs = {
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
# 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.
|
||||
|
||||
# When objects are registered, an attribute is set on this module
|
||||
# automatically, pointing to the latest version of the object.
|
||||
|
||||
|
||||
def register_all():
|
||||
# Objects should be imported here in order to be registered by services
|
||||
# that may need to receive it via RPC.
|
||||
__import__('senlin.objects.action')
|
||||
__import__('senlin.objects.cluster')
|
||||
__import__('senlin.objects.cluster_lock')
|
||||
__import__('senlin.objects.cluster_policy')
|
||||
__import__('senlin.objects.credential')
|
||||
__import__('senlin.objects.dependency')
|
||||
__import__('senlin.objects.event')
|
||||
__import__('senlin.objects.health_registry')
|
||||
__import__('senlin.objects.node')
|
||||
__import__('senlin.objects.node_lock')
|
||||
__import__('senlin.objects.policy')
|
||||
__import__('senlin.objects.profile')
|
||||
__import__('senlin.objects.receiver')
|
||||
__import__('senlin.objects.service')
|
|
@ -17,8 +17,10 @@ from oslo_versionedobjects import fields
|
|||
|
||||
from senlin.db import api as db_api
|
||||
from senlin.objects import base as senlin_base
|
||||
from senlin.objects import fields as senlin_fields
|
||||
|
||||
|
||||
@senlin_base.SenlinObjectRegistry.register
|
||||
class Action(senlin_base.SenlinObject, base.VersionedObjectDictCompat):
|
||||
"""Senlin action object."""
|
||||
|
||||
|
@ -27,7 +29,7 @@ class Action(senlin_base.SenlinObject, base.VersionedObjectDictCompat):
|
|||
'created_at': fields.DateTimeField(),
|
||||
'updated_at': fields.DateTimeField(nullable=True),
|
||||
'name': fields.StringField(),
|
||||
'context': fields.DictOfStringsField(),
|
||||
'context': senlin_fields.JsonField(),
|
||||
'target': fields.UUIDField(),
|
||||
'action': fields.StringField(),
|
||||
'cause': fields.StringField(),
|
||||
|
@ -37,14 +39,14 @@ class Action(senlin_base.SenlinObject, base.VersionedObjectDictCompat):
|
|||
'end_time': fields.FloatField(nullable=True),
|
||||
'timeout': fields.IntegerField(nullable=True),
|
||||
'status': fields.StringField(),
|
||||
'status_reason': fields.StringField(),
|
||||
'status_reason': fields.StringField(nullable=True),
|
||||
'control': fields.StringField(nullable=True),
|
||||
'inputs': fields.DictOfStringsField(nullable=True),
|
||||
'outputs': fields.DictOfStringsField(nullable=True),
|
||||
'data': fields.DictOfStringsField(nullable=True),
|
||||
'inputs': senlin_fields.JsonField(nullable=True),
|
||||
'outputs': senlin_fields.JsonField(nullable=True),
|
||||
'data': senlin_fields.JsonField(nullable=True),
|
||||
'user': fields.StringField(),
|
||||
'project': fields.StringField(),
|
||||
'domain': fields.StringField(),
|
||||
'domain': fields.StringField(nullable=True),
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
|
|
|
@ -12,8 +12,11 @@
|
|||
|
||||
"""Senlin common internal object model"""
|
||||
|
||||
from oslo_utils import versionutils
|
||||
from oslo_versionedobjects import base
|
||||
|
||||
from senlin import objects
|
||||
|
||||
|
||||
class SenlinObject(base.VersionedObject):
|
||||
"""Base class for senlin objects.
|
||||
|
@ -26,3 +29,22 @@ class SenlinObject(base.VersionedObject):
|
|||
|
||||
OBJ_PROJECT_NAMESPACE = 'senlin'
|
||||
VERSION = '1.0'
|
||||
|
||||
|
||||
class SenlinObjectRegistry(base.VersionedObjectRegistry):
|
||||
|
||||
def registration_hook(self, cls, index):
|
||||
"""Callback for object registration.
|
||||
|
||||
When an object is registered, this function will be called for
|
||||
maintaining senlin.objects.$OBJECT as the highest-versioned
|
||||
implementation of a given object.
|
||||
"""
|
||||
version = versionutils.convert_version_to_tuple(cls.VERSION)
|
||||
if not hasattr(objects, cls.obj_name()):
|
||||
setattr(objects, cls.obj_name(), cls)
|
||||
else:
|
||||
curr_version = versionutils.convert_version_to_tuple(
|
||||
getattr(objects, cls.obj_name()).VERSION)
|
||||
if version >= curr_version:
|
||||
setattr(objects, cls.obj_name(), cls)
|
||||
|
|
|
@ -17,8 +17,10 @@ from oslo_versionedobjects import fields
|
|||
|
||||
from senlin.db import api as db_api
|
||||
from senlin.objects import base as senlin_base
|
||||
from senlin.objects import fields as senlin_fields
|
||||
|
||||
|
||||
@senlin_base.SenlinObjectRegistry.register
|
||||
class Cluster(senlin_base.SenlinObject, base.VersionedObjectDictCompat):
|
||||
"""Senlin cluster object."""
|
||||
|
||||
|
@ -27,18 +29,18 @@ class Cluster(senlin_base.SenlinObject, base.VersionedObjectDictCompat):
|
|||
'name': fields.StringField(),
|
||||
'profile_id': fields.UUIDField(),
|
||||
'parent': fields.UUIDField(nullable=True),
|
||||
'init_at': fields.DateTimeField(nullable=True),
|
||||
'init_at': fields.DateTimeField(),
|
||||
'created_at': fields.DateTimeField(nullable=True),
|
||||
'updated_at': fields.DateTimeField(nullable=True),
|
||||
'min_size': fields.IntegerField(nullable=True),
|
||||
'max_size': fields.IntegerField(nullable=True),
|
||||
'desired_capacity': fields.IntegerField(nullable=True),
|
||||
'next_index': fields.IntegerField(),
|
||||
'timeout': fields.IntegerField(),
|
||||
'next_index': fields.IntegerField(nullable=True),
|
||||
'timeout': fields.IntegerField(nullable=True),
|
||||
'status': fields.StringField(),
|
||||
'status_reason': fields.StringField(),
|
||||
'metadata': fields.DictOfStringsField(),
|
||||
'data': fields.DictOfStringsField(),
|
||||
'status_reason': fields.StringField(nullable=True),
|
||||
'metadata': senlin_fields.JsonField(nullable=True),
|
||||
'data': senlin_fields.JsonField(nullable=True),
|
||||
'user': fields.StringField(),
|
||||
'project': fields.StringField(),
|
||||
'domain': fields.StringField(nullable=True),
|
||||
|
@ -86,7 +88,7 @@ class Cluster(senlin_base.SenlinObject, base.VersionedObjectDictCompat):
|
|||
return [cls._from_db_object(context, cls(), obj) for obj in objs]
|
||||
|
||||
@classmethod
|
||||
def next_index(cls, context, cluster_id):
|
||||
def get_next_index(cls, context, cluster_id):
|
||||
return db_api.cluster_next_index(context, cluster_id)
|
||||
|
||||
@classmethod
|
||||
|
|
|
@ -19,6 +19,7 @@ from senlin.db import api as db_api
|
|||
from senlin.objects import base as senlin_base
|
||||
|
||||
|
||||
@senlin_base.SenlinObjectRegistry.register
|
||||
class ClusterLock(senlin_base.SenlinObject, base.VersionedObjectDictCompat):
|
||||
"""Senlin cluster lock object."""
|
||||
|
||||
|
|
|
@ -17,8 +17,12 @@ from oslo_versionedobjects import fields
|
|||
|
||||
from senlin.db import api as db_api
|
||||
from senlin.objects import base as senlin_base
|
||||
from senlin.objects import cluster as cluster_obj
|
||||
from senlin.objects import fields as senlin_fields
|
||||
from senlin.objects import policy as policy_obj
|
||||
|
||||
|
||||
@senlin_base.SenlinObjectRegistry.register
|
||||
class ClusterPolicy(senlin_base.SenlinObject, base.VersionedObjectDictCompat):
|
||||
"""Senlin cluster-policy binding object."""
|
||||
|
||||
|
@ -26,12 +30,12 @@ class ClusterPolicy(senlin_base.SenlinObject, base.VersionedObjectDictCompat):
|
|||
'id': fields.UUIDField(),
|
||||
'cluster_id': fields.UUIDField(),
|
||||
'policy_id': fields.UUIDField(),
|
||||
'cluster': fields.ObjectField('Cluster'),
|
||||
'policy': fields.ObjectField('Policy'),
|
||||
'cluster': fields.ObjectField('Cluster', nullable=True),
|
||||
'policy': fields.ObjectField('Policy', nullable=True),
|
||||
'enabled': fields.BooleanField(),
|
||||
'priority': fields.IntegerField(),
|
||||
'data': fields.DictOfStringsField(),
|
||||
'last_op': fields.DateTimeField(),
|
||||
'data': senlin_fields.JsonField(nullable=True),
|
||||
'last_op': fields.DateTimeField(nullable=True),
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
|
@ -39,7 +43,14 @@ class ClusterPolicy(senlin_base.SenlinObject, base.VersionedObjectDictCompat):
|
|||
if db_obj is None:
|
||||
return None
|
||||
for field in binding.fields:
|
||||
binding[field] = db_obj[field]
|
||||
if field == 'cluster':
|
||||
c = cluster_obj.Cluster.get(context, db_obj['cluster_id'])
|
||||
binding['cluster'] = c
|
||||
elif field == 'policy':
|
||||
p = policy_obj.Policy.get(context, db_obj['policy_id'])
|
||||
binding['policy'] = p
|
||||
else:
|
||||
binding[field] = db_obj[field]
|
||||
|
||||
binding._context = context
|
||||
binding.obj_reset_changes()
|
||||
|
|
|
@ -17,16 +17,18 @@ from oslo_versionedobjects import fields
|
|||
|
||||
from senlin.db import api as db_api
|
||||
from senlin.objects import base as senlin_base
|
||||
from senlin.objects import fields as senlin_fields
|
||||
|
||||
|
||||
@senlin_base.SenlinObjectRegistry.register
|
||||
class Credential(senlin_base.SenlinObject, base.VersionedObjectDictCompat):
|
||||
"""Senlin credential object."""
|
||||
|
||||
fields = {
|
||||
'user': fields.StringField(),
|
||||
'project': fields.StringField(),
|
||||
'cred': fields.DictOfStringsField(),
|
||||
'data': fields.DictOfStringsField(),
|
||||
'cred': senlin_fields.JsonField(),
|
||||
'data': senlin_fields.JsonField(nullable=True),
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
|
|
|
@ -19,6 +19,7 @@ from senlin.db import api as db_api
|
|||
from senlin.objects import base as senlin_base
|
||||
|
||||
|
||||
@senlin_base.SenlinObjectRegistry.register
|
||||
class Dependency(senlin_base.SenlinObject, base.VersionedObjectDictCompat):
|
||||
"""Senlin action dependency object."""
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ from senlin.db import api as db_api
|
|||
from senlin.objects import base as senlin_base
|
||||
|
||||
|
||||
@senlin_base.SenlinObjectRegistry.register
|
||||
class Event(senlin_base.SenlinObject, base.VersionedObjectDictCompat):
|
||||
"""Senlin event object."""
|
||||
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
# 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_serialization import jsonutils
|
||||
from oslo_versionedobjects import fields
|
||||
import six
|
||||
|
||||
|
||||
class Json(fields.FieldType):
|
||||
def coerce(self, obj, attr, value):
|
||||
if isinstance(value, six.string_types):
|
||||
loaded = jsonutils.loads(value)
|
||||
return loaded
|
||||
return value
|
||||
|
||||
def from_primitive(self, obj, attr, value):
|
||||
return self.coerce(obj, attr, value)
|
||||
|
||||
def to_primitive(self, obj, attr, value):
|
||||
return jsonutils.dumps(value)
|
||||
|
||||
|
||||
class JsonField(fields.AutoTypedField):
|
||||
AUTO_TYPE = Json()
|
||||
|
||||
|
||||
class ListField(fields.AutoTypedField):
|
||||
AUTO_TYPE = fields.List(fields.FieldType())
|
||||
|
||||
|
||||
class NotificationPriority(fields.Enum):
|
||||
|
||||
ALL = (
|
||||
AUDIT, CRITICAL, DEBUG, INFO, ERROR, SAMPLE, WARN,
|
||||
) = (
|
||||
'audit', 'critical', 'debug', 'info', 'error', 'sample', 'warn',
|
||||
)
|
||||
|
||||
def __init__(self):
|
||||
super(NotificationPriority, self).__init__(
|
||||
valid_values=NotificationPriority.ALL)
|
||||
|
||||
|
||||
class NotificationPhase(fields.Enum):
|
||||
|
||||
ALL = (
|
||||
START, END, ERROR,
|
||||
) = (
|
||||
'start', 'end', 'error',
|
||||
)
|
||||
|
||||
def __init__(self):
|
||||
super(NotificationPhase, self).__init__(
|
||||
valid_values=NotificationPhase.ALL)
|
||||
|
||||
|
||||
class NotificationAction(fields.Enum):
|
||||
|
||||
ALL = (
|
||||
UPDATE,
|
||||
) = (
|
||||
'update',
|
||||
)
|
||||
|
||||
def __init__(self):
|
||||
super(NotificationAction, self).__init__(
|
||||
valid_values=NotificationAction.ALL)
|
||||
|
||||
|
||||
class NotificationPriorityField(fields.BaseEnumField):
|
||||
AUTO_TYPE = NotificationPriority()
|
||||
|
||||
|
||||
class NotificationPhaseField(fields.BaseEnumField):
|
||||
AUTO_TYPE = NotificationPhase()
|
||||
|
||||
|
||||
class NotificationActionField(fields.BaseEnumField):
|
||||
AUTO_TYPE = NotificationAction()
|
|
@ -19,6 +19,7 @@ from senlin.db import api as db_api
|
|||
from senlin.objects import base as senlin_base
|
||||
|
||||
|
||||
@senlin_base.SenlinObjectRegistry.register
|
||||
class HealthRegistry(senlin_base.SenlinObject, base.VersionedObjectDictCompat):
|
||||
"""Senlin health registry object."""
|
||||
|
||||
|
|
|
@ -17,8 +17,10 @@ from oslo_versionedobjects import fields
|
|||
|
||||
from senlin.db import api as db_api
|
||||
from senlin.objects import base as senlin_base
|
||||
from senlin.objects import fields as senlin_fields
|
||||
|
||||
|
||||
@senlin_base.SenlinObjectRegistry.register
|
||||
class Node(senlin_base.SenlinObject, base.VersionedObjectDictCompat):
|
||||
"""Senlin node object."""
|
||||
|
||||
|
@ -26,17 +28,18 @@ class Node(senlin_base.SenlinObject, base.VersionedObjectDictCompat):
|
|||
'id': fields.UUIDField(),
|
||||
'name': fields.StringField(),
|
||||
'profile_id': fields.UUIDField(),
|
||||
'cluster_id': fields.UUIDField(),
|
||||
'physical_id': fields.UUIDField(),
|
||||
# This field is treated as string because we may store '' into it
|
||||
'cluster_id': fields.StringField(),
|
||||
'physical_id': fields.UUIDField(nullable=True),
|
||||
'index': fields.IntegerField(),
|
||||
'role': fields.StringField(nullable=True),
|
||||
'init_at': fields.DateTimeField(nullable=True),
|
||||
'init_at': fields.DateTimeField(),
|
||||
'created_at': fields.DateTimeField(nullable=True),
|
||||
'updated_at': fields.DateTimeField(nullable=True),
|
||||
'status': fields.StringField(),
|
||||
'status_reason': fields.StringField(),
|
||||
'metadata': fields.DictOfStringsField(),
|
||||
'data': fields.DictOfStringsField(),
|
||||
'status_reason': fields.StringField(nullable=True),
|
||||
'metadata': senlin_fields.JsonField(nullable=True),
|
||||
'data': senlin_fields.JsonField(nullable=True),
|
||||
'user': fields.StringField(),
|
||||
'project': fields.StringField(),
|
||||
'domain': fields.StringField(nullable=True),
|
||||
|
|
|
@ -19,6 +19,7 @@ from senlin.db import api as db_api
|
|||
from senlin.objects import base as senlin_base
|
||||
|
||||
|
||||
@senlin_base.SenlinObjectRegistry.register
|
||||
class NodeLock(senlin_base.SenlinObject, base.VersionedObjectDictCompat):
|
||||
"""Senlin node lock object."""
|
||||
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
# 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 senlin.objects import base
|
||||
from senlin.objects import fields
|
||||
from senlin import rpc
|
||||
|
||||
|
||||
@base.SenlinObjectRegistry.register
|
||||
class EventType(base.SenlinObject):
|
||||
VERSION = '1.0'
|
||||
|
||||
fields = {
|
||||
'object': fields.StringField(nullable=False),
|
||||
'action': fields.NotificationActionField(nullable=False),
|
||||
'phase': fields.NotificationPhaseField(nullable=True),
|
||||
}
|
||||
|
||||
def to_notification_field(self):
|
||||
"""Serialize the object to the wire format."""
|
||||
s = '%s.%s' % (self.object, self.action)
|
||||
if self.obj_attr_is_set('phase'):
|
||||
s += '.%s' % self.phase
|
||||
return s
|
||||
|
||||
|
||||
class NotificationPayloadBase(base.NovaObject):
|
||||
"""Base class for the payload of versioned notifications."""
|
||||
# schema is a dict that defines how to populate the payload fields, where
|
||||
# each key-value pair has the following format:
|
||||
#
|
||||
# <payload_field>: (<data_source>, <data_source_field>)
|
||||
#
|
||||
# The <payload_field> is the name where the data will be stored in the
|
||||
# payload object, this field has to be defined as a field of the payload.
|
||||
# The <data_source> field shall refer to name of the parameter passed as
|
||||
# kwarg to the payload's populate_schema() call and this object will be
|
||||
# used as the source of the data.
|
||||
# The SCHEMA needs to be applied with the populate_schema() call before the
|
||||
# notification can be emitted.
|
||||
# The value of the payload.<payload_field> field will be set by the
|
||||
# <data_source>.<data_source_field> field. The <data_source> will not be
|
||||
# part of the payload object internal or external representation.
|
||||
# Payload fields that are not set by the SCHEMA can be filled in the same
|
||||
# way as in any versioned object.
|
||||
schema = {}
|
||||
VERSION = '1.0'
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(NotificationPayloadBase, self).__init__(*args, **kwargs)
|
||||
self.populated = not self.SCHEMA
|
||||
|
||||
def populate_schema(self, **kwargs):
|
||||
"""Populate the object based on the SCHEMA and the source objects
|
||||
|
||||
:param kwargs: A dict contains the source object at the key defined in
|
||||
the SCHEMA
|
||||
"""
|
||||
for key, (obj, field) in self.SCHEMA.items():
|
||||
source = kwargs[obj]
|
||||
if source.obj_attr_is_set(field):
|
||||
setattr(self, key, getattr(source, field))
|
||||
self.populated = True
|
||||
|
||||
|
||||
@base.SenlinObjectRegistry.register
|
||||
class NotificationPublisher(base.SenlinObject):
|
||||
VERSION = '1.0'
|
||||
|
||||
fields = {
|
||||
'host': fields.StringField(nullable=False),
|
||||
'binary': fields.StringField(nullable=False),
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_service_obj(cls, service):
|
||||
return cls(host=service.host, binary=service.binary)
|
||||
|
||||
|
||||
class NotificationBase(base.SenlinObject):
|
||||
"""Base class for versioned notifications.
|
||||
|
||||
Every subclass shall define a 'payload' field.
|
||||
"""
|
||||
VERSION = '1.0'
|
||||
|
||||
fields = {
|
||||
'priority': fields.NotificationPriorityField(),
|
||||
'event_type': fields.ObjectField('EventType'),
|
||||
'publisher': fields.ObjectField('NotificationPublisher'),
|
||||
}
|
||||
|
||||
def _emit(self, context, event_type, publisher_id, payload):
|
||||
notifier = rpc.get_versioned_notifier(publisher_id)
|
||||
notify = getattr(notifier, self.priority)
|
||||
notify(context, event_type=event_type, payload=payload)
|
||||
|
||||
def emit(self, context):
|
||||
"""Send the notification."""
|
||||
assert self.payload.populated
|
||||
|
||||
# Note(gibi): notification payload will be a newly populated object
|
||||
# therefore every field of it will look changed so this does not carry
|
||||
# any extra information so we drop this from the payload.
|
||||
self.payload.obj_reset_changes(recursive=False)
|
||||
|
||||
self._emit(context,
|
||||
event_type=self.event_type.to_notification_field(),
|
||||
publisher_id='%s:%s' %
|
||||
(self.publisher.binary,
|
||||
self.publisher.host),
|
||||
payload=self.payload.obj_to_primitive())
|
||||
|
||||
|
||||
def notification_sample(sample):
|
||||
"""Class decorator for documentation generation.
|
||||
|
||||
This decorator is used to attach the notification sample information
|
||||
to the notification object for documentation generation purposes.
|
||||
|
||||
:param sample: the path of the sample json file relative to the
|
||||
doc/notification_samples/ directory in the nova repository
|
||||
root.
|
||||
"""
|
||||
def wrap(cls):
|
||||
cls.sample = sample
|
||||
return cls
|
||||
return wrap
|
|
@ -17,8 +17,10 @@ from oslo_versionedobjects import fields
|
|||
|
||||
from senlin.db import api as db_api
|
||||
from senlin.objects import base as senlin_base
|
||||
from senlin.objects import fields as senlin_fields
|
||||
|
||||
|
||||
@senlin_base.SenlinObjectRegistry.register
|
||||
class Policy(senlin_base.SenlinObject, base.VersionedObjectDictCompat):
|
||||
"""Senlin policy object."""
|
||||
|
||||
|
@ -26,12 +28,12 @@ class Policy(senlin_base.SenlinObject, base.VersionedObjectDictCompat):
|
|||
'id': fields.UUIDField(),
|
||||
'name': fields.StringField(),
|
||||
'type': fields.StringField(),
|
||||
'spec': fields.DictOfStringsField(),
|
||||
'spec': senlin_fields.JsonField(),
|
||||
'cooldown': fields.IntegerField(nullable=True),
|
||||
'level': fields.IntegerField(nullable=True),
|
||||
'data': fields.DictOfStringsField(),
|
||||
'data': fields.DictOfStringsField(nullable=True),
|
||||
'created_at': fields.DateTimeField(),
|
||||
'updated_at': fields.DateTimeField(),
|
||||
'updated_at': fields.DateTimeField(nullable=True),
|
||||
'user': fields.StringField(),
|
||||
'project': fields.StringField(),
|
||||
'domain': fields.StringField(nullable=True),
|
||||
|
|
|
@ -17,8 +17,10 @@ from oslo_versionedobjects import fields
|
|||
|
||||
from senlin.db import api as db_api
|
||||
from senlin.objects import base as senlin_base
|
||||
from senlin.objects import fields as senlin_fields
|
||||
|
||||
|
||||
@senlin_base.SenlinObjectRegistry.register
|
||||
class Profile(senlin_base.SenlinObject, base.VersionedObjectDictCompat):
|
||||
"""Senlin profile object."""
|
||||
|
||||
|
@ -26,15 +28,15 @@ class Profile(senlin_base.SenlinObject, base.VersionedObjectDictCompat):
|
|||
'id': fields.UUIDField(),
|
||||
'name': fields.StringField(),
|
||||
'type': fields.StringField(),
|
||||
'context': fields.DictOfStringsField(),
|
||||
'spec': fields.DictOfStringsField(),
|
||||
'context': senlin_fields.JsonField(),
|
||||
'spec': senlin_fields.JsonField(),
|
||||
'created_at': fields.DateTimeField(),
|
||||
'updated_at': fields.DateTimeField(),
|
||||
'updated_at': fields.DateTimeField(nullable=True),
|
||||
'user': fields.StringField(),
|
||||
'project': fields.StringField(),
|
||||
'domain': fields.StringField(nullable=True),
|
||||
'permission': fields.StringField(nullable=True),
|
||||
'metadata': fields.DictOfStringsField(),
|
||||
'metadata': fields.DictOfStringsField(nullable=True),
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
|
|
|
@ -17,8 +17,10 @@ from oslo_versionedobjects import fields
|
|||
|
||||
from senlin.db import api as db_api
|
||||
from senlin.objects import base as senlin_base
|
||||
from senlin.objects import fields as senlin_fields
|
||||
|
||||
|
||||
@senlin_base.SenlinObjectRegistry.register
|
||||
class Receiver(senlin_base.SenlinObject, base.VersionedObjectDictCompat):
|
||||
"""Senlin receiver object."""
|
||||
|
||||
|
@ -27,15 +29,15 @@ class Receiver(senlin_base.SenlinObject, base.VersionedObjectDictCompat):
|
|||
'name': fields.StringField(),
|
||||
'type': fields.StringField(),
|
||||
'cluster_id': fields.UUIDField(),
|
||||
'actor': fields.DictOfStringsField(nullable=True),
|
||||
'actor': senlin_fields.JsonField(nullable=True),
|
||||
'action': fields.StringField(),
|
||||
'params': fields.DictOfStringsField(nullable=True),
|
||||
'channel': fields.DictOfStringsField(nullable=True),
|
||||
'params': senlin_fields.JsonField(nullable=True),
|
||||
'channel': senlin_fields.JsonField(nullable=True),
|
||||
'created_at': fields.DateTimeField(nullable=True),
|
||||
'updated_at': fields.DateTimeField(nullable=True),
|
||||
'user': fields.StringField(),
|
||||
'project': fields.StringField(),
|
||||
'domain': fields.StringField(),
|
||||
'domain': fields.StringField(nullable=True),
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
|
|
|
@ -19,6 +19,7 @@ from senlin.db import api as db_api
|
|||
from senlin.objects import base as senlin_base
|
||||
|
||||
|
||||
@senlin_base.SenlinObjectRegistry.register
|
||||
class Service(senlin_base.SenlinObject, base.VersionedObjectDictCompat):
|
||||
"""Senlin service object."""
|
||||
|
||||
|
@ -28,7 +29,7 @@ class Service(senlin_base.SenlinObject, base.VersionedObjectDictCompat):
|
|||
'binary': fields.StringField(),
|
||||
'topic': fields.StringField(),
|
||||
'disabled': fields.BooleanField(),
|
||||
'disabled_reason': fields.StringField(),
|
||||
'disabled_reason': fields.StringField(nullable=True),
|
||||
'created_at': fields.DateTimeField(),
|
||||
'updated_at': fields.DateTimeField(),
|
||||
}
|
||||
|
|
|
@ -167,7 +167,7 @@ class Policy(object):
|
|||
|
||||
def store(self, context):
|
||||
'''Store the policy object into database table.'''
|
||||
timestamp = timeutils.utcnow()
|
||||
timestamp = timeutils.utcnow(True)
|
||||
|
||||
values = {
|
||||
'name': self.name,
|
||||
|
@ -270,8 +270,8 @@ class Policy(object):
|
|||
'project': self.project,
|
||||
'domain': self.domain,
|
||||
'spec': self.spec,
|
||||
'created_at': utils.format_time(self.created_at),
|
||||
'updated_at': utils.format_time(self.updated_at),
|
||||
'created_at': utils.isotime(self.created_at),
|
||||
'updated_at': utils.isotime(self.updated_at),
|
||||
'data': self.data,
|
||||
}
|
||||
return pb_dict
|
||||
|
|
|
@ -160,7 +160,7 @@ class Profile(object):
|
|||
|
||||
def store(self, ctx):
|
||||
'''Store the profile into database and return its ID.'''
|
||||
timestamp = timeutils.utcnow()
|
||||
timestamp = timeutils.utcnow(True)
|
||||
|
||||
values = {
|
||||
'name': self.name,
|
||||
|
|
|
@ -25,7 +25,7 @@ class NovaClient(base.DriverBase):
|
|||
"disk": 1,
|
||||
"OS-FLV-EXT-DATA:ephemeral": 0,
|
||||
"os-flavor-access:is_public": True,
|
||||
"id": "1",
|
||||
"id": "66a81d68-bf48-4af5-897b-a3bfef7279a8",
|
||||
"links": [],
|
||||
"name": "m1.tiny",
|
||||
"ram": 512,
|
||||
|
|
|
@ -71,7 +71,7 @@ def create_cluster(ctx, profile, **kwargs):
|
|||
'next_index': 1,
|
||||
'timeout': 60,
|
||||
'desired_capacity': 0,
|
||||
'init_at': tu.utcnow(),
|
||||
'init_at': tu.utcnow(True),
|
||||
'status': 'INIT',
|
||||
'status_reason': 'Just Initialized',
|
||||
'meta_data': {},
|
||||
|
@ -168,7 +168,7 @@ def create_policy(ctx, **kwargs):
|
|||
|
||||
def create_event(ctx, **kwargs):
|
||||
values = {
|
||||
'timestamp': tu.utcnow(),
|
||||
'timestamp': tu.utcnow(True),
|
||||
'obj_id': 'FAKE_ID',
|
||||
'obj_name': 'FAKE_NAME',
|
||||
'obj_type': 'CLUSTER',
|
||||
|
|
|
@ -249,7 +249,7 @@ class DBAPIClusterTest(base.SenlinTestCase):
|
|||
|
||||
def test_cluster_get_all_default_sort_dir(self):
|
||||
clusters = [shared.create_cluster(self.ctx, self.profile,
|
||||
init_at=tu.utcnow())
|
||||
init_at=tu.utcnow(True))
|
||||
for x in range(3)]
|
||||
|
||||
st_db = db_api.cluster_get_all(self.ctx)
|
||||
|
@ -260,7 +260,7 @@ class DBAPIClusterTest(base.SenlinTestCase):
|
|||
|
||||
def test_cluster_get_all_str_sort_keys(self):
|
||||
clusters = [shared.create_cluster(self.ctx, self.profile,
|
||||
created_at=tu.utcnow())
|
||||
created_at=tu.utcnow(True))
|
||||
for x in range(3)]
|
||||
|
||||
st_db = db_api.cluster_get_all(self.ctx, sort='created_at')
|
||||
|
@ -282,7 +282,7 @@ class DBAPIClusterTest(base.SenlinTestCase):
|
|||
|
||||
def test_cluster_get_all_marker(self):
|
||||
clusters = [shared.create_cluster(self.ctx, self.profile,
|
||||
created_at=tu.utcnow())
|
||||
created_at=tu.utcnow(True))
|
||||
for x in range(3)]
|
||||
cl_db = db_api.cluster_get_all(self.ctx, marker=clusters[1].id)
|
||||
self.assertEqual(1, len(cl_db))
|
||||
|
|
|
@ -132,7 +132,7 @@ class DBAPIClusterPolicyTest(base.SenlinTestCase):
|
|||
self.assertEqual(1, len(bindings))
|
||||
self.assertIsNone(bindings[0].last_op)
|
||||
|
||||
timestamp = tu.utcnow()
|
||||
timestamp = tu.utcnow(True)
|
||||
fields = {'last_op': timestamp}
|
||||
db_api.cluster_policy_update(self.ctx, self.cluster.id, policy.id,
|
||||
fields)
|
||||
|
|
|
@ -74,7 +74,9 @@ class DBAPIEventTest(base.SenlinTestCase):
|
|||
self.assertIsNotNone(ret_event)
|
||||
tst_timestamp = tu.parse_strtime('2014-12-19 11:51:54.670244',
|
||||
'%Y-%m-%d %H:%M:%S.%f')
|
||||
self.assertEqual(tst_timestamp, ret_event.timestamp)
|
||||
|
||||
self.assertEqual(tu.isotime(tst_timestamp),
|
||||
tu.isotime(ret_event.timestamp))
|
||||
self.assertEqual('20', ret_event.level)
|
||||
self.assertEqual('', ret_event.oid)
|
||||
self.assertEqual('', ret_event.otype)
|
||||
|
@ -193,13 +195,13 @@ class DBAPIEventTest(base.SenlinTestCase):
|
|||
cluster1 = shared.create_cluster(self.ctx, self.profile)
|
||||
|
||||
event1 = self.create_event(self.ctx, entity=cluster1,
|
||||
timestamp=tu.utcnow(),
|
||||
timestamp=tu.utcnow(True),
|
||||
action='action2')
|
||||
event2 = self.create_event(self.ctx, entity=cluster1,
|
||||
timestamp=tu.utcnow(),
|
||||
timestamp=tu.utcnow(True),
|
||||
action='action3')
|
||||
event3 = self.create_event(self.ctx, entity=cluster1,
|
||||
timestamp=tu.utcnow(),
|
||||
timestamp=tu.utcnow(True),
|
||||
action='action1')
|
||||
|
||||
events = db_api.event_get_all(self.ctx, sort='timestamp')
|
||||
|
|
|
@ -178,7 +178,7 @@ class DBAPINodeTest(base.SenlinTestCase):
|
|||
node_ids = ['node1', 'node2', 'node3']
|
||||
for v in node_ids:
|
||||
shared.create_node(self.ctx, self.cluster, self.profile,
|
||||
id=v, init_at=tu.utcnow())
|
||||
id=v, init_at=tu.utcnow(True))
|
||||
|
||||
nodes = db_api.node_get_all(self.ctx, limit=1)
|
||||
self.assertEqual(1, len(nodes))
|
||||
|
@ -247,7 +247,7 @@ class DBAPINodeTest(base.SenlinTestCase):
|
|||
|
||||
def test_node_get_all_default_sorting(self):
|
||||
nodes = [shared.create_node(self.ctx, None, self.profile,
|
||||
init_at=tu.utcnow())
|
||||
init_at=tu.utcnow(True))
|
||||
for x in range(3)]
|
||||
|
||||
results = db_api.node_get_all(self.ctx)
|
||||
|
@ -442,7 +442,7 @@ class DBAPINodeTest(base.SenlinTestCase):
|
|||
|
||||
def test_node_migrate_from_none(self):
|
||||
node_orphan = shared.create_node(self.ctx, None, self.profile)
|
||||
timestamp = tu.utcnow()
|
||||
timestamp = tu.utcnow(True)
|
||||
|
||||
node = db_api.node_migrate(self.ctx, node_orphan.id, self.cluster.id,
|
||||
timestamp, 'NEW-ROLE')
|
||||
|
@ -456,7 +456,7 @@ class DBAPINodeTest(base.SenlinTestCase):
|
|||
|
||||
def test_node_migrate_to_none(self):
|
||||
node = shared.create_node(self.ctx, self.cluster, self.profile)
|
||||
timestamp = tu.utcnow()
|
||||
timestamp = tu.utcnow(True)
|
||||
|
||||
node_new = db_api.node_migrate(self.ctx, node.id, None, timestamp)
|
||||
self.assertEqual(timestamp, node_new.updated_at)
|
||||
|
@ -479,7 +479,7 @@ class DBAPINodeTest(base.SenlinTestCase):
|
|||
self.assertEqual(2, cluster1.next_index)
|
||||
self.assertEqual(1, cluster2.next_index)
|
||||
|
||||
timestamp = tu.utcnow()
|
||||
timestamp = tu.utcnow(True)
|
||||
|
||||
node_new = db_api.node_migrate(self.ctx, node.id, cluster2.id,
|
||||
timestamp)
|
||||
|
@ -496,7 +496,7 @@ class DBAPINodeTest(base.SenlinTestCase):
|
|||
self.assertEqual(2, cluster2.next_index)
|
||||
|
||||
# Migrate it back!
|
||||
timestamp = tu.utcnow()
|
||||
timestamp = tu.utcnow(True)
|
||||
|
||||
node_new = db_api.node_migrate(self.ctx, node.id, cluster1.id,
|
||||
timestamp, 'FAKE-ROLE')
|
||||
|
|
|
@ -232,7 +232,7 @@ class DBAPIPolicyTest(base.SenlinTestCase):
|
|||
def test_policy_get_all_with_limit_marker(self):
|
||||
ids = ['policy1', 'policy2', 'policy3']
|
||||
for pid in ids:
|
||||
timestamp = tu.utcnow()
|
||||
timestamp = tu.utcnow(True)
|
||||
data = self.new_policy_data(id=pid, created_at=timestamp)
|
||||
db_api.policy_create(self.ctx, data)
|
||||
|
||||
|
@ -282,7 +282,7 @@ class DBAPIPolicyTest(base.SenlinTestCase):
|
|||
{'id': '003', 'name': 'policy2'}]
|
||||
|
||||
for v in values:
|
||||
v['created_at'] = tu.utcnow()
|
||||
v['created_at'] = tu.utcnow(True)
|
||||
data = self.new_policy_data(**v)
|
||||
db_api.policy_create(self.ctx, data)
|
||||
|
||||
|
@ -310,7 +310,7 @@ class DBAPIPolicyTest(base.SenlinTestCase):
|
|||
def test_policy_get_all_default_sorting(self):
|
||||
policies = []
|
||||
for x in range(3):
|
||||
data = self.new_policy_data(created_at=tu.utcnow())
|
||||
data = self.new_policy_data(created_at=tu.utcnow(True))
|
||||
policies.append(db_api.policy_create(self.ctx, data))
|
||||
|
||||
results = db_api.policy_get_all(self.ctx)
|
||||
|
|
|
@ -184,7 +184,7 @@ class DBAPIProfileTest(base.SenlinTestCase):
|
|||
def test_profile_get_all_with_limit_marker(self):
|
||||
ids = ['profile1', 'profile2', 'profile3']
|
||||
for pid in ids:
|
||||
timestamp = tu.utcnow()
|
||||
timestamp = tu.utcnow(True)
|
||||
shared.create_profile(self.ctx, id=pid, created_at=timestamp)
|
||||
|
||||
# different limit settings
|
||||
|
@ -256,7 +256,8 @@ class DBAPIProfileTest(base.SenlinTestCase):
|
|||
def test_profile_get_all_default_sorting(self):
|
||||
profiles = []
|
||||
for x in range(3):
|
||||
profile = shared.create_profile(self.ctx, created_at=tu.utcnow())
|
||||
profile = shared.create_profile(self.ctx,
|
||||
created_at=tu.utcnow(True))
|
||||
profiles.append(profile)
|
||||
|
||||
results = db_api.profile_get_all(self.ctx)
|
||||
|
|
|
@ -156,7 +156,8 @@ class DBAPIReceiverTest(base.SenlinTestCase):
|
|||
def test_receiver_get_all_with_limit_marker(self):
|
||||
receiver_ids = ['receiver1', 'receiver2', 'receiver3']
|
||||
for v in receiver_ids:
|
||||
self._create_receiver(self.ctx, id=v, created_at=tu.utcnow())
|
||||
self._create_receiver(self.ctx, id=v,
|
||||
created_at=tu.utcnow(True))
|
||||
|
||||
receivers = db_api.receiver_get_all(self.ctx, limit=1)
|
||||
self.assertEqual(1, len(receivers))
|
||||
|
|
|
@ -14,9 +14,11 @@ import copy
|
|||
|
||||
import mock
|
||||
from oslo_config import cfg
|
||||
from oslo_utils import timeutils
|
||||
import six
|
||||
|
||||
from senlin.common import exception
|
||||
from senlin.common import utils as common_utils
|
||||
from senlin.engine.actions import base as ab
|
||||
from senlin.engine import cluster as cluster_mod
|
||||
from senlin.engine import cluster_policy as cp_mod
|
||||
|
@ -55,7 +57,7 @@ class ActionBaseTest(base.SenlinTestCase):
|
|||
'status_reason': 'FAKE_STATUS_REASON',
|
||||
'inputs': {'param': 'value'},
|
||||
'outputs': {'key': 'output_value'},
|
||||
'created_at': None,
|
||||
'created_at': timeutils.utcnow(True),
|
||||
'updated_at': None,
|
||||
'data': {'data_key': 'data_value'},
|
||||
}
|
||||
|
@ -120,7 +122,8 @@ class ActionBaseTest(base.SenlinTestCase):
|
|||
obj = ab.Action('OBJID', 'OBJECT_ACTION', self.ctx,
|
||||
**values)
|
||||
|
||||
self.assertIsNone(obj.created_at)
|
||||
self.assertEqual(common_utils.isotime(values['created_at']),
|
||||
common_utils.isotime(obj.created_at))
|
||||
self.assertIsNone(obj.updated_at)
|
||||
|
||||
# store for creation
|
||||
|
@ -172,7 +175,8 @@ class ActionBaseTest(base.SenlinTestCase):
|
|||
self.assertEqual(obj.status_reason, action_obj.status_reason)
|
||||
self.assertEqual(obj.inputs, action_obj.inputs)
|
||||
self.assertEqual(obj.outputs, action_obj.outputs)
|
||||
self.assertEqual(obj.created_at, action_obj.created_at)
|
||||
self.assertEqual(common_utils.isotime(obj.created_at),
|
||||
common_utils.isotime(action_obj.created_at))
|
||||
self.assertEqual(obj.updated_at, action_obj.updated_at)
|
||||
self.assertEqual(obj.data, action_obj.data)
|
||||
self.assertEqual(obj.user, action_obj.user)
|
||||
|
@ -552,6 +556,7 @@ class ActionBaseTest(base.SenlinTestCase):
|
|||
action = ab.Action('OBJID', 'OBJECT_ACTION', self.ctx,
|
||||
**self.action_values)
|
||||
action.id = 'FAKE_ID'
|
||||
ts = common_utils.isotime(self.action_values['created_at'])
|
||||
expected = {
|
||||
'id': 'FAKE_ID',
|
||||
'name': 'FAKE_NAME',
|
||||
|
@ -569,7 +574,7 @@ class ActionBaseTest(base.SenlinTestCase):
|
|||
'outputs': {'key': 'output_value'},
|
||||
'depends_on': ['ACTION_1'],
|
||||
'depended_by': ['ACTION_2'],
|
||||
'created_at': None,
|
||||
'created_at': ts,
|
||||
'updated_at': None,
|
||||
'data': {'data_key': 'data_value'},
|
||||
}
|
||||
|
|
|
@ -112,7 +112,7 @@ class ClusterActionTest(base.SenlinTestCase):
|
|||
|
||||
@mock.patch.object(ao.Action, 'update')
|
||||
@mock.patch.object(ab.Action, 'create')
|
||||
@mock.patch.object(co.Cluster, 'next_index')
|
||||
@mock.patch.object(co.Cluster, 'get_next_index')
|
||||
@mock.patch.object(nm, 'Node')
|
||||
@mock.patch.object(dobj.Dependency, 'create')
|
||||
@mock.patch.object(dispatcher, 'start_action')
|
||||
|
@ -185,7 +185,7 @@ class ClusterActionTest(base.SenlinTestCase):
|
|||
|
||||
@mock.patch.object(ao.Action, 'update')
|
||||
@mock.patch.object(ab.Action, 'create')
|
||||
@mock.patch.object(co.Cluster, 'next_index')
|
||||
@mock.patch.object(co.Cluster, 'get_next_index')
|
||||
@mock.patch.object(nm, 'Node')
|
||||
@mock.patch.object(dobj.Dependency, 'create')
|
||||
@mock.patch.object(dispatcher, 'start_action')
|
||||
|
|
|
@ -19,11 +19,11 @@ import six
|
|||
from senlin.common import consts
|
||||
from senlin.common import exception as exc
|
||||
from senlin.common.i18n import _
|
||||
from senlin.db.sqlalchemy import api as db_api
|
||||
from senlin.engine.actions import base as action_mod
|
||||
from senlin.engine import dispatcher
|
||||
from senlin.engine import node as node_mod
|
||||
from senlin.engine import service
|
||||
from senlin.objects import cluster as co
|
||||
from senlin.objects import node as no
|
||||
from senlin.tests.unit.common import base
|
||||
from senlin.tests.unit.common import utils
|
||||
|
@ -273,7 +273,7 @@ class NodeTest(base.SenlinTestCase):
|
|||
|
||||
@mock.patch.object(action_mod.Action, 'create')
|
||||
@mock.patch('senlin.engine.node.Node')
|
||||
@mock.patch.object(db_api, 'cluster_next_index')
|
||||
@mock.patch.object(co.Cluster, 'get_next_index')
|
||||
@mock.patch.object(service.EngineService, 'cluster_find')
|
||||
@mock.patch.object(service.EngineService, 'profile_find')
|
||||
@mock.patch.object(dispatcher, 'start_action')
|
||||
|
@ -312,7 +312,7 @@ class NodeTest(base.SenlinTestCase):
|
|||
|
||||
@mock.patch.object(action_mod.Action, 'create')
|
||||
@mock.patch('senlin.engine.node.Node')
|
||||
@mock.patch.object(db_api, 'cluster_next_index')
|
||||
@mock.patch.object(co.Cluster, 'get_next_index')
|
||||
@mock.patch.object(service.EngineService, 'cluster_find')
|
||||
@mock.patch.object(service.EngineService, 'profile_find')
|
||||
@mock.patch.object(dispatcher, 'start_action')
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
import mock
|
||||
from oslo_config import cfg
|
||||
from oslo_utils import timeutils
|
||||
import six
|
||||
|
||||
from senlin.common import exception
|
||||
|
@ -255,6 +256,7 @@ class TestCluster(base.SenlinTestCase):
|
|||
'name': 'test-cluster',
|
||||
'desired_capacity': 1,
|
||||
'status': 'INIT',
|
||||
'init_at': timeutils.utcnow(True),
|
||||
'user': self.context.user,
|
||||
'project': self.context.project,
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ from oslo_utils import timeutils
|
|||
import six
|
||||
|
||||
from senlin.common import exception
|
||||
from senlin.common import utils as common_utils
|
||||
from senlin.engine import cluster_policy as cpm
|
||||
from senlin.objects import cluster as co
|
||||
from senlin.objects import cluster_policy as cpo
|
||||
|
@ -72,7 +73,7 @@ class TestClusterPolicy(base.SenlinTestCase):
|
|||
cp.enabled = False
|
||||
cp.priority = 60
|
||||
cp.data = {'foo': 'bar'}
|
||||
timestamp = timeutils.utcnow()
|
||||
timestamp = timeutils.utcnow(True)
|
||||
cp.last_op = timestamp
|
||||
|
||||
new_id = cp.store(self.context)
|
||||
|
@ -85,26 +86,31 @@ class TestClusterPolicy(base.SenlinTestCase):
|
|||
self.assertFalse(result.enabled)
|
||||
self.assertEqual(60, result.priority)
|
||||
self.assertEqual({'foo': 'bar'}, result.data)
|
||||
self.assertEqual(timestamp, result.last_op)
|
||||
self.assertEqual(common_utils.isotime(timestamp),
|
||||
common_utils.isotime(result.last_op))
|
||||
|
||||
def _create_cluster(self, cluster_id):
|
||||
values = {
|
||||
'id': cluster_id,
|
||||
'profile_id': 'some-profile',
|
||||
'name': 'test_cluster',
|
||||
'user': 'user',
|
||||
'project': 'project'
|
||||
'status': 'ACTIVE',
|
||||
'init_at': timeutils.utcnow(True),
|
||||
'user': self.context.user,
|
||||
'project': self.context.project,
|
||||
}
|
||||
return co.Cluster.create(self.context, values)
|
||||
|
||||
def _create_policy(self, policy_id):
|
||||
values = {
|
||||
'id': policy_id,
|
||||
'name': 'test_policy',
|
||||
'type': 'policy-type',
|
||||
'spec': {'prop': 'value'},
|
||||
'created_at': timeutils.utcnow(True),
|
||||
'user': self.context.user,
|
||||
'project': self.context.project,
|
||||
'domain': self.context.domain,
|
||||
'name': 'test_policy',
|
||||
}
|
||||
return po.Policy.create(self.context, values)
|
||||
|
||||
|
@ -148,9 +154,11 @@ class TestClusterPolicy(base.SenlinTestCase):
|
|||
policy1 = self._create_policy('P1')
|
||||
policy2 = self._create_policy('P2')
|
||||
|
||||
b1 = cpm.ClusterPolicy(cluster.id, policy1.id, enabled=True)
|
||||
b1 = cpm.ClusterPolicy(cluster.id, policy1.id, enabled=True,
|
||||
priority=10)
|
||||
b1.store(self.context)
|
||||
b2 = cpm.ClusterPolicy(cluster.id, policy2.id, enabled=False)
|
||||
b2 = cpm.ClusterPolicy(cluster.id, policy2.id, enabled=False,
|
||||
priority=20)
|
||||
b2.store(self.context)
|
||||
|
||||
# NOTE: we don't test all other parameters because the db api tests
|
||||
|
@ -182,7 +190,7 @@ class TestClusterPolicy(base.SenlinTestCase):
|
|||
def test_cooldown_inprogress(self):
|
||||
values = {
|
||||
'enabled': True,
|
||||
'last_op': timeutils.utcnow(),
|
||||
'last_op': timeutils.utcnow(True),
|
||||
}
|
||||
cp = cpm.ClusterPolicy('fake-cluster', 'fake-policy', **values)
|
||||
self.assertTrue(cp.cooldown_inprogress(60))
|
||||
|
|
|
@ -146,9 +146,8 @@ class EngineStatusTest(base.SenlinTestCase):
|
|||
@mock.patch.object(service_obj.Service, 'get_all')
|
||||
@mock.patch.object(service_obj.Service, 'delete')
|
||||
def test_service_manage_report_cleanup(self, mock_delete, mock_get_all):
|
||||
ages_a_go = timeutils.utcnow() - datetime.timedelta(
|
||||
seconds=2 * cfg.CONF.periodic_interval)
|
||||
mock_get_all.return_value = [{'id': 'foo',
|
||||
'updated_at': ages_a_go}]
|
||||
delta = datetime.timedelta(seconds=2 * cfg.CONF.periodic_interval)
|
||||
ages_a_go = timeutils.utcnow(True) - delta
|
||||
mock_get_all.return_value = [{'id': 'foo', 'updated_at': ages_a_go}]
|
||||
self.eng.service_manage_cleanup()
|
||||
mock_delete.assert_called_once_with(mock.ANY, 'foo')
|
||||
|
|
|
@ -29,7 +29,7 @@ class TestEvent(base.SenlinTestCase):
|
|||
self.context = utils.dummy_context()
|
||||
|
||||
def test_event_init(self):
|
||||
timestamp = timeutils.utcnow()
|
||||
timestamp = timeutils.utcnow(True)
|
||||
kwargs = {
|
||||
'id': 'FAKE-ID',
|
||||
'user': 'test-user',
|
||||
|
@ -63,7 +63,7 @@ class TestEvent(base.SenlinTestCase):
|
|||
self.assertEqual({'foo': 'bar'}, event.metadata)
|
||||
|
||||
def test_event_init_with_entity(self):
|
||||
timestamp = timeutils.utcnow()
|
||||
timestamp = timeutils.utcnow(True)
|
||||
x_cluster = cluster_mod.Cluster('fake-cluster', 0, 'fake-profile',
|
||||
id='FAKE_CLUSTER')
|
||||
|
||||
|
@ -169,7 +169,7 @@ class TestEvent(base.SenlinTestCase):
|
|||
mock_get.assert_called_once_with(entity, fully_qualified=False)
|
||||
|
||||
def test_event_store(self):
|
||||
timestamp = timeutils.utcnow()
|
||||
timestamp = timeutils.utcnow(True)
|
||||
kwargs = {
|
||||
'user': self.context.user,
|
||||
'project': self.context.project,
|
||||
|
|
|
@ -38,12 +38,14 @@ class TestNode(base.SenlinTestCase):
|
|||
def _create_profile(self, profile_id):
|
||||
values = {
|
||||
'id': profile_id,
|
||||
'context': self.context.to_dict(),
|
||||
'type': 'os.nova.server-1.0',
|
||||
'name': 'test-profile',
|
||||
'spec': {
|
||||
'type': 'os.nova.server',
|
||||
'version': '1.0',
|
||||
},
|
||||
'created_at': timeutils.utcnow(True),
|
||||
'user': self.context.user,
|
||||
'project': self.context.project
|
||||
}
|
||||
|
@ -54,6 +56,8 @@ class TestNode(base.SenlinTestCase):
|
|||
'id': cluster_id,
|
||||
'profile_id': self.profile.id,
|
||||
'name': 'test-cluster',
|
||||
'status': 'ACTIVE',
|
||||
'init_at': timeutils.utcnow(True),
|
||||
'user': self.context.user,
|
||||
'project': self.context.project,
|
||||
'next_index': 1,
|
||||
|
@ -64,11 +68,15 @@ class TestNode(base.SenlinTestCase):
|
|||
def _create_node(self, node_id):
|
||||
values = {
|
||||
'id': node_id,
|
||||
'name': 'node1',
|
||||
'profile_id': self.profile.id,
|
||||
'cluster_id': self.cluster.id,
|
||||
'index': 2,
|
||||
'init_at': timeutils.utcnow(True),
|
||||
'user': self.context.user,
|
||||
'project': self.context.project,
|
||||
'name': 'node1',
|
||||
'role': 'test_node',
|
||||
'status': 'ACTIVE',
|
||||
}
|
||||
return node_obj.Node.create(self.context, values)
|
||||
|
||||
|
@ -510,10 +518,9 @@ class TestNode(base.SenlinTestCase):
|
|||
self.assertIsNone(node.updated_at)
|
||||
self.assertFalse(mock_migrate.called)
|
||||
|
||||
@mock.patch.object(timeutils, 'utcnow')
|
||||
@mock.patch.object(profiles_base.Profile, 'join_cluster')
|
||||
@mock.patch.object(node_obj.Node, 'migrate')
|
||||
def test_node_join(self, mock_migrate, mock_join_cluster, mock_time):
|
||||
def test_node_join(self, mock_migrate, mock_join_cluster):
|
||||
node = nodem.Node('node1', self.profile.id, self.cluster.id,
|
||||
self.context)
|
||||
mock_join_cluster.return_value = True
|
||||
|
@ -547,10 +554,9 @@ class TestNode(base.SenlinTestCase):
|
|||
self.assertEqual('', node.cluster_id)
|
||||
self.assertIsNone(node.updated_at)
|
||||
|
||||
@mock.patch.object(timeutils, 'utcnow')
|
||||
@mock.patch.object(profiles_base.Profile, 'leave_cluster')
|
||||
@mock.patch.object(node_obj.Node, 'migrate')
|
||||
def test_node_leave(self, mock_migrate, mock_leave_cluster, mock_time):
|
||||
def test_node_leave(self, mock_migrate, mock_leave_cluster):
|
||||
node = nodem.Node('node1', self.profile.id, self.cluster.id,
|
||||
self.context)
|
||||
mock_leave_cluster.return_value = True
|
||||
|
|
|
@ -48,7 +48,7 @@ class TestReceiver(base.SenlinTestCase):
|
|||
'user': self.context.user,
|
||||
'project': self.context.project,
|
||||
'domain': self.context.domain,
|
||||
'created_at': timeutils.utcnow(),
|
||||
'created_at': timeutils.utcnow(True),
|
||||
'updated_at': None,
|
||||
'actor': self.actor,
|
||||
'params': self.params,
|
||||
|
@ -64,7 +64,7 @@ class TestReceiver(base.SenlinTestCase):
|
|||
'user': 'test-user',
|
||||
'project': 'test-project',
|
||||
'domain': 'test-domain',
|
||||
'created_at': timeutils.utcnow(),
|
||||
'created_at': timeutils.utcnow(True),
|
||||
'updated_at': None,
|
||||
'actor': self.actor,
|
||||
'params': self.params,
|
||||
|
@ -111,6 +111,7 @@ class TestReceiver(base.SenlinTestCase):
|
|||
|
||||
def test_receiver_store(self):
|
||||
receiver = rb.Receiver('webhook', 'FAKE_CLUSTER', 'test-action',
|
||||
name='test_receiver_123456',
|
||||
project=self.context.project)
|
||||
self.assertIsNone(receiver.id)
|
||||
|
||||
|
@ -128,7 +129,8 @@ class TestReceiver(base.SenlinTestCase):
|
|||
self.assertEqual(receiver.user, result.user)
|
||||
self.assertEqual(receiver.project, result.project)
|
||||
self.assertEqual(receiver.domain, result.domain)
|
||||
self.assertEqual(receiver.created_at, result.created_at)
|
||||
self.assertEqual(common_utils.isotime(receiver.created_at),
|
||||
common_utils.isotime(result.created_at)),
|
||||
self.assertEqual(receiver.updated_at, result.updated_at)
|
||||
self.assertEqual(receiver.action, result.action)
|
||||
self.assertEqual(receiver.actor, result.actor)
|
||||
|
@ -139,7 +141,8 @@ class TestReceiver(base.SenlinTestCase):
|
|||
cluster = mock.Mock()
|
||||
cluster.id = 'FAKE_CLUSTER'
|
||||
receiver = rb.Receiver.create(self.context, 'webhook', cluster,
|
||||
'FAKE_ACTION')
|
||||
'FAKE_ACTION',
|
||||
name='test_receiver_2234')
|
||||
|
||||
self.assertEqual(self.context.user, receiver.user)
|
||||
self.assertEqual(self.context.project, receiver.project)
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
import datetime
|
||||
import mock
|
||||
from oslo_config import cfg
|
||||
from oslo_utils import timeutils
|
||||
|
||||
from senlin.engine import scheduler
|
||||
from senlin.engine import senlin_lock as lockm
|
||||
|
@ -285,15 +286,14 @@ class SenlinLockEnginCheckTest(base.SenlinTestCase):
|
|||
|
||||
@mock.patch.object(service_obj.Service, 'get')
|
||||
def test_engine_is_dead(self, mock_service):
|
||||
update_time = (datetime.datetime.utcnow() - datetime.timedelta(
|
||||
seconds=3 * cfg.CONF.periodic_interval))
|
||||
delta = datetime.timedelta(seconds=3 * cfg.CONF.periodic_interval)
|
||||
update_time = timeutils.utcnow(True) - delta
|
||||
mock_service.return_value = mock.Mock(updated_at=update_time)
|
||||
self.assertTrue(lockm.is_engine_dead(self.ctx, 'fake_engine_id'))
|
||||
mock_service.assert_called_once_with(self.ctx, 'fake_engine_id')
|
||||
|
||||
@mock.patch.object(service_obj.Service, 'get')
|
||||
def test_engine_is_alive(self, mock_service):
|
||||
mock_service.return_value = mock.Mock(
|
||||
updated_at=datetime.datetime.utcnow())
|
||||
def test_engine_is_alive(self, mock_svc):
|
||||
mock_svc.return_value = mock.Mock(updated_at=timeutils.utcnow(True))
|
||||
self.assertFalse(lockm.is_engine_dead(self.ctx, 'fake_engine_id'))
|
||||
mock_service.assert_called_once_with(self.ctx, 'fake_engine_id')
|
||||
mock_svc.assert_called_once_with(self.ctx, 'fake_engine_id')
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
import mock
|
||||
from oslo_context import context as oslo_ctx
|
||||
from oslo_utils import timeutils
|
||||
import six
|
||||
|
||||
from senlin.common import consts
|
||||
|
@ -79,10 +80,10 @@ class TestPolicyBase(base.SenlinTestCase):
|
|||
'name': 'test-policy',
|
||||
'type': 'senlin.policy.dummy-1.0',
|
||||
'spec': self.spec,
|
||||
'created_at': timeutils.utcnow(True),
|
||||
'user': self.ctx.user,
|
||||
'project': self.ctx.project,
|
||||
'domain': self.ctx.domain,
|
||||
'data': {}
|
||||
}
|
||||
|
||||
values.update(kwargs)
|
||||
|
@ -275,7 +276,7 @@ class TestPolicyBase(base.SenlinTestCase):
|
|||
'domain': policy.domain,
|
||||
'spec': policy.spec,
|
||||
'data': policy.data,
|
||||
'created_at': common_utils.format_time(policy.created_at),
|
||||
'created_at': common_utils.isotime(policy.created_at),
|
||||
'updated_at': None,
|
||||
}
|
||||
|
||||
|
|
|
@ -51,10 +51,14 @@ class TestScalingPolicy(base.SenlinTestCase):
|
|||
|
||||
def _create_profile(self, profile_id):
|
||||
values = {
|
||||
'context': self.context.to_dict(),
|
||||
'id': profile_id,
|
||||
'type': 'os.heat.stack',
|
||||
'name': 'test-profile',
|
||||
'created_at': timeutils.utcnow(),
|
||||
'spec': {
|
||||
'template': 'fake_stack.yml',
|
||||
},
|
||||
'created_at': timeutils.utcnow(True),
|
||||
'user': self.context.user,
|
||||
'project': self.context.project,
|
||||
}
|
||||
|
@ -71,6 +75,8 @@ class TestScalingPolicy(base.SenlinTestCase):
|
|||
'min_size': 1,
|
||||
'max_size': 5,
|
||||
'desired_capacity': 3,
|
||||
'status': 'ACTIVE',
|
||||
'init_at': timeutils.utcnow(True),
|
||||
}
|
||||
|
||||
return co.Cluster.create(self.context, values)
|
||||
|
@ -84,15 +90,17 @@ class TestScalingPolicy(base.SenlinTestCase):
|
|||
'physical_id': 'FAKE_PHY_ID_%s' % (i + 1),
|
||||
'cluster_id': cluster_id,
|
||||
'profile_id': profile_id,
|
||||
'project': self.context.project,
|
||||
'index': i + 1,
|
||||
'role': None,
|
||||
'created_at': timeutils.utcnow(),
|
||||
'init_at': timeutils.utcnow(True),
|
||||
'created_at': timeutils.utcnow(True),
|
||||
'updated_at': None,
|
||||
'status': 'ACTIVE',
|
||||
'status_reason': 'create complete',
|
||||
'metadata': {'foo': '123'},
|
||||
'data': {'key1': 'value1'},
|
||||
'user': self.context.user,
|
||||
'project': self.context.project,
|
||||
}
|
||||
db_node = no.Node.create(self.context, values)
|
||||
nodes.append(six.text_type(db_node.id))
|
||||
|
|
Loading…
Reference in New Issue