File: check.py

package info (click to toggle)
virtnbdbackup 2.42-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 672 kB
  • sloc: python: 4,426; makefile: 9
file content (135 lines) | stat: -rw-r--r-- 5,223 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
"""
Copyright (C) 2024  Michael Ablassmeier <abi@grinser.de>

This program 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.

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, see <https://www.gnu.org/licenses/>.
"""

import logging
from typing import List, Any
from argparse import Namespace
from libvirt import virDomain
from libvirtnbdbackup import virt
from libvirtnbdbackup import common as lib
from libvirtnbdbackup import exceptions

log = logging.getLogger()


def arguments(args: Namespace) -> None:
    """Check passed arguments for validity"""
    if args.compress is not False and args.type == "raw":
        raise exceptions.BackupException("Compression not supported with raw output.")

    if args.stdout is True and args.type == "raw":
        raise exceptions.BackupException("Output type raw not supported to stdout.")

    if args.stdout is True and args.raw is True:
        raise exceptions.BackupException(
            "Saving raw images to stdout is not supported."
        )

    if args.type == "raw" and args.level in ("inc", "diff"):
        raise exceptions.BackupException(
            "Stream format raw does not support incremental or differential backup."
        )


def targetDir(args: Namespace) -> None:
    """Check if target directory backup is started to meets
    all requirements based on the backup level executed"""
    if (
        args.level not in ("copy", "full", "auto")
        and not lib.hasFullBackup(args)
        and not args.stdout
    ):
        raise exceptions.BackupException(
            f"Unable to execute [{args.level}] backup: "
            f"No full backup found in target directory: [{args.output}]"
        )

    if lib.targetIsEmpty(args) and args.level == "auto":
        log.info("Backup mode auto, target folder is empty: executing full backup.")
        args.level = "full"
    elif not lib.targetIsEmpty(args) and args.level == "auto":
        if not lib.hasFullBackup(args):
            raise exceptions.BackupException(
                "Can't execute switch to auto incremental backup: "
                f"specified target folder [{args.output}] does not contain full backup.",
            )
        log.info("Backup mode auto: executing incremental backup.")
        args.level = "inc"
    elif not args.stdout and not args.startonly and not args.killonly:
        if not lib.targetIsEmpty(args):
            raise exceptions.BackupException(
                "Target directory already contains full or copy backup."
            )


def vmstate(args, virtClient: virt.client, domObj: virDomain) -> None:
    """Check virtual machine state before executing backup
    and based on situation, either fallback to regular copy
    backup or attempt to bring VM into paused state"""
    if domObj.isActive() == 0:
        args.offline = True
        if args.start_domain is True:
            log.info("Starting domain in paused state")
            if virtClient.startDomain(domObj) == 0:
                args.offline = False
            else:
                log.info("Failed to start VM in paused mode.")

    if args.level == "full" and args.offline is True:
        log.warning("Domain is offline, resetting backup options.")
        args.level = "copy"
        log.warning("New Backup level: [%s].", args.level)

    if args.offline is True and args.startonly is True:
        raise exceptions.BackupException(
            "Domain is offline: must be active for this function."
        )


def vmfeature(virtClient: virt.client, domObj: virDomain) -> None:
    """Check if required features are enabled in domain config"""
    if virtClient.hasIncrementalEnabled(domObj) is False:
        raise exceptions.BackupException(
            "Virtual machine does not support required backup features, "
            "please adjust virtual machine configuration."
        )


def diskformat(args: Namespace, disks: List[Any]) -> None:
    """Check if disks meet requirements for backup mode, if not, switch
    backup job to type copy."""
    if args.level != "copy" and lib.hasQcowDisks(disks) is False:
        args.level = "copy"
        raise exceptions.BackupException(
            "Only raw disks attached, switching to backup mode copy."
        )


def blockjobs(
    args, virtClient: virt.client, domObj: virDomain, disks: List[Any]
) -> None:
    """Check if there is an already active backup operation on the domain
    disks. If so, fail accordingly"""
    if (
        not args.killonly
        and not args.offline
        and virtClient.blockJobActive(domObj, disks)
    ):
        raise exceptions.BackupException(
            "Active block job for running domain:"
            f" Check with [virsh domjobinfo {args.domain}] or use option -k to kill the active job."
        )