Cgroup common interface. Used by coresched.py and sliver_libvirt.py.
[nodemanager.git] / sliver_libvirt.py
1 #
2
3 """LibVirt slivers"""
4
5 import accounts
6 import logger
7 import subprocess
8 import os
9 import os.path
10 import libvirt
11 import sys
12 import shutil
13 import bwlimit
14 import cgroups
15
16 from string import Template
17
18 STATES = {
19     libvirt.VIR_DOMAIN_NOSTATE: 'no state',
20     libvirt.VIR_DOMAIN_RUNNING: 'running',
21     libvirt.VIR_DOMAIN_BLOCKED: 'blocked on resource',
22     libvirt.VIR_DOMAIN_PAUSED: 'paused by user',
23     libvirt.VIR_DOMAIN_SHUTDOWN: 'being shut down',
24     libvirt.VIR_DOMAIN_SHUTOFF: 'shut off',
25     libvirt.VIR_DOMAIN_CRASHED: 'crashed',
26 }
27
28 connections = dict()
29
30 # Helper methods
31
32 def getConnection(sliver_type):
33     # TODO: error checking
34     # vtype is of the form sliver.[LXC/QEMU] we need to lower case to lxc/qemu
35     vtype = sliver_type.split('.')[1].lower()
36     uri = vtype + '://'
37     return connections.setdefault(uri, libvirt.open(uri))
38
39 def debuginfo(dom):
40     ''' Helper method to get a "nice" output of the info struct for debug'''
41     [state, maxmem, mem, ncpu, cputime] = dom.info()
42     return '%s is %s, maxmem = %s, mem = %s, ncpu = %s, cputime = %s' % (dom.name(), STATES.get(state, state), maxmem, mem, ncpu, cputime)
43
44 # Common Libvirt code
45
46 class Sliver_Libvirt(accounts.Account):
47
48     def __init__(self, rec):
49         self.name = rec['name']
50         logger.verbose ('sliver_libvirt: %s init'%(self.name))
51          
52         # Assume the directory with the image and config files
53         # are in place
54         
55         self.keys = ''
56         self.rspec = {}
57         self.slice_id = rec['slice_id']
58         self.enabled = True
59         self.conn = getConnection(rec['type'])
60         self.xid = bwlimit.get_xid(self.name)
61         
62         try:
63             self.dom = self.conn.lookupByName(self.name)
64         except:
65             logger.verbose('sliver_libvirt: Domain %s does not exist UNEXPECTED: %s'%(self.name, sys.exc_info()[0]))
66
67
68     def start(self, delay=0):
69         ''' Just start the sliver '''
70         logger.verbose('sliver_libvirt: %s start'%(self.name))
71
72         # Check if it's running to avoid throwing an exception if the
73         # domain was already running, create actually means start
74         if not self.is_running():
75             self.dom.create()
76         else:
77             logger.verbose('sliver_libvirt: sliver %s already started'%(self.name))
78
79         # After the VM is started... we can play with the virtual interface
80         # Create the ebtables rule to mark the packets going out from the virtual
81         # interface to the actual device so the filter canmatch against the mark
82         bwlimit.ebtables("-A INPUT -i veth%d -j mark --set-mark %d" % \
83             (self.xid, self.xid))
84            
85
86     def stop(self):
87         logger.verbose('sliver_libvirt: %s stop'%(self.name))
88         
89         # Remove the ebtables rule before stopping 
90         bwlimit.ebtables("-D INPUT -i veth%d -j mark --set-mark %d" % \
91             (self.xid, self.xid))
92         
93         try:
94             self.dom.destroy()
95         except:
96             logger.verbose('sliver_libvirt: Domain %s not running UNEXPECTED: %s'%(self.name, sys.exc_info()[0]))
97             print 'sliver_libvirt: Domain %s not running UNEXPECTED: %s'%(self.name, sys.exc_info()[0])
98         
99     def is_running(self):
100         ''' Return True if the domain is running '''
101         logger.verbose('sliver_libvirt: %s is_running'%self.name)
102         try:
103             [state, _, _, _, _] = self.dom.info()
104             if state == libvirt.VIR_DOMAIN_RUNNING:
105                 logger.verbose('sliver_libvirt: %s is RUNNING'%self.name)
106                 return True
107             else:
108                 info = debuginfo(self.dom)
109                 logger.verbose('sliver_libvirt: %s is NOT RUNNING...\n%s'%(self.name, info))
110                 return False
111         except:
112             logger.verbose('sliver_libvirt: UNEXPECTED ERROR in %s...\n%s'%(self.name, sys.exc_info[0]))
113             print 'sliver_libvirt: UNEXPECTED ERROR in %s...\n%s'%(self.name, sys.exc_info[0])
114
115     def configure(self, rec):
116
117         #sliver.[LXC/QEMU] tolower case
118         #sliver_type = rec['type'].split('.')[1].lower() 
119
120         #BASE_DIR = '/cgroup/libvirt/%s/%s/'%(sliver_type, self.name)
121
122         # Disk allocation
123         # No way through cgroups... figure out how to do that with user/dir quotas.
124         # There is no way to do quota per directory. Chown-ing would create
125         # problems as username namespaces are not yet implemented (and thus, host
126         # and containers share the same name ids
127
128         # Btrfs support quota per volumes
129
130         # It will depend on the FS selection
131         if rec.has_key('disk_max'):
132             disk_max = rec['disk_max']
133             if disk_max == 0:
134                 # unlimited 
135                 pass
136             else:
137                 # limit to certain number
138                 pass
139
140         # Memory allocation
141         if rec.has_key('memlock_hard'):
142             mem = rec['memlock_hard'] * 1024 # hard limit in bytes
143             cgroups.write(self.name, 'memory.limit_in_bytes', mem)
144         if rec.has_key('memlock_soft'):
145             mem = rec['memlock_soft'] * 1024 # soft limit in bytes
146             cgroups.write(self.name, 'memory.soft_limit_in_bytes', mem)
147
148         # CPU allocation
149         # Only cpu_shares until figure out how to provide limits and guarantees
150         # (RT_SCHED?)
151         if rec.has_key('cpu_share'): 
152             cpu_share = rec['cpu_share']
153             cgroups.write(self.name, 'cpu.shares', cpu_share)
154
155         # Call the upper configure method (ssh keys...)
156         accounts.Account.configure(self, rec)
157
158
159
160