# Copyright 2014 Budapest University of Technology and Economics (BME IK) # # This file is part of CIRCLE Cloud. # # CIRCLE is free software: you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free # Software Foundation, either version 3 of the License, or (at your option) # any later version. # # CIRCLE is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more # details. # # You should have received a copy of the GNU General Public License along # with CIRCLE. If not, see <http://www.gnu.org/licenses/>. from common.models import create_readable from manager.mancelery import celery from vm.tasks.agent_tasks import (restart_networking, change_password, set_time, set_hostname, start_access_server, cleanup, update, change_ip) from firewall.models import Host import time from base64 import encodestring from StringIO import StringIO from tarfile import TarFile, TarInfo from django.conf import settings from django.db.models import Q from django.utils import timezone from django.utils.translation import ugettext_noop from celery.result import TimeoutError from monitor.client import Client def send_init_commands(instance, act): vm = instance.vm_name queue = instance.get_remote_queue_name("agent") with act.sub_activity('cleanup', readable_name=ugettext_noop('cleanup')): cleanup.apply_async(queue=queue, args=(vm, )) with act.sub_activity('change_password', readable_name=ugettext_noop('change password')): change_password.apply_async(queue=queue, args=(vm, instance.pw)) with act.sub_activity('set_time', readable_name=ugettext_noop('set time')): set_time.apply_async(queue=queue, args=(vm, time.time())) with act.sub_activity('set_hostname', readable_name=ugettext_noop('set hostname')): set_hostname.apply_async( queue=queue, args=(vm, instance.short_hostname)) def send_networking_commands(instance, act): queue = instance.get_remote_queue_name("agent") with act.sub_activity('change_ip', readable_name=ugettext_noop('change ip')): change_ip.apply_async(queue=queue, args=( instance.vm_name, ) + get_network_configs(instance)) with act.sub_activity('restart_networking', readable_name=ugettext_noop('restart networking')): restart_networking.apply_async(queue=queue, args=(instance.vm_name, )) def create_agent_tar(): def exclude(tarinfo): if tarinfo.name.startswith('./.git'): return None else: return tarinfo f = StringIO() with TarFile.open(fileobj=f, mode='w|gz') as tar: tar.add(settings.AGENT_DIR, arcname='.', filter=exclude) version_fileobj = StringIO(settings.AGENT_VERSION) version_info = TarInfo(name='version.txt') version_info.size = len(version_fileobj.buf) tar.addfile(version_info, version_fileobj) return encodestring(f.getvalue()).replace('\n', '') @celery.task def agent_started(vm, version=None): from vm.models import Instance, instance_activity, InstanceActivity instance = Instance.objects.get(id=int(vm.split('-')[-1])) queue = instance.get_remote_queue_name("agent") initialized = instance.activity_log.filter( activity_code='vm.Instance.agent.cleanup').exists() with instance_activity(code_suffix='agent', readable_name=ugettext_noop('agent'), concurrency_check=False, instance=instance) as act: with act.sub_activity('starting', readable_name=ugettext_noop('starting')): pass for i in InstanceActivity.objects.filter( (Q(activity_code__endswith='.os_boot') | Q(activity_code__endswith='.agent_wait')), instance=instance, finished__isnull=True): i.finish(True) if version and version != settings.AGENT_VERSION: try: update_agent(instance, act) except TimeoutError: pass else: act.sub_activity('agent_wait', readable_name=ugettext_noop( "wait agent restarting"), interruptible=True) return # agent is going to restart if not initialized: measure_boot_time(instance) send_init_commands(instance, act) send_networking_commands(instance, act) with act.sub_activity('start_access_server', readable_name=ugettext_noop( 'start access server')): start_access_server.apply_async(queue=queue, args=(vm, )) def measure_boot_time(instance): if not instance.template: return from vm.models import InstanceActivity deploy_time = InstanceActivity.objects.filter( instance=instance, activity_code="vm.Instance.deploy" ).latest("finished").finished total_boot_time = (timezone.now() - deploy_time).total_seconds() Client().send([ "template.%(pk)d.boot_time %(val)f %(time)s" % { 'pk': instance.template.pk, 'val': total_boot_time, 'time': time.time(), } ]) @celery.task def agent_stopped(vm): from vm.models import Instance, InstanceActivity instance = Instance.objects.get(id=int(vm.split('-')[-1])) qs = InstanceActivity.objects.filter(instance=instance, activity_code='vm.Instance.agent') act = qs.latest('id') with act.sub_activity('stopping', readable_name=ugettext_noop('stopping')): pass def get_network_configs(instance): interfaces = {} for host in Host.objects.filter(interface__instance=instance): interfaces[str(host.mac)] = host.get_network_config() return (interfaces, settings.FIREWALL_SETTINGS['rdns_ip']) def update_agent(instance, act=None): if act: act = act.sub_activity( 'update', readable_name=create_readable( ugettext_noop('update to %(version)s'), version=settings.AGENT_VERSION)) else: from vm.models import instance_activity act = instance_activity( code_suffix='agent.update', instance=instance, readable_name=create_readable( ugettext_noop('update agent to %(version)s'), version=settings.AGENT_VERSION)) with act: queue = instance.get_remote_queue_name("agent") update.apply_async( queue=queue, args=(instance.vm_name, create_agent_tar())).get(timeout=10)