cc1  v2.1
CC1 source code docs
 All Classes Namespaces Files Functions Variables Pages
iso_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.iso_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.iso_image import IsoImage
32 from cm.models.user import User
33 from cm.models.vm import VM
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_controllers
39 from common.states import image_states
40 import subprocess
41 
42 
43 @user_log(log=True)
44 ##
45 #
46 # Downloads specified IsoImage and saves it with specified name and description.
47 #
48 # @cmview_user
49 # @param_post{name,string}
50 # @param_post{description,string}
51 # @param_post{path,string} HTTP or FTP path to IsoImage to download
52 # @param_post{disk_controller}
53 #
54 def download(caller_id, name, description, path, disk_controller):
55  user = User.get(caller_id)
56 
57  if not any([path.startswith('http://'), path.startswith('https://'), path.startswith('ftp://')]):
58  path = 'http://' + path.strip()
59 
60  # size value is taken
61  try:
62  connection = urllib.urlopen(path)
63  size = int(connection.info()["Content-Length"])
64  except IOError:
65  log.exception('Cannot find image')
66  raise CMException('image_not_found')
67  except KeyError:
68  log.exception(caller_id, 'Cannot calculate size')
69  raise CMException('image_calculate_size')
70 
71  user.check_storage(size / (1024 * 1024))
72 
73  image = IsoImage.create(user=user, description=description, name=name, disk_controller=disk_controller, disk_dev=1)
74 
75  try:
76  image.save()
77  except Exception, e:
78  log.error(caller_id, "Unable to save image to DB: %s" % str(e))
79  raise CMException('image_create')
80 
81  DownloadImage(image, path, size).start()
82 
83 
84 @user_log(log=False)
85 ##
86 #
87 # Returns caller's IsoImages on current CM.
88 #
89 # @cmview_user
90 # @response{list(dict)} list of the caller's IsoImages on current CM
91 #
92 def get_list(caller_id):
93  # retrieve list of the type requested
94 
95  images = IsoImage.objects.exclude(state=image_states['locked']).filter(user__id=caller_id)
96 
97  return [img.dict for img in images]
98 
99 
100 @user_log(log=True)
101 ##
102 #
103 # Returns requested IsoImage provided it belongs to caller.
104 #
105 # @cmview_user
106 # @param_post{iso_image_id,int} id of the IsoImage to get
107 #
108 # @response{dict} IsoImage.dict property of the requested IsoImage.
109 #
110 def get_by_id(caller_id, iso_image_id):
111  return IsoImage.get(caller_id, iso_image_id).dict
112 
113 
114 @user_log(log=True)
115 ##
116 #
117 # Deletes specified IsoImage.
118 #
119 # @cmview_user
120 # @param_post{iso_image_ids} id of the IsoImage to delete
121 #
122 def delete(caller_id, iso_image_ids):
123 
124  results = []
125  for iso_image_id in iso_image_ids:
126  image = IsoImage.get(caller_id, iso_image_id)
127 
128  if image.state != image_states['ok']:
129  results.append({'status': 'image_delete', 'data': ''})
130  continue
131  try:
132  subprocess.call(['rm', image.path])
133  except Exception:
134  results.append({'status': 'image_delete', 'data': ''})
135  continue
136 
137  image.check_attached()
138  image.state = image_states['locked']
139  image.save()
140  results.append({'status': 'ok', 'data': ''})
141 
142  return results
143 
144 
145 @user_log(log=True)
146 ##
147 #
148 # Updates IsoImage's attributes.
149 #
150 # @cmview_user
151 # @param_post{iso_image_id,int} id of the Image to edit
152 # @param_post{name,string} new name
153 # @param_post{description,string} new description
154 # @param_post{disk_controller} new controller (optional)
155 #
156 def edit(caller_id, iso_image_id, name=None, description=None, disk_controller=None):
157 
158  image = IsoImage.get(caller_id, iso_image_id)
159 
160  if image.state != image_states['ok']:
161  raise CMException('image_edit')
162 
163  if name:
164  image.name = name
165  if description:
166  image.description = description
167  if disk_controller:
168  image.disk_controller = disk_controller
169  try:
170  image.save()
171  except:
172  raise CMException('image_edit')
173 
174 
175 @user_log(log=True)
176 ##
177 #
178 # Attaches specified IsoImage to specified VM. It makes possible booting
179 # any operating system on created VM.
180 #
181 # @cmview_user
182 # @param_post{iso_image_id,int} id of block device (should be IsoImage type)
183 # @param_post{vm_id,int} id of the VM which IsoImage should be attached to
184 #
185 # @response{None}
186 #
187 def attach(caller_id, iso_image_id, vm_id):
188 
189  vm = VM.get(caller_id, vm_id)
190  disk = IsoImage.get(caller_id, iso_image_id)
191 
192  # Check if disk is already attached to a vm
193  if disk.vm:
194  raise CMException('image_attached')
195 
196  disk.attach(vm)
197 
198  try:
199  disk.save()
200  except:
201  raise CMException('iso_image_attach')
202 
203 
204 @user_log(log=True)
205 ##
206 #
207 # Detaches specified IsoImage from specified VM.
208 #
209 # @cmview_user
210 # @param_post{iso_image_id,int} id of the IsoImage to detach
211 # @param_post{vm_id,int} id of the VM from which IsoImage should be detached
212 #
213 # @response{None}
214 #
215 def detach(caller_id, iso_image_id, vm_id):
216  vm = VM.get(caller_id, vm_id)
217  disk = IsoImage.get(caller_id, iso_image_id)
218 
219  disk.detach(vm)
220 
221  try:
222  disk.save()
223  except:
224  raise CMException('iso_image_attach')
225 
226 
227 @user_log(log=True)
228 ##
229 #
230 # @cmview_user
231 # @response{list(dict)} \c id and \c name of each IsoImage
232 #
233 def get_disk_controllers(caller_id):
234  return [{'id': ctrl_id, 'name': name} for name, ctrl_id in disk_controllers.iteritems()]
235