11 from account import Account
13 import plnode.bwlimit as bwlimit
17 libvirt.VIR_DOMAIN_NOSTATE: 'no state',
18 libvirt.VIR_DOMAIN_RUNNING: 'running',
19 libvirt.VIR_DOMAIN_BLOCKED: 'blocked on resource',
20 libvirt.VIR_DOMAIN_PAUSED: 'paused by user',
21 libvirt.VIR_DOMAIN_SHUTDOWN: 'being shut down',
22 libvirt.VIR_DOMAIN_SHUTOFF: 'shut off',
23 libvirt.VIR_DOMAIN_CRASHED: 'crashed',
30 class Sliver_Libvirt(Account):
35 def getConnection(sliver_type):
36 # TODO: error checking
37 # vtype is of the form sliver.[LXC/QEMU] we need to lower case to lxc/qemu
38 vtype = sliver_type.split('.')[1].lower()
40 return connections.setdefault(uri, libvirt.open(uri))
44 ''' Helper method to get a "nice" output of the info struct for debug'''
45 [state, maxmem, mem, ncpu, cputime] = dom.info()
46 return '%s is %s, maxmem = %s, mem = %s, ncpu = %s, cputime = %s' % (dom.name(), STATES.get(state, state), maxmem, mem, ncpu, cputime)
48 def __init__(self, rec):
49 self.name = rec['name']
50 logger.verbose ('sliver_libvirt: %s init'%(self.name))
52 # Assume the directory with the image and config files
57 self.slice_id = rec['slice_id']
59 self.conn = Sliver_Libvirt.getConnection(rec['type'])
60 self.xid = bwlimit.get_xid(self.name)
64 dom = self.conn.lookupByName(self.name)
66 logger.log('sliver_libvirt: Domain %s does not exist. ' \
67 'Will try to create it again.' % (self.name))
68 self.__class__.create(rec['name'], rec)
69 dom = self.conn.lookupByName(self.name)
72 def start(self, delay=0):
73 ''' Just start the sliver '''
74 logger.verbose('sliver_libvirt: %s start'%(self.name))
76 # Check if it's running to avoid throwing an exception if the
77 # domain was already running, create actually means start
78 if not self.is_running():
81 logger.verbose('sliver_libvirt: sliver %s already started'%(self.name))
83 # After the VM is started... we can play with the virtual interface
84 # Create the ebtables rule to mark the packets going out from the virtual
85 # interface to the actual device so the filter canmatch against the mark
86 bwlimit.ebtables("-A INPUT -i veth%d -j mark --set-mark %d" % \
90 logger.verbose('sliver_libvirt: %s stop'%(self.name))
92 # Remove the ebtables rule before stopping
93 bwlimit.ebtables("-D INPUT -i veth%d -j mark --set-mark %d" % \
99 logger.verbose('sliver_libvirt: Domain %s not running ' \
100 'UNEXPECTED: %s'%(self.name, sys.exc_info()[1]))
101 print 'sliver_libvirt: Domain %s not running ' \
102 'UNEXPECTED: %s'%(self.name, sys.exc_info()[1])
104 def is_running(self):
105 ''' Return True if the domain is running '''
106 logger.verbose('sliver_libvirt: %s is_running'%self.name)
108 [state, _, _, _, _] = self.dom.info()
109 if state == libvirt.VIR_DOMAIN_RUNNING:
110 logger.verbose('sliver_libvirt: %s is RUNNING'%self.name)
113 info = Sliver_Libvirt.debuginfo(self.dom)
114 logger.verbose('sliver_libvirt: %s is ' \
115 'NOT RUNNING...\n%s'%(self.name, info))
118 logger.verbose('sliver_libvirt: UNEXPECTED ERROR in ' \
119 '%s: %s'%(self.name, sys.exc_info()[1]))
120 print 'sliver_libvirt: UNEXPECTED ERROR in ' \
121 '%s: %s'%(self.name, sys.exc_info()[1])
124 def configure(self, rec):
126 #sliver.[LXC/QEMU] tolower case
127 #sliver_type = rec['type'].split('.')[1].lower()
129 #BASE_DIR = '/cgroup/libvirt/%s/%s/'%(sliver_type, self.name)
132 # No way through cgroups... figure out how to do that with user/dir quotas.
133 # There is no way to do quota per directory. Chown-ing would create
134 # problems as username namespaces are not yet implemented (and thus, host
135 # and containers share the same name ids
137 # Btrfs support quota per volumes
139 if rec.has_key("rspec") and rec["rspec"].has_key("tags"):
140 if cgroups.get_cgroup_path(self.name) == None:
141 # If configure is called before start, then the cgroups won't exist
142 # yet. NM will eventually re-run configure on the next iteration.
143 # TODO: Add a post-start configure, and move this stuff there
144 logger.log("Configure: postponing tag check on %s as cgroups are not yet populated" % self.name)
146 tags = rec["rspec"]["tags"]
147 # It will depend on the FS selection
148 if tags.has_key('disk_max'):
149 disk_max = tags['disk_max']
154 # limit to certain number
158 if tags.has_key('memlock_hard'):
159 mem = str(int(tags['memlock_hard']) * 1024) # hard limit in bytes
160 cgroups.write(self.name, 'memory.limit_in_bytes', mem, subsystem="memory")
161 if tags.has_key('memlock_soft'):
162 mem = str(int(tags['memlock_soft']) * 1024) # soft limit in bytes
163 cgroups.write(self.name, 'memory.soft_limit_in_bytes', mem, subsystem="memory")
166 # Only cpu_shares until figure out how to provide limits and guarantees
168 if tags.has_key('cpu_share'):
169 cpu_share = tags['cpu_share']
170 cgroups.write(self.name, 'cpu.shares', cpu_share)
172 # Call the upper configure method (ssh keys...)
173 Account.configure(self, rec)
176 def get_unique_vif():
177 return 'veth%s' % random.getrandbits(32)
179 # A placeholder until we get true VirtualInterface objects
181 def get_interfaces_xml(rec):
183 <interface type='network'>
184 <source network='default'/>
187 """ % (Sliver_Libvirt.get_unique_vif())
189 tags = rec['rspec']['tags']
190 if 'interface' in tags:
191 interfaces = eval(tags['interface'])
192 if not isinstance(interfaces, (list, tuple)):
193 # if interface is not a list, then make it into a singleton list
194 interfaces = [interfaces]
196 for interface in interfaces:
197 if 'vlan' in interface:
198 vlanxml = "<vlan><tag id='%s'/></vlan>" % interface['vlan']
201 if 'bridge' in interface:
202 tag_xml = tag_xml + """
203 <interface type='bridge'>
204 <source bridge='%s'/>
206 <virtualport type='openvswitch'/>
209 """ % (interface['bridge'], vlanxml, Sliver_Libvirt.get_unique_vif())
211 tag_xml = tag_xml + """
212 <interface type='network'>
213 <source network='default'/>
216 """ % (Sliver_Libvirt.get_unique_vif())
219 logger.log('sliver_libvirty.py: interface XML is: %s' % xml)
222 logger.log('sliver_libvirt.py: ERROR parsing "interface" tag for slice %s' % rec['name'])
223 logger.log('sliver_libvirt.py: tag value: %s' % tags['interface'])