qq2clone V 0.1.0

This commit is contained in:
Jesse Gardner 2021-03-17 08:55:34 -07:00
commit 7e033f0089
4 changed files with 3968 additions and 0 deletions

118
LICENSE Normal file
View File

@ -0,0 +1,118 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too.
When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.
Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and modification follow.
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.
You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.
c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.
In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.
3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.
If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.
5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.
7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.
This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.
10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.
one line to give the program's name and an idea of what it does. Copyright (C) yyyy name of author
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 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. Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker.
signature of Ty Coon, 1 April 1989 Ty Coon, President of Vice

527
man.pandoc Normal file
View File

@ -0,0 +1,527 @@
% QQ2CLONE(1) qq2clone 0.1
% Jesse Gardner
% February 2021
# NAME
qq2clone - Create and manage QEMU/KVM VMs using template machines and qcow2
images with backing files
# SYNOPSIS
**qq2clone** [*OPTION*]... *COMMAND* [*ARG*]...
# DESCRIPTION
**qq2clone** is a tool working on top of virsh that makes creating clones
of template QEMU/KVM machines simple. By using the copy on write feature
for which qcow2 is named, clones of an existing virtual machine can be made
without inadvertently altering the original image (with caveats - read the
**LIMITATIONS** section if you aren't already familiar with how copy on
write works). **qq2clone** makes creating and managing these clones simple
and efficient.
**qq2clone** supports creating numerous clones of a template and
performing batch operations on them - including the execution of arbitrary
commands with exec. This simplifies workflows involving large numbers of
virtual machines, or the frequent creation/destruction of virtual machines.
In addition to virsh, basic linux utilities and QEMU/KVM, qq2clone
requires:
Bash 4.0+
qemu-img
libvirt tools:
virt-clone
virt-xml
virt-xml-validate
xmllint (from libxml2)
If you want to easily establish graphical connections to your virtual
machines, you should have virt-viewer and/or spicy installed and configure
your templates to use Spice graphics. This is not strictly necessary, and
with the use of **qq2clone** **exec** and a small script of your own
you can automate connecting to Spice/VNC clients of your choice without
too much hassle
# OPTIONS
Not every option has an effect in the context of every command. Specifying
an option that has no effect in the context of the command being invoked
will not produce an error, it simply will not do anything
Options are parsed left to right, and right-hand options override
left-hand options. The only exception is for \-Q/\-\-quieter, which *must*
be the first option listed to work properly.
\-c, \-\-connection [*URI*]
: Specify a non-default connection URI: sets the value of
LIBVIRT_DEFAULT_URI
\-f, \-\-no\-spice
: Do not attempt to connect to a virtual machine's Spice graphics.
Overrides USE_SPICE setting in configuration
\-g, \-\-use\-spice
: Attempt to connect to a virtual machine's spice graphics. Overrides
SPICE setting in configuration
\-h, \-\-help
: Print basic help information and exit
\-n, \-\-no-run
: After making a clone of a template, do not run it. Overrides NORUN
setting in configuration
\-q, \-\-quiet
: Suppress most non-error output. Overrides QUIET setting in
configuration. Also suppresses various prompts for user choices, either
exiting with an error or making a safe default choice depending on the
command. Recommended only once familiar with the behavior of **qq2clone**
\-Q, \-\-quieter
: This option is (currently) required to appear immediately following the
invocation of **qq2clone**. Suppresses all output, error message or
otherwise, except when running interactive commands or
commands that require output to be useful. The commands for which output
is not entirely supressed are: config list, config info, list,
list-templates, exec, edit, modify-template edit, and check. Other
commands will receive only an exit code as output. This option is intended
for calling qq2clone from a script.
\-r, \-\-run
: Run a clone when creating it. Overrides NORUN setting in configuration
\-s, \-\-storage [*LOCATION*]
: When creating a clone, place new disk image file(s) at location
specified by [*LOCATION*]. [*LOCATION*] may be one of an absolute
filepath, or the name of a libvirt directory type storage pool. Also
defines where state files will be saved when using **save** command.
Overrides STORAGE option in configuration
\-S, \-\-spicy
: Use spicy rather than virt-viewer when connecting to the spice graphics
of a clone. Overrides SPICY setting in configuration
\-t, \-\-template [*NAME*]
: Use template of given name as context when executing a clone command
(see TYPES OF COMMAND section above). Overrides TEMPLATE option in
configuration
\-v, \-\-verbose
: Enable all output. Overrides QUIET setting in configuration
\-V, \-\-virt\-viewer
: Use virt-viewer rather than spicy when connecting to the spice graphics
of a clone. Overrides SPICY setting in configuration
# TYPES OF COMMAND
There are two main classes of commands: commands that operate directly on
templates, and commands that create or operate on clones of templates. In
order to make it less likely that the user may unintentionally invoke a
command of one class when they intended to invoke one of the other, they
use a different syntax. Commands that operate on templates use the syntax:
**qq2clone** **command** [*template-name*] [*ARG*] ...
while commands that operate on clones use the syntax:
**qq2clone** \-\-template [*template-name*] **command** [*ARG*] ...
Notice that commands operating on clones work within the context of a
template defined by the option \-\-template/\-t. Conversely, commands
operating on templates specify the template as an argument to the
command. There can also be a default template defined by the
TEMPLATE option in the configuration file, allowing the \-\-template
option to be omitted for commands that operate on clones. Commands
operating on templates do not respect this default - the template must
always be explicitly defined, further reducing the likelihood of
accidentally modifying or deleting a template.
# TEMPLATE COMMMANDS
**copy-template** [*CURRENT-NAME*] [*NEW-NAME*]
: Copy the XML of template *CURRENT-NAME* to a new template with
*NEW-NAME*. The new template will not receive a copy of the old template's
storage devices - it will point to the same locations
**delete-template** [*NAME*]
: Delete the template *NAME*. This operation will succeed only if there
are currently no clones of the template
**import-template** [*LIBVIRT-DOMAIN*] [*NAME*], **import-template**
[*XML-LOCATION*] [*NAME*]
: Import a new template from either an existing libvirt domain, or a fully
qualified filepath to a libvirt domain XML file on disk. If argument
*NAME* is ommited, qq2clone will assume you want to use the machine's name
as described in the XML file as the template name
**list-templates**
: List the names of all existing templates
**modify-template** [*NAME*] **sub-command** [*ARG*] ...
: Templates can be modified in various ways by invoking
**modify-template**. Each subcommand is described below
**modify-template** [*NAME*] **commit-image**
: After an image has been created and modified as desired using
**modify-template** [*NAME*] **prepare-image**, **commit-image** is used
to alter a template's underlying storage device by commiting any changes
made using prepare-image. See the commit command described in **man**
**qemu-img** for more information on how this works
**modify-template** [*NAME*] **destroy-image**
: Invoke virsh destroy on a running image created/run through
**modify-template** [*NAME*] **prepare-image**. This is generally not
wise, as it is equivalent to unplugging a physical machine and could cause
corruption to the image that will later be commited as a permanent change
to the template's image
**modify-template** [*NAME*] **discard-image**
: Delete an image produced by **modify-template** [*NAME*]
**prepare-image** without commiting any changes
**modify-template** [*NAME*] **edit**
: Edit the XML document defining a template
**modify-template** [*NAME*] **rename** [*NEW-NAME*]
: Change the name of a template, and all of its clones
**modify-template** [*NAME*] **prepare-image**
: Create and/or run a clone that acts as a staging area for changes to
the `template's` actual image. For instance, you could update the
`template's` software by running **modify-template** [*NAME*]
**prepare-image**, updating the clone produced by this command,
shutting it down, and then running **modify-template** [*NAME*]
**commit-image**. This serves a twofold purpose - to prevent incidental
damage to an underlying image by providing a safe buffer to work in, and
to allow modifications to be safely prepared for an underlying image even
while that image has existing clones.
# CLONE COMMANDS
A description of the argument *SET* is described in the **SETS** section
below
**clone** [*NUMBER*]
: Invoke without any argument to produce a single clone. Supply a number
as an argument to specify the number of clones to create
**connect** [*SET*]
: Start any machine in *SET* that `isn't` already running. If any machine
in *SET* has spice graphics and spicy or virt-viewer is installed, use one
or the other (chosen by command-line option or configuration) to connect
to the graphical console
**destroy** [*SET*]
: Invoke virsh destroy on any running machine in *SET* (in other words, if
the domain is running forcibly turn it off)
**edit** [*NUMBER*]
: Edit the XML file of the clone with given number
**exec** [*SET*] [*command-string*]
: For every machine in *SET*, sequentially, execute the contents of the
command string in an environment where the following variables are defined
per clone: `"$uuid"`, `"$name"`, `"$disks"` (a newline delimited string
containing the machine's qcow2 disk device filepaths). This is done using
bash's eval command, so be sure to put any instances of these variables in
single quotes (double quotes inside the single quotes is best practice) or
they will not be set properly. If any instance of exec has a non-zero
return value, execution stops.
**list** [*ARG*]
: Without arguments, list all clones of the current template and their
state. With argument "all", provide list including all clones of every
template. With argument "xml", produce an XML document with information
about every template, their clones, and their state. The XML option
is not complete - its format is at this point defined only implicitly, by
the output of this command.
**resume** [*SET*]
: Resume any suspended machines in *SET*
**rm** [*SET*]
: Destroy every domain in *SET* (if running), undefine them and delete
their storage volumes
**rm-wipe** [*SET*]
: Destroy every domain in *SET* (if running), undefine them and wipe their
storage volumes using virsh
**rm-shred** [*SET*]
: Destroy every domain in *SET* (if running), undefine them and shred
their storage volumes
**save** [*SET*]
: Save execution state of every running domain in *SET* to file
**save-rm** [*SET*]
: Delete the state file associated with every machine in *SET*
**start** [*SET*]
: Start every machine in *SET* that is currently not running. For saved
domains, their state will be restored
**suspend** [*SET*]
: Suspend execution of every machine in *SET*
# OTHER COMMANDS
**check** [*TEMPLATE-NAME*]
: As described in the limitations section, there are ways that qq2clone
can lose track of a clone. If this happens, it will remain in qq2clone's
database, its ID number will remain reserved, and its image files may not
be deleted and take up space doing nothing. the **check** command tries to
find and fix this and other problems. The *TEMPLATE-NAME* argument is
optional, and restricts the check to that template and its clones.
Otherwise, all templates are checked
**config** list, **config** info [*OPTION*], **config** edit [*OPTION*]
: List all configuration options and their current value, get info about a
particular option, or edit one
# SETS
*SET* is listed as an argument to many commands. *SET* simply describes a
set of virtual machines - clones of a given template. *SET* is a comma
delimited list with no whitespace. *SET* can be an individual machine or
several individual machines designated by number:
1 (Machine 1)
3,7 (Machines 3 and 7)
Machine numbers can be shown with **qq2clone** **list**. Ranges and
omitted values are supported as well:
1,2-5,^3 (Machines 1 and 2-5 excluding 3)
1-10,^3-7 (Machines 1-10 excluding 3-7)
Lastly, groups of machines can be addressed by their state:
all (All machines)
all,^running (All machines that aren't running)
^running,1-10 (Machines 1-10 except those that are running)
The possible states of a virtual machine are based on the states listed in
**man virsh**, with some modifications. States in qq2clone are:
all
crashed
idle
in-shutdown
off
paused
pmsuspended
running
saved
Specifying machines that do not exist will not cause an error: i.e.,
1-10 is a valid set even if only machines 3-7 exist. A set will only cause
an error if it is malformed, includes zero existing machines, contains no
machines that the command being invoked may act upon, or includes numbers
less than 1.
# CONFIG
There is no need to refer to the manual to understand configuration
options. Use "**qq2clone** config list" to see all options and their
current values, and "**qq2clone** config info [*OPTION*]" to get
information about a particular option. However, here is the same
information provided by **qq2clone** info for each option
TEMPLATE
> This template will be used for commands like clone, rm, destroy when
option \-\-template/\-t is not specified
>
> Default value: Default value: `'0'`
TEMPLATE_DIR
> This is the where template XML files will be kept
>
> Default value: `'${HOME}/storage-qq2clone/templates'`
QUIET
> If set to 1, most non-error output will be suppressed
>
> Default value: `'0'`
USE_SPICE
> If set to 1, attempt to connect
> to the spice graphics of a virtual machine by default when cloning it,
if it is configured to use spice graphics. qq2clone can do this using the
programs spicy and virt-viewer. If either is installed on your system
during the first run, the default value is `'1'` (enabled). Otherwise, the
default value is `'0'`
S_TIMEOUT
> Wait this many seconds before timing out when trying to connect to a
virtual `machine's` spice graphics.
>
> Default value: `'10'`
STORAGE
> The default location to store clone images when creating them. Changing
this location is fine, but it is a good idea to ensure that whatever
location you do choose is only used by qq2clone
>
> Default value: `'${HOME}/storage-qq2clone/qq2clone-pool'`
# EXAMPLES
**qq2clone** \-\-template Debian \-\-run \-\-virt-viewer clone
: Make a clone of Debian, run it, and connect to its spice graphics using
virt\-viewer. All of these options could have instead been defined in the
configuration, so that the entire command would be: **qq2clone** clone
**qq2clone** \-\-template Debian exec 3 'virsh console "$uuid"'
: Use virsh to connect to the serial console of template Debian's clone
with number 3 (as shown in **qq2clone** list)
**qq2clone** **modify-template** Debian *prepare-image*
: Create a clone of Debian that can be used as a staging area for
permanent changes to the backing template storage device
**qq2clone** **modify-template** Debian **commit-image**
: Commit changes to the image Debian staged with the previous command
**qq2clone** **copy-template** Debian Debian_2
: Copy the XML of template Debian, creating a new template with the same
backing storage device that you can edit as you please
# LIMITATIONS
The largest limitation of **qq2clone** is that it cannot protect your
template images from the actions of other software. If nothing else
touches a template's storage volumes, qq2clone can safely handle them
(barring unknown bugs or bad luck during a commit-image). However,
if something else alters the image upon which a template is based, its
existing clones may be corrupted and future clones may behave differently
than expected. It is the user's responsibility to understand this aspect
of copy on write and carefully manage template images. Future updates to
qq2clone may add features that give some additional protections, but this
risk is inherent to copy on write.
Libvirt has permissions errors when a storage pool is in a "hidden"
directory with a name beginning with "." and qcow2 files with backing files
are involved. This may be due to apparmor, or it may be an issue with
libvirt. It is unknown how widespread this issue is, but it is the reason
that the default directory storage-qq2clone does not start with '.'
If the UUID of a clone is changed, qq2clone will no longer be able to
track it and will not be able to perform commands on it anymore.
If virsh undefine is run on a clone, qq2clone will not be able to see
it once it is turned off. This limitation will be eliminated or reduced in
the future, when qq2clone moves away from relying on virsh and implements
direct usage of the libvirt API. It could be addressed now by using
transient domains, but that would require qq2clone to do more things
manually instead of just invoking virsh. Since the plan is to
transition to a different approach later, that would be wasted effort. For
now, if you find yourself in this position just use **qq2clone** check.
qq2clone can only produce clones by making qcow2 image files. The backing
file need not be qcow2, but the images produced by qq2clone always will
be. This is unlikely to ever change - levaraging the features of qcow2 is
the entire purpose of qq2clone. If it does change, qq2clone will need a
new name.
qq2clone does not support creating images in pool types other than
directories, and attempting to use a machine as a template when it has
storage volumes in a non-directory pool is likely to fail or have
unexpected results. Support for some other pool types may be added in the
future.
qq2clone currently cannot copy storage volumes when importing a template
(it just references the originals), or when copying a template. This will
change in the future, and qq2clone will also be able to handle more complex
relationships between templates, clones and their images
# FILES
~/.config/qq2clone
: This document simply contains a string defining the location at which
qq2clone will store files, including the database containing the rest of
it configuration options. Currently, qq2clone cannot run without ${HOME}
being defined unless a few lines are altered to refer to a new location
~/storage-qq2clone
: Directory where qq2clone stores all files and binary executables. Can be
changed by modifying ~/.config/qq2clone. This directory is not
named "qq2clone" because it can then slightly interfere with bash
completion when in the home directory, and it does not start with a '.'
for the reasons described in the **LIMITATIONS** section above
~/storage-qq2clone/qq2clone.db
: sqlite3 database containing the configuration information for qq2clone,
as well as data about templates and clones
~/storage-qq2clone/qq2clone-pool
: Storage pool used for clone images and saved state files, if the
\-\-storage option is not used when creating or saving a clone and the
option STORAGE is not changed in the configuration file
~/qq2clone/templates
: Directory in which template XML files are stored. These can be edited
manually, but it is more advisable to use **qq2clone** **modify-template**
[*template-name*] edit
# BUGS
As described in the options section, the implementation of the
\-\-quieter/\-Q option needs some work. Its current behavior is the
easiest functional approach without complicating the options parser, but it
will eventually be modified and become better behaved. In addition to the
previously described problem, very early error messages will not be
suppressed. Most likely, the solution is to implement a better options
parser and make it the first thing to run when executing qq2clone. However,
the impact of this bug is minimal and other improvements are likely to
come before this bug fix.
If you find any worse bugs, and I'm sure I missed some, please let me know
and I will fix them as time allows.
# EXIT VALUES
**10**
: No permission to access file or file doesn't exist
**11**
: Required software dependencies are not met (see description for a list),
or are cannot be found in PATH
**12**
: Invalid command line argument specified, or command specifies an invalid
action
**13**
: Problem with a template - i.e., specified template does not exist, or
import-template failed because template of specified name already exists
**14**
: Invocation of an external command failed
**15**
: Problem with a libvirt XML file
**16**
: Attempted action with a libvirt tool resulted in failure
**17**
: Could not establish graphical spice connection to machine before timeout
expired
**18**
: A file is of the wrong type or does not exist
**19**
: Unexpected error - a bug in qq2clone, or a highly unexpected failure of
some command

3218
qq2clone Executable file

File diff suppressed because it is too large Load Diff

105
qq2clone.completion Executable file
View File

@ -0,0 +1,105 @@
#!/bin/bash
#shellcheck disable=1090 disable=2012
[[ -e "${HOME:?}/.config/qq2clone" ]] || return 1
QQ2_DIR="$(<"${HOME}/.config/qq2clone")"
[[ "$QQ2_DIR" =~ ^[[:space:]]*([^[:space:]].*)$ ]] &&
QQ2_DIR="${BASH_REMATCH[1]}"
[[ "$QQ2_DIR" =~ ^(.*[^[:space:]])[[:space:]]*$ ]] &&
QQ2_DIR="${BASH_REMATCH[1]}"
[[ -e "${QQ2_DIR}/sqlite3" ]] || return 1
chmod +rw "${QQ2_DIR}/sqlite3" &>/dev/null || return 1
declare -a templates
declare line
while read -r line; do
templates=( "${templates[@]}" "$line" )
done < <("${QQ2_DIR}/sqlite3" --batch "${QQ2_DIR}/qq2clone.db" \
"select name from TEMPLATES")
_qq2clone ()
{
declare -a COMS FLAGS
COMS=( check clone config connect copy-template delete-template destroy \
edit exec import-template list list-templates modify-template restore \
resume rm rm-save save shred shred-save start suspend )
FLAGS=( connection no-spice use-spice help no-run quiet quieter run spicy \
storage template verbose virt-viewer )
local LAST_ARG THIS_ARG B4_LAST_ARG P set_coms
(( COMP_CWORD > 0 )) &&
LAST_ARG="${COMP_WORDS[$((COMP_CWORD - 1))]}"
(( COMP_CWORD > 1 )) &&
B4_LAST_ARG="${COMP_WORDS[$((COMP_CWORD - 2))]}"
THIS_ARG="${COMP_WORDS[$COMP_CWORD]}"
set_coms="connect|destroy|exec|resume|rm|rm\-save|save|shred|shred\-save|"
set_coms="${set_coms}start|suspend|restore"
declare -a suggestions
if [[ "$THIS_ARG" =~ ^\-\- ]]; then
suggestions=("${FLAGS[@]}")
P="--"
elif [[ "$LAST_ARG" =~ ^(\-|modify|delete|copy)\-template$ ]] ||
[[ "$LAST_ARG" == "template-snapshot" ]] ||
[[ "$LAST_ARG" == "-t" ]]; then
suggestions=( "${templates[@]}" )
elif [[ "$LAST_ARG" =~ ^(\-\-storage|\-s)$ ]]; then
read -ra suggestions < <(virsh pool-list --name | tr -d '\n')
elif [[ "$LAST_ARG" == "config" ]]; then
suggestions=( list edit info )
elif [[ "$LAST_ARG" =~ ^(${set_coms})$ ]]; then
suggestions=( all running saved off in-shutdown idle paused crashed )
suggestions=( "${suggestions[@]}" pmsuspended )
elif [[ "$LAST_ARG" == "list" ]] &&
[[ ! "$B4_LAST_ARG" == "config" ]]; then
suggestions=( all xml )
else
local curr_com word elem
for word in "${COMP_WORDS[@]}"; do
for elem in "${COMS[@]}"; do
[[ "$elem" == "$word" ]] && { curr_com="$word"; break 2; }
done
done
if [[ -n "$curr_com" ]]; then
if [[ "$curr_com" == "modify-template" ]] &&
[[ "${COMP_WORDS[$((COMP_CWORD - 2))]}" == "$curr_com" ]]; then
suggestions=( edit prepare-image commit-image discard-image \
destroy-image rename )
elif [[ "$curr_com" == config ]] &&
[[ "${COMP_WORDS[$((COMP_CWORD - 2))]}" == "$curr_com" ]] &&
[[ "$LAST_ARG" =~ ^(info|edit)$ ]]; then
local line
while read -r line; do
[[ "$line" =~ \
^[[:space:]]*([^[:space:]].*[^[:space:]])[[:space:]]*$ ]] &&
line="${BASH_REMATCH[1]}"
[[ "$line" =~ ^# ]] && continue
[[ "$line" =~ ^([^=]+).* ]] &&
suggestions=( "${suggestions[@]}" "${BASH_REMATCH[1]}" )
done <"${QQ2_DIR}/config"
suggestions=(NORUN QUIET USE_SPICE SPICY STORAGE S_TIMEOUT TEMPLATE \
TEMPLATE_DIR)
else
suggestions=( )
fi
else
suggestions=("${COMS[@]}")
fi
fi
local i
declare -a comp
for ((i=0;i<${#suggestions[@]};i++)); do
if [[ "${P}${suggestions["$i"]}" =~ ^"${THIS_ARG}" ]]; then
comp=( "${comp[@]}" "${suggestions["$i"]}" )
fi
done
(( ${#comp} > 0 )) &&
read -ra COMPREPLY < <(compgen -P "${P}" -W "${comp[*]}" | tr "\n" " ")
}
complete -F _qq2clone qq2clone