OSDN Git Service

Change disk space check
[karesansui/karesansui.git] / karesansui / gadget / guestby1.py
1 # -*- coding: utf-8 -*-
2 #
3 # This file is part of Karesansui.
4 #
5 # Copyright (C) 2009-2010 HDE, Inc.
6 #
7 # This program is free software; you can redistribute it and/or
8 # modify it under the terms of the GNU General Public License
9 # as published by the Free Software Foundation; either version 2
10 # of the License, or (at your option) any later version.
11 #
12
13 import os
14
15 import web
16 from web.utils import Storage
17
18 import karesansui
19 from karesansui.lib.rest import Rest, auth
20
21 from karesansui.lib.utils import \
22     comma_split, uniq_sort, is_param, json_dumps
23
24 from karesansui.lib.checker import Checker, \
25     CHECK_EMPTY, CHECK_LENGTH, CHECK_ONLYSPACE
26
27 from karesansui.lib.const import \
28     NOTE_TITLE_MIN_LENGTH, NOTE_TITLE_MAX_LENGTH, \
29     MACHINE_NAME_MIN_LENGTH, MACHINE_NAME_MAX_LENGTH, \
30     TAG_MIN_LENGTH, TAG_MAX_LENGTH, \
31     VIRT_COMMAND_DELETE_GUEST, VIRT_COMMAND_DELETE_STORAGE_VOLUME, \
32     DISK_USES
33
34 from karesansui.lib.virt.virt import KaresansuiVirtConnection
35 from karesansui.lib.merge import MergeGuest
36
37 from karesansui.db.access.machine import \
38      findbyguest1, findby1name, logical_delete, \
39      update as m_update, delete as m_delete
40
41 from karesansui.db.access.machine2jobgroup import new as m2j_new
42 from karesansui.db.access._2pysilhouette import save_job_collaboration
43 from karesansui.db.access.tag import \
44      new as t_new, samecount as t_count, findby1name as t_name
45
46 from karesansui.db.model._2pysilhouette import Job, JobGroup
47
48 from karesansui.gadget.guestby1diskby1 import delete_storage_volume, delete_disk_job
49 from pysilhouette.command import dict2command
50
51 def validates_guest_edit(obj):
52     checker = Checker()
53     check = True
54
55     _ = obj._
56     checker.errors = []
57
58     if not is_param(obj.input, 'm_name'):
59         check = False
60         checker.add_error(_('Parameter m_name does not exist.'))
61     else:
62         check = checker.check_string(
63                     _('Machine Name'),
64                     obj.input.m_name,
65                     CHECK_EMPTY | CHECK_LENGTH | CHECK_ONLYSPACE,
66                     None,
67                     min = MACHINE_NAME_MIN_LENGTH,
68                     max = MACHINE_NAME_MAX_LENGTH,
69             ) and check
70
71     if is_param(obj.input, 'note_title'):
72         check = checker.check_string(
73                     _('Title'),
74                     obj.input.note_title,
75                     CHECK_LENGTH | CHECK_ONLYSPACE,
76                     None,
77                     min = NOTE_TITLE_MIN_LENGTH,
78                     max = NOTE_TITLE_MAX_LENGTH,
79                 ) and check
80
81     if is_param(obj.input, 'note_value'):
82         check = checker.check_string(
83                     _('Note'),
84                     obj.input.note_value,
85                     CHECK_ONLYSPACE,
86                     None,
87                     None,
88                     None,
89                 ) and check
90
91
92     if is_param(obj.input, 'tags'):
93         for tag in comma_split(obj.input.tags):
94             check = checker.check_string(
95                         _('Tag'),
96                         tag,
97                         CHECK_LENGTH | CHECK_ONLYSPACE,
98                         None,
99                         min = TAG_MIN_LENGTH,
100                         max = TAG_MAX_LENGTH,
101                     ) and check
102
103     obj.view.alert = checker.errors
104     return check
105
106 class GuestBy1(Rest):
107
108     def _post(self, f):
109         ret = Rest._post(self, f)
110         if hasattr(self, "kvc") is True:
111             self.kvc.close()
112         return ret
113
114     @auth
115     def _GET(self, *param, **params):
116         (host_id, guest_id) = self.chk_guestby1(param)
117         if guest_id is None:
118             return web.notfound()
119
120         model = findbyguest1(self.orm, guest_id)
121
122         self.kvc = KaresansuiVirtConnection()
123         if self.is_mode_input() is True:
124             try:
125                 domname = self.kvc.uuid_to_domname(model.uniq_key)
126                 if not domname:
127                     return web.notfound()
128
129                 virt = self.kvc.search_kvg_guests(domname)[0]
130                 guest = MergeGuest(model, virt)
131                 self.view.model = guest.info["model"]
132                 return True
133             except:
134                 self.kvc.close()
135                 raise
136         else:
137             try:
138                 domname = self.kvc.uuid_to_domname(model.uniq_key)
139                 if not domname:
140                     return web.notfound()
141
142                 virt = self.kvc.search_kvg_guests(domname)[0]
143
144                 guest = MergeGuest(model, virt)
145
146                 guest_info = guest.info["virt"].get_info()
147                 info = {}
148                 info['memory'] = guest_info["memory"]
149                 info['cpu'] = guest_info["cpuTime"]
150                 info['os'] = guest_info["OSType"]
151                 info['hypervisor'] = guest_info["hypervisor"]
152                 info['type'] = guest_info["VMType"]
153                 info['hv_version'] = guest_info["hv_version"]
154
155                 guest_diskinfo = guest.info["virt"].get_disk_info()
156                 disks = []
157                 for disk in guest_diskinfo:
158                     disks.append("%s(%sMB)" % (disk['target']['dev'],disk['source']['size']))
159                 diskinfo = disks
160
161                 inters = []
162                 nics = []
163
164                 guest_interfaceinfo = guest.info["virt"].get_interface_info()
165                 for inter in guest_interfaceinfo:
166                     inters.append(inter["type"])
167                     try:
168                         nics.append(inter["source"]["bridge"])
169                     except:
170                         pass
171                 interfaceinfo = inters
172
173                 if len(nics) == 0:
174                     guest_netinfo = guest.info["virt"].get_netinfo()
175                     for nic in guest_netinfo.keys():
176                         nics.append(nic)
177                 netinfo = nics
178
179                 #pool_name = self.kvc.get_storage_pool_name_bydomain(domname)[0]
180                 #pool = self.kvc.search_kvn_storage_pools(pool_name)[0]
181                 #poolinfo = pool.get_info()
182                 poolinfo = {}
183
184                 if self.__template__["media"] == 'json':
185                     json_guest = guest.get_json(self.me.languages)
186                     self.view.data = json_dumps(
187                         {
188                             "model": json_guest["model"],
189                             "virt": json_guest["virt"],
190                             "autostart": guest.info["virt"].autostart(),
191                             "info": info,
192                             "diskinfo": diskinfo,
193                             "netinfo": netinfo,
194                             "interfaceinfo": interfaceinfo,
195                             "poolinfo": poolinfo
196                         }
197                     )
198                 else:
199                     self.view.model = guest.info["model"]
200                     self.view.virt = guest.info["virt"]
201                     self.view.autostart = guest.info["virt"].autostart()
202                     self.view.info = info
203                     self.view.diskinfo = diskinfo
204                     self.view.netinfo = netinfo
205                     self.view.interfaceinfo = interfaceinfo
206                     self.view.poolinfo = poolinfo
207             except:
208                 self.kvc.close()
209                 raise
210
211             return True
212
213     @auth
214     def _PUT(self, *param, **params):
215
216         (host_id, guest_id) = self.chk_guestby1(param)
217         if guest_id is None:
218             return web.notfound()
219
220         if not validates_guest_edit(self):
221             self.logger.debug("Update Guest OS is failed, Invalid input value.")
222             return web.badrequest(self.view.alert)
223
224         guest = findbyguest1(self.orm, guest_id)
225
226         # notebook
227         if is_param(self.input, "note_title"):
228             guest.notebook.title = self.input.note_title
229         if is_param(self.input, "note_value"):
230             guest.notebook.value = self.input.note_value
231
232         if is_param(self.input, "m_name"):
233             guest.name = self.input.m_name
234
235         # Icon
236         icon_filename = None
237         if is_param(self.input, "icon_filename", empty=True):
238             guest.icon = self.input.icon_filename
239
240         # tag UPDATE
241         if is_param(self.input, "tags"):
242             _tags = []
243             tag_array = comma_split(self.input.tags)
244             tag_array = uniq_sort(tag_array)
245             for x in tag_array:
246                 if t_count(self.orm, x) == 0:
247                     _tags.append(t_new(x))
248                 else:
249                     _tags.append(t_name(self.orm, x))
250             guest.tags = _tags
251
252         guest.modified_user = self.me
253
254         m_update(self.orm, guest)
255         return web.seeother(web.ctx.path)
256
257
258     @auth
259     def _DELETE(self, *param, **params):
260         (host_id, guest_id) = self.chk_guestby1(param)
261         if guest_id is None:
262             return web.notfound()
263
264         model = findbyguest1(self.orm, guest_id)
265
266         self.kvc = KaresansuiVirtConnection()
267         try:
268             domname = self.kvc.uuid_to_domname(model.uniq_key)
269             if not domname:
270                 self.logger.info("Did not exist in libvirt. - guestid=%s" % model.id)
271                 logical_delete(self.orm, model)
272                 # TODO ファイルシステムにゴミが残るので、delete_guest.pyを実行する必要がある。
273                 self.orm.commit()
274                 return web.nocontent()
275
276             kvg_guest = self.kvc.search_kvg_guests(domname)
277             if not kvg_guest:
278                 return web.badrequest(_("Guest OS not found. - name=%s") % domname)
279             else:
280                 kvg_guest = kvg_guest[0]
281
282             if kvg_guest.is_active():
283                 # TRANSLATORS:
284                 #   起動中のゲストOSは削除できません
285                 return web.badrequest(_("Can not delete a running guest OS. - name=%s") % domname)
286
287             # jobs order
288             order = 0
289
290             jobs = []
291             os_storage = {}
292             for disk in kvg_guest.get_disk_info():
293                 if disk['type'] == 'file': # type="dir"
294                     # delete_storage_volume
295                     pool = self.kvc.get_storage_pool_name_byimage(disk['source']['file'])
296                     if not pool:
297                         return web.badrequest(_("Can not find the storage pool is not running. - target=%s") % (disk['source']['file']))
298                     else:
299                         pool = pool[0]
300
301                     disk_volumes = self.kvc.get_storage_volume_bydomain(domname, 'disk', 'key')
302                     volume = None
303                     for key in disk_volumes.keys():
304                         if disk['source']['file'] == os.path.realpath(disk_volumes[key]):
305                             volume = key # disk image
306
307                     use = DISK_USES['DISK']
308                     if volume is None: # os image
309                         os_volume = self.kvc.get_storage_volume_bydomain(domname, 'os', 'key')
310                         if not os_volume:
311                             return web.badrequest(_("Guest OS disk could not be found."))
312
313                         if disk['source']['file'] == os.path.realpath(os_volume.values()[0]):
314                             use = DISK_USES['IMAGES']
315                             volume = os_volume.keys()[0]
316                             os_storage["pool"] = pool
317                             os_storage["volume"] = volume
318                             continue # OS delete command to do "VIRT_COMMAND_DELETE_GUEST" image.
319
320                     jobs.append(delete_storage_volume(self,
321                                                       volume,
322                                                       pool,
323                                                       order,
324                                                       use))
325                     order += 1
326
327                     # delete_disk
328                     jobs.append(delete_disk_job(self,
329                                                domname,
330                                                disk["target"]["dev"],
331                                                order))
332                     order += 1
333
334                 elif disk['type'] == 'block': # type="iscsi"
335
336                     pool = self.kvc.get_storage_pool_name_byimage(disk['source']['dev'])
337                     if not pool:
338                         return web.badrequest(_("Can not find the storage pool is not running."))
339                     else:
340                         pool = pool[0]
341
342                     os_volume = self.kvc.get_storage_volume_bydomain(domname, 'os', 'key')
343                     if not os_volume:
344                         return web.badrequest(_("Storage volume could not be found."))
345                     else:
346                         volume = os_volume.values()[0]
347                         if disk['source']['dev'] == volume:
348                             os_storage["pool"] = pool
349                             os_storage["volume"] = volume
350                             continue # OS delete command to do "VIRT_COMMAND_DELETE_GUEST" image.
351
352                     # delete_disk
353                     jobs.append(delete_disk_job(self,
354                                                domname,
355                                                disk["target"]["dev"],
356                                                order))
357                     order += 1
358                 else:
359                     return web.internalerror(
360                         _("Not expected storage type. type=%") % disk['type'])
361
362
363             # DELETE GUEST
364             cmdname = "Delete Guest"
365             _jobgroup = JobGroup(cmdname, karesansui.sheconf['env.uniqkey'])
366             _jobgroup.jobs = jobs # Set Disk
367             action_cmd = dict2command(
368                 "%s/%s" % (karesansui.config['application.bin.dir'], VIRT_COMMAND_DELETE_GUEST),
369                 {"name" : domname,
370                  "pool" : os_storage["pool"],
371                  "volume" : os_storage["volume"],
372                  }
373                 )
374
375             _job = Job('%s command' % cmdname, order, action_cmd)
376             _jobgroup.jobs.append(_job)
377
378             logical_delete(self.orm, model)
379
380             _machine2jobgroup = m2j_new(machine=model,
381                                         jobgroup_id=-1,
382                                         uniq_key=karesansui.sheconf['env.uniqkey'],
383                                         created_user=self.me,
384                                         modified_user=self.me,
385                                         )
386
387             save_job_collaboration(self.orm,
388                                    self.pysilhouette.orm,
389                                    _machine2jobgroup,
390                                    _jobgroup,
391                                    )
392
393             return web.accepted(url = web.ctx.path)
394         finally:
395             #self.kvc.close() GuestBy1#_post
396             pass
397
398 urls = (
399     '/host/(\d+)/guest/(\d+)/?(\.html|\.part|\.json)?$', GuestBy1,
400     )