integrated lv_api_do into qq2clone for load_template

This commit is contained in:
Jesse Gardner 2021-03-22 18:24:54 -07:00
parent e11b7e85e2
commit 2f89821404
3 changed files with 140 additions and 83 deletions

BIN
lv_api_do

Binary file not shown.

View File

@ -27,7 +27,7 @@ const char CONN_BAD[]= "# No Connection";
const char CONN_GOOD[]="# Connected";
/*After a command is issued, one of these displays. Only GOOD is followed
by the requested information */
by the requested information, then EOF */
const char BAD_REQ[]="# Bad Request";
const char FATAL[]= "# Fatal error";
const char GOOD[]= "# Making API Request";
@ -47,6 +47,7 @@ const char NOMATCH[]="# No matching domain";
*/
int main () {
setlinebuf(stdout); /* Make sure output is always line buffered */
/* Connect to libvirt API */
conn=virConnectOpen(NULL);
int loop=1;
@ -117,30 +118,30 @@ int main () {
***********************************/
void pr_bad() {
printf("+%s\n",BAD_REQ);
printf("%s\n",BAD_REQ);
}
void pr_conn_bad() {
printf("+%s\n", CONN_BAD);
printf("%s\n", CONN_BAD);
}
void pr_conn_good() {
printf("+%s\n",CONN_GOOD);
printf("%s\n",CONN_GOOD);
}
/* Okay, this one provides a basic output sequence *and* quits */
void pr_fatal_and_exit(int e) {
printf("+%s\n",FATAL);
printf("%s\n",FATAL);
virConnectClose;
exit(e);
}
void pr_good() {
printf("+%s\n",GOOD);
printf("%s\n",GOOD);
}
void pr_no_match() {
printf("+%s\n",NOMATCH);
printf("%s\n",NOMATCH);
}
/*****************************************
@ -197,6 +198,7 @@ void lv_get_name (char *uuid){
if (name!=NULL){ printf("+%s\n",name); }
else { pr_fatal_and_exit(E_LIBVIRT); }
virDomainFree(domain);
printf("EOF\n");
}else{
pr_no_match();
}
@ -216,6 +218,7 @@ void lv_get_state(char *uuid){
virDomainFree(domain);
free(state);
free(reason);
printf("EOF\n");
}else{
pr_no_match();
}
@ -228,7 +231,6 @@ void lv_get_xml(char *uuid){
char *xml;
xml=virDomainGetXMLDesc(domain, 0);
if ( xml!=NULL ){
char *token;
token=strtok(xml, "\n");
if(token==NULL) { free(xml); virDomainFree(domain); return; }
@ -238,10 +240,10 @@ void lv_get_xml(char *uuid){
token=strtok(NULL, "\n");
}
free(xml);
}
else { pr_fatal_and_exit(E_LIBVIRT); }
} else { pr_fatal_and_exit(E_LIBVIRT); }
virDomainFree(domain);
}else{
printf("EOF\n");
} else {
pr_no_match();
}
}
@ -250,7 +252,7 @@ void lv_list_all_uuid() {
virDomainPtr *domains;
int ret_list, ret_uuid, i;
ret_list=virConnectListAllDomains(conn,&domains,0);
if(ret_list<0){ virConnectClose(conn);
if(ret_list<0){ virConnectClose(conn);
pr_fatal_and_exit(E_LIBVIRT); };
pr_good();
@ -259,12 +261,13 @@ void lv_list_all_uuid() {
ret_uuid=virDomainGetUUIDString(domains[i],uuid);
if (ret_uuid==0) {
printf("+%s\n",uuid);
virDomainFree(domains[i]);
}
virDomainFree(domains[i]);
}
free(uuid);
free(domains);
printf("EOF\n");
}
void lv_list_all_name() {
@ -283,4 +286,5 @@ void lv_list_all_name() {
}
free(domains);
printf("EOF\n");
}

193
qq2clone
View File

@ -1,11 +1,11 @@
#!/bin/bash
#shellcheck disable=1090 disable=2012
#-----------------#
#@@@@@@@@@@@@@@@@@#
#---ERROR CODES---#
#@@@@@@@@@@@@@@@@@#
#-----------------#
#--------------------#
#@@@@@@@@@@@@@@@@@@@@#
#---LITERAL VALUES---#
#@@@@@@@@@@@@@@@@@@@@#
#--------------------#
E_permission=10 # No permission for access or file does not exist
E_depends=11 # Lacking required software
@ -20,6 +20,16 @@ E_timeout=17 # Timeout was exceeded before spice connection to clone
E_file=18 # Expected file does not exist or is of wrong type/format
E_unexpected=19 # Probably a bug in qq2clone
# lv_api_do prints one of these when started
CONN_BAD="# No Connection"
CONN_GOOD="# Connected"
# lv_api_do prints one of these immediately following a line of input
BAD_REQ="# Bad Request"
FATAL="# Fatal error"
GOOD="# Making API Request"
NOMATCH="# No matching domain"
#---------------------------------------------------#
#@@@#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#
#---NAMED PIPE FOR PASSING DATA BETWEEN FUNCTIONS---#
@ -55,8 +65,7 @@ TEMPDIR=$(mktemp -d) || temp_error
#shellcheck disable=2064
trap "exec 3>&-; exec 3<&-;rm -rf $TEMPDIR" EXIT
fifo_path="${TEMPDIR}/qq2clone_fifo"
mkfifo "$fifo_path" ||
{ echo "Cannot make fifo" >&2; exit "$E_extcom" ;}
mkfifo "$fifo_path" || fifo_error
exec 3<>"$fifo_path"
return 0
}
@ -75,7 +84,7 @@ read_pipe ()
echo "EOF" >&3
local line match
while IFS= read -r line <&3; do
# write_pipe puts a + at the start of every line for read_pipe
# write_pipe puts a + at the start of every line
if [[ "$line" =~ ^\+(.*)$ ]]; then
match="${BASH_REMATCH[1]}"
echo "$match"
@ -114,6 +123,78 @@ fi
return 0
}
#-------------------#
#@@@@@@@@@@@@@@@@@@@#
#---USE LV_API_DO---#
#@@@@@@@@@@@@@@@@@@@#
#-------------------#
#=========================================================================#
lv_api_do_open ()
# DESCRIPTION: Open lv_api_do in background
# INPUT: None
# OUTPUT: Return 0 on success, exit on failure
# PARAMETERS: None
#=========================================================================#
{
declare -g lv_api_temp;
lv_api_temp="$(mktemp -d )" || temp_error
mkfifo "${lv_api_temp}/lv_api_do_fifo" || fifo_error
exec 4<>"${lv_api_temp}/lv_api_do_fifo"
${QQ2_DIR}/lv_api_do <&4 >&3 2>/dev/null &
local check
read -r check <&3
[[ "$check" == "$CONN_BAD" ]] && lv_api_do_bad_conn
[[ "$check" == "$CONN_GOOD" ]] || unexpected_error lv_api_do_open
return 0
}
#=========================================================================#
lv_api_do_comm ()
# DESCRIPTION: Issue a command to lv_api_do
# INPUT: The command
# OUTPUT: Return 0 on success, lv_api_do output can be accessed with
# read_pipe. Return 1 on failure. Exit and error message if lv_api_do
# encounters a fatal error
# PARAMETERS: $@: command string to lv_api_do
#=========================================================================#
{
echo "$*" >&4
local check
read -r check <&3
[[ "$check" == "$BAD_REQ" ]] && unexpected_error lv_api_do_comm
[[ "$check" == "$NOMATCH" ]] && return 1
[[ "$check" == "$FATAL" ]] &&
{ echo "Error using libvirt API" >&2; exit "$E_libvirt"; }
[[ "$check" == "$GOOD" ]] || unexpected_error lv_api_do_comm
# This loop avoids a race condition when trying to read_pipe later by
# ensuring that lv_api_do has finished its output before this function
# returns
local line
while read -r line <&3; do
[[ "$line" == "EOF" ]] && break
write_pipe 0 "${line:1}"
done
return 0
}
#=========================================================================#
lv_api_do_close ()
# DESCRIPTION: Tell lv_api_do to exit and close the extra pipe
# INPUT: None
# OUTPUT: None
# PARAMETERS: None
#=========================================================================#
{
echo "exit" >&4
exec 4>&-
exec 4<&-
rm -rf "${lv_api_temp:?}"
return 0
}
#-------------------------------------------#
#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#
#---GET/ALTER CONFIGURATION, CHECK SYSTEM---#
@ -1147,6 +1228,28 @@ check="$(sqlite3 "select exists ( select * from TEMPLATES where\
return 1
}
#=========================================================================#
fifo_error ()
# DESCRIPTION: Error to display if fifo creation files
# INPUT: None
# OUTPUT: Error message and exit code
# PARAMETERS: None
#=========================================================================#
{
echo "Cannot make fifo"
exit "$E_extcom"
} >&2
#=========================================================================#
lv_api_do_bad_conn ()
# DESCRIPTION: Error displayed when lv_api_do cannot connect to API
# INPUT: None
# OUTPUT: Error message and exit code
# PARAMETERS: None
#=========================================================================#
{
echo "Cannot connect to libvirt API"
exit "$E_libvirt"
} 2>/dev/null
#=========================================================================#
set_error ()
# DESCRIPTION: Used when convert_to_seq fails
# INPUT: None
@ -2098,12 +2201,6 @@ load_template ()
# PARAMETERS: None
#=========================================================================#
{
# This is a hacky way of getting the information we need in a reasonably
# performant manner. It is a bit fragile, but not overly so assuming that
# virsh's output is fairly consistent across versions. This method is
# temporary, as later on qq2clone will include portions in C that use the
# libvirt API instead of virsh
check_template
unset BAD_CL CL_MAP CL_STATE NAME_MAP
declare -ga BAD_CL CL_MAP CL_STATE NAME_MAP
@ -2123,29 +2220,13 @@ while read -r id; do
uuid_map["$uuid"]="$id"
done < <(sqlite3 "select id,uuid from CLONES where template='$t';")
# To use virsh in shell mode without having to repeatedly invoke it in
# different subshells for a large performance penalty, we will run it in
# the background and write to it with one fifo while reading it from
# another
local temp
temp="$(mktemp -d)" || temp_error
mkfifo "$temp/fifo" &>/dev/null || unexpected_error load_template
exec 4<>"$temp/fifo"
virsh <&3 >&4 2>&4 &
# virsh prepends 5 lines of useless output.
local c; for ((c=5;c>0;c--)); do read -r <&4; done
lv_api_do_open
local prompt="virsh #" # In the virsh shell, input lines start with this
echo "list --all --uuid" >&3
echo "echo EOF" >&3
while read -r uuid <&4; do
{ [[ "$uuid" =~ ^$prompt ]] || [[ -z "$uuid" ]] ; } && continue
[[ "$uuid" == "EOF" ]] && break
[[ -n "${uuid_map["$uuid"]}" ]] &&
CL_MAP["${uuid_map["$uuid"]}"]="$uuid"
done
lv_api_do_comm list
while read -r uuid; do
[[ -n "${uuid_map["$uuid"]}" ]] &&
CL_MAP["${uuid_map["$uuid"]}"]="$uuid"
done < <(read_pipe);
local match _uuid
for uuid in "${!uuid_map[@]}"; do
@ -2157,43 +2238,15 @@ for uuid in "${!uuid_map[@]}"; do
BAD_CL["${uuid_map["$uuid"]}"]="$uuid"
done
local line
local state="" name=""
for id in "${!CL_MAP[@]}"; do
uuid="${CL_MAP["$id"]}"
echo "domstate $uuid" >&3
echo "echo EOF" >&3
while read -r line <&4; do
{ [[ "$line" =~ ^$prompt ]] || [[ -z "$line" ]] ; } && continue
[[ "$line" == "EOF" ]] && break
[[ "$line" == "in shutdown" ]] && line="in-shutdown"
[[ "$line" == "shut off" ]] && line="off"
CL_STATE["$id"]="$line"
done
echo "domname $uuid" >&3
echo "echo EOF" >&3
while read -r line <&4; do
{ [[ "$line" =~ ^$prompt ]] || [[ -z "$line" ]] ; } && continue
[[ "$line" == "EOF" ]] && break
NAME_MAP["$id"]="$line"
done
lv_api_do_comm get_state "$uuid" && state="$(read_pipe)"
CL_STATE["$id"]="$state"
lv_api_do_comm get_name "$uuid" && name="$(read_pipe)"
NAME_MAP["$id"]="$name"
done
echo "list --all --uuid --with-managed-save" >&3
echo "echo EOF" >&3
while read -r uuid <&4; do
{ [[ "$uuid" =~ ^$prompt ]] || [[ -z "$uuid" ]] ; } && continue
[[ "$uuid" == "EOF" ]] && break
id="${uuid_map["$uuid"]}"
[[ -z "$id" ]] && continue; [[ -z "${CL_MAP["$id"]}" ]] && continue;
CL_STATE["$id"]="saved"
done
echo "quit" >&3
exec 4>&-
exec 4<&-
rm -rf "$temp" &>/dev/null
lv_api_do_close
return 0
}