summaryrefslogtreecommitdiffstats
path: root/cobbler/modules/serializer_shelve.py
blob: 09495dd57401a640840fdae0be276eb31294baaa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
"""
Serializer code for cobbler

Copyright 2007, Red Hat, Inc
Michael DeHaan <mdehaan@redhat.com>

NOTE: as it stands, the performance of this serializer is not great
      nor has it been throughly tested.  It is, however, about 4x faster 
      than the YAML version.  It could be optimized further.

This software may be freely redistributed under the terms of the GNU
general public license.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
"""

## FIXME: serializer needs a close() call
## FIXME: investigate locking

import distutils.sysconfig
import os
import sys
import glob
import traceback
from utils import _
import os
import shelve
import time
#import gdbm # FIXME: check if available in EL4?
import bsddb

plib = distutils.sysconfig.get_python_lib()
mod_path="%s/cobbler" % plib
sys.path.insert(0, mod_path)

import cexceptions
import utils

DATABASES = {}

def open_db(collection_type):
    if DATABASES.has_key(collection_type):
        return DATABASES[collection_type]
    ending = collection_type
    if not ending.endswith("s"):
        ending = ending + "s"
    while 1:
        try:
            filename = "/var/lib/cobbler/%s.shelve" % ending

	    internal_db = bsddb.btopen( filename, 'c', 0644 )


            #internal_db = gdbm.open(filename, 'c', 0644)
            database = shelve.BsdDbShelf(internal_db)
            DATABASES[collection_type] = database
            return database
        except:
            traceback.print_exc()
            print "- can't access %s right now, waiting..." % filename
            time.sleep(1)
	    continue

def register():
    """
    The mandatory cobbler module registration hook.
    """
    return "serializer"

def serialize(obj):
    """
    Save an object to disk.  Object must "implement" Serializable.
    Will create intermediate paths if it can.  Returns True on Success,
    False on permission errors.
    """

    # FIXME: this needs to understand deletes
    # FIXME: create partial serializer and don't use this
    fd = open_db(obj.collection_type())

    for entry in obj:
        fd[entry.name] = entry.to_datastruct()
    # fd.sync()
    return True

def serialize_item(obj, item):
    fd = open_db(obj.collection_type())
    fd[item.name] = item.to_datastruct()
    # fd.sync()
    return True

# NOTE: not heavily tested
def serialize_delete(obj, item):
    fd = open_db(obj.collection_type())
    if fd.has_key(item.name):
        print "DEBUG: deleting: %s" % item.name
        del fd[item.name]
    # fd.sync()
    return True

def deserialize_raw(collection_type):
    fd = open_db(collection_type)
    datastruct = []
    # FIXME: see if we can call items() directly
    for (key,value) in fd.iteritems():
        datastruct.append(value)
    # fd.close()
    return datastruct

def deserialize(obj,topological=False):
    """
    Populate an existing object with the contents of datastruct.
    Object must "implement" Serializable.  Returns True assuming
    files could be read and contained decent YAML.  Otherwise returns
    False.
    """
    fd = open_db(obj.collection_type())

    datastruct = []
    for (key,value) in fd.iteritems():
       datastruct.append(value)

    # fd.close()

    if topological and type(datastruct) == list:
       # in order to build the graph links from the flat list, sort by the
       # depth of items in the graph.  If an object doesn't have a depth, sort it as
       # if the depth were 0.  It will be assigned a proper depth at serialization
       # time.  This is a bit cleaner implementation wise than a topological sort,
       # though that would make a shiny upgrade.
       datastruct.sort(__depth_cmp)
    obj.from_datastruct(datastruct)
    return True

def __depth_cmp(item1, item2):
    if not item1.has_key("depth"):
       return 1
    if not item2.has_key("depth"):
       return -1
    return cmp(item1["depth"],item2["depth"])