Revision 87d1bf2e
b/snf-image-helper/common.sh | ||
---|---|---|
63 | 63 |
local timestamp=$(date +%s.%N) |
64 | 64 |
local name="${PROGNAME}" |
65 | 65 |
|
66 |
report="{\"id\":\"$id\"," |
|
67 |
report+="\"type\":\"$type\"," \ |
|
68 |
report+="\"timestamp\":$(date +%s.%N)," \ |
|
66 |
report+="\"type\":\"$type\"," |
|
67 |
report+="\"timestamp\":$(date +%s.%N)," |
|
69 | 68 |
report+="\"name\":\"$name\"}" |
70 | 69 |
|
71 | 70 |
echo "$report" > "$MONITOR" |
... | ... | |
93 | 92 |
local name=${PROGNAME} |
94 | 93 |
local warnings=$(json_list WARNINGS[@]) |
95 | 94 |
|
96 |
report="{\"id\":\"$id\"," |
|
97 |
report+="\"type\":\"$type\"," \ |
|
98 |
report+="\"timestamp\":$(date +%s)," \ |
|
99 |
report+="\"name\":\"$name\"," \ |
|
95 |
report="\"type\":\"$type\"," |
|
96 |
report+="\"timestamp\":$(date +%s)," |
|
97 |
report+="\"name\":\"$name\"," |
|
100 | 98 |
report+="\"warnings\":\"$warnings\"}" |
101 | 99 |
|
102 | 100 |
echo "$report" > "$MONITOR" |
... | ... | |
110 | 108 |
local warnings=$(json_list WARNINGS[@]) |
111 | 109 |
local stderr="$(cat "$STDERR_FILE" | sed 's/"/\\"/g')" |
112 | 110 |
|
113 |
report="{\"id\":\"$id\"," |
|
114 |
report+="\"type\":\"$type\"," \ |
|
115 |
report+="\"timestamp\":$(date +%s)," \ |
|
116 |
report+="\"location\":\"$location\"," \ |
|
117 |
report+="\"errors\":$errors," \ |
|
118 |
report+="\"warnings\":$warnings," \ |
|
111 |
report="\"type\":\"$type\"," |
|
112 |
report+="\"timestamp\":$(date +%s)," |
|
113 |
report+="\"location\":\"$location\"," |
|
114 |
report+="\"errors\":$errors," |
|
115 |
report+="\"warnings\":$warnings," |
|
119 | 116 |
report+="\"stderr\":\"$stderr\"}" |
120 | 117 |
|
121 | 118 |
echo "$report" > "$MONITOR" |
b/snf-image-host/common.sh.in | ||
---|---|---|
27 | 27 |
|
28 | 28 |
network_backend_support="@network_backend_support@" |
29 | 29 |
|
30 |
# Use file descriptors in the range 3-9. File descriptors below 3 are used for |
|
31 |
# standard input, output, and error, the ones above 9 may be used by the shell |
|
32 |
# internally. |
|
33 |
MONITOR_FD=9 |
|
34 |
|
|
35 | 30 |
ERROR_TYPE="ganeti-error" |
36 | 31 |
|
37 | 32 |
CLEANUP=( ) |
... | ... | |
50 | 45 |
|
51 | 46 |
close_fd() { |
52 | 47 |
local fd="$1" |
53 |
eval "exec $fd>&-"
|
|
48 |
exec {fd}>&-
|
|
54 | 49 |
} |
55 | 50 |
|
56 | 51 |
report_error() { |
57 | 52 |
local error_file=$1 |
53 |
local monitor_fd=$2 |
|
58 | 54 |
|
59 |
local id=$(sed 's/"/\\"/g' <<< "$INSTANCE_NAME") |
|
60 | 55 |
local type="$ERROR_TYPE" |
61 | 56 |
local location="host" |
62 | 57 |
|
... | ... | |
72 | 67 |
|
73 | 68 |
local stderr="$(cat "$error_file" | sed 's/"/\\"/g')" |
74 | 69 |
|
75 |
report="{\"id\":\"$id\"," |
|
76 |
report+="\"type\":\"$type\"," \ |
|
77 |
report+="\"timestamp\":$(date +%s.%N)," \ |
|
78 |
report+="\"location\":\"$location\"," \ |
|
79 |
report+="\"messages\":$msg," \ |
|
70 |
report="\"type\":\"$type\"," |
|
71 |
report+="\"timestamp\":$(date +%s.%N)," |
|
72 |
report+="\"location\":\"$location\"," |
|
73 |
report+="\"messages\":$msg," |
|
80 | 74 |
report+="\"stderr\":\"$stderr\"}" |
81 | 75 |
|
82 |
eval "echo $(printf "%q" "$report") >&${MONITOR_FD}"
|
|
76 |
eval "echo $(printf "%q" "$report") >&${monitor_fd}"
|
|
83 | 77 |
} |
84 | 78 |
|
85 | 79 |
get_api5_arguments() { |
... | ... | |
331 | 325 |
report_and_cleanup(){ |
332 | 326 |
|
333 | 327 |
local err_file="$1" |
328 |
local fd="$2" |
|
334 | 329 |
|
335 |
report_error "$err_file" |
|
330 |
report_error "$err_file" "$fd"
|
|
336 | 331 |
cleanup |
337 | 332 |
} |
338 | 333 |
|
b/snf-image-host/copy-monitor.py | ||
---|---|---|
52 | 52 |
help="The expected number of bytes to be read, " \ |
53 | 53 |
"used to compute input progress", |
54 | 54 |
default=None) |
55 |
parser.add_option("-o", "--output", dest="output", default=None, |
|
56 |
metavar="FILE", |
|
57 |
help="Write output notifications to this file") |
|
55 |
parser.add_option("-o", "--output_fd", dest="output", default=None,
|
|
56 |
metavar="FILE", type="int",
|
|
57 |
help="Write output notifications to this file descriptor")
|
|
58 | 58 |
|
59 | 59 |
(opts, args) = parser.parse_args(args) |
60 | 60 |
|
... | ... | |
95 | 95 |
|
96 | 96 |
def send_message(to, message): |
97 | 97 |
message['timestamp'] = time.time() |
98 |
to.write("%s\n" % json.dumps(message)) |
|
99 |
to.flush() |
|
98 |
os.write(to, "%s\n" % json.dumps(message)) |
|
100 | 99 |
|
101 | 100 |
|
102 | 101 |
def main(): |
103 | 102 |
(opts, args) = parse_arguments(sys.argv[1:]) |
104 |
|
|
105 |
with open(opts.output, 'w') as out: |
|
106 |
pid = os.fork() |
|
107 |
if pid == 0: |
|
108 |
# In child process: |
|
109 |
|
|
110 |
# Make sure we die with the parent and are not left behind |
|
111 |
# WARNING: This uses the prctl(2) call and is Linux-specific. |
|
112 |
prctl.set_pdeathsig(signal.SIGHUP) |
|
113 |
|
|
114 |
# exec command specified in arguments, |
|
115 |
# searching the $PATH, keeping all environment |
|
116 |
os.execvpe(args[0], args, os.environ) |
|
117 |
sys.stderr.write("execvpe failed, exiting with non-zero status") |
|
118 |
os.exit(1) |
|
119 |
|
|
120 |
# In parent process: |
|
121 |
iofname = "/proc/%d/io" % pid |
|
122 |
iof = open(iofname, "r", 0) # 0: unbuffered open |
|
123 |
sys.stderr.write("%s: created child PID = %d, monitoring file %s\n" % |
|
124 |
(sys.argv[0], pid, iofname)) |
|
125 |
|
|
126 |
message = {} |
|
127 |
message['type'] = 'copy-progress' |
|
128 |
message['total'] = opts.read_bytes |
|
129 |
|
|
130 |
while True: |
|
131 |
# check if the child process is still alive |
|
132 |
(wpid, status) = os.waitpid(pid, os.WNOHANG) |
|
133 |
if wpid == pid: |
|
134 |
report_wait_status(pid, status) |
|
135 |
if (os.WIFEXITED(status) or os.WIFSIGNALED(status)): |
|
136 |
if not (os.WIFEXITED(status) and |
|
137 |
os.WEXITSTATUS(status) == 0): |
|
138 |
return 1 |
|
139 |
else: |
|
140 |
message['position'] = message['total'] |
|
141 |
message['progress'] = float(100) |
|
142 |
send_message(out, message) |
|
143 |
return 0 |
|
144 |
|
|
145 |
iof.seek(0) |
|
146 |
for l in iof.readlines(): |
|
147 |
if l.startswith("rchar:"): |
|
148 |
message['position'] = int(l.split(': ')[1]) |
|
149 |
message['progress'] = float(100) if opts.read_bytes == 0 \ |
|
150 |
else float("%2.2f" % ( |
|
151 |
message['position'] * 100.0 / message['total'])) |
|
103 |
out = opts.output |
|
104 |
pid = os.fork() |
|
105 |
if pid == 0: |
|
106 |
# In child process: |
|
107 |
|
|
108 |
# Make sure we die with the parent and are not left behind |
|
109 |
# WARNING: This uses the prctl(2) call and is Linux-specific. |
|
110 |
prctl.set_pdeathsig(signal.SIGHUP) |
|
111 |
|
|
112 |
# exec command specified in arguments, |
|
113 |
# searching the $PATH, keeping all environment |
|
114 |
os.execvpe(args[0], args, os.environ) |
|
115 |
sys.stderr.write("execvpe failed, exiting with non-zero status") |
|
116 |
os.exit(1) |
|
117 |
|
|
118 |
# In parent process: |
|
119 |
iofname = "/proc/%d/io" % pid |
|
120 |
iof = open(iofname, "r", 0) # 0: unbuffered open |
|
121 |
sys.stderr.write("%s: created child PID = %d, monitoring file %s\n" % |
|
122 |
(sys.argv[0], pid, iofname)) |
|
123 |
|
|
124 |
message = {} |
|
125 |
message['type'] = 'copy-progress' |
|
126 |
message['total'] = opts.read_bytes |
|
127 |
|
|
128 |
while True: |
|
129 |
# check if the child process is still alive |
|
130 |
(wpid, status) = os.waitpid(pid, os.WNOHANG) |
|
131 |
if wpid == pid: |
|
132 |
report_wait_status(pid, status) |
|
133 |
if (os.WIFEXITED(status) or os.WIFSIGNALED(status)): |
|
134 |
if not (os.WIFEXITED(status) and |
|
135 |
os.WEXITSTATUS(status) == 0): |
|
136 |
return 1 |
|
137 |
else: |
|
138 |
message['position'] = message['total'] |
|
139 |
message['progress'] = float(100) |
|
152 | 140 |
send_message(out, message) |
153 |
break |
|
154 |
|
|
155 |
# Sleep for a while |
|
156 |
time.sleep(3) |
|
157 |
|
|
141 |
return 0 |
|
142 |
|
|
143 |
iof.seek(0) |
|
144 |
for l in iof.readlines(): |
|
145 |
if l.startswith("rchar:"): |
|
146 |
message['position'] = int(l.split(': ')[1]) |
|
147 |
message['progress'] = float(100) if opts.read_bytes == 0 \ |
|
148 |
else float("%2.2f" % ( |
|
149 |
message['position'] * 100.0 / message['total'])) |
|
150 |
send_message(out, message) |
|
151 |
break |
|
152 |
|
|
153 |
# Sleep for a while |
|
154 |
time.sleep(3) |
|
158 | 155 |
|
159 | 156 |
if __name__ == "__main__": |
160 | 157 |
sys.exit(main()) |
b/snf-image-host/create | ||
---|---|---|
32 | 32 |
add_cleanup rm -f "$monitor_pipe" |
33 | 33 |
|
34 | 34 |
if [ -n "$PROGRESS_MONITOR" ]; then |
35 |
{ sleep 1; tee >( $PROGRESS_MONITOR ) < "$monitor_pipe" ; } &
|
|
35 |
{ sleep 1; $PROGRESS_MONITOR "$instance" < "$monitor_pipe" ; } &
|
|
36 | 36 |
monitor_pid="$!" |
37 | 37 |
else |
38 | 38 |
cat "$monitor_pipe" & |
... | ... | |
40 | 40 |
fi |
41 | 41 |
|
42 | 42 |
# Create file descriptor to monitor_pipe |
43 |
eval "exec ${MONITOR_FD}>${monitor_pipe}"
|
|
43 |
exec {MONITOR_FD}>${monitor_pipe}
|
|
44 | 44 |
add_cleanup close_fd ${MONITOR_FD} |
45 | 45 |
|
46 | 46 |
# Ignore sigpipe signals. If progress monitor is dead and snf-image-host tries |
47 |
# to output something to the opened pipe, then a sigpipe signal will be raised.
|
|
48 |
# If I do not catch this, the program will terminate.
|
|
47 |
# to output something to the opened pipe, then a sigpipe will be raised. If we
|
|
48 |
# do not catch this, the program will terminate. |
|
49 | 49 |
trap "" SIGPIPE |
50 | 50 |
|
51 |
trap "report_and_cleanup $(printf "%q" "$stderr")" EXIT |
|
51 |
trap "report_and_cleanup $(printf "%q" "$stderr") ${MONITOR_FD}" EXIT
|
|
52 | 52 |
|
53 | 53 |
ganeti_os_main |
54 | 54 |
|
... | ... | |
108 | 108 |
;; |
109 | 109 |
esac |
110 | 110 |
|
111 |
monitor="./copy-monitor.py -o $(printf "%q" "$monitor_pipe") -r $image_size"
|
|
111 |
monitor="./copy-monitor.py -o $MONITOR_FD -r $image_size"
|
|
112 | 112 |
if [ "$BACKEND_TYPE" = "local" ]; then |
113 | 113 |
# dd the dump to its new home :-) |
114 | 114 |
# Deploying an image file on a target block device is a streaming copy |
Also available in: Unified diff