#!/usr/bin/python2
#
# Copyright (c) 2016-2017, Parallels International GmbH
# Copyright (c) 2017-2019 Virtuozzo International GmbH. All rights reserved.
#
# This file is part of Virtuozzo Core. Virtuozzo Core 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 2 of the License, or (at your option) any
# later version.
#
# This program 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 this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
#
# Our contact details: Virtuozzo International GmbH, Vordergasse 59, 8200
# Schaffhausen, Switzerland.
#

import os
import re
import sys
import shutil
import errno
import prlsdkapi

units_to_start = ()

# Import config file
try:
    sys.path.insert(0, "/var/spool/prl-disp")
    import prl_disp_autostart
    units_to_start = prl_disp_autostart.units_to_start
    sys.path.pop(0)
except:
    pass

# Get units dir
try:
    unitsdir = sys.argv[3]
except:
    unitsdir = "/run/systemd/generator.late"

# Maximum timeout - 32400000 seconds (9000 hours)
timeout = 32400000 * 1000

# Units list
unitslist = []

deftarget = "virtuozzo.target"

started_dir = "/run/vz-generator"
target_dir = unitsdir + "/" + deftarget + ".wants"
lockfile = "/run/lock/vz-autostart.lock"

def log(mess):
    with open("/dev/kmsg", "w") as f:
        f.write(mess + "\n")
        f.close()

def error(mess):
    log(mess)
    sys.exit(1)

def get_vmtype(vmtype):
    if vmtype == prlsdkapi.consts.PVT_CT:
        return "Container"
    return "Virtual Machine"

def get_classtype(obj):
    return re.sub("^Systemd_", "", obj.__class__.__name__)

class Systemd_unit(object):
    def __init__(self, config):
        self.uuid = config.get_uuid()
        self.service_prefix = "vz_"
        self.deftarget = deftarget
        self.description = " ".join((get_vmtype(config.get_vm_type()), self.uuid, get_classtype(self)))

    @property
    def nobr_uuid(self):
        return re.sub("({|})", "", self.uuid)

    @property
    def unitname(self):
        return self.service_prefix + self.nobr_uuid + ".%s" % get_classtype(self)

    @property
    def unitname_f(self):
        return unitsdir + "/" + self.unitname

    def exists(self):
        return os.path.exists(self.unitname)

    def install(self):
        if self.exists():
            return
        with open(self.unitname_f, "w") as f:
            f.write(str(self))
            f.close()

class Systemd_service(Systemd_unit):
    def __init__(self, config):
        super(Systemd_service, self).__init__(config)

    def __str__(self):
        return \
"[Unit]\n" \
"Description={self.description}\n" \
"After={self.deftarget} prl-disp.service vz.service\n" \
"\n" \
"[Service]\n" \
"ExecStart=/bin/prlctl start {self.uuid}\n" \
"Type=simple\n" \
"RestartSec=60s\n" \
"RestartForceExitStatus=253\n" \
"\n".format(**locals())

class Systemd_timer(Systemd_unit):
    def __init__(self, config):
        super(Systemd_timer, self).__init__(config)
        self.autostart = config.get_auto_start_delay()

    def __str__(self):
        return \
"[Unit]\n" \
"Description={self.description}\n" \
"\n" \
"[Timer]\n" \
"OnActiveSec={self.autostart}\n" \
"\n" \
"[Install]\n" \
"WantedBy={self.deftarget}\n".format(**locals())

    def install(self):
        super(Systemd_timer, self).install()
        try:
            os.symlink(self.unitname_f, target_dir + "/" + self.unitname)
        except OSError, e:
            if e.errno == errno.EEXIST:
                pass
            else:
                error("Failed to create %s: %s" % (_dir, e))

class Unit():
    def __init__(self, config):
        self.service = Systemd_service(config)
        self.timer = Systemd_timer(config)

    def install(self):
        self.service.install()
        self.timer.install()

# Create base directories
for _dir in (started_dir, target_dir):
    try:
        os.mkdir(_dir)
    except OSError, e:
        if e.errno == errno.EEXIST:
            pass
        else:
            error("Failed to create %s: %s" % (_dir, e))

if os.path.exists(lockfile):
    error("Autostart in progress")
try:
    # Connect to dispatcher
    prlsdkapi.init_server_sdk()
    server = prlsdkapi.Server()
    server.login_local().wait(msecs = timeout)

    # Get VMs + CT list
    vms = server.get_vm_list_ex(prlsdkapi.consts.PVTF_VM + prlsdkapi.consts.PVTF_CT)
    for res in [ r for r in vms.wait(msecs = timeout)
            if r.get_config().get_auto_start() ]:
        if res.get_config().get_auto_start() == prlsdkapi.consts.PAO_VM_START_ON_RELOAD and \
                res.get_config().get_uuid() not in units_to_start:
            continue
        unitslist.append(Unit(res.get_config()))

    # Disconnect
    server.logoff().wait(msecs = timeout)
    prlsdkapi.deinit_sdk()
except Exception, err:
    if not unitslist:
        error(repr(err))

for unit in unitslist:
    unit.install()

# lock file is on tmpfs will be released on node boot
open(lockfile, 'w').close()
