checked in initial versions
[sfa.git] / util / record.py
1 # record.py
2 #
3 # implements support for geni records
4 #
5 # TODO: Use existing PLC database methods? or keep this separate?
6
7 from pg import DB
8
9 # Record is a tuple (Name, GID, Type, Info)
10 #    info is implemented as a pointer to a PLC record
11 #    privkey is stored for convenience on the registry for entities which
12 #        the registry holds their private keys
13
14 class GeniRecord():
15     def __init__(self, name=None, gid=None, type=None, pointer=None, privkey=None, dict=None):
16         self.dirty=True
17         if name:
18             self.set_name(name)
19         if gid:
20             self.set_gid(gid)
21         if type:
22             self.set_type(type)
23         if pointer:
24             self.set_pointer(pointer)
25         if privkey:
26             self.set_privkey(privkey)
27         if dict:
28             self.set_name(dict['name'])
29             self.set_gid(dict['gid'])
30             self.set_type(dict['type'])
31             self.set_pointer(dict['pointer'])
32             self.set_privkey(dict['privkey'])
33
34     def set_name(self, name):
35         self.name = name
36         self.dirty = True
37
38     def set_gid(self, gid):
39         self.gid = gid
40         self.dirty = True
41
42     def set_type(self, type):
43         self.type = type
44         self.dirty = True
45
46     def set_pointer(self, pointer):
47         self.pointer = pointer
48         self.dirty = True
49
50     def set_privkey(self, privkey):
51         self.privkey = privkey
52         self.dirty = True
53
54     def get_key(self):
55         return self.name + "#" + self.type
56
57     def get_field_names(self):
58         return ["name", "gid", "type", "pointer", "privkey"]
59
60     def get_field_value_string(self, fieldname):
61         if fieldname == "key":
62             val = self.get_key()
63         else:
64             val = getattr(self, fieldname)
65         if isinstance(val, str):
66             return "'" + str(val) + "'"
67         else:
68             return str(val)
69
70     def get_field_value_strings(self, fieldnames):
71         strs = []
72         for fieldname in fieldnames:
73             strs.append(self.get_field_value_string(fieldname))
74         return strs
75
76     def as_dict(self):
77         dict = {}
78         names = self.get_field_names()
79         for name in names:
80             dict[name] = self.getattr(name)
81         return dict
82
83 # GeniTable
84 #
85 # Represents a single table on a registry for a single authority.
86
87 class GeniTable():
88     def __init__(self, create=False, hrn="unspecified.default.registry", cninfo=None, privkey=None, gid=None):
89         # XXX privkey/gid are necessary so the table can generate GIDs for its
90         #    records; might move that out of here as it doesn't seem the right place
91
92         self.hrn = hrn
93
94         # pgsql doesn't like table names with "." in them, to replace it with "$"
95         self.tablename = self.hrn.replace(".", "$")
96
97         # establish a connection to the pgsql server
98         self.cnx = DB(cninfo['dbname'], cninfo['address'], port=cninfo['port'], user=cninfo['user'], passwd=cninfo['password'])[
99
100         # the private key is necessary for creation of GIDs
101         self.privkey = privkey
102
103         self.gid = gid
104
105         # if asked to create the table, then create it
106         if create:
107             self.create()
108
109     def create(self):
110         querystr = "CREATE TABLE " + self.tablename + " ( \
111                 key text, \
112                 name text, \
113                 gid text, \
114                 type text, \
115                 privkey text, \
116                 pointer integer);"
117
118         self.cnx.query('DROP TABLE IF EXISTS ' + self.tablename)
119         self.cnx.query(querystr)
120
121     def insert(self, record):
122         fieldnames = ["key"] + record.get_field_names()
123         fieldvals = record.get_field_value_strings(fieldnames)
124         query_str = "INSERT INTO " + self.tablename + \
125                        "(" + ",".join(fieldnames) + ") " + \
126                        "VALUES(" + ",".join(fieldvals) + ")"
127         #print query_str
128         self.cnx.query(query_str)
129
130     def update(self, record):
131         names = record.get_field_names()
132         pairs = []
133         for name in names:
134            val = record.get_field_value_string(name)
135            pairs.append(name + " = " + val)
136         update = ", ".join(pairs)
137
138         query_str = "UPDATE " + self.tablename+ " SET " + update + " WHERE key = '" + record.get_key() + "'"
139         #print query_str
140         self.cnx.query(query_str)
141
142     def resolve_raw(self, type, hrn):
143         query_str = "SELECT * FROM " + self.tablename + " WHERE name = '" + hrn + "'"
144         dict_list = self.cnx.query(query_str).dictresult()
145         result_dict_list = []
146         for dict in dict_list:
147            if (type=="*") or (dict['type'] == type):
148                result_dict_list.append(dict)
149         return result_dict_list
150
151     def resolve(self, type, hrn):
152         result_dict_list = self.resolve_raw(type, hrn)
153         result_rec_list = []
154         for dict in result_dict_list:
155             result_rec_list.append(GeniRecord(dict=dict))
156         return result_rec_list
157
158     def create_gid(self, hrn, uuid, pubkey):
159         gid = GID(subject=hrn, uuid=uuid, hrn=hrn)
160         gid.set_pubkey(pubkey)
161         gid.set_issuer(key=self.privkey, subject=self.hrn)
162         gid.set_parent(self.gid)
163         gid.encode()
164         gid.sign()
165
166         return gid
167
168     def update_gid(self, record)
169         old_gid = GID(string = record.get_gid())
170         pubkey = old_gid.get_pubkey()
171
172         gid = self.create_gid(old_gid.get_hrn(), old_gid.get_uuid(), old_gid.get_pubkey())
173
174         record.set_gid(gid.save_to_string())
175