10 from account import Account
12 import plnode.bwlimit as bwlimit
16 libvirt.VIR_DOMAIN_NOSTATE: 'no state',
17 libvirt.VIR_DOMAIN_RUNNING: 'running',
18 libvirt.VIR_DOMAIN_BLOCKED: 'blocked on resource',
19 libvirt.VIR_DOMAIN_PAUSED: 'paused by user',
20 libvirt.VIR_DOMAIN_SHUTDOWN: 'being shut down',
21 libvirt.VIR_DOMAIN_SHUTOFF: 'shut off',
22 libvirt.VIR_DOMAIN_CRASHED: 'crashed',
29 class Sliver_Libvirt(Account):
34 def getConnection(sliver_type):
35 # TODO: error checking
36 # vtype is of the form sliver.[LXC/QEMU] we need to lower case to lxc/qemu
37 vtype = sliver_type.split('.')[1].lower()
39 return connections.setdefault(uri, libvirt.open(uri))
43 ''' Helper method to get a "nice" output of the info struct for debug'''
44 [state, maxmem, mem, ncpu, cputime] = dom.info()
45 return '%s is %s, maxmem = %s, mem = %s, ncpu = %s, cputime = %s' % (dom.name(), STATES.get(state, state), maxmem, mem, ncpu, cputime)
47 def __init__(self, rec):
48 self.name = rec['name']
49 logger.verbose ('sliver_libvirt: %s init'%(self.name))
51 # Assume the directory with the image and config files
56 self.slice_id = rec['slice_id']
58 self.conn = Sliver_Libvirt.getConnection(rec['type'])
59 self.xid = bwlimit.get_xid(self.name)
63 dom = self.conn.lookupByName(self.name)
65 logger.log('sliver_libvirt: Domain %s does not exist. ' \
66 'Will try to create it again.' % (self.name))
67 self.__class__.create(rec['name'], rec)
68 dom = self.conn.lookupByName(self.name)
71 def start(self, delay=0):
72 ''' Just start the sliver '''
73 logger.verbose('sliver_libvirt: %s start'%(self.name))
75 # Check if it's running to avoid throwing an exception if the
76 # domain was already running, create actually means start
77 if not self.is_running():
80 logger.verbose('sliver_libvirt: sliver %s already started'%(self.name))
82 # After the VM is started... we can play with the virtual interface
83 # Create the ebtables rule to mark the packets going out from the virtual
84 # interface to the actual device so the filter canmatch against the mark
85 bwlimit.ebtables("-A INPUT -i veth%d -j mark --set-mark %d" % \
89 logger.verbose('sliver_libvirt: %s stop'%(self.name))
91 # Remove the ebtables rule before stopping
92 bwlimit.ebtables("-D INPUT -i veth%d -j mark --set-mark %d" % \
98 logger.verbose('sliver_libvirt: Domain %s not running ' \
99 'UNEXPECTED: %s'%(self.name, sys.exc_info()[1]))
100 print 'sliver_libvirt: Domain %s not running ' \
101 'UNEXPECTED: %s'%(self.name, sys.exc_info()[1])
103 def is_running(self):
104 ''' Return True if the domain is running '''
105 logger.verbose('sliver_libvirt: %s is_running'%self.name)
107 [state, _, _, _, _] = self.dom.info()
108 if state == libvirt.VIR_DOMAIN_RUNNING:
109 logger.verbose('sliver_libvirt: %s is RUNNING'%self.name)
112 info = debuginfo(self.dom)
113 logger.verbose('sliver_libvirt: %s is ' \
114 'NOT RUNNING...\n%s'%(self.name, info))
117 logger.verbose('sliver_libvirt: UNEXPECTED ERROR in ' \
118 '%s: %s'%(self.name, sys.exc_info()[1]))
119 print 'sliver_libvirt: UNEXPECTED ERROR in ' \
120 '%s: %s'%(self.name, sys.exc_info()[1])
123 def configure(self, rec):
125 #sliver.[LXC/QEMU] tolower case
126 #sliver_type = rec['type'].split('.')[1].lower()
128 #BASE_DIR = '/cgroup/libvirt/%s/%s/'%(sliver_type, self.name)
131 # No way through cgroups... figure out how to do that with user/dir quotas.
132 # There is no way to do quota per directory. Chown-ing would create
133 # problems as username namespaces are not yet implemented (and thus, host
134 # and containers share the same name ids
136 # Btrfs support quota per volumes
138 # It will depend on the FS selection
139 if rec.has_key('disk_max'):
140 disk_max = rec['disk_max']
145 # limit to certain number
149 if rec.has_key('memlock_hard'):
150 mem = rec['memlock_hard'] * 1024 # hard limit in bytes
151 cgroups.write(self.name, 'memory.limit_in_bytes', mem)
152 if rec.has_key('memlock_soft'):
153 mem = rec['memlock_soft'] * 1024 # soft limit in bytes
154 cgroups.write(self.name, 'memory.soft_limit_in_bytes', mem)
157 # Only cpu_shares until figure out how to provide limits and guarantees
159 if rec.has_key('cpu_share'):
160 cpu_share = rec['cpu_share']
161 cgroups.write(self.name, 'cpu.shares', cpu_share)
163 # Call the upper configure method (ssh keys...)
164 Account.configure(self, rec)