rally/rally/common/db/models.py

375 lines
12 KiB
Python

# Copyright 2013: Mirantis Inc.
# All Rights Reserved.
#
# 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.
"""
SQLAlchemy models for rally data.
"""
import datetime as dt
import uuid
import sqlalchemy as sa
import sqlalchemy.orm # noqa (used as sa.orm)
if sa.__version__.startswith("2."):
from sqlalchemy.orm import declarative_base
else:
from sqlalchemy.ext.declarative import declarative_base
from rally.common.db import sa_types
from rally import consts
BASE = declarative_base()
def UUID():
return str(uuid.uuid4())
class RallyBase(object):
"""Base class for models."""
__table_initialized__ = False
metadata = None
created_at = sa.Column(sa.DateTime, default=dt.datetime.utcnow)
updated_at = sa.Column(sa.DateTime, default=dt.datetime.utcnow,
onupdate=dt.datetime.utcnow)
def as_dict(self):
result = {}
res = sa.inspect(self)
for c in self.__table__.columns:
if c.key not in res.unloaded:
result[c.name] = getattr(self, c.name)
for r in self.__mapper__.relationships:
if r.key not in res.unloaded:
result[r.key] = getattr(self, r.key)
return result
def get(self, key, default=None):
return getattr(self, key, default)
def update(self, values):
"""Make the model object behave like a dict."""
for k, v in values.items():
setattr(self, k, v)
class Env(BASE, RallyBase):
"""Represent an environment."""
__tablename__ = "envs"
__table_args__ = (
sa.Index("env_uuid", "uuid", unique=True),
sa.Index("env_name", "name", unique=True),
sa.Index("env_status", "status")
)
id = sa.Column(sa.Integer, primary_key=True, autoincrement=True)
uuid = sa.Column(sa.String(36), default=UUID, nullable=False)
name = sa.Column(sa.String(255), nullable=False)
description = sa.Column(sa.Text, default="")
status = sa.Column(sa.String(36), nullable=False)
extras = sa.Column(sa_types.MutableJSONEncodedDict, default={})
config = sa.Column(sa_types.MutableJSONEncodedDict, default={})
spec = sa.Column(sa_types.MutableJSONEncodedDict, default={})
class Platform(BASE, RallyBase):
"""Represent environment's platforms."""
__tablename__ = "platforms"
__table_args__ = (
sa.Index("platform_uuid", "uuid", unique=True),
sa.Index("platform_env_uuid", "env_uuid")
)
id = sa.Column(sa.Integer, primary_key=True, autoincrement=True)
uuid = sa.Column(sa.String(36), default=UUID, nullable=False)
env_uuid = sa.Column(sa.String(36), nullable=False)
status = sa.Column(sa.String(36), nullable=False)
plugin_name = sa.Column(sa.String(36), nullable=False)
plugin_spec = sa.Column(sa_types.MutableJSONEncodedDict, default={},
nullable=False)
plugin_data = sa.Column(sa_types.MutableJSONEncodedDict, default={})
platform_name = sa.Column(sa.String(36))
platform_data = sa.Column(sa_types.MutableJSONEncodedDict, default={})
class Task(BASE, RallyBase):
"""Represents a task."""
__tablename__ = "tasks"
__table_args__ = (
sa.Index("task_uuid", "uuid", unique=True),
sa.Index("task_status", "status"),
)
id = sa.Column(sa.Integer, primary_key=True, autoincrement=True)
uuid = sa.Column(sa.String(36), default=UUID, nullable=False)
env_uuid = sa.Column(sa.String(36), nullable=False)
# we do not save the whole input task
input_task = sa.orm.deferred(sa.Column(sa.Text, default=""))
title = sa.Column(sa.String(128), default="")
description = sa.Column(sa.Text, default="")
validation_result = sa.Column(
sa_types.MutableJSONEncodedDict, default={}, nullable=False)
# we do not calculate the duration of a validation step yet
validation_duration = sa.orm.deferred(sa.Column(sa.Float))
task_duration = sa.Column(sa.Float, default=0.0)
pass_sla = sa.Column(sa.Boolean, default=True)
status = sa.Column(sa.String(36), default=consts.TaskStatus.INIT)
class Subtask(BASE, RallyBase):
__tablename__ = "subtasks"
__table_args__ = (
sa.Index("subtask_uuid", "uuid", unique=True),
sa.Index("subtask_status", "status"),
)
id = sa.Column(sa.Integer, primary_key=True, autoincrement=True)
uuid = sa.Column(sa.String(36), default=UUID, nullable=False)
task_uuid = sa.Column(
sa.String(36),
sa.ForeignKey(Task.uuid),
nullable=False,
)
task = sa.orm.relationship(
Task,
backref=sa.orm.backref("subtasks"),
foreign_keys=task_uuid,
primaryjoin=(task_uuid == Task.uuid),
)
title = sa.Column(sa.String(128), default="")
description = sa.Column(sa.Text, default="")
# we do not support subtask contexts feature yet, see
# https://review.openstack.org/#/c/404168/
contexts = sa.orm.deferred(sa.Column(
sa_types.JSONEncodedDict, default={}, nullable=False))
contexts_results = sa.orm.deferred(sa.Column(
sa_types.MutableJSONEncodedList, default=[], nullable=False))
sla = sa.Column(
sa_types.JSONEncodedDict, default={}, nullable=False)
# It is always False for now
run_in_parallel = sa.orm.deferred(
sa.Column(sa.Boolean, default=False, nullable=False))
duration = sa.Column(sa.Float, default=0.0)
pass_sla = sa.Column(sa.Boolean, default=True)
status = sa.Column(sa.String(36), default=consts.SubtaskStatus.RUNNING)
class Workload(BASE, RallyBase):
__tablename__ = "workloads"
__table_args__ = (
sa.Index("workload_uuid", "uuid", unique=True),
)
id = sa.Column(sa.Integer, primary_key=True, autoincrement=True)
uuid = sa.Column(sa.String(36), default=UUID, nullable=False)
task_uuid = sa.Column(
sa.String(36),
sa.ForeignKey(Task.uuid),
nullable=False,
)
subtask_uuid = sa.Column(
sa.String(36),
sa.ForeignKey(Subtask.uuid),
nullable=False,
)
subtask = sa.orm.relationship(
Subtask,
backref=sa.orm.backref("workloads"),
foreign_keys=subtask_uuid,
primaryjoin=(subtask_uuid == Subtask.uuid),
)
name = sa.Column(sa.String(64), nullable=False)
description = sa.Column(sa.Text, default="")
position = sa.Column(sa.Integer, default=0, nullable=False)
runner = sa.Column(
sa_types.JSONEncodedDict, default={}, nullable=False)
runner_type = sa.Column(sa.String(64), nullable=False)
contexts = sa.Column(
sa_types.JSONEncodedDict, default={}, nullable=False)
contexts_results = sa.Column(
sa_types.MutableJSONEncodedList, default=[], nullable=False)
sla = sa.Column(
sa_types.JSONEncodedDict, default={}, nullable=False)
sla_results = sa.Column(
sa_types.MutableJSONEncodedDict, default={}, nullable=False)
args = sa.Column(
sa_types.JSONEncodedDict, default={}, nullable=False)
hooks = sa.Column(
sa_types.JSONEncodedList, default=[], nullable=False)
start_time = sa.Column(sa_types.TimeStamp)
load_duration = sa.Column(sa.Float, default=0.0)
full_duration = sa.Column(sa.Float, default=0.0)
min_duration = sa.Column(sa.Float)
max_duration = sa.Column(sa.Float)
total_iteration_count = sa.Column(sa.Integer, default=0)
failed_iteration_count = sa.Column(sa.Integer, default=0)
statistics = sa.Column(
sa_types.MutableJSONEncodedDict, default={}, nullable=False)
pass_sla = sa.Column(sa.Boolean, default=True)
_profiling_data = sa.orm.deferred(sa.Column(sa.Text, default=""))
class WorkloadData(BASE, RallyBase):
__tablename__ = "workloaddata"
__table_args__ = (
sa.Index("workload_data_uuid", "uuid", unique=True),
)
id = sa.Column(sa.Integer, primary_key=True, autoincrement=True)
uuid = sa.Column(sa.String(36), default=UUID, nullable=False)
task_uuid = sa.Column(
sa.String(36),
sa.ForeignKey(Task.uuid),
nullable=False,
)
workload_uuid = sa.Column(
sa.String(36),
sa.ForeignKey(Workload.uuid),
nullable=False,
)
workload = sa.orm.relationship(
Workload,
backref=sa.orm.backref("workload_data"),
foreign_keys=workload_uuid,
primaryjoin=(workload_uuid == Workload.uuid),
)
chunk_order = sa.Column(sa.Integer, nullable=False)
chunk_data = sa.Column(
sa_types.MutableJSONEncodedDict, default={}, nullable=False)
# all these fields are not used
iteration_count = sa.orm.deferred(sa.Column(sa.Integer, nullable=False))
failed_iteration_count = sa.orm.deferred(sa.Column(
sa.Integer, nullable=False))
chunk_size = sa.orm.deferred(sa.Column(
sa.Integer, nullable=False))
compressed_chunk_size = sa.orm.deferred(sa.Column(
sa.Integer, nullable=False))
started_at = sa.orm.deferred(sa.Column(
sa.DateTime, default=dt.datetime.utcnow, nullable=False))
finished_at = sa.orm.deferred(sa.Column(
sa.DateTime, default=dt.datetime.utcnow, nullable=False))
class Tag(BASE, RallyBase):
__tablename__ = "tags"
__table_args__ = (
sa.Index("d_type_tag", "uuid", "type", "tag", unique=True),
)
id = sa.Column(sa.Integer, primary_key=True, autoincrement=True)
uuid = sa.Column(sa.String(36), default=UUID, nullable=False)
type = sa.Column(sa.String(36), nullable=False)
tag = sa.Column(sa.String(255), nullable=False)
class Verifier(BASE, RallyBase):
"""Represents a verifier."""
__tablename__ = "verifiers"
__table_args__ = (
sa.Index("verifier_uuid", "uuid", unique=True),
)
id = sa.Column(sa.Integer, primary_key=True, autoincrement=True)
uuid = sa.Column(sa.String(36), default=UUID, nullable=False)
name = sa.Column(sa.String(255), unique=True)
description = sa.Column(sa.Text)
type = sa.Column(sa.String(255), nullable=False)
platform = sa.Column(sa.String(255))
source = sa.Column(sa.String(255))
version = sa.Column(sa.String(255))
system_wide = sa.Column(sa.Boolean)
status = sa.Column(sa.String(36), default=consts.VerifierStatus.INIT,
nullable=False)
extra_settings = sa.Column(sa_types.MutableJSONEncodedDict)
class Verification(BASE, RallyBase):
"""Represents a verification."""
__tablename__ = "verifications"
__table_args__ = (
sa.Index("verification_uuid", "uuid", unique=True),
)
id = sa.Column(sa.Integer, primary_key=True, autoincrement=True)
uuid = sa.Column(sa.String(36), default=UUID, nullable=False)
verifier_uuid = sa.Column(sa.String(36),
sa.ForeignKey(Verifier.uuid),
nullable=False)
env_uuid = sa.Column(sa.String(36), nullable=False)
run_args = sa.Column(sa_types.MutableJSONEncodedDict)
status = sa.Column(sa.String(36), default=consts.VerificationStatus.INIT,
nullable=False)
tests_count = sa.Column(sa.Integer, default=0)
failures = sa.Column(sa.Integer, default=0)
skipped = sa.Column(sa.Integer, default=0)
success = sa.Column(sa.Integer, default=0)
unexpected_success = sa.Column(sa.Integer, default=0)
expected_failures = sa.Column(sa.Integer, default=0)
tests_duration = sa.Column(sa.Float, default=0.0)
tests = sa.Column(sa_types.MutableJSONEncodedDict, default={})