200 lines
6.7 KiB
Python
200 lines
6.7 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
# Copyright 2016 Mirantis, Inc.
|
|
#
|
|
# 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 datetime import datetime
|
|
|
|
from nailgun import consts
|
|
from nailgun.db import db
|
|
from nailgun.db.sqlalchemy import models
|
|
from nailgun import errors
|
|
from nailgun.objects import NailgunCollection
|
|
from nailgun.objects import NailgunObject
|
|
from nailgun.objects.node_deployment_info import NodeDeploymentInfo
|
|
from nailgun.objects.node_deployment_info import NodeDeploymentInfoCollection
|
|
from nailgun.objects.serializers.transaction import TransactionSerializer
|
|
|
|
|
|
class Transaction(NailgunObject):
|
|
|
|
model = models.Task
|
|
serializer = TransactionSerializer
|
|
|
|
@classmethod
|
|
def get_by_uuid(cls, uuid, fail_if_not_found=False, lock_for_update=False):
|
|
# maybe consider using uuid as pk?
|
|
q = db().query(cls.model).filter_by(uuid=uuid)
|
|
if lock_for_update:
|
|
q = q.order_by('id')
|
|
q = q.with_lockmode('update')
|
|
res = q.first()
|
|
|
|
if not res and fail_if_not_found:
|
|
raise errors.ObjectNotFound(
|
|
"Task with UUID={0} is not found in DB".format(uuid)
|
|
)
|
|
return res
|
|
|
|
@classmethod
|
|
def attach_deployment_info(cls, instance, deployment_info):
|
|
for uid, dinfo in deployment_info['nodes'].items():
|
|
NodeDeploymentInfo.create({'task_id': instance.id,
|
|
'node_uid': uid,
|
|
'deployment_info': dinfo})
|
|
if 'common' in deployment_info:
|
|
instance.deployment_info = deployment_info['common']
|
|
|
|
@classmethod
|
|
def get_deployment_info(cls, instance, node_uids=None):
|
|
if instance is None:
|
|
return {}
|
|
|
|
node_di_list = NodeDeploymentInfoCollection.filter_by(
|
|
None, task_id=instance.id)
|
|
if node_uids:
|
|
node_di_list = NodeDeploymentInfoCollection.filter_by_list(
|
|
node_di_list, "node_uid", node_uids)
|
|
|
|
nodes_info = {node_di.node_uid: node_di.deployment_info
|
|
for node_di in node_di_list}
|
|
if nodes_info or instance.deployment_info:
|
|
return {'common': instance.deployment_info or {},
|
|
'nodes': nodes_info}
|
|
return {}
|
|
|
|
@classmethod
|
|
def attach_network_settings(cls, instance, settings):
|
|
instance.network_settings = settings
|
|
|
|
@classmethod
|
|
def get_network_settings(cls, instance):
|
|
if instance is not None:
|
|
return instance.network_settings
|
|
|
|
@classmethod
|
|
def attach_cluster_settings(cls, instance, settings):
|
|
instance.cluster_settings = settings
|
|
|
|
@classmethod
|
|
def get_cluster_settings(cls, instance):
|
|
if instance is not None:
|
|
return instance.cluster_settings
|
|
|
|
@classmethod
|
|
def attach_tasks_snapshot(cls, instance, tasks_snapshot):
|
|
instance.tasks_snapshot = tasks_snapshot
|
|
|
|
@classmethod
|
|
def get_tasks_snapshot(cls, instance):
|
|
if instance is not None:
|
|
return instance.tasks_snapshot
|
|
|
|
@classmethod
|
|
def on_start(cls, instance):
|
|
cls.update(instance, {
|
|
'time_start': datetime.utcnow(),
|
|
'status': consts.TASK_STATUSES.running
|
|
})
|
|
|
|
@classmethod
|
|
def on_finish(cls, instance, status, message=None):
|
|
data = {
|
|
'progress': 100,
|
|
'status': status,
|
|
'time_end': datetime.utcnow(),
|
|
}
|
|
if message is not None:
|
|
data['message'] = message
|
|
|
|
# set time start the same time of there is no time start
|
|
cls.update(instance, data)
|
|
|
|
|
|
class TransactionCollection(NailgunCollection):
|
|
|
|
single = Transaction
|
|
|
|
@classmethod
|
|
def get_transactions(cls, cluster_id=None,
|
|
transaction_types=None,
|
|
statuses=None):
|
|
"""Get list of transactions by given filters.
|
|
|
|
:param cluster_id: db id of cluster object
|
|
:param transaction_types: list with transaction types
|
|
:param statuses: list of statuses
|
|
:returns: list of Task objects
|
|
"""
|
|
query = cls.all()
|
|
if cluster_id:
|
|
query = cls.filter_by(query, cluster_id=cluster_id)
|
|
if transaction_types:
|
|
query = cls.filter_by_list(query, 'name', transaction_types)
|
|
if statuses:
|
|
query = cls.filter_by_list(query, 'status', statuses)
|
|
return query
|
|
|
|
@classmethod
|
|
def get_last_succeed_run(cls, cluster):
|
|
# TODO(bgaifullin) remove hardcoded name of task
|
|
return cls.filter_by(
|
|
None, cluster_id=cluster.id, name=consts.TASK_NAMES.deployment,
|
|
status=consts.TASK_STATUSES.ready, dry_run=False,
|
|
).order_by('-id').limit(1).first()
|
|
|
|
@classmethod
|
|
def get_successful_transactions_per_task(cls, cluster_id,
|
|
task_names=None,
|
|
nodes_uids=None):
|
|
"""Get last successful transaction for every task name.
|
|
|
|
:param cluster_id: db id of cluster object
|
|
:param task_names: list with task names
|
|
:param nodes_uids: db Node uids, which state you need
|
|
:returns: [(Transaction, node_id, task_name), ...]
|
|
"""
|
|
history = models.DeploymentHistory
|
|
model = cls.single.model
|
|
|
|
transactions = db().query(
|
|
model,
|
|
history.node_id,
|
|
history.deployment_graph_task_name,
|
|
).join(history).filter(
|
|
model.cluster_id == cluster_id,
|
|
model.name == consts.TASK_NAMES.deployment,
|
|
model.dry_run.is_(False),
|
|
history.status == consts.HISTORY_TASK_STATUSES.ready,
|
|
)
|
|
|
|
if nodes_uids is not None:
|
|
transactions = transactions.filter(
|
|
history.node_id.in_(nodes_uids),
|
|
)
|
|
|
|
if task_names is not None:
|
|
transactions = transactions.filter(
|
|
history.deployment_graph_task_name.in_(task_names),
|
|
)
|
|
|
|
transactions = transactions.order_by(
|
|
history.deployment_graph_task_name,
|
|
history.node_id,
|
|
history.task_id.desc(),
|
|
).distinct(
|
|
history.deployment_graph_task_name, history.node_id
|
|
)
|
|
return transactions
|