Commit c08afb10 by Szeberényi Imre

Form batman:

  two-factor fix
  vm-details fix
  storage model (duisk types?)
parent 2a3a6018
......@@ -333,7 +333,7 @@ DJANGO_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
# 'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
......@@ -357,6 +357,7 @@ THIRD_PARTY_APPS = (
'statici18n',
'django_sshkey',
'pipeline',
'qrcode2',
)
......@@ -413,7 +414,7 @@ LOGGING = {
'address': '/dev/log',
# 'socktype': SOCK_STREAM,
# 'address': ('host', '514'),
}
},
},
'loggers': {
'django.request': {
......@@ -531,6 +532,7 @@ LOGIN_REDIRECT_URL = "/"
AGENT_DIR = get_env_variable(
'DJANGO_AGENT_DIR', join(unicode(expanduser("~")), 'agent'))
# AGENT_DIR is the root directory for the agent.
# The directory structure SHOULD be:
# /home/username/agent
......@@ -542,12 +544,45 @@ AGENT_DIR = get_env_variable(
#
try:
git_env = {'GIT_DIR': join(join(AGENT_DIR, "agent-linux"), '.git')}
git_env = {'GIT_DIR': join(join(AGENT_DIR, "agent"), ".git")}
AGENT_VERSION = check_output(
('git', 'log', '-1', r'--pretty=format:%h', 'HEAD'), env=git_env)
except:
AGENT_VERSION = None
print("LEGACY VERSION: %s ------" % AGENT_VERSION)
#### NEW ####
####
# AGENT_VERSIONS is a dict eg: { "Linux" : "vers1" , "Windows" : "vers2", .... }
# Normally it is fetched from Jason fromatted AGENT_DIR/wersions.txt file
#
# The dir namings ha changed:
# The same, but the dir names are lowercase and generated like this:
# agent-(agent_system)-(version). Eg: agent-linux-vers1, agent-window-vers2
try:
with open("%s/versions.txt" % AGENT_DIR, "r") as f:
AGENT_VERSIONS = loads(f.read())
print("-----KONWN VERSIONS-----")
print(AGENT_VERSIONS)
except:
print("Format ERROR in versions.txt !!!! ") # TODO more error reposrting
AGENT_VERSIONS = None
## PUBLIC function for getting the latest version ad the DIR
def GET_AGENT_VERSION_BY_SYSTEM(agent_system):
if agent_system is None:
return None, None
if type(AGENT_VERSIONS) is not dict:
# legacy naming
return AGENT_VERSION, AGENT_DIR + "/agent-" + agent_system.lower()
ret = AGENT_VERSIONS.get(agent_system)
if ret is None:
return None, None
return ret, AGENT_DIR + "/agent-" + agent_system.lower() + "-" + ret
LOCALE_PATHS = (join(SITE_ROOT, 'locale'), )
COMPANY_NAME = get_env_variable("COMPANY_NAME", "BME IK 2015")
......
......@@ -543,7 +543,7 @@ class TemplateForm(forms.ModelForm):
else:
self.allowed_fields = (
'name', 'access_method', 'description', 'system', 'tags',
'arch', 'lease', 'has_agent')
'arch', 'lease', 'has_agent',)
if (self.user.has_perm('vm.change_template_resources') or
not self.instance.pk):
self.allowed_fields += tuple(set(self.fields.keys()) -
......@@ -972,11 +972,14 @@ class VmImportDiskForm(OperationForm):
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user')
super(VmImportDiskForm, self).__init__(*args, **kwargs)
allowed = ()
allowed = allowed + Disk.EXPORT_FORMATS
print(allowed)
disk_paths = Store(self.user).get_files_with_exts(
[f[0] for f in Disk.EXPORT_FORMATS]
[f[0] for f in allowed]
)
disk_filenames = [os.path.basename(item) for item in disk_paths]
#raise Error(disk_filenames)
self.choices = zip(disk_paths, disk_filenames)
self.fields['name'] = forms.CharField(max_length=100, label=_('Name'))
......
{% extends "dashboard/base.html" %}
{% load i18n %}
{% load qrcode2 %}
{% block content %}
<div class="row">
......@@ -27,8 +29,9 @@
Your secret key is: <strong>{{ secret }}</strong>
{% endblocktrans %}
</span>
<img src="//chart.googleapis.com/chart?chs=255x255&chld=L|0&cht=qr&chl={{ uri }}"/>
<small><a href="{{ uri }}">{{ uri }}</a></small>
{# <img src="//chart.googleapis.com/chart?chs=255x255&chld=L|0&cht=qr&chl={{ uri }}"/> #}
<img src="{{ uri | qrcode_src }}" with="300"i height=300 alt="{{ uri }}">
{# <small><a href="{{ uri }}">{{ uri }}</a></small> #}
</div>
<hr />
<div id="two-factor-confirm">
......
......@@ -112,15 +112,13 @@
<dd>{{ instance.access_method|upper }}</dd>
<dt>{% trans "Host" %}</dt>
<dd>
{% if instance.get_connect_port %}
{{ instance.get_connect_host }}:<strong>{{ instance.get_connect_port }}</strong>
{% if instance.get_connect_port %}{{ instance.get_connect_host }}:<strong>{{ instance.get_connect_port }}</strong>
{% elif instance.interface_set.count < 1%}
<strong>{% trans "The VM doesn't have any network interface." %}</strong>
{% else %}
<strong>{% trans "The required port for this protocol is not forwarded." %}</strong>
{% endif %}
</dd>
{% if instance.ipv6 and instance.get_connect_port %}
<dt>{% trans "Host (IPv6)" %}</dt>
<dd>{{ ipv6_host }}:<strong>{{ ipv6_port }}</strong></dd>
......
......@@ -58,7 +58,8 @@ from .views import (
MessageList, MessageDetail, MessageCreate, MessageDelete,
EnableTwoFactorView, DisableTwoFactorView,
AclUserGroupAutocomplete, AclUserAutocomplete,
RescheduleView, GroupImportView, GroupExportView
RescheduleView, GroupImportView, GroupExportView,
start_instance, shutdown_instance, get_instance
)
from .views.node import node_ops
from .views.vm import vm_ops, vm_mass_ops
......@@ -78,7 +79,9 @@ urlpatterns = [
name="dashboard.views.lease-delete"),
url(r'^lease/(?P<pk>\d+)/acl/$', LeaseAclUpdateView.as_view(),
name="dashboard.views.lease-acl"),
url(r'^vmstart/(?P<pk>\d+)', start_instance),
url(r'^vmshutdown/(?P<pk>\d+)', shutdown_instance),
url(r'^vmget/(?P<pk>\d+)', get_instance),
url(r'^template/create/$', TemplateCreate.as_view(),
name="dashboard.views.template-create"),
url(r'^template/choose/$', TemplateChoose.as_view(),
......
......@@ -723,7 +723,6 @@ if hasattr(settings, 'SAML_ORG_ID_ATTRIBUTE'):
# authenticate the remote user
session_info = response.session_info()
if callable(attribute_mapping):
attribute_mapping = attribute_mapping()
if callable(create_unknown_user):
......
......@@ -36,7 +36,7 @@ from django.template.loader import render_to_string
from django.utils.translation import (
ugettext as _, ugettext_noop, ungettext_lazy,
)
from django.views.decorators.http import require_GET
from django.views.decorators.http import require_GET, require_POST
from django.views.generic import (
UpdateView, ListView, TemplateView
)
......@@ -70,6 +70,7 @@ from ..forms import (
VmRemoveInterfaceForm,
VmRenameForm,
)
from vm.operations import DeployOperation, ShutdownOperation
from request.models import TemplateAccessType, LeaseType
from request.forms import LeaseRequestForm, TemplateRequestForm
from ..models import Favourite
......@@ -1266,6 +1267,51 @@ def get_disk_download_status(request, pk):
content_type="application/json",
)
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
@require_POST
def start_instance(request, pk):
instance = Instance.objects.get(pk=pk)
DeployOperation(instance).call(node=None, user=request.user)
return HttpResponse(
json.dumps({
'id': pk,
'op': 'deploy'
}),
content_type="application/json",
)
@csrf_exempt
@require_POST
def shutdown_instance(request, pk):
instance = Instance.objects.get(pk=pk)
ShutdownOperation(instance).call(user=request.user)
return HttpResponse(
json.dumps({
'id': pk,
'op': 'shutdown'
}),
content_type="application/json",
)
@require_GET
def get_instance(request, pk):
instance = Instance.objects.get(pk=pk)
if instance.owner != request.user:
raise PermissionDenied()
return HttpResponse(
json.dumps({
'id': pk,
'name': instance.name,
'status': instance.status,
'pw': instance.pw,
'ipv4': str(instance.ipv4),
'hostipv4': instance.get_connect_host(use_ipv6=False),
'sshport': instance.get_connect_port(use_ipv6=False)
}),
content_type="application/json",
)
class ClientCheck(LoginRequiredMixin, TemplateView):
......
......@@ -126,7 +126,8 @@ class Disk(TimeStampedModel):
EXPORT_FORMATS = (('qcow2', _('QEMU disk image')),
('vmdk', _('VMware disk image')),
('vdi', _('VirtualBox disk image')),
('vpc', _('HyperV disk image')))
('vpc', _('HyperV disk image')),
('iso', 'ISO image'))
name = CharField(blank=True, max_length=100, verbose_name=_("name"))
filename = CharField(max_length=256, unique=True,
verbose_name=_("filename"))
......
......@@ -873,7 +873,7 @@ class ShutdownOperation(AbortableRemoteOperationMixin,
remote_queue = ("vm", "slow")
remote_timeout = 180
def _operation(self, task):
def _operation(self, task=vm_tasks.shutdown):
super(ShutdownOperation, self)._operation(task=task)
self.instance.yield_node()
......@@ -1575,19 +1575,6 @@ class AgentStartedOperation(InstanceOperation):
self.instance._change_ip(parent_activity=activity)
self.instance._restart_networking(parent_activity=activity)
new_version = settings.AGENT_VERSION
if new_version and old_version and new_version != old_version:
try:
self.instance.update_agent(
parent_activity=activity, agent_system=agent_system)
except TimeoutError:
pass
else:
activity.sub_activity(
'agent_wait', readable_name=ugettext_noop(
"wait agent restarting"), interruptible=True)
return # agent is going to restart
if not self.initialized:
try:
self.measure_boot_time()
......@@ -1600,6 +1587,20 @@ class AgentStartedOperation(InstanceOperation):
self.instance._set_time(parent_activity=activity)
self.instance._set_hostname(parent_activity=activity)
new_version = settings.GET_AGENT_VERSION_BY_SYSTEM(agent_system)[0]
# if agent_system and new_version and (old_version is None or ("NOAGENTUPDATE" not in old_version and new_version != old_version)) :
if agent_system and new_version and old_version and "NOAGENTUPDATE" not in old_version and new_version != old_version :
try:
self.instance.update_agent(
parent_activity=activity, agent_system=agent_system)
except TimeoutError:
pass
else:
activity.sub_activity(
'agent_wait', readable_name=ugettext_noop(
"wait agent restarting"), interruptible=True)
return # agent is going to restart
@register_operation
class CleanupOperation(SubOperationMixin, RemoteAgentOperation):
id = '_cleanup'
......@@ -1658,11 +1659,12 @@ class UpdateAgentOperation(RemoteAgentOperation):
def get_activity_name(self, kwargs):
return create_readable(
ugettext_noop('update agent to %(version)s'),
version=settings.AGENT_VERSION)
ugettext_noop('update agent'))
# ugettext_noop('update agent to %(version)s'),
# version=settings.GET_AGENT_VERSION_BY_SYSTEM(agent_system)[0])
@staticmethod
def create_linux_tar():
def create_linux_tar(agent_system):
def exclude(tarinfo):
ignored = ('./.', './misc', './windows')
if any(tarinfo.name.startswith(x) for x in ignored):
......@@ -1670,13 +1672,14 @@ class UpdateAgentOperation(RemoteAgentOperation):
else:
return tarinfo
_vers, _dir = settings.GET_AGENT_VERSION_BY_SYSTEM(agent_system)
f = StringIO()
with TarFile.open(fileobj=f, mode='w:gz') as tar:
agent_path = os.path.join(settings.AGENT_DIR, "agent-linux")
agent_path = _dir
tar.add(agent_path, arcname='.', filter=exclude)
version_fileobj = StringIO(settings.AGENT_VERSION)
version_fileobj = StringIO(_vers)
version_info = TarInfo(name='version.txt')
version_info.size = len(version_fileobj.buf)
tar.addfile(version_info, version_fileobj)
......@@ -1684,14 +1687,15 @@ class UpdateAgentOperation(RemoteAgentOperation):
return encodestring(f.getvalue()).replace('\n', '')
@staticmethod
def create_windows_tar():
def create_windows_tar(agent_system):
_vers, _dir = settings.GET_AGENT_VERSION_BY_SYSTEM(agent_system)
f = StringIO()
agent_path = os.path.join(settings.AGENT_DIR, "agent-win")
agent_path = _dir
with TarFile.open(fileobj=f, mode='w|gz') as tar:
tar.add(agent_path, arcname='.')
version_fileobj = StringIO(settings.AGENT_VERSION)
version_fileobj = StringIO(_vers)
version_info = TarInfo(name='version.txt')
version_info.size = len(version_fileobj.buf)
tar.addfile(version_info, version_fileobj)
......@@ -1699,15 +1703,15 @@ class UpdateAgentOperation(RemoteAgentOperation):
return encodestring(f.getvalue()).replace('\n', '')
def _operation(self, user, activity, agent_system):
_vers, _dir = settings.GET_AGENT_VERSION_BY_SYSTEM(agent_system)
queue = self._get_remote_queue()
instance = self.instance
if agent_system == "Windows":
executable = os.listdir(
os.path.join(settings.AGENT_DIR, "agent-win"))[0]
data = self.create_windows_tar()
executable = sorted(os.listdir(_dir))[0]
data = self.create_windows_tar(agent_system)
elif agent_system == "Linux":
executable = ""
data = self.create_linux_tar()
data = self.create_linux_tar(agent_system)
else:
# Legacy update method
executable = ""
......@@ -1720,7 +1724,7 @@ class UpdateAgentOperation(RemoteAgentOperation):
chunk_size = 1024 * 1024
chunk_number = 0
index = 0
filename = settings.AGENT_VERSION + ".tar"
filename = _vers + ".tar"
while True:
chunk = data[index:index + chunk_size]
if chunk:
......@@ -1734,7 +1738,7 @@ class UpdateAgentOperation(RemoteAgentOperation):
agent_tasks.update.apply_async(
queue=queue,
args=(instance.vm_name, filename, executable, checksum)
).get(timeout=60)
).get(timeout=120)
break
......
......@@ -50,17 +50,19 @@ def garbage_collector(offset=timezone.timedelta(seconds=20)):
for i in Instance.objects.filter(destroyed_at=None).all():
logger.debug("Garbage_collector work_package:%d %s: %s:", work_package, i.pk, now > i.time_of_delete)
if i.time_of_delete and now > i.time_of_delete + grace_period and work_package > 0:
logger.debug("Garbage_collector delete")
work_package -= 1
i.destroy.async(system=True)
logger.debug("Garbage_collector delete")
logger.info("Expired instance %d destroyed.", i.pk)
try:
i.destroy.async(system=True)
i.owner.profile.notify(
ugettext_noop('%(instance)s destroyed'),
ugettext_noop(
'Your instance <a href="%(url)s">%(instance)s</a> '
'has been destroyed due to expiration.'),
instance=i.name, url=i.get_absolute_url())
except ActivityInProgressError:
logger.error("Expired instance %d can't be destroyed due the AtctivityInPorgressError.", i.pk)
except Exception as e:
logger.debug('Could not notify owner of instance %d .%s',
i.pk, unicode(e))
......@@ -78,7 +80,7 @@ def garbage_collector(offset=timezone.timedelta(seconds=20)):
'You can resume or destroy it.'),
instance=i.name, url=i.get_absolute_url())
except ActivityInProgressError:
logger.error("Expired instance %d can't be destroyed due the AtctivityInPorgressError.", i.pk)
logger.error("Expired instance %d can't be suspended due the AtctivityInPorgressError.", i.pk)
except Exception as e:
logger.info('Could not notify owner of instance %d .%s',
i.pk, unicode(e))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment