]>
git.proxmox.com Git - ovs.git/blob - ovsdb/OVSDB.py
3 class Error(Exception):
4 def __init__(self
, msg
):
5 Exception.__init
__(self
)
8 def getMember(json
, name
, validTypes
, description
, default
=None):
11 if len(validTypes
) and type(member
) not in validTypes
:
12 raise Error("%s: type mismatch for '%s' member"
13 % (description
, name
))
17 def mustGetMember(json
, name
, expectedType
, description
):
18 member
= getMember(json
, name
, expectedType
, description
)
20 raise Error("%s: missing '%s' member" % (description
, name
))
24 def __init__(self
, name
, tables
):
30 name
= mustGetMember(json
, 'name', [unicode], 'database')
31 tablesJson
= mustGetMember(json
, 'tables', [dict], 'database')
33 for tableName
, tableJson
in tablesJson
.iteritems():
34 tables
[tableName
] = TableSchema
.fromJson(tableJson
,
35 "%s table" % tableName
)
36 return DbSchema(name
, tables
)
38 class IdlSchema(DbSchema
):
39 def __init__(self
, name
, tables
, idlPrefix
, idlHeader
):
40 DbSchema
.__init
__(self
, name
, tables
)
41 self
.idlPrefix
= idlPrefix
42 self
.idlHeader
= idlHeader
46 schema
= DbSchema
.fromJson(json
)
47 idlPrefix
= mustGetMember(json
, 'idlPrefix', [unicode], 'database')
48 idlHeader
= mustGetMember(json
, 'idlHeader', [unicode], 'database')
49 return IdlSchema(schema
.name
, schema
.tables
, idlPrefix
, idlHeader
)
52 def __init__(self
, columns
):
53 self
.columns
= columns
56 def fromJson(json
, description
):
57 columnsJson
= mustGetMember(json
, 'columns', [dict], description
)
59 for name
, json
in columnsJson
.iteritems():
60 columns
[name
] = ColumnSchema
.fromJson(
61 json
, "column %s in %s" % (name
, description
))
62 return TableSchema(columns
)
65 def __init__(self
, type, persistent
):
67 self
.persistent
= persistent
70 def fromJson(json
, description
):
71 type = Type
.fromJson(mustGetMember(json
, 'type', [dict, unicode],
73 'type of %s' % description
)
74 ephemeral
= getMember(json
, 'ephemeral', [bool], description
)
75 persistent
= ephemeral
!= True
76 return ColumnSchema(type, persistent
)
78 def escapeCString(src
):
99 dst
+= '\\%03o' % ord(c
)
104 def returnUnchanged(x
):
109 uuidRE
= re
.compile("^(%s{8})-(%s{4})-(%s{4})-(%s{4})-(%s{4})(%s{8})$"
110 % (x
, x
, x
, x
, x
, x
))
112 def __init__(self
, value
):
117 if not uuidRE
.match(s
):
118 raise Error("%s is not a valid UUID" % s
)
123 if UUID
.isValidJson(json
):
126 raise Error("%s is not valid JSON for a UUID" % json
)
129 def isValidJson(json
):
130 return len(json
) == 2 and json
[0] == "uuid" and uuidRE
.match(json
[1])
133 return ["uuid", self
.value
]
135 def cInitUUID(self
, var
):
136 m
= re
.match(self
.value
)
137 return ["%s.parts[0] = 0x%s;" % (var
, m
.group(1)),
138 "%s.parts[1] = 0x%s%s;" % (var
, m
.group(2), m
.group(3)),
139 "%s.parts[2] = 0x%s%s;" % (var
, m
.group(4), m
.group(5)),
140 "%s.parts[3] = 0x%s;" % (var
, m
.group(6))]
143 def __init__(self
, type, value
):
148 def fromJson(type_
, json
):
149 if ((type_
== 'integer' and type(json
) in [int, long])
150 or (type_
== 'real' and type(json
) in [int, long, float])
151 or (type_
== 'boolean' and json
in [True, False])
152 or (type_
== 'string' and type(json
) in [str, unicode])):
153 return Atom(type_
, json
)
154 elif type_
== 'uuid':
155 return UUID
.fromJson(json
)
157 raise Error("%s is not valid JSON for type %s" % (json
, type_
))
160 if self
.type == 'uuid':
161 return self
.value
.toString()
165 def cInitAtom(self
, var
):
166 if self
.type == 'integer':
167 return ['%s.integer = %d;' % (var
, self
.value
)]
168 elif self
.type == 'real':
169 return ['%s.real = %.15g;' % (var
, self
.value
)]
170 elif self
.type == 'boolean':
172 return ['%s.boolean = true;']
174 return ['%s.boolean = false;']
175 elif self
.type == 'string':
176 return ['%s.string = xstrdup("%s");'
177 % (var
, escapeCString(self
.value
))]
178 elif self
.type == 'uuid':
179 return self
.value
.cInitUUID(var
)
181 def toEnglish(self
, escapeLiteral
=returnUnchanged
):
182 if self
.type == 'integer':
183 return '%d' % self
.value
184 elif self
.type == 'real':
185 return '%.15g' % self
.value
186 elif self
.type == 'boolean':
191 elif self
.type == 'string':
192 return escapeLiteral(self
.value
)
193 elif self
.type == 'uuid':
194 return self
.value
.value
196 # Returns integer x formatted in decimal with thousands set off by commas.
198 return _commafy("%d" % x
)
200 if s
.startswith('-'):
201 return '-' + _commafy(s
[1:])
205 return _commafy(s
[:-3]) + ',' + _commafy(s
[-3:])
208 def __init__(self
, type,
210 refTable
=None, refType
="strong",
211 minInteger
=None, maxInteger
=None,
212 minReal
=None, maxReal
=None,
213 minLength
=None, maxLength
=None):
216 self
.refTable
= refTable
217 self
.refType
= refType
218 self
.minInteger
= minInteger
219 self
.maxInteger
= maxInteger
220 self
.minReal
= minReal
221 self
.maxReal
= maxReal
222 self
.minLength
= minLength
223 self
.maxLength
= maxLength
226 def fromJson(json
, description
):
227 if type(json
) == unicode:
228 return BaseType(json
)
230 atomicType
= mustGetMember(json
, 'type', [unicode], description
)
231 enum
= getMember(json
, 'enum', [], description
)
233 enumType
= Type(atomicType
, None, 0, 'unlimited')
234 enum
= Datum
.fromJson(enumType
, enum
)
235 refTable
= getMember(json
, 'refTable', [unicode], description
)
236 refType
= getMember(json
, 'refType', [unicode], description
)
239 minInteger
= getMember(json
, 'minInteger', [int, long], description
)
240 maxInteger
= getMember(json
, 'maxInteger', [int, long], description
)
241 minReal
= getMember(json
, 'minReal', [int, long, float], description
)
242 maxReal
= getMember(json
, 'maxReal', [int, long, float], description
)
243 minLength
= getMember(json
, 'minLength', [int], description
)
244 maxLength
= getMember(json
, 'minLength', [int], description
)
245 return BaseType(atomicType
, enum
, refTable
, refType
, minInteger
, maxInteger
, minReal
, maxReal
, minLength
, maxLength
)
247 def toEnglish(self
, escapeLiteral
=returnUnchanged
):
248 if self
.type == 'uuid' and self
.refTable
:
249 s
= escapeLiteral(self
.refTable
)
250 if self
.refType
== 'weak':
251 s
= "weak reference to " + s
256 def constraintsToEnglish(self
, escapeLiteral
=returnUnchanged
):
258 literals
= [value
.toEnglish(escapeLiteral
)
259 for value
in self
.enum
.values
]
260 if len(literals
) == 2:
261 return 'either %s or %s' % (literals
[0], literals
[1])
263 return 'one of %s, %s, or %s' % (literals
[0],
264 ', '.join(literals
[1:-1]),
266 elif self
.minInteger
!= None and self
.maxInteger
!= None:
267 return 'in range %s to %s' % (commafy(self
.minInteger
),
268 commafy(self
.maxInteger
))
269 elif self
.minInteger
!= None:
270 return 'at least %s' % commafy(self
.minInteger
)
271 elif self
.maxInteger
!= None:
272 return 'at most %s' % commafy(self
.maxInteger
)
273 elif self
.minReal
!= None and self
.maxReal
!= None:
274 return 'in range %g to %g' % (self
.minReal
, self
.maxReal
)
275 elif self
.minReal
!= None:
276 return 'at least %g' % self
.minReal
277 elif self
.maxReal
!= None:
278 return 'at most %g' % self
.maxReal
279 elif self
.minLength
!= None and self
.maxLength
!= None:
280 if self
.minLength
== self
.maxLength
:
281 return 'exactly %d characters long' % (self
.minLength
)
283 return 'between %d and %d characters long' % (self
.minLength
, self
.maxLength
)
284 elif self
.minLength
!= None:
285 return 'at least %d characters long' % self
.minLength
286 elif self
.maxLength
!= None:
287 return 'at most %d characters long' % self
.maxLength
291 def toCType(self
, prefix
):
293 return "struct %s%s *" % (prefix
, self
.refTable
.lower())
295 return {'integer': 'int64_t ',
297 'uuid': 'struct uuid ',
299 'string': 'char *'}[self
.type]
301 def toAtomicType(self
):
302 return "OVSDB_TYPE_%s" % self
.type.upper()
304 def copyCValue(self
, dst
, src
):
305 args
= {'dst': dst
, 'src': src
}
307 return ("%(dst)s = %(src)s->header_.uuid;") % args
308 elif self
.type == 'string':
309 return "%(dst)s = xstrdup(%(src)s);" % args
311 return "%(dst)s = %(src)s;" % args
313 def initCDefault(self
, var
, isOptional
):
315 return "%s = NULL;" % var
316 elif self
.type == 'string' and not isOptional
:
317 return "%s = \"\";" % var
319 return {'integer': '%s = 0;',
321 'uuid': 'uuid_zero(&%s);',
322 'boolean': '%s = false;',
323 'string': '%s = NULL;'}[self
.type] % var
325 def cInitBaseType(self
, indent
, var
):
327 stmts
.append('ovsdb_base_type_init(&%s, OVSDB_TYPE_%s);' % (
328 var
, self
.type.upper()),)
330 stmts
.append("%s.enum_ = xmalloc(sizeof *%s.enum_);"
332 stmts
+= self
.enum
.cInitDatum("%s.enum_" % var
)
333 if self
.type == 'integer':
334 if self
.minInteger
!= None:
335 stmts
.append('%s.u.integer.min = INT64_C(%d);' % (var
, self
.minInteger
))
336 if self
.maxInteger
!= None:
337 stmts
.append('%s.u.integer.max = INT64_C(%d);' % (var
, self
.maxInteger
))
338 elif self
.type == 'real':
339 if self
.minReal
!= None:
340 stmts
.append('%s.u.real.min = %d;' % (var
, self
.minReal
))
341 if self
.maxReal
!= None:
342 stmts
.append('%s.u.real.max = %d;' % (var
, self
.maxReal
))
343 elif self
.type == 'string':
344 if self
.minLength
!= None:
345 stmts
.append('%s.u.string.minLen = %d;' % (var
, self
.minLength
))
346 if self
.maxLength
!= None:
347 stmts
.append('%s.u.string.maxLen = %d;' % (var
, self
.maxLength
))
348 elif self
.type == 'uuid':
349 if self
.refTable
!= None:
350 stmts
.append('%s.u.uuid.refTableName = "%s";' % (var
, escapeCString(self
.refTable
)))
351 return '\n'.join([indent
+ stmt
for stmt
in stmts
])
354 def __init__(self
, key
, value
=None, min=1, max=1):
361 def fromJson(json
, description
):
362 if type(json
) == unicode:
363 return Type(BaseType(json
))
365 keyJson
= mustGetMember(json
, 'key', [dict, unicode], description
)
366 key
= BaseType
.fromJson(keyJson
, 'key in %s' % description
)
368 valueJson
= getMember(json
, 'value', [dict, unicode], description
)
370 value
= BaseType
.fromJson(valueJson
,
371 'value in %s' % description
)
375 min = getMember(json
, 'min', [int], description
, 1)
376 max = getMember(json
, 'max', [int, unicode], description
, 1)
377 return Type(key
, value
, min, max)
380 return self
.min == 1 and self
.max == 1 and not self
.value
382 def isOptional(self
):
383 return self
.min == 0 and self
.max == 1
385 def isOptionalPointer(self
):
386 return (self
.min == 0 and self
.max == 1 and not self
.value
387 and (self
.key
.type == 'string' or self
.key
.refTable
))
389 def toEnglish(self
, escapeLiteral
=returnUnchanged
):
390 keyName
= self
.key
.toEnglish(escapeLiteral
)
392 valueName
= self
.value
.toEnglish(escapeLiteral
)
396 elif self
.isOptional():
398 return "optional %s-%s pair" % (keyName
, valueName
)
400 return "optional %s" % keyName
402 if self
.max == "unlimited":
404 quantity
= "%d or more " % self
.min
408 quantity
= "%d to %d " % (self
.min, self
.max)
410 quantity
= "up to %d " % self
.max
413 return "map of %s%s-%s pairs" % (quantity
, keyName
, valueName
)
415 if keyName
.endswith('s'):
416 plural
= keyName
+ "es"
418 plural
= keyName
+ "s"
419 return "set of %s%s" % (quantity
, plural
)
421 def constraintsToEnglish(self
, escapeLiteral
=returnUnchanged
):
425 keyConstraints
= self
.key
.constraintsToEnglish(escapeLiteral
)
428 constraints
+= ['key ' + keyConstraints
]
430 constraints
+= [keyConstraints
]
433 valueConstraints
= self
.value
.constraintsToEnglish(escapeLiteral
)
435 constraints
+= ['value ' + valueConstraints
]
437 return ', '.join(constraints
)
439 def cDeclComment(self
):
440 if self
.min == 1 and self
.max == 1 and self
.key
.type == "string":
441 return "\t/* Always nonnull. */"
445 def cInitType(self
, indent
, var
):
446 initKey
= self
.key
.cInitBaseType(indent
, "%s.key" % var
)
448 initValue
= self
.value
.cInitBaseType(indent
, "%s.value" % var
)
450 initValue
= ('%sovsdb_base_type_init(&%s.value, '
451 'OVSDB_TYPE_VOID);' % (indent
, var
))
452 initMin
= "%s%s.n_min = %s;" % (indent
, var
, self
.min)
453 if self
.max == "unlimited":
457 initMax
= "%s%s.n_max = %s;" % (indent
, var
, max)
458 return "\n".join((initKey
, initValue
, initMin
, initMax
))
461 def __init__(self
, type, values
):
466 def fromJson(type_
, json
):
468 if len(json
) == 2 and json
[0] == "set":
470 for atomJson
in json
[1]:
471 values
+= [Atom
.fromJson(type_
.key
, atomJson
)]
473 values
= [Atom
.fromJson(type_
.key
, json
)]
475 if len(json
) != 2 or json
[0] != "map":
476 raise Error("%s is not valid JSON for a map" % json
)
478 for pairJson
in json
[1]:
479 values
+= [(Atom
.fromJson(type_
.key
, pairJson
[0]),
480 Atom
.fromJson(type_
.value
, pairJson
[1]))]
481 return Datum(type_
, values
)
483 def cInitDatum(self
, var
):
484 if len(self
.values
) == 0:
485 return ["ovsdb_datum_init_empty(%s);" % var
]
487 s
= ["%s->n = %d;" % (var
, len(self
.values
))]
488 s
+= ["%s->keys = xmalloc(%d * sizeof *%s->keys);"
489 % (var
, len(self
.values
), var
)]
491 for i
in range(len(self
.values
)):
495 s
+= key
.cInitAtom("%s->keys[%d]" % (var
, i
))
498 s
+= ["%s->values = xmalloc(%d * sizeof *%s->values);"
499 % (var
, len(self
.values
), var
)]
500 for i
in range(len(self
.values
)):
501 value
= self
.values
[i
][1]
502 s
+= key
.cInitAtom("%s->values[%d]" % (var
, i
))
504 s
+= ["%s->values = NULL;" % var
]
506 if len(self
.values
) > 1:
507 s
+= ["ovsdb_datum_sort_assert(%s, OVSDB_TYPE_%s);"
508 % (var
, self
.type.key
.upper())]