[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-API] [PATCH] Add -debug-on-fail option to "xe" and other minor improvements
Unlike -debug, -debug-on-fail will only output debug information and connection diagnosis when the exit code is not 0. Signed-off-by: Zheng Li <dev@xxxxxxxx> ocaml/xe-cli/newcli.ml | 474 +++++++++++++++++++++++++++++----------------------- 1 files changed, 266 insertions(+), 208 deletions(-) diff -r ede6c001c56e -r eaa56c96bcbf ocaml/xe-cli/newcli.ml --- a/ocaml/xe-cli/newcli.ml Tue Mar 23 00:50:49 2010 +0000 +++ b/ocaml/xe-cli/newcli.ml Wed Mar 31 10:30:27 2010 +0100 @@ -28,16 +28,22 @@ let xapicompathost = ref "127.0.0.1" let usessl = ref true +let stunnel_process = ref None let xapiport = ref None let get_xapiport ssl = match !xapiport with None -> if ssl then 443 else 80 | Some p -> p -let debug_enabled = ref false +let debug_channel = ref None +let debug_file = ref None let error fmt = Printf.fprintf stderr fmt -let debug fmt = Printf.kprintf (fun s -> if !debug_enabled then output_string stderr s) fmt +let debug fmt = + let printer s = match !debug_channel with + | Some c -> output_string c s + | None -> () in + Printf.kprintf printer fmt (* usage message *) exception Usage @@ -91,7 +97,9 @@ if String.startswith "https://" url then let stripped = end_of_string url (String.length "https://") in - let (host::rest) = String.split '/' stripped in + let host, rest = + let l = String.split '/' stripped in + List.hd l, List.tl l in (host,"/" ^ (String.concat "/" rest)) else (!xapiserver,url) @@ -199,9 +207,10 @@ debug "Connecting via stunnel to [%s] port [%d]\n%!" server port; (* We don't bother closing fds since this requires our close_and_exec wrapper *) let x = Stunnel.connect ~use_external_fd_wrapper:false - ~write_to_log:(fun x -> debug "stunnel: %s\n%!" x) server port in + ~write_to_log:(fun x -> debug "stunnel: %s\n%!" x) + ~extended_diagnosis:(!debug_file <> None) server port in + stunnel_process := Some x; Unix.in_channel_of_descr x.Stunnel.fd, Unix.out_channel_of_descr x.Stunnel.fd - (* leak the stunnel process: ok because we're short-lived *) let open_tcp server = if !usessl && not(is_localhost server) then (* never use SSL on-host *) @@ -230,6 +239,8 @@ exception Connect_failure exception Protocol_version_mismatch of string exception ClientSideError of string +exception Stunnel_exit of int * Unix.process_status +exception Unexpected_msg of message let attr = ref None @@ -238,7 +249,7 @@ (* Save the terminal state to restore it at exit *) (attr := try Some (Unix.tcgetattr Unix.stdin) with _ -> None); at_exit (fun () -> - match !attr with Some a -> Unix.tcsetattr Unix.stdin Unix.TCSANOW a | None -> ()); + match !attr with Some a -> Unix.tcsetattr Unix.stdin Unix.TCSANOW a | None -> ()); (* Intially exchange version information *) let major', minor' = try unmarshal_protocol ifd with End_of_file -> raise Connect_failure in (* Be very conservative for the time-being *) @@ -248,219 +259,266 @@ then raise (Protocol_version_mismatch msg); marshal_protocol ofd; - try - while true do - let cmd = unmarshal ifd in - debug "Read: %s\n%!" (string_of_message cmd); flush stderr; - match cmd with - | Command (Print x) -> print_endline x; flush stdout - | Command (PrintStderr x) -> Printf.fprintf stderr "%s\n%!" x - | Command (Debug x) -> debug "debug from server: %s\n%!" x - | Command (Load x) -> - begin - try - let fd = Unix.openfile x [ Unix.O_RDONLY ] 0 in - marshal ofd (Response OK); - let length = (Unix.stat x).Unix.st_size in - marshal ofd (Blob (Chunk (Int32.of_int length))); - let buffer = String.make (1024 * 1024 * 10) '\000' in - let left = ref length in - while !left > 0 do - let n = Unix.read fd buffer 0 (min (String.length buffer) !left) in - really_write ofd buffer 0 n; - left := !left - n - done; - marshal ofd (Blob End); - Unix.close fd - with - | e -> marshal ofd (Response Failed) - end - | Command (HttpPut(filename, url)) -> - begin - try - let rec doit url = - let (server,path) = parse_url url in - if not (Sys.file_exists filename) then - raise (ClientSideError (Printf.sprintf "file '%s' does not exist" filename)); - let fd = Unix.openfile filename [ Unix.O_RDONLY ] 0 in - let stat = Unix.LargeFile.fstat fd in - let ic, oc = open_tcp server in - debug "PUTting to path [%s]\n%!" path; - Printf.fprintf oc "PUT %s HTTP/1.0\r\ncontent-length: %Ld\r\n\r\n" path stat.Unix.LargeFile.st_size; - flush oc; - let resultline = input_line ic in - let headers = read_rest_of_headers ic in - (* Get the result header immediately *) - match http_response_code resultline with - | 200 -> - let fd' = Unix.descr_of_out_channel oc in - let bytes = Unixext.copy_file fd fd' in - debug "Written %s bytes\n%!" (Int64.to_string bytes); - Unix.close fd; - Unix.shutdown fd' Unix.SHUTDOWN_SEND; - marshal ofd (Response OK) - | 302 -> - let newloc = List.assoc "location" headers in - doit newloc - | _ -> failwith "Unhandled response code" - in - doit url - with - | ClientSideError msg -> - marshal ofd (Response Failed); - Printf.fprintf stderr "Operation failed. Error: %s\n" msg; - exit 1 - | e -> - debug "HttpPut failure: %s\n%!" (Printexc.to_string e); - (* Assume the server will figure out what's wrong and tell us over - the normal communication channel *) - marshal ofd (Response Failed) - end - | Command (HttpGet(filename, url)) -> - begin - try - let rec doit url = - let (server,path) = parse_url url in - debug "Opening connection to server '%s' path '%s'\n%!" server path; - let ic, oc = open_tcp server in - Printf.fprintf oc "GET %s HTTP/1.0\r\n\r\n" path; - flush oc; - (* Get the result header immediately *) - let resultline = input_line ic in - debug "Got %s\n%!" resultline; - match http_response_code resultline with - | 200 -> - (* Copy from channel to the file descriptor *) - let finished = ref false in - while not(!finished) do - finished := input_line ic = "\r"; - done; - let buffer = String.make 65536 '\000' in - let finished = ref false in - let fd = - try - if filename = "" then - Unix.dup Unix.stdout - else - Unix.openfile filename [ Unix.O_WRONLY; Unix.O_CREAT; Unix.O_EXCL ] 0o600 - with - Unix.Unix_error (a,b,c) -> - (* Note that this will close the connection to the export handler, causing the task to fail *) - raise (ClientSideError (Printf.sprintf "%s: %s, %s." (Unix.error_message a) b c)) - in - while not(!finished) do - let num = input ic buffer 0 (String.length buffer) in - begin try - really_write fd buffer 0 num; - with - Unix.Unix_error (a,b,c) -> - raise (ClientSideError (Printf.sprintf "%s: %s, %s." (Unix.error_message a) b c)) - end; - finished := num = 0; - done; - Unix.close fd; - (try close_in ic with _ -> ()); (* Nb. Unix.close_connection only requires the in_channel *) - marshal ofd (Response OK) - | 302 -> - let headers = read_rest_of_headers ic in - let newloc = List.assoc "location" headers in - (try close_in ic with _ -> ()); (* Nb. Unix.close_connection only requires the in_channel *) - doit newloc - | _ -> failwith "Unhandled response code" - in - doit url - with - | ClientSideError msg -> - marshal ofd (Response Failed); - Printf.fprintf stderr "Operation failed. Error: %s\n" msg; - exit 1 - | e -> - debug "HttpGet failure: %s\n%!" (Printexc.to_string e); - marshal ofd (Response Failed) - end - | Command Prompt -> - let data = input_line stdin in - marshal ofd (Blob (Chunk (Int32.of_int (String.length data)))); - Unix.write ofd data 0 (String.length data); - marshal ofd (Blob End) - | Command (Error(code, params)) -> - error "Error code: %s\n" code; - error "Error parameters: %s\n" (String.concat ", " params) - | Command (Exit x) -> exit x - | x -> - debug "CLI protocol failure; received non-command: %s\n%!" (string_of_message x); - exit 1 - done - with e -> - debug "CLI protocol failure; caught exception: %s\n%!" (Printexc.to_string e); - raise e - + let exit_code = ref None in + while !exit_code = None do + while (match Unix.select [ofd] [] [] 5.0 with + | _ :: _, _, _ -> false + | _ -> + match !stunnel_process with + | Some { Stunnel.pid = Stunnel.FEFork pid } -> begin + match Forkhelpers.waitpid_nohang pid with + | 0, _ -> true + | i, e -> raise (Stunnel_exit (i, e)) + end + | Some {Stunnel.pid = Stunnel.StdFork pid} -> begin + match Unix.waitpid [Unix.WNOHANG] pid with + | 0, _ -> true + | i, e -> raise (Stunnel_exit (i, e)) + end + | _ -> true) do () + done; + let cmd = unmarshal ifd in + debug "Read: %s\n%!" (string_of_message cmd); flush stderr; + match cmd with + | Command (Print x) -> print_endline x; flush stdout + | Command (PrintStderr x) -> Printf.fprintf stderr "%s\n%!" x + | Command (Debug x) -> debug "debug from server: %s\n%!" x + | Command (Load x) -> + begin + try + let fd = Unix.openfile x [ Unix.O_RDONLY ] 0 in + marshal ofd (Response OK); + let length = (Unix.stat x).Unix.st_size in + marshal ofd (Blob (Chunk (Int32.of_int length))); + let buffer = String.make (1024 * 1024 * 10) '\000' in + let left = ref length in + while !left > 0 do + let n = Unix.read fd buffer 0 (min (String.length buffer) !left) in + really_write ofd buffer 0 n; + left := !left - n + done; + marshal ofd (Blob End); + Unix.close fd + with + | e -> marshal ofd (Response Failed) + end + | Command (HttpPut(filename, url)) -> + begin + try + let rec doit url = + let (server,path) = parse_url url in + if not (Sys.file_exists filename) then + raise (ClientSideError (Printf.sprintf "file '%s' does not exist" filename)); + let fd = Unix.openfile filename [ Unix.O_RDONLY ] 0 in + let stat = Unix.LargeFile.fstat fd in + let ic, oc = open_tcp server in + debug "PUTting to path [%s]\n%!" path; + Printf.fprintf oc "PUT %s HTTP/1.0\r\ncontent-length: %Ld\r\n\r\n" path stat.Unix.LargeFile.st_size; + flush oc; + let resultline = input_line ic in + let headers = read_rest_of_headers ic in + (* Get the result header immediately *) + match http_response_code resultline with + | 200 -> + let fd' = Unix.descr_of_out_channel oc in + let bytes = Unixext.copy_file fd fd' in + debug "Written %s bytes\n%!" (Int64.to_string bytes); + Unix.close fd; + Unix.shutdown fd' Unix.SHUTDOWN_SEND; + marshal ofd (Response OK) + | 302 -> + let newloc = List.assoc "location" headers in + doit newloc + | _ -> failwith "Unhandled response code" + in + doit url + with + | ClientSideError msg -> + marshal ofd (Response Failed); + Printf.fprintf stderr "Operation failed. Error: %s\n" msg; + exit 1 + | e -> ( ...... 240 lines left ...... ) Attachment:
xen-api.patch _______________________________________________ xen-api mailing list xen-api@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/mailman/listinfo/xen-api
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |