integrated lv_api_do into qq2clone for load_template
This commit is contained in:
parent
e11b7e85e2
commit
2f89821404
30
lv_api_do.c
30
lv_api_do.c
|
@ -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
193
qq2clone
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue