Files
deb-python-taskflow/taskflow/persistence/backends/memory/api.py
Joshua Harlow acd545f9c2 File movements
In order to rework some of the persistence layer I would
like to move around some of the files first, keeping job
specifics in a jobs folder. Having some of the items which
are root level taskflow items (flow, task) be at the root
of the hiearchy. Also for now until the celery work is
commited move that, since it doesn't make sense in backends
anyway.

Change-Id: If6c149710b40f70d4ec69ee8e523defe8f5e766d
2013-08-17 20:34:19 -07:00

454 lines
14 KiB
Python

# -*- coding: utf-8 -*-
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (C) 2012 Yahoo! Inc. All Rights Reserved.
# Copyright (C) 2013 Rackspace Hosting 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.
"""Implementation of in-memory backend."""
import logging
from taskflow import exceptions as exception
from taskflow.persistence.backends.memory import memory
from taskflow.persistence import flowdetail
from taskflow.persistence import logbook
from taskflow.persistence import taskdetail
from taskflow.utils import LockingDict
LOG = logging.getLogger(__name__)
logbooks = LockingDict()
flowdetails = LockingDict()
taskdetails = LockingDict()
"""
LOGBOOK
"""
def logbook_create(name, lb_id=None):
"""Creates a new LogBook model with matching lb_id"""
# Create the LogBook model
lb = memory.MemoryLogBook(name, lb_id)
# Store it in the LockingDict for LogBooks
logbooks[lb_id] = lb
def logbook_destroy(lb_id):
"""Deletes the LogBook model with matching lb_id"""
# Try deleting the LogBook
try:
del logbooks[lb_id]
# Raise a NotFound error if the LogBook doesn't exist
except KeyError:
raise exception.NotFound("No Logbook found with id "
"%s." % (lb_id,))
def logbook_save(lb):
"""Saves a generic LogBook object to the db"""
# Create a LogBook model if one doesn't exist
if not _logbook_exists(lb.uuid):
logbook_create(lb.name, lb.uuid)
# Get a copy of the LogBook model in the LockingDict
ld_lb = logbook_get(lb.uuid)
for fd in lb:
# Save each FlowDetail the LogBook to save has
fd.save()
# Add the FlowDetail to the LogBook model if not already there
if fd not in ld_lb:
logbook_add_flow_detail(lb.uuid, fd.uuid)
def logbook_delete(lb):
"""Deletes a LogBook from db based on a generic type"""
# Try to get the LogBook
try:
ld_lb = logbooks[lb.uuid]
# Raise a NotFound exception if the LogBook cannot be found
except KeyError:
raise exception.NotFound("No Logbook found with id "
"%s." % (lb.uuid,))
# Raise an error if the LogBook still has FlowDetails
if len(ld_lb):
raise exception.Error("Logbook <%s> still has "
"dependents." % (lb.uuid,))
# Destroy the LogBook model if it is safe
else:
logbook_destroy(lb.uuid)
def logbook_get(lb_id):
"""Gets a LogBook with matching lb_id, if it exists"""
# Try to get the LogBook
try:
ld_lb = logbooks[lb_id]
# Raise a NotFound exception if the LogBook is not there
except KeyError:
raise exception.NotFound("No Logbook found with id "
"%s." % (lb_id,))
# Acquire a read lock on the LogBook
with ld_lb.acquire_lock(read=True):
# Create a generic type LogBook to return
retVal = logbook.LogBook(ld_lb.name, ld_lb.uuid)
# Attach the appropriate generic FlowDetails to the generic LogBook
for fd in ld_lb:
retVal.add_flow_detail(flowdetail_get(fd.uuid))
return retVal
def logbook_add_flow_detail(lb_id, fd_id):
"""Adds a FlowDetail with id fd_id to a LogBook with id lb_id"""
# Try to get the LogBook
try:
ld_lb = logbooks[lb_id]
# Raise a NotFound exception if the LogBook is not there
except KeyError:
raise exception.NotFound("No Logbook found with id "
"%s." % (lb_id,))
# Try to get the FlowDetail to add
try:
ld_fd = flowdetails[fd_id]
# Raise a NotFound exception if the FlowDetail is not there
except KeyError:
raise exception.NotFound("No FlowDetail found with id "
"%s." % (fd_id,))
# Acquire a write lock on the LogBook
with ld_lb.acquire_lock(read=False):
# Add the FlowDetail model to the LogBook model
ld_lb.add_flow_detail(ld_fd)
def logbook_remove_flowdetail(lb_id, fd_id):
"""Removes a FlowDetail with id fd_id from a LogBook with id lb_id"""
# Try to get the LogBook
try:
ld_lb = logbooks[lb_id]
# Raise a NotFound exception if it is not there
except KeyError:
raise exception.NotFound("No Logbook found with id "
"%s." % (lb_id,))
# Try to get the FlowDetail to remove
try:
ld_fd = flowdetails[fd_id]
# Raise a NotFound exception if it is not there
except KeyError:
raise exception.NotFound("No FlowDetail found with id "
"%s." % (fd_id,))
# Acquire a write lock on the LogBook model
with ld_lb.acquire_lock(read=False):
# Remove the FlowDetail from the LogBook model
ld_lb.remove_flow_detail(ld_fd)
def logbook_get_ids_names():
"""Returns all LogBook ids and names"""
lb_ids = []
lb_names = []
# Iterate through the LockingDict and append to the Lists
for (k, v) in logbooks.items():
lb_ids.append(k)
lb_names.append(v.name)
# Return a dict of the ids and names
return dict(zip(lb_ids, lb_names))
def _logbook_exists(lb_id, session=None):
"""Check if a LogBook with lb_id exists"""
return lb_id in logbooks.keys()
"""
FLOWDETAIL
"""
def flowdetail_create(name, wf, fd_id=None):
"""Create a new FlowDetail model with matching fd_id"""
# Create a FlowDetail model to save
fd = memory.MemoryFlowDetail(name, wf, fd_id)
#Save the FlowDetail model to the LockingDict
flowdetails[fd_id] = fd
def flowdetail_destroy(fd_id):
"""Deletes the FlowDetail model with matching fd_id"""
# Try to delete the FlowDetail model
try:
del flowdetails[fd_id]
# Raise a NotFound exception if the FlowDetail is not there
except KeyError:
raise exception.NotFound("No FlowDetail found with id "
"%s." % (fd_id,))
def flowdetail_save(fd):
"""Saves a generic FlowDetail object to the db"""
# Create a FlowDetail model if one does not exist
if not _flowdetail_exists(fd.uuid):
flowdetail_create(fd.name, fd.flow, fd.uuid)
# Get a copy of the FlowDetail model in the LockingDict
ld_fd = flowdetail_get(fd.uuid)
for td in fd:
# Save the TaskDetails in the FlowDetail to save
td.save()
# Add the TaskDetail model to the FlowDetail model if it is not there
if td not in ld_fd:
flowdetail_add_task_detail(fd.uuid, td.uuid)
def flowdetail_delete(fd):
"""Deletes a FlowDetail from db based on a generic type"""
# Try to get the FlowDetails
try:
ld_fd = flowdetails[fd.uuid]
# Raise a NotFound exception if the FlowDetail is not there
except KeyError:
raise exception.NotFound("No FlowDetail found with id "
"%s." % (fd.uuid,))
# Raise an error if the FlowDetail still has TaskDetails
if len(ld_fd):
raise exception.Error("FlowDetail <%s> still has "
"dependents." % (fd.uuid,))
# If it is safe, delete the FlowDetail model
else:
flowdetail_destroy(fd.uuid)
def flowdetail_get(fd_id):
"""Gets a FlowDetail with matching fd_id, if it exists"""
# Try to get the FlowDetail
try:
fd = flowdetails[fd_id]
# Raise a NotFound exception if it is not there
except KeyError:
raise exception.NotFound("No FlowDetail found with id "
"%s." % (fd_id,))
# Acquire a read lock on the FlowDetail
with fd.acquire_lock(read=True):
# Get the Flow this FlowDetail represents
wf = fd.flow
# Create a FlowDetail to return
retVal = flowdetail.FlowDetail(fd.name, wf, fd.uuid)
# Change updated_at to reflect the current data
retVal.updated_at = fd.updated_at
# Add the generic TaskDetails to the FlowDetail to return
for td in fd:
retVal.add_task_detail(taskdetail_get(td.uuid))
return retVal
def flowdetail_add_task_detail(fd_id, td_id):
"""Adds a TaskDetail with id td_id to a Flowdetail with id fd_id"""
# Try to get the FlowDetail
try:
fd = flowdetails[fd_id]
# Raise a NotFound exception if it is not there
except KeyError:
raise exception.NotFound("No FlowDetail found with id "
"%s." % (fd_id,))
# Try to get the TaskDetail to add
try:
td = taskdetails[td_id]
# Raise a NotFound exception if it is not there
except KeyError:
raise exception.NotFound("No TaskDetail found with id "
"%s." % (td_id,))
# Acquire a write lock on the FlowDetail model
with fd.acquire_lock(read=False):
# Add the TaskDetail to the FlowDetail model
fd.add_task_detail(td)
def flowdetail_remove_taskdetail(fd_id, td_id):
"""Removes a TaskDetail with id td_id from a FlowDetail with id fd_id"""
# Try to get the FlowDetail
try:
fd = flowdetails[fd_id]
# Raise a NotFound exception if it is not there
except KeyError:
raise exception.NotFound("No FlowDetail found with id "
"%s." % (fd_id,))
# Try to get the TaskDetail to remove
try:
td = taskdetails[td_id]
# Raise a NotFound exception if it is not there
except KeyError:
raise exception.NotFound("No TaskDetail found with id "
"%s." % (td_id,))
# Acquire a write lock on the FlowDetail
with fd.acquire_lock(read=False):
# Remove the TaskDetail model from the FlowDetail model
fd.remove_task_detail(td)
def flowdetail_get_ids_names():
"""Returns all FlowDetail ids and names"""
fd_ids = []
fd_names = []
# Iterate through the LockingDict and append to lists
for (k, v) in flowdetails.items():
fd_ids.append(k)
fd_names.append(v.name)
# Return a dict of the uuids and names
return dict(zip(fd_ids, fd_names))
def _flowdetail_exists(fd_id):
"""Checks if a FlowDetail with fd_id exists"""
return fd_id in flowdetails.keys()
"""
TASKDETAIL
"""
def taskdetail_create(name, tsk, td_id=None):
"""Create a new TaskDetail model with matching td_id"""
# Create a TaskDetail model to save
td = memory.MemoryTaskDetail(name, tsk, td_id)
# Save the TaskDetail model to the LockingDict
taskdetails[td_id] = td
def taskdetail_destroy(td_id):
"""Deletes the TaskDetail model with matching td_id"""
# Try to delete the TaskDetails
try:
del taskdetails[td_id]
# Raise a NotFound exception if it is not there
except KeyError:
raise exception.NotFound("No TaskDetail found with id "
"%s." % (td_id,))
def taskdetail_save(td):
"""Saves a generic TaskDetail object to the db"""
# Create a TaskDetail model if it doesn't exist
if not _taskdetail_exists(td.uuid):
taskdetail_create(td.name, td.task, td.uuid)
# Prepare values for updating
values = dict(state=td.state,
results=td.results,
exception=td.exception,
stacktrace=td.stacktrace,
meta=td.meta)
# Update the values of the TaskDetail model
taskdetail_update(td.uuid, values)
def taskdetail_delete(td):
"""Deletes a TaskDetail from db based on a generic type"""
# Destroy the TaskDetail model
taskdetail_destroy(td.uuid)
def taskdetail_get(td_id):
"""Gets a TaskDetail with matching td_id, if it exists"""
# Try to get the TaskDetail
try:
ld_td = taskdetails[td_id]
# Raise NotFound exception if it is not there
except KeyError:
raise exception.NotFound("No TaskDetail found with id "
"%s." % (td_id,))
# Acquire a read lock
with ld_td.acquire_lock(read=True):
# Get the Task this TaskDetail represents
tsk = ld_td.task
# Update TaskDetail to return
retVal = taskdetail.TaskDetail(ld_td.name, tsk, ld_td.uuid)
retVal.updated_at = ld_td.updated_at
retVal.state = ld_td.state
retVal.results = ld_td.results
retVal.exception = ld_td.exception
retVal.stacktrace = ld_td.stacktrace
retVal.meta = ld_td.meta
return retVal
def taskdetail_update(td_id, values):
"""Updates a TaskDetail with matching td_id"""
# Try to get the TaskDetail
try:
ld_td = taskdetails[td_id]
# Raise a NotFound exception if it is not there
except KeyError:
raise exception.NotFound("No TaskDetail found with id "
"%s." % (td_id,))
# Acquire a write lock for the TaskDetail
with ld_td.acquire_lock(read=False):
# Write the values to the TaskDetail
for k, v in values.iteritems():
setattr(ld_td, k, v)
def taskdetail_get_ids_names():
"""Returns all TaskDetail ids and names"""
td_ids = []
td_names = []
# Iterate through the LockingDict and append to Lists
for (k, v) in taskdetails.items():
td_ids.append(k)
td_names.append(v.name)
# Return a dict of uuids and names
return dict(zip(td_ids, td_names))
def _taskdetail_exists(td_id, session=None):
"""Check if a TaskDetail with td_id exists"""
return td_id in taskdetails.keys()