1 # Copyright (C) 2010 Oregon State University et al.
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software
15 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
18 from django
.contrib
.auth
.decorators
import login_required
19 from django
.core
.urlresolvers
import reverse
20 from django
.http
import HttpResponse
, HttpResponseRedirect
21 from django
.shortcuts
import get_object_or_404
, render_to_response
22 from django
.template
import RequestContext
23 from django
.views
.decorators
.http
import require_http_methods
24 from django
.views
.generic
.edit
import FormView
26 from django_tables2
import SingleTableView
28 from ganeti_web
.backend
.templates
import (instance_to_template
,
30 from ganeti_web
.forms
.vm_template
import (VirtualMachineTemplateCopyForm
,
31 VMInstanceFromTemplate
,
32 TemplateFromVMInstance
)
33 from ganeti_web
.middleware
import Http403
34 from ganeti_web
.models
import Cluster
, VirtualMachineTemplate
, VirtualMachine
35 from ganeti_web
.views
.generic
import (LoginRequiredMixin
, PaginationMixin
,
37 from ganeti_web
.views
.tables
import VMTemplateTable
40 class TemplateListView(LoginRequiredMixin
, PaginationMixin
, SingleTableView
):
41 queryset
= VirtualMachineTemplate
.objects
.exclude(temporary
=True)
42 table_class
= VMTemplateTable
43 template_name
= "ganeti/vm_template/list.html"
45 def get_queryset(self
):
46 qs
= super(TemplateListView
, self
).get_queryset()
48 return self
.sum_disks(templates
)
50 def sum_disks(self
, templates
):
52 Helper function to sum disk templates since they're stored in the
53 database using a serialized field.
55 Note - This expects a list of templates, and does not return a queryset
58 for template
in templates
:
59 total_disk_size
= sum([disk
['size'] for disk
in template
.disks
])
60 template
.disk_space
= total_disk_size
64 class TemplateFromVMInstanceView(LoginRequiredMixin
, FormView
):
66 Create a template from a virtual machine instance.
69 form_class
= TemplateFromVMInstance
70 template_name
= "ganeti/vm_template/to_instance.html"
73 cluster_slug
= self
.kwargs
["cluster_slug"]
74 hostname
= self
.kwargs
["instance"]
76 self
.cluster
= get_object_or_404(Cluster
, slug
=cluster_slug
)
77 self
.vm
= get_object_or_404(VirtualMachine
, hostname
=hostname
,
78 cluster__slug
=cluster_slug
)
80 user
= self
.request
.user
81 if not (user
.is_superuser
or
82 user
.has_perm('admin', self
.cluster
) or
83 user
.has_perm('create_vm', self
.cluster
)):
84 raise Http403(NO_PRIVS
)
86 def form_valid(self
, form
):
88 Create the new VM and then redirect to the new VM's page.
91 template_name
= form
.cleaned_data
["template_name"]
95 template
= instance_to_template(self
.vm
, template_name
)
97 return HttpResponseRedirect(reverse("template-detail",
98 args
=[self
.cluster
.slug
,
99 template
.template_name
]))
101 def get_context_data(self
, **kwargs
):
102 context
= super(TemplateFromVMInstanceView
,
103 self
).get_context_data(**kwargs
)
107 context
["vm"] = self
.vm
112 class VMInstanceFromTemplateView(LoginRequiredMixin
, FormView
):
114 Create a virtual machine instance from a template.
117 form_class
= VMInstanceFromTemplate
118 template_name
= "ganeti/vm_template/to_vm.html"
120 def _get_stuff(self
):
121 cluster_slug
= self
.kwargs
["cluster_slug"]
122 template_name
= self
.kwargs
["template"]
124 self
.cluster
= get_object_or_404(Cluster
, slug
=cluster_slug
)
125 self
.template
= get_object_or_404(VirtualMachineTemplate
,
126 template_name
=template_name
,
127 cluster__slug
=cluster_slug
)
129 user
= self
.request
.user
130 if not (user
.is_superuser
or
131 user
.has_perm('admin', self
.cluster
) or
132 user
.has_perm('create_vm', self
.cluster
)):
133 raise Http403(NO_PRIVS
)
135 def form_valid(self
, form
):
137 Create the new VM and then redirect to the new VM's page.
140 hostname
= form
.cleaned_data
["hostname"]
141 owner
= form
.cleaned_data
["owner"]
145 vm
= template_to_instance(self
.template
, hostname
, owner
)
147 return HttpResponseRedirect(reverse('instance-detail',
148 args
=[self
.cluster
.slug
,
151 def get_context_data(self
, **kwargs
):
152 context
= super(VMInstanceFromTemplateView
,
153 self
).get_context_data(**kwargs
)
157 context
["template"] = self
.template
163 def detail(request
, cluster_slug
, template
):
166 cluster
= get_object_or_404(Cluster
, slug
=cluster_slug
)
167 if not (user
.is_superuser
or
168 user
.has_perm('admin', cluster
) or
169 user
.has_perm('create_vm', cluster
)):
170 raise Http403(NO_PRIVS
)
172 vm_template
= get_object_or_404(VirtualMachineTemplate
,
173 template_name
=template
,
174 cluster__slug
=cluster_slug
)
175 return render_to_response(
176 'ganeti/vm_template/detail.html',
177 {'template': vm_template
,
178 'cluster': cluster_slug
, },
179 context_instance
=RequestContext(request
)
183 @require_http_methods(["GET", "POST"])
185 def copy(request
, cluster_slug
, template
):
187 View used to create a copy of a VirtualMachineTemplate
191 cluster
= get_object_or_404(Cluster
, slug
=cluster_slug
)
192 if not (user
.is_superuser
or
193 user
.has_perm('admin', cluster
) or
194 user
.has_perm('create_vm', cluster
)):
195 raise Http403(NO_PRIVS
)
197 obj
= get_object_or_404(VirtualMachineTemplate
,
198 template_name
=template
,
199 cluster__slug
=cluster_slug
)
200 if request
.method
== "GET":
201 form
= VirtualMachineTemplateCopyForm()
202 return render_to_response(
203 'ganeti/vm_template/copy.html',
206 'cluster': cluster_slug
, },
207 context_instance
=RequestContext(request
)
209 elif request
.method
== "POST":
210 form
= VirtualMachineTemplateCopyForm(request
.POST
)
212 data
= form
.cleaned_data
213 name
= data
.get('template_name', 'unnamed')
214 desc
= data
.get('description', None)
215 # Set pk to None to create new object instead of editing
218 obj
.template_name
= name
219 obj
.description
= desc
221 return HttpResponseRedirect(reverse('template-detail',
222 args
=[cluster_slug
, obj
]))
226 @require_http_methods(["DELETE"])
227 def delete(request
, cluster_slug
, template
):
230 cluster
= get_object_or_404(Cluster
, slug
=cluster_slug
)
231 if not (user
.is_superuser
or
232 user
.has_perm('admin', cluster
) or
233 user
.has_perm('create_vm', cluster
)):
234 raise Http403(NO_PRIVS
)
237 vm_template
= VirtualMachineTemplate
.objects \
238 .get(template_name
=template
,
239 cluster__slug
=cluster_slug
)
241 except VirtualMachineTemplate
.DoesNotExist
:
242 return HttpResponse('-1', mimetype
='application/json')
243 return HttpResponse('1', mimetype
='application/json')