cc1  v2.1
CC1 source code docs
 All Classes Namespaces Files Functions Variables Pages
storage.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.admin_cm.storage
22 #
23 # @alldecoratedby{src.cm.utils.decorators.admin_cm_log}
24 #
25 # @author Maciej Nabożny <di.dijo@gmail.com>
26 #
27 
28 from cm.utils.exception import CMException
29 from cm.models.storage import Storage
30 from cm.models.node import Node
31 from cm.utils import log
32 from common.states import storage_states
33 from cm.utils.decorators import admin_cm_log
34 import libvirt
35 
36 # Django templates
37 from django.template import loader, Context
38 from django.conf import settings
39 
40 
41 @admin_cm_log(log=True)
42 ##
43 #
44 # Registers new Storage.
45 #
46 # @cmview_admin_cm
47 # @param_post{name,string} libvirt's pool name
48 # @param_post{address,string} storage ip address or hostname
49 # @param_post{directory,string} directory on storage
50 # @param_post{capacity,int} maximum storage capacity [MB]
51 #
52 # @raises{storage_already_exist,CMException}
53 # @raises{storage_create,CMException}
54 #
55 def create(caller_id, name, address, directory, capacity):
56 
57  #error if already exists a storage with the same name
58  if Storage.objects.filter(name__exact=name).exists():
59  raise CMException('storage_already_exist')
60 
61  try:
62  st = Storage()
63  st.name = name
64  st.address = address
65  st.dir = directory
66  st.capacity = capacity
67  st.state = storage_states['ok']
68 
69  except Exception, e:
70  log.debug(caller_id, 'Cannot register storage - missing element: %s' % str(e))
71  raise CMException('storage_create')
72 
73  try:
74  st.save()
75  except Exception, e:
76  log.debug(caller_id, 'Cannot save storage in database: %s' % str(e))
77  raise CMException('storage_create')
78 
79 
80 @admin_cm_log(log=True)
81 ##
82 #
83 # Returns list of Storages.
84 #
85 # @cmview_admin_cm
86 # @response{list(dict)} Storage.dict property for each Storage
87 #
88 def get_list(caller_id):
89  return [st.dict for st in Storage.objects.all()]
90 
91 
92 @admin_cm_log(log=True)
93 ##
94 #
95 # Locks specified Storage.
96 #
97 # @cmview_admin_cm
98 # @param_post{storage_id,int}
99 #
100 def lock(caller_id, storage_id):
101  try:
102  st = Storage.objects.get(pk=storage_id)
103  st.state = storage_states['locked']
104  st.save()
105  except Exception, e:
106  log.debug(caller_id, 'Cannot lock storage: %s' % str(e))
107  raise CMException('storage_lock')
108 
109 
110 @admin_cm_log(log=True)
111 ##
112 #
113 # Unlocks specified Storage.
114 #
115 # @cmview_admin_cm
116 # @param_post{storage_id,int}
117 #
118 def unlock(caller_id, storage_id):
119  try:
120  st = Storage.objects.get(pk=storage_id)
121  st.state = storage_states['ok']
122  st.save()
123  except Exception, e:
124  log.debug(caller_id, 'Cannot unlock storage: %s' % str(e))
125  raise CMException('storage_unlock')
126 
127 
128 @admin_cm_log(log=True)
129 ##
130 #
131 # Mounts specified Storages on specified Node.
132 #
133 # @cmview_admin_cm
134 # @param_post{storage_id} id of Storage to mount (None for all)
135 # @param_post{node_id} id of Node where to mount Storage (None for all)
136 #
137 # @response{dict} Node's responses
138 #
139 def mount(caller_id, storage_id=None, node_id=None):
140  #if node_id is sent, get that node, otherwise every node
141  if node_id:
142  nodes = Node.objects.filter(id__exact=node_id)
143  else:
144  nodes = Node.objects.all()
145 
146  #if storage_id is sent, get that storage, otherwise every storage
147  if storage_id:
148  storages = Storage.objects.filter(id__exact=storage_id)
149  else:
150  storages = Storage.objects.all()
151 
152  node_response = {}
153  for node in nodes:
154  log.debug(caller_id, "Mounting node: %d" % node.id)
155  storage_response = {}
156  try:
157  conn = libvirt.open(node.conn_string)
158  except Exception, e:
159  log.debug(caller_id, 'Cannot connect to libvirt: %s' % str(e))
160  node.lock()
161  node.save()
162  raise CMException('storage_libvirt')
163 
164  for storage in storages:
165  try:
166  st_template = loader.get_template("storage_%s.xml" % storage.transport)
167  log.info(caller_id, "Rendered template: %s" % st_template)
168  except Exception, e:
169  raise CMException('cm_storage_mount')
170 
171  try:
172  # Create pool from xml template
173  #TODO: change 331 to be read from config
174  context = Context({'storage': storage, 'cc_userid': settings.CC_USERID, 'cc_groupid': settings.CC_GROUPID})
175  t = st_template.render(context)
176  log.info(caller_id, t)
177  # Define pool, then set autostart, create mountpoint and start it
178  try:
179  pool = conn.storagePoolDefineXML(t, 0)
180  except Exception, e:
181  log.debug(caller_id, "Cannot define storage: %s" % str(e))
182  pool = conn.storagePoolLookupByName(storage.name)
183  pool.setAutostart(1)
184  pool.build(0)
185  pool.create(0)
186  storage_response[str(storage.id)] = 'ok'
187  except Exception, e:
188  log.debug(caller_id, 'Cannot mount storage %d on node %d: %s' % (storage_id, node_id, str(e)))
189  storage_response[str(storage.id)] = 'failed'
190  node_response[str(node.id)] = storage_response
191 
192  return node_response
193 
194 
195 @admin_cm_log(log=True)
196 ##
197 #
198 # Check each Node for mounted and unmounted Storages.
199 #
200 # @cmview_admin_cm
201 # @param_post{node_list,list(int)} list of Node ids
202 #
203 # @response{list(dict)} for each node dict with fields:
204 # @dictkey{mounted,list} list of Storages mounted to each Node
205 # @dictkey{unmounted,list} list of Storages not mounted to each Node
206 #
207 def check(caller_id, node_list):
208  result = {}
209  for n in node_list:
210  # Connect and get running storage list
211  node = Node.objects.get(pk=n)
212  conn = libvirt.open(node.conn_string)
213  pools = conn.listStoragePools()
214 
215  mounted = []
216  for pool in pools:
217  if Storage.objects.filter(name=pool).exists():
218  mounted.append(pool)
219 
220  # Other storages are unmounted
221  unmounted = Storage.objects.all().exclude(name__in=mounted).values_list('name', flat=True)
222  result['%d' % n] = {'mounted': mounted, 'unmounted': unmounted}
223  return result
224