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