Some code refactor
[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 libvirt
10 import sys
11
12 from string import Template
13
14 states = {
15     libvirt.VIR_DOMAIN_NOSTATE: 'no state',
16     libvirt.VIR_DOMAIN_RUNNING: 'running',
17     libvirt.VIR_DOMAIN_BLOCKED: 'blocked on resource',
18     libvirt.VIR_DOMAIN_PAUSED: 'paused by user',
19     libvirt.VIR_DOMAIN_SHUTDOWN: 'being shut down',
20     libvirt.VIR_DOMAIN_SHUTOFF: 'shut off',
21     libvirt.VIR_DOMAIN_CRASHED: 'crashed',
22 }
23
24 def randomMAC():
25     mac = [ random.randint(0x00, 0xff),
26             random.randint(0x00, 0xff),
27             random.randint(0x00, 0xff),
28             random.randint(0x00, 0xff),
29             random.randint(0x00, 0xff),
30             random.randint(0x00, 0xff) ]
31     return ':'.join(map(lambda x: "%02x" % x, mac))
32
33 class Sliver_LV(accounts.Account):
34     """This class wraps LibVirt commands"""
35    
36     SHELL = '/bin/sh' 
37
38     # Need to add a tag at myplc to actually use this account
39     # type = 'sliver.LIBVIRT'
40     TYPE = 'sliver.LIBVIRT'
41     
42
43     @staticmethod
44     def create(name, rec = None):
45         ''' Create dirs, copy fs image, lxc_create '''
46         print "LIBVIRT %s create"%(name)
47         logger.verbose ('sliver_libvirt: %s create'%(name))
48         dir = '/vservers/%s'%(name)
49         
50         # Template for sliver configuration
51         template = Template(open('/vservers/config_template.xml').read())
52         config = template.substitute(name=name)
53         
54         lxc_log = '%s/log'%(dir)
55        
56         # TODO: copy the sliver FS to the correct path if sliver does not
57         # exist. Update MAC addresses and insert an entry on the libvirt DHCP
58         # server to get an actual known IP. Some sort of pool?
59         if not (os.path.isdir(dir) and 
60             os.access(dir, os.R_OK | os.W_OK | os.X_OK)):
61             logger.verbose('lxc_create: directory %s does not exist or wrong perms'%(dir))
62             return
63
64         # TODO: set hostname
65         file('/vservers/%s/rootfs/etc/hostname' % name, 'w').write(name)
66        
67         # Get a connection and lookup for the sliver before actually
68         # defining it, just in case it was already defined.
69         conn = Sliver_LV.getConnection()
70         try:
71             dom = conn.lookupByName(name)
72         except:
73             dom = conn.defineXML(config)
74         print Sliver_LV.info(dom)
75
76     @staticmethod
77     def destroy(name):
78         ''' NEVER CALLED... Figure out when and what to do... '''
79         
80         print "LIBVIRT %s destroy"%(name)
81         logger.verbose ('sliver_libvirt: %s destroy'%(name))
82         
83         dir = '/vservers/%s'%(name)
84         lxc_log = '%s/lxc.log'%(dir)
85
86         conn = conn.Sliver_LV.getConnection()
87
88         try:
89             dom = conn.lookupByName(name)
90             conn.destroy(dom)
91             conn.undefine(dom)
92             print Sliver_LV.info(dom)
93         except:
94             logger.verbose('sliver_libvirt: %s domain does not exists'%(name))
95             print "Unexpected error:", sys.exc_info()[0]
96
97     def __init__(self, rec):
98         self.name = rec['name']
99         print "LIBVIRT %s __init__"%(self.name)
100         logger.verbose ('sliver_libvirt: %s init'%(self.name))
101          
102         self.dir = '/vservers/%s'%(self.name)
103         
104         # Assume the directory with the image and config files
105         # are in place
106         
107         self.keys = ''
108         self.rspec = {}
109         self.slice_id = rec['slice_id']
110         self.disk_usage_initialized = False
111         self.initscript = ''
112         self.enabled = True
113         conn = Sliver_LV.getConnection()
114         try:
115             self.container = conn.lookupByName(self.name)
116         except:
117             print "Unexpected error:", sys.exc_info()[0]
118
119     def configure(self, rec):
120         ''' Allocate resources and fancy configuration stuff '''
121         print "LIBVIRT %s configure"%(self.name) 
122         logger.verbose('sliver_libvirt: %s configure'%(self.name)) 
123
124     def start(self, delay=0):
125         ''' Just start the sliver '''
126         print "LIBVIRT %s start"%(self.name)
127
128         # Check if it's running to avoid throwing an exception if the
129         # domain was already running, create actually means start
130         if not self.is_running():
131             self.container.create()
132         else:
133             logger.verbose('sliver_libvirt: sliver %s already started'%(self.name))
134             
135     def stop(self):
136         ''' NEVER CALLED... Figure out when and what to do... '''
137         
138         print "LIBVIRT %s stop"%(self.name)
139         logger.verbose('sliver_libvirt: %s stop'%(self.name))
140         
141         try:
142             self.container.destroy()
143         except:
144             print "Unexpected error:", sys.exc_info()[0]
145     
146     def is_running(self):
147         ''' Return True if the domain is running '''
148         print "LIBVIRT %s is_running"%(self.name)
149         logger.verbose('sliver_libvirt: %s is_running'%(self.name))
150         try:
151             [state, _, _, _, _] = self.container.info()
152             if state == libvirt.VIR_DOMAIN_RUNNING:
153                 logger.verbose('sliver_libvirt: %s is RUNNING'%(self.name))
154                 return True
155             else:
156                 info = Sliver_LV.info(self.container)
157                 logger.verbose('sliver_libvirt: %s is NOT RUNNING...\n%s'%(self.name, info))
158                 return False
159         except:
160             print "Unexpected error:", sys.exc_info()
161
162     ''' PRIVATE/HELPER/STATIC METHODS '''
163     @staticmethod
164     def getConnection():
165         ''' Helper method to get a connection to the LXC driver of Libvirt '''
166         conn = libvirt.open('lxc:///')
167         if conn == None:
168             print 'Failed to open connection to LXC hypervisor'
169             sys.exit(1)
170         else: return conn
171
172     @staticmethod
173     def info(dom):
174         ''' Helper method to get a "nice" output of the info struct for debug'''
175         [state, maxmem, mem, ncpu, cputime] = dom.info()
176         return '%s is %s, maxmem = %s, mem = %s, ncpu = %s, cputime = %s' % (dom.name(), states.get(state, state), maxmem, mem, ncpu, cputime)
177
178