cc1  v2.1
CC1 source code docs
 All Classes Namespaces Files Functions Variables Pages
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.models.image
22 #
23 # @author Tomek Sośnicki <tom.sosnicki@gmail.com>
24 # @author Maciej Nabożny <mn@mnabozny.pl>
25 #
26 
27 from datetime import datetime
28 
29 from django.db import models
30 
31 from cm.models.storage import Storage
32 from cm.models.user import User
33 from cm.utils import log
34 from cm.utils.exception import CMException
35 from common.hardware import disk_controllers, disk_controllers_reversed
36 from common.states import image_states, storage_states, image_access
37 import os
38 
39 from typedmodels import TypedModel
40 
41 
42 ##
43 #
44 # abstract @model{IMAGE} Basic class for all of Image types.
45 #
46 # Images are files that should be considered as virtual disks attachable
47 # to Virtual Machines.
48 # CC1 images are divided into 3 groups:
49 # - VM images (sytem_image)
50 # - Storage images (disk_volune),
51 # - Iso images (iso_image).
52 #
53 # @note
54 # 1. default values put in the fields definition of the model, not __init__
55 # 2. getStorage operation,to initialize storage field, is now in image.utils.create(), not __init__
56 # 3. disk_dev is now an integer, in dict is put as a string, ex: sda, if the value is 1
57 # 4. no 'get method' because Image is abstract class, it is defined for the subclasses
58 # 5. 'path method' defined in subclasses
59 # 6. 'has_access method' put in system_image and iso_images (they can be in groups)
60 #
61 #
62 class Image(TypedModel):
63  name = models.CharField(max_length=45)
64  description = models.CharField(max_length=512)
65  user = models.ForeignKey(User)
66 
67  # NOTE: disk_dev is now an integer
68  disk_dev = models.IntegerField(null=True, blank=True)
69  disk_controller = models.IntegerField(default=disk_controllers['scsi'])
70  # creation_date is datetime.now by default
71  creation_date = models.DateTimeField(default=datetime.now)
72  size = models.IntegerField(null=True, blank=True)
73  state = models.SmallIntegerField()
74  storage = models.ForeignKey(Storage, null=True, blank=True)
75  progress = models.IntegerField(default=100)
76  access = models.SmallIntegerField()
77 
78  class Meta:
79  app_label = 'cm'
80 
81  @staticmethod
82  def create(cls, name, description, user, disk_dev, disk_controller, size=0, progress=100):
83  image = cls()
84  image.name = name
85  image.description = description
86  image.state = image_states['adding']
87  image.user = user
88  image.size = size
89  image.progress = progress
90  image.disk_dev = disk_dev
91  image.storage = Storage.get()
92  image.disk_controller = disk_controller
93  image.access = image_access['private']
94  return image
95 
96  # method for printing object instance
97  def __unicode__(self):
98  return self.name
99 
100  # @property
101  # method used by the subclasses, it put in dict the fields common to all images
102  ##
103  #
104  # @returns{dict} image's data
105  # \n fields:
106  # @dictkey{id}
107  # @dictkey{user_id,int}
108  # @dictkey{name}
109  # @dictkey{description}
110  # @dictkey{creation_date}
111  # @dictkey{progress}
112  # @dictkey{state}
113  # @dictkey{size}
114  #
115  def dictImg(self):
116  d = {}
117  d['image_id'] = self.id
118  d['user_id'] = self.user.id
119  d['name'] = self.name
120  d['description'] = self.description
121  d['disk_controller'] = self.disk_controller
122 
123  # disk_dev put in dict of subclasses
124  # d['disk_dev'] = self.disk_dev
125 
126  d['creation_date'] = self.creation_date
127  d['progress'] = self.progress
128 
129  # Image's state depends on storage's state (storage could be unavailable
130  if self.storage is None or self.storage.state != storage_states['ok']:
131  d['state'] = image_states['unavailable']
132  else:
133  d['state'] = self.state
134 
135  if self.size is not None:
136  d['size'] = self.size
137  else:
138  d['size'] = 0
139 
140  return d
141 
142  ##
143  #
144  # @parameter{state,string} slug name of the new state for this Image
145  #
146  # @raises{vm_wrong_state,CMException} such a state doesn't exist
147  #
148  def set_state(self, state):
149 
150  # Key - destination state
151  # Values - actual available states
152  states = {'init': (),
153  'adding': ('init'),
154  'failed': ('init', 'adding', 'formatting', 'ok', 'unavailable', 'locked', 'deleted'),
155  'formatting': ('adding'),
156  'ok': ('formatting', 'adding', 'locked'),
157  'unavailable': (),
158  'locked': ('ok'),
159  'deleted': ('ok', 'locked', 'failed'),
160  }
161 
162  # Find my state:
163  my_state = False
164  for s in image_states.keys():
165  if self.state == image_states[s]:
166  my_state = s
167 
168  if self.storage.state == storage_states['locked']:
169  if state == 'adding' or state == 'formatting':
170  raise CMException('vm_wrong_state')
171 
172  # Check if Image could go from actual state to given
173  if not my_state in states[state] or my_state == False:
174  raise CMException('vm_wrong_state')
175 
176  @property
177  ##
178  #
179  # #@returns{string} path to image
180  #
181  def path(self):
182  img_path = '%d' % self.id
183  log.info(self.user.id, 'Storage: %s, user_id: %d, image_id: %s' % (self.storage.path, self.user.id, img_path))
184  return os.path.join(self.storage.path, str(self.user.id), img_path)
185 
186  @property
187  ##
188  #
189  # Method filters DISK_CONTROLLERS list to find controller name by
190  # the disk_controller id with is assigned to this Image.
191  # @returns{string} name of this Image's disk controller, if
192  # such a controller exists
193  #
195  try:
196  return disk_controllers_reversed[self.disk_controller]
197  except Exception:
198  log.error(self.user.id, 'Cannot find disk controller')
199