107 lines
3.9 KiB
Python
107 lines
3.9 KiB
Python
import sqlite3
|
|
import os
|
|
import time
|
|
|
|
# States:
|
|
# The cloud provider is building this machine. We have an ID, but it's
|
|
# not ready for use.
|
|
BUILDING=1
|
|
# The machine is ready for use.
|
|
READY=2
|
|
# This can mean in-use, or used but complete. We don't actually need to
|
|
# distinguish between those states -- we'll just delete a machine 24 hours
|
|
# after it transitions into the USED state.
|
|
USED=3
|
|
# An error state, should just try to delete it.
|
|
ERROR=4
|
|
|
|
# Columns:
|
|
# state: one of the above values
|
|
# state_time: the time of transition into that state
|
|
# user: set if the machine is given to a user
|
|
# id: identifier from cloud provider
|
|
# name: machine name
|
|
# ip: machine ip
|
|
# uuid: uuid from libcloud
|
|
# provider: libcloud driver for this server
|
|
# image: name of image this server is based on
|
|
|
|
class VMDatabase(object):
|
|
def __init__(self, path=os.path.expanduser("~/vm.db")):
|
|
# Set isolation_level = None, which means "autocommit" mode
|
|
# but more importantly lets you manage transactions manually
|
|
# without the isolation emulation getting in your way.
|
|
# Most of our writes can be autocomitted, and the one(s)
|
|
# that can't, we'll set up the transaction around the critical
|
|
# section.
|
|
if not os.path.exists(path):
|
|
conn = sqlite3.connect(path, isolation_level=None)
|
|
conn.execute("""create table machines
|
|
(provider text, id int, image text,
|
|
name text, ip text, uuid text,
|
|
state_time int, state int, user text)""")
|
|
del conn
|
|
self.conn = sqlite3.connect(path, isolation_level = None)
|
|
# This turns the returned rows into objects that are like lists
|
|
# and dicts at the same time:
|
|
self.conn.row_factory = sqlite3.Row
|
|
|
|
def addMachine(self, provider, mid, image, name, ip, uuid):
|
|
self.conn.execute("""insert into machines
|
|
(provider, id, image, name, ip,
|
|
uuid, state_time, state)
|
|
values (?, ?, ?, ?, ?, ?, ?, ?)""",
|
|
(provider, mid, image, name, ip, uuid,
|
|
int(time.time()), BUILDING))
|
|
|
|
def delMachine(self, uuid):
|
|
self.conn.execute("delete from machines where uuid=?", (uuid,))
|
|
|
|
def setMachineUser(self, uuid, user):
|
|
self.conn.execute("update machines set user=? where uuid=?",
|
|
(user, uuid))
|
|
|
|
def setMachineState(self, uuid, state):
|
|
self.conn.execute("""update machines set state=?, state_time=?
|
|
where uuid=?""",
|
|
(state, int(time.time()), uuid))
|
|
|
|
def getMachines(self):
|
|
return self.conn.execute("select * from machines order by state_time")
|
|
|
|
def getMachine(self, uuid):
|
|
for x in self.conn.execute("select * from machines where uuid=?",
|
|
(uuid,)):
|
|
return x
|
|
|
|
def getMachineForUse(self):
|
|
"""Atomically find a machine that is ready for use, and update
|
|
its state."""
|
|
self.conn.execute("begin exclusive transaction")
|
|
ret = None
|
|
for m in self.getMachines():
|
|
if m['state']==READY:
|
|
self.setMachineState(m['uuid'], USED)
|
|
ret = m
|
|
break
|
|
self.conn.execute("commit")
|
|
return ret
|
|
|
|
if __name__=='__main__':
|
|
db = VMDatabase("/tmp/vm.db")
|
|
db.addMachine('rackspace', 1, 'devstack', 'foo', '1.2.3.4', 'uuid1')
|
|
db.setMachineState('uuid1', READY)
|
|
db.addMachine('rackspace', 2, 'devstack', 'foo2', '1.2.3.4', 'uuid2')
|
|
db.setMachineState('uuid2', READY)
|
|
m = db.getMachineForUse()
|
|
print 'got machine'
|
|
print m
|
|
db.setMachineUser(m['uuid'], 'jeblair')
|
|
print db.getMachines()
|
|
print db.getMachine(1)
|
|
print 'waiting to delete'
|
|
time.sleep(2)
|
|
db.delMachine('uuid1')
|
|
db.delMachine('uuid2')
|
|
|