cc1  v2.1
CC1 source code docs
 All Classes Namespaces Files Functions Variables Pages
system_image.py
Go to the documentation of this file.
1 # -*- coding: utf-8 -*-
2 # @COPYRIGHT_begin
3 #
4 # Copyright [2010-2014] Institute of Nuclear Physics PAN, Krakow, Poland
5 #
6 # Licensed under the Apache License, Version 2.0 (the "License");
7 # you may not use this file except in compliance with the License.
8 # You may obtain a copy of the License at
9 #
10 # http://www.apache.org/licenses/LICENSE-2.0
11 #
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 # See the License for the specific language governing permissions and
16 # limitations under the License.
17 #
18 # @COPYRIGHT_end
19 
20 ##
21 # @package src.cm.views.user.system_image
22 # @alldecoratedby{src.cm.utils.decorators.user_log}
23 #
24 # @author Tomek Sośnicki <tom.sosnicki@gmail.com>
25 # @author Miłosz Zdybał <milosz.zdybal@ifj.edu.pl>
26 # @author Maciej Nabożny <mn@mnabozny.pl>
27 #
28 
29 import urllib
30 
31 from cm.models.system_image import SystemImage
32 from cm.models.system_image_group import SystemImageGroup
33 from cm.models.user import User
34 from cm.utils import log
35 from cm.utils.decorators import user_log
36 from cm.utils.exception import CMException
37 from cm.utils.threads.image import DownloadImage
38 from common.hardware import disk_filesystems, disk_controllers, video_devices, \
39  network_devices
40 from common.states import image_access, image_states
41 import subprocess
42 
43 
44 # ======================== jak coś nie będzie działać to to wywalić :D ========================
45 
46 @user_log(log=True)
47 ##
48 #
49 # Creates dummy SystemImage for future upload. Returns the id of the newly
50 # created SystemImage. SystemImage is only created in database, there's no
51 # physical entity representing it.
52 #
53 # @cmview_user
54 # @param_post{name,string}
55 # @param_post{description,string}
56 # @param_post{size,int}
57 # @param_post{disk_controller,int}
58 # @param_post{network_device}
59 # @param_post{platform}
60 # @param_post{video_device}
61 #
62 # @response{dict} {'system_image_id': SystemImage.id}
63 #
64 # @raises{image_create,CMException}
65 #
66 def create(caller_id, name, description, size, disk_controller, network_device, platform, video_device):
67  # size value is taken
68  size = int(size)
69 
70  user = User.get(caller_id)
71  user.check_storage(size / (1024 * 1024))
72 
73  image = SystemImage.create(name=name, description=description, user=user, platform=platform,
74  disk_controller=disk_controller, network_device=network_device, video_device=video_device)
75 
76  try:
77  image.save()
78  except Exception, e:
79  log.error(caller_id, "Unable to save image to DB: %s" % str(e))
80  raise CMException('image_create')
81 
82  return {'system_image_id': image.id}
83  # DownloadImage(image, path, size).start()
84 
85 
86 @user_log(log=True)
87 ##
88 #
89 # Downloads specified SystemImage to CM via EC2
90 #
91 # @cmview_user
92 # @param_post{system_image_id,int}
93 # @param_post{path,string} HTTP or FTP path to SystemImage
94 #
95 # @raises{image_not_found,CMException}
96 # @raises{image_create,CMException}
97 #
98 def download_ec2(caller_id, system_image_id, path):
99 
100  if not any([path.startswith('http://'), path.startswith('https://'), path.startswith('ftp://')]):
101  path = 'http://' + path.strip()
102 
103  # size value is taken
104  try:
105  connection = urllib.urlopen(path)
106  size = int(connection.info()["Content-Length"])
107  except IOError:
108  log.exception(caller_id, 'Cannot find image')
109  raise CMException('image_not_found')
110  except KeyError:
111  log.exception(caller_id, 'Cannot calculate size')
112  raise CMException('image_calculate_size')
113 
114  image = SystemImage.get(caller_id, system_image_id)
115 
116  DownloadImage(image, path, size).start()
117 
118 # ======================== END OF 'jak coś nie będzie działać to to wywalić :D' ========================
119 
120 
121 @user_log(log=True)
122 ##
123 #
124 # Downloads specified SystemImage file to CM storage and makes it available in
125 # CC1 system to start VM with.
126 #
127 # @cmview_user
128 # @param_post{name,string}
129 # @param_post{description,string}
130 # @param_post{path,string} HTTP or FTP path to image to download
131 # @param_post{disk_controller}
132 # @param_post{network_device}
133 # @param_post{platform}
134 # @param_post{video_device}
135 #
136 # @raises{image_not_found,CMException}
137 # @raises{image_create,CMException}
138 #
139 def download(caller_id, name, description, path, disk_controller, network_device, platform, video_device):
140  if not any([path.startswith('http://'), path.startswith('https://'), path.startswith('ftp://')]):
141  path = 'http://' + path.strip()
142 
143  # size value is taken
144  try:
145  connection = urllib.urlopen(path)
146  size = int(connection.info()["Content-Length"])
147  except IOError:
148  log.exception(caller_id, 'Cannot find image')
149  raise CMException('image_not_found')
150  except KeyError:
151  log.exception(caller_id, 'Cannot calculate size')
152  raise CMException('image_calculate_size')
153 
154  user = User.get(caller_id)
155  user.check_storage(size / (1024 * 1024))
156 
157  image = SystemImage.create(name=name, description=description, user=user, platform=platform,
158  disk_controller=disk_controller, network_device=network_device, video_device=video_device)
159 
160  try:
161  image.save()
162  except Exception, e:
163  log.error(caller_id, "Unable to save image to DB: %s" % str(e))
164  raise CMException('image_create')
165 
166  DownloadImage(image, path, size).start()
167 
168 
169 @user_log(log=True) # XXX
170 ##
171 #
172 # Returns SystemImages with specified access (and from specific Group if
173 # @prm{group_id} is specified).
174 #
175 # @cmview_user
176 # @param_post{access} one of common.hardware.image_access
177 # @param_post{group_id,list(int)} list of Groups ids, required for @val{group} access
178 #
179 # @response{list(dict)} list of the images from CM
180 #
181 def get_list(caller_id, access, group_id=None):
182  # retrieve list of the type requested
183  images = SystemImage.objects.exclude(state=image_states['locked']).filter(access=access)
184 
185  # private access
186  if access == image_access['private']:
187  images = images.filter(user__id__exact=caller_id)
188 
189  # if group access, we need 'group_id' parameter in 'data'
190  # list only images with group access that belong to the group of 'gid' given
191  if access == image_access['group']:
192  images = images.filter(systemimagegroup__group_id__in=group_id)
193 
194  return [img.dict for img in images]
195 
196 
197 @user_log(log=True)
198 ##
199 #
200 # @cmview_user
201 # @param_post{groups,list(int)} list of Groups ids, required for @val{group} access
202 # @param_post{system_image_id,int} id of the requested Image
203 #
204 # @response{dict} SystemImage.dict property of the requested SystemImage
205 #
206 def get_by_id(caller_id, system_image_id, groups):
207  return SystemImage.get(caller_id, system_image_id, groups).dict
208 
209 
210 @user_log(log=True)
211 ##
212 #
213 # Deletes specified SystemImage
214 #
215 # @cmview_user
216 # @param_post{system_image_ids,list(int)} id of the SystemImage to delete
217 #
218 def delete(caller_id, system_image_ids):
219 
220  results = []
221  for system_image_id in system_image_ids:
222  image = SystemImage.get(caller_id, system_image_id)
223 
224  if image.state != image_states['ok']:
225  results.append({'status': 'image_delete', 'data': ''})
226  continue
227 
228  try:
229  subprocess.call(['rm', image.path])
230  except Exception:
231  results.append({'status': 'image_delete', 'data': ''})
232  continue
233 
234  image.state = image_states['locked']
235  image.save()
236  results.append({'status': 'ok', 'data': ''})
237 
238  return results
239 
240 
241 @user_log(log=True)
242 ##
243 #
244 # Updates attributes of the specified SystemImage.
245 #
246 # @cmview_user
247 # @param_post{system_image_id,int} id of the SystemImage to edit
248 # @param_post{name,string} SystemImage new name (optional)
249 # @param_post{description,string} SystemImage new description (optional)
250 # @param_post{disk_controller} SystemImage new controller (optional)
251 # @param_post{video_device} SystemImage new video device (optional)
252 # @param_post{network_device} SystemImage new network device (optional)
253 # @param_post{platform} (optional)
254 #
255 def edit(caller_id, system_image_id, name=None, description=None, disk_controller=None, video_device=None, network_device=None, platform=None):
256 
257  image = SystemImage.get(caller_id, system_image_id)
258 
259  if image.state != image_states['ok']:
260  raise CMException('image_edit')
261 
262  image.name = name or image.name
263  image.description = description or image.description
264  image.disk_controller = disk_controller or image.disk_controller
265  image.video_device = video_device or image.video_device
266  image.network_device = network_device or image.network_device
267  image.platform = platform or image.platform
268 
269  try:
270  image.save()
271  except:
272  raise CMException('image_edit')
273 
274 
275 @user_log(log=True)
276 ##
277 #
278 # Marks SystemImage as @val{private}. The caller needs to be:
279 # - either the <b>owner of the SystemImage</b>
280 # - or the <b>leader of the group</b> to which SystemImage belongs
281 #
282 # @cmview_user
283 # @param_post{system_image_id,int} id of the Image to set private
284 # @param_post{leader_groups,list(int)} ids of the group where the caller is
285 # leader, requierd if Image's access type is group
286 #
287 def set_private(caller_id, system_image_id, leader_groups):
288 
289  image = SystemImage.get(caller_id, system_image_id, leader_groups)
290  image.access = image_access['private']
291  # delete the existing group association
292  try:
293  image.save()
294  image.systemimagegroup_set.all().delete()
295  except:
296  log.exception(caller_id, 'image_set_private')
297  raise CMException('image_set_private')
298 
299 
300 @user_log(log=True)
301 ##
302 #
303 # Method sets specified Image access type as group (belonging to specified Group)
304 # (only for sys and cd images - from private or public to group)
305 #
306 # @cmview_user
307 # @param_post{group_id,int} id of the Group Image should belong to
308 # @param_post{system_image_id,int}
309 #
310 # @response{None}
311 #
312 def set_group(caller_id, system_image_id, group_id):
313  image = SystemImage.get(caller_id, system_image_id)
314  image.access = image_access['group']
315 
316  # create new group-image object
317  ig = SystemImageGroup()
318  ig.image = image
319  ig.group_id = group_id
320 
321  try:
322  ig.save()
323  image.save()
324  except:
325  raise CMException('image_set_group')
326 
327 
328 @user_log(log=True)
329 ##
330 #
331 # Changes type of the given Image.
332 #
333 # @cmview_user
334 # @param_post{system_image_id,int} ID of an Image to change type of
335 #
336 def convert_to_storage_image(caller_id, system_image_id):
337  image = SystemImage.get(caller_id, system_image_id)
338  try:
339  image.recast('cm.storageimage')
340  image.save()
341  except Exception:
342  log.exception(caller_id, "convert_to_storage_image")
343  raise CMException('image_change_type')
344 
345 
346 @user_log(log=True)
347 ##
348 #
349 # @cmview_user
350 # @response{list(dict)} common.hardware.disk_filesystems
351 #
352 def get_filesystems(caller_id):
353  return disk_filesystems
354 
355 
356 @user_log(log=True)
357 ##
358 #
359 # @cmview_user
360 # @response{list(dict)} common.hardware.video_devices
361 #
362 def get_video_devices(caller_id):
363  return video_devices
364 
365 
366 @user_log(log=True)
367 ##
368 #
369 # @cmview_user
370 # @response{list(dict)} common.hardware.network_devices
371 #
372 def get_network_devices(caller_id):
373  return network_devices
374 
375 
376 @user_log(log=True)
377 ##
378 #
379 # @cmview_user
380 # @response{list(dict)} \c id and \c name for each disk controller
381 #
382 def get_disk_controllers(caller_id):
383  return [{'id': ctrl_id, 'name': name} for name, ctrl_id in disk_controllers.iteritems()]
384