Return base64 encoded image.
[plcapi.git] / PLC / Methods / GetDummyBoxMedium.py
1 #
2 # Marta Carbone - UniPi
3 # $Id$
4 #
5 # This class requires the rpm package containing
6 # the picobsd image to be installed
7 # on the Central Site system.
8 #
9
10 import base64
11 import os
12 import datetime
13
14 from PLC.Faults import *                          # faults library
15 from PLC.Method import Method                     # base class for methods
16 from PLC.Parameter import Parameter               # use the Parameter wrapper
17 from PLC.Auth import Auth                         # import the Auth parameter
18 from PLC.Nodes import *                           # nodes functions
19 from PLC.Methods.GetBootMedium import compute_key # key generation function
20 from PLC.Accessors.Accessors_dummynetbox import *                       # import dummynet accessors
21
22 WORK_DIR = "/var/tmp/DummynetBoxMedium"
23 BASE_IMAGE = "/usr/share/dummynet/picobsd"
24
25 class GetDummyBoxMedium(Method):
26     """
27     This method is used to get a boot image of the DummyNetBox
28     equipped with the configuration file.
29
30     We need to provide the dummybox_id of the DummyNetBox
31     we want to generate.
32     Since every time a new configuration file will be generater,
33     THIS OPERATION WILL INVALIDATE ANY PREVIOUSLY DUMMYNETBOX BOOT MEDIUM.
34     # XXX add checks for picobsd.bin existence
35
36     Returns the iso image customized for the DummyNetBox with the new
37     key integrated in the image, and update the key fields in the database.
38     """
39     # I added the session role, because this method should be called from the web
40     roles = ['admin', 'pi', 'tech', 'session']
41
42     accepts = [
43         Auth(),
44         Parameter(int, "The dummybox_id"),
45         Parameter(str, "The image type (bin or iso)")
46     ]
47
48     returns = Parameter(str, "DummynetBox boot medium")
49
50     # Generate a new configuration file in the working directory
51     # input parameters follows:
52     # self is used to access instance data,
53     # dummybox is the dummybox_id,
54     # new_key is the new generated key,
55     # configfile is the output file of the configuration.
56     def generate_conf_file(self, dummybox, new_key, configfile):
57         
58         # Generate the dummynet box configuration file
59         today = datetime.date.today()
60         file = ""
61         file += "# This is the dummynetbox configuration file\n"
62         file += "# and was generated the %s\n" % str(today)
63         
64         host_domain = dummybox['hostname']
65         host_domain = host_domain.split('.', 1)
66         file += 'HOST_NAME="%s"\n' % host_domain[0]
67         file += 'DOMAIN_NAME="%s"\n' % host_domain[1]
68         
69         file += 'IP_ADDRESS="%s"\n' % dummybox['ip']
70         file += 'IP_NETMASK="%s"\n' % dummybox['netmask']
71         file += 'IP_GATEWAY="%s"\n' % dummybox['gateway']
72         file += 'IP_DNS1="%s"\n' % dummybox['dns1']
73         file += 'IP_DNS2="%s"\n' % dummybox['dns2']
74         file += 'DUMMYBOX_ID="%s"\n' % dummybox['node_id']
75         file += 'DUMMYBOX_KEY="%s"\n' % new_key
76         
77         file += 'CS_IP="%s"\n' % self.api.config.PLC_API_HOST
78
79         # write the configuration file
80         # WORK_DIR must be writable
81         FILE = open(configfile, "w")
82         FILE.write(file)
83         FILE.close()
84         
85         return
86         
87     # Here starts the execution of the call
88     def call(self, auth, dummybox_id, type):
89
90         # check for dummynet box existence and get dummyboxes information
91         dummybox_info = Nodes(self.api, {'node_id':dummybox_id, 'node_type':'dummynet'}, \
92                 ['hostname', 'interface_ids'])
93  
94         if dummybox_id != None and not dummybox_info:
95             raise PLCInvalidArgument, "No such DummyBox %s" % dummybox_id
96
97         # Get the dummynet box hostname
98         dummybox_hostname = dummybox_info[0]['hostname']
99         print "dummybox hostname %s" % dummybox_hostname
100
101         # get the node interface, if configured
102         interfaces = Interfaces(self.api, dummybox_info[0]['interface_ids'])
103         for i in interfaces:
104             if i['is_primary']:
105                 interface_info = i
106                 break
107
108         if not interface_info:
109             raise PLCInvalidArgument, "No primary network configured on %s" % dummybox_hostname
110
111         dummybox = interface_info
112         dummybox['hostname']=dummybox_hostname
113
114         # Select the base image, default to bin image
115         if type != 'iso':
116                 type="bin"
117         IMAGE_NAME = str(WORK_DIR) + "/dummybox_" + dummybox_hostname + str(type)
118         BASE_IMAGE = "/usr/share/dummynet/picobsd." + str(type)
119         configfile = WORK_DIR + '/dummybox.conf'
120         lockfile =  WORK_DIR + '/lockfile'
121
122         # Permission checks
123         assert self.caller is not None
124
125         # Start the generation of the image
126         # Generate a new key
127         new_key = compute_key()
128
129         # create working dir and lock file for concurrent runs
130         if not os.path.exists(WORK_DIR):
131             print "Creating working directory %s" % WORK_DIR
132             os.mkdir(WORK_DIR)
133
134         if os.path.exists(lockfile):
135             raise PLCInvalidArgument, "Lockfile %s exist, try again " % lockfile
136         else:
137             print "Executing "+"touch %s" % lockfile
138             os.system("touch %s" % lockfile)
139
140         # generate the configuration file
141         conf_file = self.generate_conf_file(dummybox, new_key, configfile)
142
143         # build the shell script to customize the dummynetbox image
144         # copy the raw file and find the configuration file position
145         shell_script = "(cp %s %s; export MATCH=`grep -abo START_USER_DATA %s | cut -d: -f1`; " \
146                            % (BASE_IMAGE, IMAGE_NAME, IMAGE_NAME)
147
148         # set permission file
149         shell_script += " chmod u+w %s; chmod u+w %s; " % (IMAGE_NAME, configfile)
150
151         # cat the configuration file in the raw image
152         shell_script += "cat %s | dd of=%s seek=$MATCH conv=notrunc bs=1)" \
153                            % (configfile, IMAGE_NAME)
154
155         # check returned values, 0 means OK, remove the lock file
156         os.system(shell_script)
157         os.system("rm %s" % (lockfile))
158
159         # if all goes fine store the key in the database
160         dummybox['key'] = new_key
161         dummybox.sync()
162
163         # return the file
164         #return IMAGE_NAME
165         return base64.b64encode(file(IMAGE_NAME).read())