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