From 478ecc4e2b7fb1c20cc1e45688c7e4d03c78de63 Mon Sep 17 00:00:00 2001 From: Timothy Johnson Date: Fri, 4 Feb 2022 10:43:26 -0500 Subject: [PATCH 01/29] WIP Use mio for sockets and named pipes Signed-off-by: Timothy Johnson --- zowex/Cargo.lock | 185 +++++++++++++++++++++++++++++++++++++++++++--- zowex/Cargo.toml | 5 +- zowex/src/main.rs | 135 +++++++++++++++++++++------------ 3 files changed, 265 insertions(+), 60 deletions(-) diff --git a/zowex/Cargo.lock b/zowex/Cargo.lock index a8299007d9..7d6e727fbc 100644 --- a/zowex/Cargo.lock +++ b/zowex/Cargo.lock @@ -16,7 +16,7 @@ checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ "hermit-abi", "libc", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -31,12 +31,24 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bumpalo" version = "3.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + [[package]] name = "cfg-if" version = "1.0.0" @@ -55,7 +67,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "crossbeam-utils", ] @@ -65,7 +77,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "crossbeam-epoch", "crossbeam-utils", ] @@ -76,7 +88,7 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "crossbeam-utils", "lazy_static", "memoffset", @@ -89,7 +101,7 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "lazy_static", ] @@ -99,6 +111,22 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +[[package]] +name = "fuchsia-zircon" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" +dependencies = [ + "bitflags", + "fuchsia-zircon-sys", +] + +[[package]] +name = "fuchsia-zircon-sys" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -108,6 +136,24 @@ dependencies = [ "libc", ] +[[package]] +name = "home" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2456aef2e6b6a9784192ae780c0f15bc57df0e918585282325e8c8ac27737654" +dependencies = [ + "winapi 0.3.9", +] + +[[package]] +name = "iovec" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" +dependencies = [ + "libc", +] + [[package]] name = "itoa" version = "0.4.8" @@ -123,6 +169,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -141,7 +197,7 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", ] [[package]] @@ -153,13 +209,89 @@ dependencies = [ "autocfg", ] +[[package]] +name = "mio" +version = "0.6.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" +dependencies = [ + "cfg-if 0.1.10", + "fuchsia-zircon", + "fuchsia-zircon-sys", + "iovec", + "kernel32-sys", + "libc", + "log", + "miow 0.2.2", + "net2", + "slab", + "winapi 0.2.8", +] + +[[package]] +name = "mio" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba272f85fa0b41fc91872be579b3bbe0f56b792aa361a380eb669469f68dafb2" +dependencies = [ + "libc", + "log", + "miow 0.3.7", + "ntapi", + "winapi 0.3.9", +] + +[[package]] +name = "mio-named-pipes" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0840c1c50fd55e521b247f949c241c9997709f23bd7f023b9762cd561e935656" +dependencies = [ + "log", + "mio 0.6.23", + "miow 0.3.7", + "winapi 0.3.9", +] + +[[package]] +name = "miow" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" +dependencies = [ + "kernel32-sys", + "net2", + "winapi 0.2.8", + "ws2_32-sys", +] + +[[package]] +name = "miow" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" +dependencies = [ + "winapi 0.3.9", +] + +[[package]] +name = "net2" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae" +dependencies = [ + "cfg-if 0.1.10", + "libc", + "winapi 0.3.9", +] + [[package]] name = "ntapi" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" dependencies = [ - "winapi", + "winapi 0.3.9", ] [[package]] @@ -238,7 +370,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffc936cf8a7ea60c58f030fd36a612a48f440610214dc54bc36431f9ea0c3efb" dependencies = [ "libc", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -284,6 +416,12 @@ dependencies = [ "serde", ] +[[package]] +name = "slab" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" + [[package]] name = "syn" version = "1.0.81" @@ -301,13 +439,13 @@ version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f1bfab07306a27332451a662ca9c8156e3a9986f82660ba9c8e744fe8455d43" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "core-foundation-sys", "libc", "ntapi", "once_cell", "rayon", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -322,7 +460,7 @@ version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "wasm-bindgen-macro", ] @@ -390,6 +528,12 @@ dependencies = [ "web-sys", ] +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" + [[package]] name = "winapi" version = "0.3.9" @@ -400,6 +544,12 @@ dependencies = [ "winapi-x86_64-pc-windows-gnu", ] +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" + [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" @@ -412,12 +562,25 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "ws2_32-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] + [[package]] name = "zowe" version = "0.6.1" dependencies = [ "atty", "base64", + "home", + "mio 0.8.0", + "mio-named-pipes", "pathsearch", "rpassword", "serde", diff --git a/zowex/Cargo.toml b/zowex/Cargo.toml index 3ad49256f9..1c74758fbc 100644 --- a/zowex/Cargo.toml +++ b/zowex/Cargo.toml @@ -11,9 +11,12 @@ repository = "https://github.com/zowe/zowe-cli" [dependencies] atty = "0.2.14" base64 = "0.13.0" +home = "0.5.3" +mio = "0.8.0" +mio-named-pipes = "0.1.7" pathsearch = "0.2.0" rpassword = "5.0.1" serde = { version = "1.0.130", features = ["derive"]} serde_json = "1.0.69" sysinfo = "0.22.5" -whoami = "1.2.1" \ No newline at end of file +whoami = "1.2.1" diff --git a/zowex/src/main.rs b/zowex/src/main.rs index d5ecdde542..8db875cf8d 100644 --- a/zowex/src/main.rs +++ b/zowex/src/main.rs @@ -12,11 +12,12 @@ use std::collections::HashMap; use std::env; +use std::fs::OpenOptions; use std::io; use std::io::prelude::*; use std::io::BufReader; use std::net::Shutdown; -use std::net::TcpStream; +use std::os::windows::prelude::*; use std::process::{Command, Stdio}; use std::str; use std::thread; @@ -28,6 +29,18 @@ use atty::Stream; extern crate base64; use base64::encode; +extern crate home; +#[cfg(target_family = "unix")] +use home::home_dir; + +extern crate mio; +#[cfg(target_family = "unix")] +use mio::net::UnixStream; + +extern crate mio_named_pipes; +#[cfg(target_family = "windows")] +use mio_named_pipes::NamedPipe; + extern crate pathsearch; use pathsearch::PathSearcher; @@ -43,8 +56,6 @@ use sysinfo::{ProcessExt, System, SystemExt}; extern crate whoami; use whoami::username; -const DEFAULT_PORT: i32 = 4000; - const EXIT_CODE_SUCCESS: i32 = 0; const EXIT_CODE_CANNOT_CONNECT_TO_RUNNING_DAEMON: i32 = 100; const EXIT_CODE_CANNOT_GET_MY_PATH: i32 = 101; @@ -279,30 +290,45 @@ fn run_daemon_command(args: &mut Vec) -> io::Result<()> { _resp.append(&mut stdin); } - // form our host, port, and connection strings - let daemon_host = "127.0.0.1".to_owned(); - let port_string = get_port_string(); - - let mut stream = establish_connection(daemon_host, port_string)?; + let socket_string = get_socket_string(); + let mut stream = establish_connection(socket_string)?; talk(&_resp, &mut stream) } +#[cfg(target_family = "unix")] +type DaemonClient = UnixStream; + +#[cfg(target_family = "windows")] +type DaemonClient = NamedPipe; + +#[cfg(target_family = "windows")] +fn create_named_pipe(daemon_socket: &String) -> io::Result { + const FILE_FLAG_OVERLAPPED: u32 = 0x40000000; + let pipe_file = OpenOptions::new().custom_flags(FILE_FLAG_OVERLAPPED).read(true).write(true).open(&daemon_socket); + match pipe_file { + Ok(file) => unsafe { Ok(NamedPipe::from_raw_handle(file.as_raw_handle())) }, + Err(e) => Err(e), + } +} + /** * Attempt to make a TCP connection to the daemon. * Iterate to enable a slow system to start the daemon. */ -fn establish_connection(host: String, port: String) -> io::Result { +fn establish_connection(daemon_socket: String) -> io::Result { const THREE_SEC_DELAY: u64 = 3; const THREE_MIN_OF_RETRIES: i32 = 60; const RETRY_TO_SHOW_DIAG: i32 = 5; - let host_port_conn_str = format!("{}:{}", host, port); let mut conn_retries = 0; let mut we_started_daemon = false; let mut cmd_to_show: String = String::new(); let stream = loop { - let conn_result = TcpStream::connect(&host_port_conn_str); + #[cfg(target_family = "unix")] + let conn_result = UnixStream::connect(&daemon_socket); + #[cfg(target_family = "windows")] + let conn_result = create_named_pipe(&daemon_socket); if let Ok(good_stream) = conn_result { // We made our connection. Break with the actual stream value break good_stream; @@ -319,8 +345,8 @@ fn establish_connection(host: String, port: String) -> io::Result { we_started_daemon = true; cmd_to_show = start_daemon(&njs_zowe_path); } else if we_started_daemon { - println!("The Zowe daemon that we started is not running on host = {} with port = {}.", - host, port + println!("The Zowe daemon that we started is not running on socket: {}.", + daemon_socket ); println!( "Command used to start the Zowe daemon was:\n {}\nTerminating.", @@ -346,8 +372,8 @@ fn establish_connection(host: String, port: String) -> io::Result { } else { println!("Command = {}", daemon_proc_info.cmd); } - println!("Process name = {} pid = {} host = {} port = {}\n", - daemon_proc_info.name, daemon_proc_info.pid, host, port + println!("Process name = {} pid = {} socket = {}\n", + daemon_proc_info.name, daemon_proc_info.pid, daemon_socket ); } @@ -366,12 +392,12 @@ fn establish_connection(host: String, port: String) -> io::Result { Ok(stream) } -fn talk(message: &[u8], stream: &mut TcpStream) -> io::Result<()> { +fn talk(message: &[u8], stream: &mut DaemonClient) -> io::Result<()> { /* * Send the command line arguments to the daemon and await responses. */ stream.write_all(message).unwrap(); // write it - let mut stream_clone = stream.try_clone().expect("clone failed"); + // let mut stream_clone = stream.try_clone().expect("clone failed"); let mut reader = BufReader::new(&*stream); @@ -432,7 +458,8 @@ fn talk(message: &[u8], stream: &mut TcpStream) -> io::Result<()> { }; let v = serde_json::to_string(&response)?; - stream_clone.write_all(v.as_bytes()).unwrap(); + // stream_clone.write_all(v.as_bytes()).unwrap(); + stream.write_all(v.as_bytes()).unwrap(); } if let Some(s) = p.securePrompt { @@ -449,7 +476,8 @@ fn talk(message: &[u8], stream: &mut TcpStream) -> io::Result<()> { user: Some(encode(username())), }; let v = serde_json::to_string(&response)?; - stream_clone.write_all(v.as_bytes()).unwrap(); + // stream_clone.write_all(v.as_bytes()).unwrap(); + stream.write_all(v.as_bytes()).unwrap(); } exit_code = p.exitCode.unwrap_or(0); @@ -461,16 +489,17 @@ fn talk(message: &[u8], stream: &mut TcpStream) -> io::Result<()> { } } - // Terminate connection. Ignore NotConnected errors returned on macOS. - // https://doc.rust-lang.org/std/net/struct.TcpStream.html#method.shutdown - match stream.shutdown(Shutdown::Read) { - Err(ref e) if e.kind() == io::ErrorKind::NotConnected => (), - result => result?, - } - match stream.shutdown(Shutdown::Write) { - Err(ref e) if e.kind() == io::ErrorKind::NotConnected => (), - result => result?, - } + // // Terminate connection. Ignore NotConnected errors returned on macOS. + // // https://doc.rust-lang.org/std/net/struct.TcpStream.html#method.shutdown + // match stream.shutdown(Shutdown::Read) { + // Err(ref e) if e.kind() == io::ErrorKind::NotConnected => (), + // result => result?, + // } + // match stream.shutdown(Shutdown::Write) { + // Err(ref e) if e.kind() == io::ErrorKind::NotConnected => (), + // result => result?, + // } + stream.disconnect()?; // TODO(Kelosky): maybe this should just be a `return Err` if exit_code != 0 { @@ -480,16 +509,26 @@ fn talk(message: &[u8], stream: &mut TcpStream) -> io::Result<()> { Ok(()) } -fn get_port_string() -> String { - let mut _port = DEFAULT_PORT; +#[cfg(target_family = "unix")] +fn get_socket_string() -> String { + let mut _socket = format!("{}/{}", home_dir().unwrap().to_string_lossy(), "zowe-daemon.sock"); - match env::var("ZOWE_DAEMON") { - // TODO(Kelosky): handle unwrap properly - Ok(val) => _port = val.parse::().unwrap(), - Err(_e) => _port = DEFAULT_PORT, + if let Ok(socket_path) = env::var("ZOWE_DAEMON") { + _socket = format!("{}/{}", socket_path, "zowe-daemon.sock"); } - _port.to_string() + _socket +} + +#[cfg(target_family = "windows")] +fn get_socket_string() -> String { + let mut _socket = format!("\\\\?\\pipe\\{}\\{}", username(), "ZoweDaemon"); + + if let Ok(pipe_name) = env::var("ZOWE_DAEMON") { + _socket = format!("\\\\?\\pipe\\{}\\{}", username(), pipe_name); + } + + _socket } // Get the file path to the command that runs the NodeJS version of Zowe @@ -719,18 +758,18 @@ mod tests { // Note this useful idiom: importing names from outer (for mod tests) scope. use super::*; - #[test] - fn test_get_port_string() { - // expect default port with no env - let port_string = get_port_string(); - assert_eq!("4000", port_string); - - // expect override port with env - env::set_var("ZOWE_DAEMON", "777"); - let port_string = get_port_string(); - assert_eq!("777", port_string); - env::remove_var("ZOWE_DAEMON"); - } + // #[test] + // fn test_get_port_string() { + // // expect default port with no env + // let port_string = get_port_string(); + // assert_eq!("4000", port_string); + + // // expect override port with env + // env::set_var("ZOWE_DAEMON", "777"); + // let port_string = get_port_string(); + // assert_eq!("777", port_string); + // env::remove_var("ZOWE_DAEMON"); + // } #[test] fn test_get_zowe_env() { From 8a3ba535891b8da592f4dbfebce365b200203e51 Mon Sep 17 00:00:00 2001 From: Timothy Johnson Date: Fri, 4 Feb 2022 13:22:45 -0500 Subject: [PATCH 02/29] Hopefully more progress for Windows Signed-off-by: Timothy Johnson --- packages/cli/src/daemon/DaemonDecider.ts | 41 +++--- zowex/Cargo.lock | 177 +++-------------------- zowex/Cargo.toml | 3 +- zowex/src/main.rs | 69 ++++----- 4 files changed, 71 insertions(+), 219 deletions(-) diff --git a/packages/cli/src/daemon/DaemonDecider.ts b/packages/cli/src/daemon/DaemonDecider.ts index 198e41679a..0b8443a661 100644 --- a/packages/cli/src/daemon/DaemonDecider.ts +++ b/packages/cli/src/daemon/DaemonDecider.ts @@ -9,9 +9,11 @@ * */ -import { Imperative } from "@zowe/imperative"; +import * as fs from "fs"; import * as net from "net"; -import { userInfo } from "os"; +import * as os from "os"; +import * as path from "path"; +import { Imperative } from "@zowe/imperative"; import { DaemonClient } from "./DaemonClient"; // TODO(Kelosky): handle prompting cases from login command @@ -26,15 +28,6 @@ import { DaemonClient } from "./DaemonClient"; * @class DaemonDecider */ export class DaemonDecider { - - /** - * Default port number - * @private - * @static - * @memberof DaemonDecider - */ - private static readonly DEFAULT_PORT = 4000; - /** * Undocumented paramter for launching in server mode * @private @@ -52,12 +45,12 @@ export class DaemonDecider { private mServer: net.Server; /** - * Hold current port number for the server + * Hold current socket path for the server * @private * @type {number} * @memberof DaemonDecider */ - private mPort: number; + private mSocket: string; /** * Hold current owner for the server @@ -90,7 +83,7 @@ export class DaemonDecider { this.initialParse(); if (this.startServer) { - this.mUser = userInfo().username; + this.mUser = os.userInfo().username; this.mServer = net.createServer((c) => { new DaemonClient(c, this.mServer, this.mUser).run(); }); @@ -107,9 +100,17 @@ export class DaemonDecider { */ public runOrUseDaemon() { if (this.mServer) { - this.mServer.listen(this.mPort, "127.0.0.1", () => { - Imperative.api.appLogger.debug(`daemon server bound ${this.mPort}`); - Imperative.console.info(`server bound ${this.mPort}`); + if (process.platform !== "win32" && fs.existsSync(this.mSocket)) { + fs.unlinkSync(this.mSocket); + } + + // TODO Handle other exit signals? + process.on("SIGINT", this.close.bind(this)); + process.on("SIGKILL", this.close.bind(this)); + + this.mServer.listen(this.mSocket, () => { + Imperative.api.appLogger.debug(`daemon server bound ${this.mSocket}`); + Imperative.console.info(`server bound ${this.mSocket}`); }); } else { Imperative.parse(); @@ -152,9 +153,9 @@ export class DaemonDecider { * NOTE(Kelosky): For now, we use an undocumented paramter `--daemon`. If found first, * we bypass `yargs` and begin running this as a persistent Processor. */ - const portOffset = parm.indexOf(DaemonDecider.DAEMON_KEY); + const daemonOffset = parm.indexOf(DaemonDecider.DAEMON_KEY); - if (portOffset > -1) { + if (daemonOffset > -1) { this.startServer = true; if (process.env.ZOWE_DAEMON) { try { @@ -163,7 +164,7 @@ export class DaemonDecider { // do nothing } } - Imperative.api.appLogger.debug(`daemon server port ${this.mPort}`); + Imperative.api.appLogger.debug(`daemon server socket ${this.mSocket}`); } } } diff --git a/zowex/Cargo.lock b/zowex/Cargo.lock index 7d6e727fbc..f625e53b94 100644 --- a/zowex/Cargo.lock +++ b/zowex/Cargo.lock @@ -16,7 +16,7 @@ checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ "hermit-abi", "libc", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -31,24 +31,12 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - [[package]] name = "bumpalo" version = "3.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - [[package]] name = "cfg-if" version = "1.0.0" @@ -67,7 +55,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crossbeam-utils", ] @@ -77,7 +65,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] @@ -88,7 +76,7 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crossbeam-utils", "lazy_static", "memoffset", @@ -101,7 +89,7 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "lazy_static", ] @@ -111,22 +99,6 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" -[[package]] -name = "fuchsia-zircon" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" -dependencies = [ - "bitflags", - "fuchsia-zircon-sys", -] - -[[package]] -name = "fuchsia-zircon-sys" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" - [[package]] name = "hermit-abi" version = "0.1.19" @@ -142,16 +114,7 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2456aef2e6b6a9784192ae780c0f15bc57df0e918585282325e8c8ac27737654" dependencies = [ - "winapi 0.3.9", -] - -[[package]] -name = "iovec" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" -dependencies = [ - "libc", + "winapi", ] [[package]] @@ -169,16 +132,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "kernel32-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -dependencies = [ - "winapi 0.2.8", - "winapi-build", -] - [[package]] name = "lazy_static" version = "1.4.0" @@ -197,7 +150,7 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -210,79 +163,12 @@ dependencies = [ ] [[package]] -name = "mio" -version = "0.6.23" +name = "named_pipe" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" +checksum = "ad9c443cce91fc3e12f017290db75dde490d685cdaaf508d7159d7cf41f0eb2b" dependencies = [ - "cfg-if 0.1.10", - "fuchsia-zircon", - "fuchsia-zircon-sys", - "iovec", - "kernel32-sys", - "libc", - "log", - "miow 0.2.2", - "net2", - "slab", - "winapi 0.2.8", -] - -[[package]] -name = "mio" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba272f85fa0b41fc91872be579b3bbe0f56b792aa361a380eb669469f68dafb2" -dependencies = [ - "libc", - "log", - "miow 0.3.7", - "ntapi", - "winapi 0.3.9", -] - -[[package]] -name = "mio-named-pipes" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0840c1c50fd55e521b247f949c241c9997709f23bd7f023b9762cd561e935656" -dependencies = [ - "log", - "mio 0.6.23", - "miow 0.3.7", - "winapi 0.3.9", -] - -[[package]] -name = "miow" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" -dependencies = [ - "kernel32-sys", - "net2", - "winapi 0.2.8", - "ws2_32-sys", -] - -[[package]] -name = "miow" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" -dependencies = [ - "winapi 0.3.9", -] - -[[package]] -name = "net2" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae" -dependencies = [ - "cfg-if 0.1.10", - "libc", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -291,7 +177,7 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" dependencies = [ - "winapi 0.3.9", + "winapi", ] [[package]] @@ -370,7 +256,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffc936cf8a7ea60c58f030fd36a612a48f440610214dc54bc36431f9ea0c3efb" dependencies = [ "libc", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -416,12 +302,6 @@ dependencies = [ "serde", ] -[[package]] -name = "slab" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" - [[package]] name = "syn" version = "1.0.81" @@ -439,13 +319,13 @@ version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f1bfab07306a27332451a662ca9c8156e3a9986f82660ba9c8e744fe8455d43" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "core-foundation-sys", "libc", "ntapi", "once_cell", "rayon", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -460,7 +340,7 @@ version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "wasm-bindgen-macro", ] @@ -528,12 +408,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "winapi" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" - [[package]] name = "winapi" version = "0.3.9" @@ -544,12 +418,6 @@ dependencies = [ "winapi-x86_64-pc-windows-gnu", ] -[[package]] -name = "winapi-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" - [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" @@ -562,16 +430,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "ws2_32-sys" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" -dependencies = [ - "winapi 0.2.8", - "winapi-build", -] - [[package]] name = "zowe" version = "0.6.1" @@ -579,8 +437,7 @@ dependencies = [ "atty", "base64", "home", - "mio 0.8.0", - "mio-named-pipes", + "named_pipe", "pathsearch", "rpassword", "serde", diff --git a/zowex/Cargo.toml b/zowex/Cargo.toml index 1c74758fbc..8575857a6c 100644 --- a/zowex/Cargo.toml +++ b/zowex/Cargo.toml @@ -12,8 +12,7 @@ repository = "https://github.com/zowe/zowe-cli" atty = "0.2.14" base64 = "0.13.0" home = "0.5.3" -mio = "0.8.0" -mio-named-pipes = "0.1.7" +named_pipe = "0.4.1" pathsearch = "0.2.0" rpassword = "5.0.1" serde = { version = "1.0.130", features = ["derive"]} diff --git a/zowex/src/main.rs b/zowex/src/main.rs index 8db875cf8d..e21c0bf99d 100644 --- a/zowex/src/main.rs +++ b/zowex/src/main.rs @@ -11,18 +11,18 @@ use std::collections::HashMap; use std::env; - -use std::fs::OpenOptions; use std::io; -use std::io::prelude::*; use std::io::BufReader; +use std::io::prelude::*; use std::net::Shutdown; -use std::os::windows::prelude::*; use std::process::{Command, Stdio}; use std::str; use std::thread; use std::time::Duration; +#[cfg(target_family = "unix")] +use std::os::unix::net::UnixStream; + extern crate atty; use atty::Stream; @@ -33,13 +33,9 @@ extern crate home; #[cfg(target_family = "unix")] use home::home_dir; -extern crate mio; -#[cfg(target_family = "unix")] -use mio::net::UnixStream; - -extern crate mio_named_pipes; +extern crate named_pipe; #[cfg(target_family = "windows")] -use mio_named_pipes::NamedPipe; +use named_pipe::PipeClient; extern crate pathsearch; use pathsearch::PathSearcher; @@ -299,17 +295,7 @@ fn run_daemon_command(args: &mut Vec) -> io::Result<()> { type DaemonClient = UnixStream; #[cfg(target_family = "windows")] -type DaemonClient = NamedPipe; - -#[cfg(target_family = "windows")] -fn create_named_pipe(daemon_socket: &String) -> io::Result { - const FILE_FLAG_OVERLAPPED: u32 = 0x40000000; - let pipe_file = OpenOptions::new().custom_flags(FILE_FLAG_OVERLAPPED).read(true).write(true).open(&daemon_socket); - match pipe_file { - Ok(file) => unsafe { Ok(NamedPipe::from_raw_handle(file.as_raw_handle())) }, - Err(e) => Err(e), - } -} +type DaemonClient = PipeClient; /** * Attempt to make a TCP connection to the daemon. @@ -328,7 +314,7 @@ fn establish_connection(daemon_socket: String) -> io::Result { #[cfg(target_family = "unix")] let conn_result = UnixStream::connect(&daemon_socket); #[cfg(target_family = "windows")] - let conn_result = create_named_pipe(&daemon_socket); + let conn_result = PipeClient::connect(&daemon_socket); if let Ok(good_stream) = conn_result { // We made our connection. Break with the actual stream value break good_stream; @@ -397,9 +383,14 @@ fn talk(message: &[u8], stream: &mut DaemonClient) -> io::Result<()> { * Send the command line arguments to the daemon and await responses. */ stream.write_all(message).unwrap(); // write it - // let mut stream_clone = stream.try_clone().expect("clone failed"); + #[cfg(target_family = "unix")] + let mut stream_clone = stream.try_clone().expect("clone failed"); + + #[cfg(target_family = "unix")] let mut reader = BufReader::new(&*stream); + #[cfg(target_family = "windows")] + let mut reader = BufReader::new(stream); let mut exit_code = 0; let mut _progress = false; @@ -457,8 +448,9 @@ fn talk(message: &[u8], stream: &mut DaemonClient) -> io::Result<()> { user: Some(encode(username())), }; let v = serde_json::to_string(&response)?; - - // stream_clone.write_all(v.as_bytes()).unwrap(); + #[cfg(target_family = "unix")] + stream_clone.write_all(v.as_bytes()).unwrap(); + #[cfg(target_family = "unix")] stream.write_all(v.as_bytes()).unwrap(); } @@ -476,7 +468,9 @@ fn talk(message: &[u8], stream: &mut DaemonClient) -> io::Result<()> { user: Some(encode(username())), }; let v = serde_json::to_string(&response)?; - // stream_clone.write_all(v.as_bytes()).unwrap(); + #[cfg(target_family = "unix")] + stream_clone.write_all(v.as_bytes()).unwrap(); + #[cfg(target_family = "unix")] stream.write_all(v.as_bytes()).unwrap(); } @@ -489,17 +483,18 @@ fn talk(message: &[u8], stream: &mut DaemonClient) -> io::Result<()> { } } - // // Terminate connection. Ignore NotConnected errors returned on macOS. - // // https://doc.rust-lang.org/std/net/struct.TcpStream.html#method.shutdown - // match stream.shutdown(Shutdown::Read) { - // Err(ref e) if e.kind() == io::ErrorKind::NotConnected => (), - // result => result?, - // } - // match stream.shutdown(Shutdown::Write) { - // Err(ref e) if e.kind() == io::ErrorKind::NotConnected => (), - // result => result?, - // } - stream.disconnect()?; + // Terminate connection. Ignore NotConnected errors returned on macOS. + // https://doc.rust-lang.org/std/net/struct.TcpStream.html#method.shutdown + #[cfg(target_family = "unix")] + match stream.shutdown(Shutdown::Read) { + Err(ref e) if e.kind() == io::ErrorKind::NotConnected => (), + result => result?, + } + #[cfg(target_family = "unix")] + match stream.shutdown(Shutdown::Write) { + Err(ref e) if e.kind() == io::ErrorKind::NotConnected => (), + result => result?, + } // TODO(Kelosky): maybe this should just be a `return Err` if exit_code != 0 { From 8792232e4b39991eb0317883c581f7895535e552 Mon Sep 17 00:00:00 2001 From: Timothy Johnson Date: Fri, 4 Feb 2022 14:33:07 -0500 Subject: [PATCH 03/29] Get named pipes working Signed-off-by: Timothy Johnson --- packages/cli/src/daemon/DaemonDecider.ts | 12 +++++++----- zowex/src/main.rs | 8 ++++---- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/packages/cli/src/daemon/DaemonDecider.ts b/packages/cli/src/daemon/DaemonDecider.ts index 0b8443a661..1012f5c7b5 100644 --- a/packages/cli/src/daemon/DaemonDecider.ts +++ b/packages/cli/src/daemon/DaemonDecider.ts @@ -144,7 +144,9 @@ export class DaemonDecider { */ private initialParse() { const numOfParms = this.mParms.length - 2; - this.mPort = DaemonDecider.DEFAULT_PORT; + // TODO Support ZOWE_CLI_HOME environment variable here and in client + this.mSocket = (process.platform !== "win32") ? path.join(os.homedir(), ".zowe", "daemon.sock") : + `\\\\.\\pipe\\${os.userInfo().username}\\ZoweDaemon`; if (numOfParms > 0) { const parm = this.mParms[2]; @@ -158,10 +160,10 @@ export class DaemonDecider { if (daemonOffset > -1) { this.startServer = true; if (process.env.ZOWE_DAEMON) { - try { - this.mPort = parseInt(process.env.ZOWE_DAEMON, 10); - } catch (err) { - // do nothing + if (process.platform !== "win32") { + this.mSocket = process.env.ZOWE_DAEMON; + } else { + this.mSocket = `\\\\.\\pipe\\${os.userInfo().username}\\${process.env.ZOWE_DAEMON}`; } } Imperative.api.appLogger.debug(`daemon server socket ${this.mSocket}`); diff --git a/zowex/src/main.rs b/zowex/src/main.rs index e21c0bf99d..bb67e37c11 100644 --- a/zowex/src/main.rs +++ b/zowex/src/main.rs @@ -506,10 +506,10 @@ fn talk(message: &[u8], stream: &mut DaemonClient) -> io::Result<()> { #[cfg(target_family = "unix")] fn get_socket_string() -> String { - let mut _socket = format!("{}/{}", home_dir().unwrap().to_string_lossy(), "zowe-daemon.sock"); + let mut _socket = format!("{}/{}", home_dir().unwrap().to_string_lossy(), ".zowe", "daemon.sock"); if let Ok(socket_path) = env::var("ZOWE_DAEMON") { - _socket = format!("{}/{}", socket_path, "zowe-daemon.sock"); + _socket = socket_path; } _socket @@ -517,10 +517,10 @@ fn get_socket_string() -> String { #[cfg(target_family = "windows")] fn get_socket_string() -> String { - let mut _socket = format!("\\\\?\\pipe\\{}\\{}", username(), "ZoweDaemon"); + let mut _socket = format!("\\\\.\\pipe\\{}\\{}", username(), "ZoweDaemon"); if let Ok(pipe_name) = env::var("ZOWE_DAEMON") { - _socket = format!("\\\\?\\pipe\\{}\\{}", username(), pipe_name); + _socket = format!("\\\\.\\pipe\\{}\\{}", username(), pipe_name); } _socket From c12963bf01da564ce947e6ce284e8d2bc785f415 Mon Sep 17 00:00:00 2001 From: Timothy Johnson Date: Fri, 4 Feb 2022 14:51:55 -0500 Subject: [PATCH 04/29] Make named_pipe dependency Windows-only Signed-off-by: Timothy Johnson --- zowex/Cargo.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/zowex/Cargo.toml b/zowex/Cargo.toml index 8575857a6c..74d6aea2f0 100644 --- a/zowex/Cargo.toml +++ b/zowex/Cargo.toml @@ -12,10 +12,12 @@ repository = "https://github.com/zowe/zowe-cli" atty = "0.2.14" base64 = "0.13.0" home = "0.5.3" -named_pipe = "0.4.1" pathsearch = "0.2.0" rpassword = "5.0.1" serde = { version = "1.0.130", features = ["derive"]} serde_json = "1.0.69" sysinfo = "0.22.5" whoami = "1.2.1" + +[target.'cfg(windows)'.dependencies] +named_pipe = "0.4.1" From 995dc620e3f7f1a880e01bc50d694607a3d52d8b Mon Sep 17 00:00:00 2001 From: Timothy Johnson Date: Fri, 4 Feb 2022 14:56:47 -0500 Subject: [PATCH 05/29] Make named_pipe dependency Windows-only pt 2 Signed-off-by: Timothy Johnson --- zowex/src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/zowex/src/main.rs b/zowex/src/main.rs index bb67e37c11..ab8cecac36 100644 --- a/zowex/src/main.rs +++ b/zowex/src/main.rs @@ -33,6 +33,7 @@ extern crate home; #[cfg(target_family = "unix")] use home::home_dir; +#[cfg(target_family = "windows")] extern crate named_pipe; #[cfg(target_family = "windows")] use named_pipe::PipeClient; From 24c88b8ca62cf5b8f872a1c1068796fe7cf8292e Mon Sep 17 00:00:00 2001 From: Timothy Johnson Date: Fri, 4 Feb 2022 15:05:56 -0500 Subject: [PATCH 06/29] Fix number of parameters to format! Signed-off-by: Timothy Johnson --- zowex/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zowex/src/main.rs b/zowex/src/main.rs index ab8cecac36..a17c2e4ba9 100644 --- a/zowex/src/main.rs +++ b/zowex/src/main.rs @@ -507,7 +507,7 @@ fn talk(message: &[u8], stream: &mut DaemonClient) -> io::Result<()> { #[cfg(target_family = "unix")] fn get_socket_string() -> String { - let mut _socket = format!("{}/{}", home_dir().unwrap().to_string_lossy(), ".zowe", "daemon.sock"); + let mut _socket = format!("{}/{}", home_dir().unwrap().to_string_lossy(), ".zowe/daemon.sock"); if let Ok(socket_path) = env::var("ZOWE_DAEMON") { _socket = socket_path; From 637aef9057de3aab88d3bf62aa8987aed32aa197 Mon Sep 17 00:00:00 2001 From: Timothy Johnson Date: Mon, 7 Feb 2022 13:39:09 -0500 Subject: [PATCH 07/29] Use BufStream to allow simultaneous read/write Signed-off-by: Timothy Johnson --- zowex/Cargo.lock | 7 +++++++ zowex/Cargo.toml | 1 + zowex/src/main.rs | 22 +++++----------------- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/zowex/Cargo.lock b/zowex/Cargo.lock index f625e53b94..409f6766a6 100644 --- a/zowex/Cargo.lock +++ b/zowex/Cargo.lock @@ -31,6 +31,12 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +[[package]] +name = "bufstream" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40e38929add23cdf8a366df9b0e088953150724bcbe5fc330b0d8eb3b328eec8" + [[package]] name = "bumpalo" version = "3.9.1" @@ -436,6 +442,7 @@ version = "0.6.1" dependencies = [ "atty", "base64", + "bufstream", "home", "named_pipe", "pathsearch", diff --git a/zowex/Cargo.toml b/zowex/Cargo.toml index 74d6aea2f0..4ad1d4bf28 100644 --- a/zowex/Cargo.toml +++ b/zowex/Cargo.toml @@ -11,6 +11,7 @@ repository = "https://github.com/zowe/zowe-cli" [dependencies] atty = "0.2.14" base64 = "0.13.0" +bufstream = "0.1.4" home = "0.5.3" pathsearch = "0.2.0" rpassword = "5.0.1" diff --git a/zowex/src/main.rs b/zowex/src/main.rs index a17c2e4ba9..7851a81131 100644 --- a/zowex/src/main.rs +++ b/zowex/src/main.rs @@ -12,7 +12,6 @@ use std::collections::HashMap; use std::env; use std::io; -use std::io::BufReader; use std::io::prelude::*; use std::net::Shutdown; use std::process::{Command, Stdio}; @@ -29,8 +28,10 @@ use atty::Stream; extern crate base64; use base64::encode; +extern crate bufstream; +use bufstream::BufStream; + extern crate home; -#[cfg(target_family = "unix")] use home::home_dir; #[cfg(target_family = "windows")] @@ -384,14 +385,7 @@ fn talk(message: &[u8], stream: &mut DaemonClient) -> io::Result<()> { * Send the command line arguments to the daemon and await responses. */ stream.write_all(message).unwrap(); // write it - - #[cfg(target_family = "unix")] - let mut stream_clone = stream.try_clone().expect("clone failed"); - - #[cfg(target_family = "unix")] - let mut reader = BufReader::new(&*stream); - #[cfg(target_family = "windows")] - let mut reader = BufReader::new(stream); + let mut stream_clone = BufStream::new(stream); let mut exit_code = 0; let mut _progress = false; @@ -401,7 +395,7 @@ fn talk(message: &[u8], stream: &mut DaemonClient) -> io::Result<()> { let payload: String; // read until form feed (\f) - if reader.read_until(0xC, &mut u_payload).unwrap() > 0 { + if stream_clone.read_until(0xC, &mut u_payload).unwrap() > 0 { // remove form feed and convert to a string u_payload.pop(); // remove the 0xC payload = str::from_utf8(&u_payload).unwrap().to_string(); @@ -449,10 +443,7 @@ fn talk(message: &[u8], stream: &mut DaemonClient) -> io::Result<()> { user: Some(encode(username())), }; let v = serde_json::to_string(&response)?; - #[cfg(target_family = "unix")] stream_clone.write_all(v.as_bytes()).unwrap(); - #[cfg(target_family = "unix")] - stream.write_all(v.as_bytes()).unwrap(); } if let Some(s) = p.securePrompt { @@ -469,10 +460,7 @@ fn talk(message: &[u8], stream: &mut DaemonClient) -> io::Result<()> { user: Some(encode(username())), }; let v = serde_json::to_string(&response)?; - #[cfg(target_family = "unix")] stream_clone.write_all(v.as_bytes()).unwrap(); - #[cfg(target_family = "unix")] - stream.write_all(v.as_bytes()).unwrap(); } exit_code = p.exitCode.unwrap_or(0); From 71ea7f8075634ab7d624faf0f1ff645403028b20 Mon Sep 17 00:00:00 2001 From: Timothy Johnson Date: Mon, 7 Feb 2022 16:47:34 -0500 Subject: [PATCH 08/29] Hopefully fix Linux compilation errors Signed-off-by: Timothy Johnson --- zowex/Cargo.lock | 7 ------- zowex/Cargo.toml | 1 - zowex/src/main.rs | 18 ++++++++---------- 3 files changed, 8 insertions(+), 18 deletions(-) diff --git a/zowex/Cargo.lock b/zowex/Cargo.lock index 409f6766a6..f625e53b94 100644 --- a/zowex/Cargo.lock +++ b/zowex/Cargo.lock @@ -31,12 +31,6 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" -[[package]] -name = "bufstream" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40e38929add23cdf8a366df9b0e088953150724bcbe5fc330b0d8eb3b328eec8" - [[package]] name = "bumpalo" version = "3.9.1" @@ -442,7 +436,6 @@ version = "0.6.1" dependencies = [ "atty", "base64", - "bufstream", "home", "named_pipe", "pathsearch", diff --git a/zowex/Cargo.toml b/zowex/Cargo.toml index 4ad1d4bf28..74d6aea2f0 100644 --- a/zowex/Cargo.toml +++ b/zowex/Cargo.toml @@ -11,7 +11,6 @@ repository = "https://github.com/zowe/zowe-cli" [dependencies] atty = "0.2.14" base64 = "0.13.0" -bufstream = "0.1.4" home = "0.5.3" pathsearch = "0.2.0" rpassword = "5.0.1" diff --git a/zowex/src/main.rs b/zowex/src/main.rs index 7851a81131..2c2009144b 100644 --- a/zowex/src/main.rs +++ b/zowex/src/main.rs @@ -12,6 +12,7 @@ use std::collections::HashMap; use std::env; use std::io; +use std::io::BufReader; use std::io::prelude::*; use std::net::Shutdown; use std::process::{Command, Stdio}; @@ -28,9 +29,6 @@ use atty::Stream; extern crate base64; use base64::encode; -extern crate bufstream; -use bufstream::BufStream; - extern crate home; use home::home_dir; @@ -385,7 +383,9 @@ fn talk(message: &[u8], stream: &mut DaemonClient) -> io::Result<()> { * Send the command line arguments to the daemon and await responses. */ stream.write_all(message).unwrap(); // write it - let mut stream_clone = BufStream::new(stream); + + let mut writer = stream.try_clone().expect("clone failed"); + let reader = BufReader::new(&*stream); let mut exit_code = 0; let mut _progress = false; @@ -395,7 +395,7 @@ fn talk(message: &[u8], stream: &mut DaemonClient) -> io::Result<()> { let payload: String; // read until form feed (\f) - if stream_clone.read_until(0xC, &mut u_payload).unwrap() > 0 { + if reader.read_until(0xC, &mut u_payload).unwrap() > 0 { // remove form feed and convert to a string u_payload.pop(); // remove the 0xC payload = str::from_utf8(&u_payload).unwrap().to_string(); @@ -443,7 +443,7 @@ fn talk(message: &[u8], stream: &mut DaemonClient) -> io::Result<()> { user: Some(encode(username())), }; let v = serde_json::to_string(&response)?; - stream_clone.write_all(v.as_bytes()).unwrap(); + writer.write_all(v.as_bytes()).unwrap(); } if let Some(s) = p.securePrompt { @@ -460,7 +460,7 @@ fn talk(message: &[u8], stream: &mut DaemonClient) -> io::Result<()> { user: Some(encode(username())), }; let v = serde_json::to_string(&response)?; - stream_clone.write_all(v.as_bytes()).unwrap(); + writer.write_all(v.as_bytes()).unwrap(); } exit_code = p.exitCode.unwrap_or(0); @@ -474,12 +474,10 @@ fn talk(message: &[u8], stream: &mut DaemonClient) -> io::Result<()> { // Terminate connection. Ignore NotConnected errors returned on macOS. // https://doc.rust-lang.org/std/net/struct.TcpStream.html#method.shutdown - #[cfg(target_family = "unix")] match stream.shutdown(Shutdown::Read) { Err(ref e) if e.kind() == io::ErrorKind::NotConnected => (), result => result?, } - #[cfg(target_family = "unix")] match stream.shutdown(Shutdown::Write) { Err(ref e) if e.kind() == io::ErrorKind::NotConnected => (), result => result?, @@ -509,7 +507,7 @@ fn get_socket_string() -> String { let mut _socket = format!("\\\\.\\pipe\\{}\\{}", username(), "ZoweDaemon"); if let Ok(pipe_name) = env::var("ZOWE_DAEMON") { - _socket = format!("\\\\.\\pipe\\{}\\{}", username(), pipe_name); + _socket = format!("\\\\.\\pipe\\{}", pipe_name); } _socket From a7e7963b882e250f7b622db125f06b43ff5f2e65 Mon Sep 17 00:00:00 2001 From: Timothy Johnson Date: Mon, 7 Feb 2022 16:51:49 -0500 Subject: [PATCH 09/29] Forgot reader must also be mutable Signed-off-by: Timothy Johnson --- zowex/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zowex/src/main.rs b/zowex/src/main.rs index 2c2009144b..c40f0a6ecc 100644 --- a/zowex/src/main.rs +++ b/zowex/src/main.rs @@ -385,7 +385,7 @@ fn talk(message: &[u8], stream: &mut DaemonClient) -> io::Result<()> { stream.write_all(message).unwrap(); // write it let mut writer = stream.try_clone().expect("clone failed"); - let reader = BufReader::new(&*stream); + let mut reader = BufReader::new(&*stream); let mut exit_code = 0; let mut _progress = false; From 59a6077fbce385c0faf0918b144bcd441fd3efa3 Mon Sep 17 00:00:00 2001 From: Timothy Johnson Date: Tue, 8 Feb 2022 10:14:25 -0500 Subject: [PATCH 10/29] Fix prompting with named pipes Signed-off-by: Timothy Johnson --- zowex/src/main.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/zowex/src/main.rs b/zowex/src/main.rs index c40f0a6ecc..5d6dd2f949 100644 --- a/zowex/src/main.rs +++ b/zowex/src/main.rs @@ -311,10 +311,7 @@ fn establish_connection(daemon_socket: String) -> io::Result { let mut cmd_to_show: String = String::new(); let stream = loop { - #[cfg(target_family = "unix")] - let conn_result = UnixStream::connect(&daemon_socket); - #[cfg(target_family = "windows")] - let conn_result = PipeClient::connect(&daemon_socket); + let conn_result = DaemonClient::connect(&daemon_socket); if let Ok(good_stream) = conn_result { // We made our connection. Break with the actual stream value break good_stream; @@ -384,8 +381,12 @@ fn talk(message: &[u8], stream: &mut DaemonClient) -> io::Result<()> { */ stream.write_all(message).unwrap(); // write it + #[cfg(target_family = "unix")] let mut writer = stream.try_clone().expect("clone failed"); + #[cfg(target_family = "unix")] let mut reader = BufReader::new(&*stream); + #[cfg(target_family = "windows")] + let mut reader = BufReader::new(stream); let mut exit_code = 0; let mut _progress = false; @@ -443,7 +444,10 @@ fn talk(message: &[u8], stream: &mut DaemonClient) -> io::Result<()> { user: Some(encode(username())), }; let v = serde_json::to_string(&response)?; + #[cfg(target_family = "unix")] writer.write_all(v.as_bytes()).unwrap(); + #[cfg(target_family = "windows")] + reader.get_mut().write_all(v.as_bytes()).unwrap(); } if let Some(s) = p.securePrompt { @@ -460,7 +464,10 @@ fn talk(message: &[u8], stream: &mut DaemonClient) -> io::Result<()> { user: Some(encode(username())), }; let v = serde_json::to_string(&response)?; + #[cfg(target_family = "unix")] writer.write_all(v.as_bytes()).unwrap(); + #[cfg(target_family = "windows")] + reader.get_mut().write_all(v.as_bytes()).unwrap(); } exit_code = p.exitCode.unwrap_or(0); @@ -474,10 +481,12 @@ fn talk(message: &[u8], stream: &mut DaemonClient) -> io::Result<()> { // Terminate connection. Ignore NotConnected errors returned on macOS. // https://doc.rust-lang.org/std/net/struct.TcpStream.html#method.shutdown + #[cfg(target_family = "unix")] match stream.shutdown(Shutdown::Read) { Err(ref e) if e.kind() == io::ErrorKind::NotConnected => (), result => result?, } + #[cfg(target_family = "unix")] match stream.shutdown(Shutdown::Write) { Err(ref e) if e.kind() == io::ErrorKind::NotConnected => (), result => result?, From 9e46021dbb5549d52b59c22662e46f2aa65c13e6 Mon Sep 17 00:00:00 2001 From: Timothy Johnson Date: Tue, 8 Feb 2022 10:23:41 -0500 Subject: [PATCH 11/29] Make pipe name consistent on Windows Signed-off-by: Timothy Johnson --- npm-shrinkwrap.json | 168 ++++++++++++----------- packages/cli/src/daemon/DaemonDecider.ts | 7 +- 2 files changed, 93 insertions(+), 82 deletions(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 0ae640d959..ae1df1d9ad 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -61,7 +61,8 @@ } }, "__tests__/__packages__/cli-test-utils": { - "version": "7.0.0-next.202201252014", + "name": "@zowe/cli-test-utils", + "version": "7.0.0-next.202201261615", "license": "EPL-2.0", "dependencies": { "@types/js-yaml": "^4.0.0", @@ -24745,22 +24746,23 @@ } }, "packages/cli": { - "version": "7.0.0-next.202201252014", + "name": "@zowe/cli", + "version": "7.0.0-next.202201261615", "hasInstallScript": true, "license": "EPL-2.0", "dependencies": { - "@zowe/core-for-zowe-sdk": "7.0.0-next.202201252014", + "@zowe/core-for-zowe-sdk": "7.0.0-next.202201261615", "@zowe/imperative": "5.0.0-next.202201251614", "@zowe/perf-timing": "1.0.7", - "@zowe/provisioning-for-zowe-sdk": "7.0.0-next.202201252014", - "@zowe/zos-console-for-zowe-sdk": "7.0.0-next.202201252014", - "@zowe/zos-files-for-zowe-sdk": "7.0.0-next.202201252014", - "@zowe/zos-jobs-for-zowe-sdk": "7.0.0-next.202201252014", - "@zowe/zos-logs-for-zowe-sdk": "7.0.0-next.202201252014", - "@zowe/zos-tso-for-zowe-sdk": "7.0.0-next.202201252014", - "@zowe/zos-uss-for-zowe-sdk": "7.0.0-next.202201252014", - "@zowe/zos-workflows-for-zowe-sdk": "7.0.0-next.202201252014", - "@zowe/zosmf-for-zowe-sdk": "7.0.0-next.202201252014", + "@zowe/provisioning-for-zowe-sdk": "7.0.0-next.202201261615", + "@zowe/zos-console-for-zowe-sdk": "7.0.0-next.202201261615", + "@zowe/zos-files-for-zowe-sdk": "7.0.0-next.202201261615", + "@zowe/zos-jobs-for-zowe-sdk": "7.0.0-next.202201261615", + "@zowe/zos-logs-for-zowe-sdk": "7.0.0-next.202201261615", + "@zowe/zos-tso-for-zowe-sdk": "7.0.0-next.202201261615", + "@zowe/zos-uss-for-zowe-sdk": "7.0.0-next.202201261615", + "@zowe/zos-workflows-for-zowe-sdk": "7.0.0-next.202201261615", + "@zowe/zosmf-for-zowe-sdk": "7.0.0-next.202201261615", "find-process": "1.4.7", "get-stdin": "7.0.0", "lodash": "4.17.21", @@ -24776,7 +24778,7 @@ "@types/node": "^12.12.24", "@types/tar": "6.1.1", "@types/which": "2.0.1", - "@zowe/cli-test-utils": "7.0.0-next.202201252014", + "@zowe/cli-test-utils": "7.0.0-next.202201261615", "comment-json": "^4.1.0", "eslint": "^7.32.0", "js-yaml": "^3.13.1", @@ -24810,7 +24812,8 @@ } }, "packages/core": { - "version": "7.0.0-next.202201252014", + "name": "@zowe/core-for-zowe-sdk", + "version": "7.0.0-next.202201261615", "license": "EPL-2.0", "dependencies": { "comment-json": "4.1.0", @@ -24818,7 +24821,7 @@ }, "devDependencies": { "@types/node": "^12.12.24", - "@zowe/cli-test-utils": "7.0.0-next.202201252014", + "@zowe/cli-test-utils": "7.0.0-next.202201261615", "@zowe/imperative": "5.0.0-next.202201251614", "chalk": "^4.1.0", "eslint": "^7.32.0", @@ -24832,7 +24835,8 @@ } }, "packages/provisioning": { - "version": "7.0.0-next.202201252014", + "name": "@zowe/provisioning-for-zowe-sdk", + "version": "7.0.0-next.202201261615", "license": "EPL-2.0", "dependencies": { "js-yaml": "3.14.1" @@ -24840,8 +24844,8 @@ "devDependencies": { "@types/js-yaml": "^3.12.5", "@types/node": "^12.12.24", - "@zowe/cli-test-utils": "7.0.0-next.202201252014", - "@zowe/core-for-zowe-sdk": "7.0.0-next.202201252014", + "@zowe/cli-test-utils": "7.0.0-next.202201261615", + "@zowe/core-for-zowe-sdk": "7.0.0-next.202201261615", "@zowe/imperative": "5.0.0-next.202201251614", "eslint": "^7.32.0", "madge": "^4.0.1", @@ -24861,15 +24865,16 @@ "dev": true }, "packages/workflows": { - "version": "7.0.0-next.202201252014", + "name": "@zowe/zos-workflows-for-zowe-sdk", + "version": "7.0.0-next.202201261615", "license": "EPL-2.0", "dependencies": { - "@zowe/zos-files-for-zowe-sdk": "7.0.0-next.202201252014" + "@zowe/zos-files-for-zowe-sdk": "7.0.0-next.202201261615" }, "devDependencies": { "@types/node": "^12.12.24", - "@zowe/cli-test-utils": "7.0.0-next.202201252014", - "@zowe/core-for-zowe-sdk": "7.0.0-next.202201252014", + "@zowe/cli-test-utils": "7.0.0-next.202201261615", + "@zowe/core-for-zowe-sdk": "7.0.0-next.202201261615", "@zowe/imperative": "5.0.0-next.202201251614", "eslint": "^7.32.0", "madge": "^4.0.1", @@ -24883,12 +24888,13 @@ } }, "packages/zosconsole": { - "version": "7.0.0-next.202201252014", + "name": "@zowe/zos-console-for-zowe-sdk", + "version": "7.0.0-next.202201261615", "license": "EPL-2.0", "devDependencies": { "@types/node": "^12.12.24", - "@zowe/cli-test-utils": "7.0.0-next.202201252014", - "@zowe/core-for-zowe-sdk": "7.0.0-next.202201252014", + "@zowe/cli-test-utils": "7.0.0-next.202201261615", + "@zowe/core-for-zowe-sdk": "7.0.0-next.202201261615", "@zowe/imperative": "5.0.0-next.202201251614", "eslint": "^7.32.0", "madge": "^4.0.1", @@ -24902,17 +24908,18 @@ } }, "packages/zosfiles": { - "version": "7.0.0-next.202201252014", + "name": "@zowe/zos-files-for-zowe-sdk", + "version": "7.0.0-next.202201261615", "license": "EPL-2.0", "dependencies": { "minimatch": "3.0.4" }, "devDependencies": { "@types/node": "^12.12.24", - "@zowe/cli-test-utils": "7.0.0-next.202201252014", - "@zowe/core-for-zowe-sdk": "7.0.0-next.202201252014", + "@zowe/cli-test-utils": "7.0.0-next.202201261615", + "@zowe/core-for-zowe-sdk": "7.0.0-next.202201261615", "@zowe/imperative": "5.0.0-next.202201251614", - "@zowe/zos-uss-for-zowe-sdk": "7.0.0-next.202201252014", + "@zowe/zos-uss-for-zowe-sdk": "7.0.0-next.202201261615", "eslint": "^7.32.0", "madge": "^4.0.1", "rimraf": "^2.6.3", @@ -24925,15 +24932,16 @@ } }, "packages/zosjobs": { - "version": "7.0.0-next.202201252014", + "name": "@zowe/zos-jobs-for-zowe-sdk", + "version": "7.0.0-next.202201261615", "license": "EPL-2.0", "dependencies": { - "@zowe/zos-files-for-zowe-sdk": "7.0.0-next.202201252014" + "@zowe/zos-files-for-zowe-sdk": "7.0.0-next.202201261615" }, "devDependencies": { "@types/node": "^12.12.24", - "@zowe/cli-test-utils": "7.0.0-next.202201252014", - "@zowe/core-for-zowe-sdk": "7.0.0-next.202201252014", + "@zowe/cli-test-utils": "7.0.0-next.202201261615", + "@zowe/core-for-zowe-sdk": "7.0.0-next.202201261615", "@zowe/imperative": "5.0.0-next.202201251614", "eslint": "^7.32.0", "madge": "^4.0.1", @@ -24947,12 +24955,13 @@ } }, "packages/zoslogs": { - "version": "7.0.0-next.202201252014", + "name": "@zowe/zos-logs-for-zowe-sdk", + "version": "7.0.0-next.202201261615", "license": "EPL-2.0", "devDependencies": { "@types/node": "^12.12.24", - "@zowe/cli-test-utils": "7.0.0-next.202201252014", - "@zowe/core-for-zowe-sdk": "7.0.0-next.202201252014", + "@zowe/cli-test-utils": "7.0.0-next.202201261615", + "@zowe/core-for-zowe-sdk": "7.0.0-next.202201261615", "@zowe/imperative": "5.0.0-next.202201251614", "eslint": "^7.32.0", "madge": "^4.0.1", @@ -24966,12 +24975,13 @@ } }, "packages/zosmf": { - "version": "7.0.0-next.202201252014", + "name": "@zowe/zosmf-for-zowe-sdk", + "version": "7.0.0-next.202201261615", "license": "EPL-2.0", "devDependencies": { "@types/node": "^12.12.24", - "@zowe/cli-test-utils": "7.0.0-next.202201252014", - "@zowe/core-for-zowe-sdk": "7.0.0-next.202201252014", + "@zowe/cli-test-utils": "7.0.0-next.202201261615", + "@zowe/core-for-zowe-sdk": "7.0.0-next.202201261615", "@zowe/imperative": "5.0.0-next.202201251614", "eslint": "^7.32.0", "madge": "^4.0.1", @@ -24985,15 +24995,16 @@ } }, "packages/zostso": { - "version": "7.0.0-next.202201252014", + "name": "@zowe/zos-tso-for-zowe-sdk", + "version": "7.0.0-next.202201261615", "license": "EPL-2.0", "dependencies": { - "@zowe/zosmf-for-zowe-sdk": "7.0.0-next.202201252014" + "@zowe/zosmf-for-zowe-sdk": "7.0.0-next.202201261615" }, "devDependencies": { "@types/node": "^12.12.24", - "@zowe/cli-test-utils": "7.0.0-next.202201252014", - "@zowe/core-for-zowe-sdk": "7.0.0-next.202201252014", + "@zowe/cli-test-utils": "7.0.0-next.202201261615", + "@zowe/core-for-zowe-sdk": "7.0.0-next.202201261615", "@zowe/imperative": "5.0.0-next.202201251614", "eslint": "^7.32.0", "madge": "^4.0.1", @@ -25007,7 +25018,8 @@ } }, "packages/zosuss": { - "version": "7.0.0-next.202201252014", + "name": "@zowe/zos-uss-for-zowe-sdk", + "version": "7.0.0-next.202201261615", "license": "EPL-2.0", "dependencies": { "ssh2": "1.4.0" @@ -25015,7 +25027,7 @@ "devDependencies": { "@types/node": "^12.12.24", "@types/ssh2": "^0.5.44", - "@zowe/cli-test-utils": "7.0.0-next.202201252014", + "@zowe/cli-test-utils": "7.0.0-next.202201261615", "@zowe/imperative": "5.0.0-next.202201251614", "eslint": "^7.32.0", "madge": "^4.0.1", @@ -29109,19 +29121,19 @@ "@types/node": "^12.12.24", "@types/tar": "6.1.1", "@types/which": "2.0.1", - "@zowe/cli-test-utils": "7.0.0-next.202201252014", - "@zowe/core-for-zowe-sdk": "7.0.0-next.202201252014", + "@zowe/cli-test-utils": "7.0.0-next.202201261615", + "@zowe/core-for-zowe-sdk": "7.0.0-next.202201261615", "@zowe/imperative": "5.0.0-next.202201251614", "@zowe/perf-timing": "1.0.7", - "@zowe/provisioning-for-zowe-sdk": "7.0.0-next.202201252014", - "@zowe/zos-console-for-zowe-sdk": "7.0.0-next.202201252014", - "@zowe/zos-files-for-zowe-sdk": "7.0.0-next.202201252014", - "@zowe/zos-jobs-for-zowe-sdk": "7.0.0-next.202201252014", - "@zowe/zos-logs-for-zowe-sdk": "7.0.0-next.202201252014", - "@zowe/zos-tso-for-zowe-sdk": "7.0.0-next.202201252014", - "@zowe/zos-uss-for-zowe-sdk": "7.0.0-next.202201252014", - "@zowe/zos-workflows-for-zowe-sdk": "7.0.0-next.202201252014", - "@zowe/zosmf-for-zowe-sdk": "7.0.0-next.202201252014", + "@zowe/provisioning-for-zowe-sdk": "7.0.0-next.202201261615", + "@zowe/zos-console-for-zowe-sdk": "7.0.0-next.202201261615", + "@zowe/zos-files-for-zowe-sdk": "7.0.0-next.202201261615", + "@zowe/zos-jobs-for-zowe-sdk": "7.0.0-next.202201261615", + "@zowe/zos-logs-for-zowe-sdk": "7.0.0-next.202201261615", + "@zowe/zos-tso-for-zowe-sdk": "7.0.0-next.202201261615", + "@zowe/zos-uss-for-zowe-sdk": "7.0.0-next.202201261615", + "@zowe/zos-workflows-for-zowe-sdk": "7.0.0-next.202201261615", + "@zowe/zosmf-for-zowe-sdk": "7.0.0-next.202201261615", "comment-json": "^4.1.0", "eslint": "^7.32.0", "find-process": "1.4.7", @@ -29206,7 +29218,7 @@ "version": "file:packages/core", "requires": { "@types/node": "^12.12.24", - "@zowe/cli-test-utils": "7.0.0-next.202201252014", + "@zowe/cli-test-utils": "7.0.0-next.202201261615", "@zowe/imperative": "5.0.0-next.202201251614", "chalk": "^4.1.0", "comment-json": "4.1.0", @@ -29387,8 +29399,8 @@ "requires": { "@types/js-yaml": "^3.12.5", "@types/node": "^12.12.24", - "@zowe/cli-test-utils": "7.0.0-next.202201252014", - "@zowe/core-for-zowe-sdk": "7.0.0-next.202201252014", + "@zowe/cli-test-utils": "7.0.0-next.202201261615", + "@zowe/core-for-zowe-sdk": "7.0.0-next.202201261615", "@zowe/imperative": "5.0.0-next.202201251614", "eslint": "^7.32.0", "js-yaml": "3.14.1", @@ -29410,8 +29422,8 @@ "version": "file:packages/zosconsole", "requires": { "@types/node": "^12.12.24", - "@zowe/cli-test-utils": "7.0.0-next.202201252014", - "@zowe/core-for-zowe-sdk": "7.0.0-next.202201252014", + "@zowe/cli-test-utils": "7.0.0-next.202201261615", + "@zowe/core-for-zowe-sdk": "7.0.0-next.202201261615", "@zowe/imperative": "5.0.0-next.202201251614", "eslint": "^7.32.0", "madge": "^4.0.1", @@ -29424,10 +29436,10 @@ "version": "file:packages/zosfiles", "requires": { "@types/node": "^12.12.24", - "@zowe/cli-test-utils": "7.0.0-next.202201252014", - "@zowe/core-for-zowe-sdk": "7.0.0-next.202201252014", + "@zowe/cli-test-utils": "7.0.0-next.202201261615", + "@zowe/core-for-zowe-sdk": "7.0.0-next.202201261615", "@zowe/imperative": "5.0.0-next.202201251614", - "@zowe/zos-uss-for-zowe-sdk": "7.0.0-next.202201252014", + "@zowe/zos-uss-for-zowe-sdk": "7.0.0-next.202201261615", "eslint": "^7.32.0", "madge": "^4.0.1", "minimatch": "3.0.4", @@ -29440,10 +29452,10 @@ "version": "file:packages/zosjobs", "requires": { "@types/node": "^12.12.24", - "@zowe/cli-test-utils": "7.0.0-next.202201252014", - "@zowe/core-for-zowe-sdk": "7.0.0-next.202201252014", + "@zowe/cli-test-utils": "7.0.0-next.202201261615", + "@zowe/core-for-zowe-sdk": "7.0.0-next.202201261615", "@zowe/imperative": "5.0.0-next.202201251614", - "@zowe/zos-files-for-zowe-sdk": "7.0.0-next.202201252014", + "@zowe/zos-files-for-zowe-sdk": "7.0.0-next.202201261615", "eslint": "^7.32.0", "madge": "^4.0.1", "rimraf": "^2.6.3", @@ -29455,8 +29467,8 @@ "version": "file:packages/zoslogs", "requires": { "@types/node": "^12.12.24", - "@zowe/cli-test-utils": "7.0.0-next.202201252014", - "@zowe/core-for-zowe-sdk": "7.0.0-next.202201252014", + "@zowe/cli-test-utils": "7.0.0-next.202201261615", + "@zowe/core-for-zowe-sdk": "7.0.0-next.202201261615", "@zowe/imperative": "5.0.0-next.202201251614", "eslint": "^7.32.0", "madge": "^4.0.1", @@ -29469,10 +29481,10 @@ "version": "file:packages/zostso", "requires": { "@types/node": "^12.12.24", - "@zowe/cli-test-utils": "7.0.0-next.202201252014", - "@zowe/core-for-zowe-sdk": "7.0.0-next.202201252014", + "@zowe/cli-test-utils": "7.0.0-next.202201261615", + "@zowe/core-for-zowe-sdk": "7.0.0-next.202201261615", "@zowe/imperative": "5.0.0-next.202201251614", - "@zowe/zosmf-for-zowe-sdk": "7.0.0-next.202201252014", + "@zowe/zosmf-for-zowe-sdk": "7.0.0-next.202201261615", "eslint": "^7.32.0", "madge": "^4.0.1", "rimraf": "^2.6.3", @@ -29485,7 +29497,7 @@ "requires": { "@types/node": "^12.12.24", "@types/ssh2": "^0.5.44", - "@zowe/cli-test-utils": "7.0.0-next.202201252014", + "@zowe/cli-test-utils": "7.0.0-next.202201261615", "@zowe/imperative": "5.0.0-next.202201251614", "eslint": "^7.32.0", "madge": "^4.0.1", @@ -29499,10 +29511,10 @@ "version": "file:packages/workflows", "requires": { "@types/node": "^12.12.24", - "@zowe/cli-test-utils": "7.0.0-next.202201252014", - "@zowe/core-for-zowe-sdk": "7.0.0-next.202201252014", + "@zowe/cli-test-utils": "7.0.0-next.202201261615", + "@zowe/core-for-zowe-sdk": "7.0.0-next.202201261615", "@zowe/imperative": "5.0.0-next.202201251614", - "@zowe/zos-files-for-zowe-sdk": "7.0.0-next.202201252014", + "@zowe/zos-files-for-zowe-sdk": "7.0.0-next.202201261615", "eslint": "^7.32.0", "madge": "^4.0.1", "rimraf": "^2.6.3", @@ -29514,8 +29526,8 @@ "version": "file:packages/zosmf", "requires": { "@types/node": "^12.12.24", - "@zowe/cli-test-utils": "7.0.0-next.202201252014", - "@zowe/core-for-zowe-sdk": "7.0.0-next.202201252014", + "@zowe/cli-test-utils": "7.0.0-next.202201261615", + "@zowe/core-for-zowe-sdk": "7.0.0-next.202201261615", "@zowe/imperative": "5.0.0-next.202201251614", "eslint": "^7.32.0", "madge": "^4.0.1", diff --git a/packages/cli/src/daemon/DaemonDecider.ts b/packages/cli/src/daemon/DaemonDecider.ts index 1012f5c7b5..32a08e2900 100644 --- a/packages/cli/src/daemon/DaemonDecider.ts +++ b/packages/cli/src/daemon/DaemonDecider.ts @@ -160,10 +160,9 @@ export class DaemonDecider { if (daemonOffset > -1) { this.startServer = true; if (process.env.ZOWE_DAEMON) { - if (process.platform !== "win32") { - this.mSocket = process.env.ZOWE_DAEMON; - } else { - this.mSocket = `\\\\.\\pipe\\${os.userInfo().username}\\${process.env.ZOWE_DAEMON}`; + this.mSocket = process.env.ZOWE_DAEMON; + if (process.platform === "win32") { + this.mSocket = `\\\\.\\pipe\\${this.mSocket}`; } } Imperative.api.appLogger.debug(`daemon server socket ${this.mSocket}`); From ada5600ff9db5e87f339cc1c7185abd73264e90f Mon Sep 17 00:00:00 2001 From: Timothy Johnson Date: Tue, 8 Feb 2022 11:45:32 -0500 Subject: [PATCH 12/29] Support ZOWE_CLI_HOME variable for daemon socket Signed-off-by: Timothy Johnson --- packages/cli/src/daemon/DaemonDecider.ts | 31 ++++++++++++++---------- zowex/src/main.rs | 27 +++++++++++---------- 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/packages/cli/src/daemon/DaemonDecider.ts b/packages/cli/src/daemon/DaemonDecider.ts index 32a08e2900..2c7eb8103f 100644 --- a/packages/cli/src/daemon/DaemonDecider.ts +++ b/packages/cli/src/daemon/DaemonDecider.ts @@ -14,6 +14,7 @@ import * as net from "net"; import * as os from "os"; import * as path from "path"; import { Imperative } from "@zowe/imperative"; +import { Constants } from "../Constants"; import { DaemonClient } from "./DaemonClient"; // TODO(Kelosky): handle prompting cases from login command @@ -104,9 +105,9 @@ export class DaemonDecider { fs.unlinkSync(this.mSocket); } - // TODO Handle other exit signals? - process.on("SIGINT", this.close.bind(this)); - process.on("SIGKILL", this.close.bind(this)); + ["exit", "SIGINT", "SIGQUIT", "SIGTERM"].forEach((eventType: any) => { + process.on(eventType, this.close.bind(this, true)); + }); this.mServer.listen(this.mSocket, () => { Imperative.api.appLogger.debug(`daemon server bound ${this.mSocket}`); @@ -122,8 +123,11 @@ export class DaemonDecider { * @private * @memberof DaemonDecider */ - private close() { + private close(shouldExit?: boolean) { Imperative.api.appLogger.debug(`server closed`); + if (shouldExit) { + process.exit(); + } } /** @@ -143,28 +147,29 @@ export class DaemonDecider { * @memberof DaemonDecider */ private initialParse() { - const numOfParms = this.mParms.length - 2; - // TODO Support ZOWE_CLI_HOME environment variable here and in client - this.mSocket = (process.platform !== "win32") ? path.join(os.homedir(), ".zowe", "daemon.sock") : - `\\\\.\\pipe\\${os.userInfo().username}\\ZoweDaemon`; - - if (numOfParms > 0) { - const parm = this.mParms[2]; - + if (this.mParms.length > 2) { /** - * NOTE(Kelosky): For now, we use an undocumented paramter `--daemon`. If found first, + * NOTE(Kelosky): For now, we use an undocumented parameter `--daemon`. If found first, * we bypass `yargs` and begin running this as a persistent Processor. */ + const parm = this.mParms[2]; const daemonOffset = parm.indexOf(DaemonDecider.DAEMON_KEY); if (daemonOffset > -1) { this.startServer = true; + if (process.env.ZOWE_DAEMON) { this.mSocket = process.env.ZOWE_DAEMON; if (process.platform === "win32") { this.mSocket = `\\\\.\\pipe\\${this.mSocket}`; } + } else if (process.platform !== "win32") { + const cliHomeDir = process.env[Constants.HOME_ENV_KEY] || path.join(os.homedir(), ".zowe"); + this.mSocket = path.join(cliHomeDir, "daemon.sock"); + } else { + this.mSocket = `\\\\.\\pipe\\${os.userInfo().username}\\ZoweDaemon`; } + Imperative.api.appLogger.debug(`daemon server socket ${this.mSocket}`); } } diff --git a/zowex/src/main.rs b/zowex/src/main.rs index 5d6dd2f949..cb70adbcbe 100644 --- a/zowex/src/main.rs +++ b/zowex/src/main.rs @@ -502,7 +502,8 @@ fn talk(message: &[u8], stream: &mut DaemonClient) -> io::Result<()> { #[cfg(target_family = "unix")] fn get_socket_string() -> String { - let mut _socket = format!("{}/{}", home_dir().unwrap().to_string_lossy(), ".zowe/daemon.sock"); + let cli_home_dir = env::var("ZOWE_CLI_HOME").unwrap_or(format!("{}/{}", home_dir().unwrap().to_string_lossy(), ".zowe")); + let mut _socket = format!("{}/{}", cli_home_dir, "daemon.sock"); if let Ok(socket_path) = env::var("ZOWE_DAEMON") { _socket = socket_path; @@ -749,18 +750,18 @@ mod tests { // Note this useful idiom: importing names from outer (for mod tests) scope. use super::*; - // #[test] - // fn test_get_port_string() { - // // expect default port with no env - // let port_string = get_port_string(); - // assert_eq!("4000", port_string); - - // // expect override port with env - // env::set_var("ZOWE_DAEMON", "777"); - // let port_string = get_port_string(); - // assert_eq!("777", port_string); - // env::remove_var("ZOWE_DAEMON"); - // } + #[test] + fn test_get_socket_string() { + // expect default port with no env + let socket_string = get_socket_string(); + assert!(!socket_string.contains("NotADaemon")); + + // expect override port with env + env::set_var("ZOWE_DAEMON", "NotADaemon"); + let socket_string = get_socket_string(); + assert!(socket_string.contains("NotADaemon")); + env::remove_var("ZOWE_DAEMON"); + } #[test] fn test_get_zowe_env() { From fbe581a98699078d52a727814b81d5863bd82333 Mon Sep 17 00:00:00 2001 From: Timothy Johnson Date: Tue, 8 Feb 2022 11:59:31 -0500 Subject: [PATCH 13/29] Test removing complex shutdown logic for macOS Signed-off-by: Timothy Johnson --- zowex/src/main.rs | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/zowex/src/main.rs b/zowex/src/main.rs index cb70adbcbe..800642b842 100644 --- a/zowex/src/main.rs +++ b/zowex/src/main.rs @@ -14,7 +14,6 @@ use std::env; use std::io; use std::io::BufReader; use std::io::prelude::*; -use std::net::Shutdown; use std::process::{Command, Stdio}; use std::str; use std::thread; @@ -30,6 +29,7 @@ extern crate base64; use base64::encode; extern crate home; +#[cfg(target_family = "unix")] use home::home_dir; #[cfg(target_family = "windows")] @@ -479,18 +479,8 @@ fn talk(message: &[u8], stream: &mut DaemonClient) -> io::Result<()> { } } - // Terminate connection. Ignore NotConnected errors returned on macOS. - // https://doc.rust-lang.org/std/net/struct.TcpStream.html#method.shutdown - #[cfg(target_family = "unix")] - match stream.shutdown(Shutdown::Read) { - Err(ref e) if e.kind() == io::ErrorKind::NotConnected => (), - result => result?, - } #[cfg(target_family = "unix")] - match stream.shutdown(Shutdown::Write) { - Err(ref e) if e.kind() == io::ErrorKind::NotConnected => (), - result => result?, - } + stream.shutdown(std::net::Shutdown::Both)?; // terminate connection // TODO(Kelosky): maybe this should just be a `return Err` if exit_code != 0 { From 9abd0f1896f83596414a7104bdb85ec001c01b93 Mon Sep 17 00:00:00 2001 From: "Andrew W. Harn" Date: Tue, 8 Feb 2022 13:17:23 -0500 Subject: [PATCH 14/29] Fix unit tests for sockets and pipes. Signed-off-by: Andrew W. Harn --- .../daemon/__unit__/DaemonDecider.unit.test.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/cli/__tests__/daemon/__unit__/DaemonDecider.unit.test.ts b/packages/cli/__tests__/daemon/__unit__/DaemonDecider.unit.test.ts index fdd5807753..3d576a7443 100644 --- a/packages/cli/__tests__/daemon/__unit__/DaemonDecider.unit.test.ts +++ b/packages/cli/__tests__/daemon/__unit__/DaemonDecider.unit.test.ts @@ -64,7 +64,7 @@ describe("DaemonDecider tests", () => { // do nothing }); - const listen = jest.fn((port, hostname, method) => { + const listen = jest.fn((socket, method) => { // do nothing method(); }); @@ -109,7 +109,7 @@ describe("DaemonDecider tests", () => { expect(err.message).toBe("data"); }); - it("should set port based on env variable", () => { + it("should set socket based on env variable", () => { const log = jest.fn(() => { // do nothing @@ -125,12 +125,11 @@ describe("DaemonDecider tests", () => { const daemonDecider = new DaemonDecider(["anything"]); - const testPort = "1234"; - + const testSocket = "/fake/pipe/path"; (daemonDecider as any).mParms = ["one", "two", "--daemon"]; - process.env.ZOWE_DAEMON = testPort; + process.env.ZOWE_DAEMON = testSocket; (daemonDecider as any).initialParse(); - expect((daemonDecider as any).mPort).toBe(parseInt(testPort, 10)); + expect((daemonDecider as any).mSocket).toBe(process.platform === "win32" ? "\\\\.\\pipe\\" + testSocket : testSocket); }); }); From e1cf1400796e0ab6a3dfda2a0fa2222c73aff6a1 Mon Sep 17 00:00:00 2001 From: "Andrew W. Harn" Date: Tue, 8 Feb 2022 13:54:20 -0500 Subject: [PATCH 15/29] Update the location of the daemon socket on *nix Signed-off-by: Andrew W. Harn --- packages/cli/src/daemon/DaemonDecider.ts | 4 +--- zowex/src/main.rs | 3 +-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/cli/src/daemon/DaemonDecider.ts b/packages/cli/src/daemon/DaemonDecider.ts index 2c7eb8103f..e5e5bd3ae4 100644 --- a/packages/cli/src/daemon/DaemonDecider.ts +++ b/packages/cli/src/daemon/DaemonDecider.ts @@ -14,7 +14,6 @@ import * as net from "net"; import * as os from "os"; import * as path from "path"; import { Imperative } from "@zowe/imperative"; -import { Constants } from "../Constants"; import { DaemonClient } from "./DaemonClient"; // TODO(Kelosky): handle prompting cases from login command @@ -164,8 +163,7 @@ export class DaemonDecider { this.mSocket = `\\\\.\\pipe\\${this.mSocket}`; } } else if (process.platform !== "win32") { - const cliHomeDir = process.env[Constants.HOME_ENV_KEY] || path.join(os.homedir(), ".zowe"); - this.mSocket = path.join(cliHomeDir, "daemon.sock"); + this.mSocket = path.join(os.homedir(), ".zowe-daemon.sock"); } else { this.mSocket = `\\\\.\\pipe\\${os.userInfo().username}\\ZoweDaemon`; } diff --git a/zowex/src/main.rs b/zowex/src/main.rs index 800642b842..b7e0b87e1d 100644 --- a/zowex/src/main.rs +++ b/zowex/src/main.rs @@ -492,8 +492,7 @@ fn talk(message: &[u8], stream: &mut DaemonClient) -> io::Result<()> { #[cfg(target_family = "unix")] fn get_socket_string() -> String { - let cli_home_dir = env::var("ZOWE_CLI_HOME").unwrap_or(format!("{}/{}", home_dir().unwrap().to_string_lossy(), ".zowe")); - let mut _socket = format!("{}/{}", cli_home_dir, "daemon.sock"); + let mut _socket = format!("{}/{}", home_dir().unwrap().to_string_lossy(), ".zowe-daemon.sock"); if let Ok(socket_path) = env::var("ZOWE_DAEMON") { _socket = socket_path; From 0c067667bd69a6c6e8f020ad0c4583fa735517a8 Mon Sep 17 00:00:00 2001 From: "Andrew W. Harn" Date: Tue, 8 Feb 2022 14:33:42 -0500 Subject: [PATCH 16/29] Revert "Test removing complex shutdown logic for macOS" This reverts commit fbe581a98699078d52a727814b81d5863bd82333. Signed-off-by: Andrew W. Harn --- zowex/src/main.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/zowex/src/main.rs b/zowex/src/main.rs index b7e0b87e1d..49cf905e67 100644 --- a/zowex/src/main.rs +++ b/zowex/src/main.rs @@ -14,6 +14,7 @@ use std::env; use std::io; use std::io::BufReader; use std::io::prelude::*; +use std::net::Shutdown; use std::process::{Command, Stdio}; use std::str; use std::thread; @@ -29,7 +30,6 @@ extern crate base64; use base64::encode; extern crate home; -#[cfg(target_family = "unix")] use home::home_dir; #[cfg(target_family = "windows")] @@ -479,8 +479,18 @@ fn talk(message: &[u8], stream: &mut DaemonClient) -> io::Result<()> { } } + // Terminate connection. Ignore NotConnected errors returned on macOS. + // https://doc.rust-lang.org/std/net/struct.TcpStream.html#method.shutdown + #[cfg(target_family = "unix")] + match stream.shutdown(Shutdown::Read) { + Err(ref e) if e.kind() == io::ErrorKind::NotConnected => (), + result => result?, + } #[cfg(target_family = "unix")] - stream.shutdown(std::net::Shutdown::Both)?; // terminate connection + match stream.shutdown(Shutdown::Write) { + Err(ref e) if e.kind() == io::ErrorKind::NotConnected => (), + result => result?, + } // TODO(Kelosky): maybe this should just be a `return Err` if exit_code != 0 { From f740a9761fc4c878ddee8dde6db546fa7377344d Mon Sep 17 00:00:00 2001 From: "Andrew W. Harn" Date: Tue, 8 Feb 2022 16:01:58 -0500 Subject: [PATCH 17/29] Add changelog entry Signed-off-by: Andrew W. Harn --- packages/cli/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index 926e38565f..c2813eeb1b 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to the Zowe CLI package will be documented in this file. +## Recent Changes + +- **NEXT BREAKING** Enhancement: Use sockets and named pipes instead of ports for daemon communication for improved access control. + ## `7.0.0-next.202202041954` - BugFix: Fixed daemon binaries missing from package and Keytar binaries not found at install time. From 8a97ce4215e24d6a41ddb3459afa58c31b8cf1af Mon Sep 17 00:00:00 2001 From: "Andrew W. Harn" Date: Tue, 8 Feb 2022 16:56:51 -0500 Subject: [PATCH 18/29] Add unit tests Signed-off-by: Andrew W. Harn --- .../__unit__/DaemonDecider.unit.test.ts | 189 ++++++++++++++++++ 1 file changed, 189 insertions(+) diff --git a/packages/cli/__tests__/daemon/__unit__/DaemonDecider.unit.test.ts b/packages/cli/__tests__/daemon/__unit__/DaemonDecider.unit.test.ts index 3d576a7443..85745f4aa9 100644 --- a/packages/cli/__tests__/daemon/__unit__/DaemonDecider.unit.test.ts +++ b/packages/cli/__tests__/daemon/__unit__/DaemonDecider.unit.test.ts @@ -11,13 +11,19 @@ jest.mock("net"); jest.mock("@zowe/imperative"); +import * as fs from "fs"; import * as net from "net"; +import * as os from "os"; +import * as path from "path"; import Mock = jest.Mock; import { Imperative } from "@zowe/imperative"; import { DaemonDecider } from "../../../src/daemon/DaemonDecider"; jest.mock("../../../src/daemon//DaemonClient"); describe("DaemonDecider tests", () => { + afterEach(() => { + delete process.env.ZOWE_DAEMON; + }); it("should call normal parse method if no daemon keyword", () => { @@ -132,4 +138,187 @@ describe("DaemonDecider tests", () => { expect((daemonDecider as any).mSocket).toBe(process.platform === "win32" ? "\\\\.\\pipe\\" + testSocket : testSocket); }); + + (process.platform !== "win32" ? it : it.skip)("should try to delete an existing socket on *nix", () => { + const log = jest.fn(() => { + // do nothing + }); + + const on = jest.fn((event, func) => { + // do nothing + }); + + const listen = jest.fn((event, func) => { + // do nothing + }); + + const parse = jest.fn( (data, context) => { + expect(data).toBe(undefined); + expect(context).toBe(undefined); + }); + + (Imperative as any) = { + api: { + appLogger: { + trace: log, + debug: log, + error: log + } + }, + console: { + info: log + }, + parse + }; + + const fn = net.createServer as Mock; + fn.mockImplementation((unusedclient, ...args: any[]) => { + return {on, listen}; + }); + + const daemonDecider = new DaemonDecider(["node", "zowe", "--daemon"]); + const testSocket = "/fake/pipe/path"; + process.env.ZOWE_DAEMON = testSocket; + + const existsSyncSpy = jest.spyOn(fs, "existsSync"); + existsSyncSpy.mockImplementation(() => true); + + const unlinkSyncSpy = jest.spyOn(fs, "unlinkSync"); + unlinkSyncSpy.mockImplementation(() => true); + + daemonDecider.init(); + daemonDecider.runOrUseDaemon(); + expect(existsSyncSpy).toHaveBeenCalledTimes(1); + expect(unlinkSyncSpy).toHaveBeenCalledTimes(1); + }); + + (process.platform === "win32" ? it : it.skip)("should use the default socket location (win32)", () => { + const log = jest.fn(() => { + // do nothing + }); + + const on = jest.fn((event, func) => { + // do nothing + }); + + const listen = jest.fn((event, func) => { + // do nothing + }); + + const parse = jest.fn( (data, context) => { + expect(data).toBe(undefined); + expect(context).toBe(undefined); + }); + + (Imperative as any) = { + api: { + appLogger: { + trace: log, + debug: log, + error: log + } + }, + console: { + info: log + }, + parse + }; + + const fn = net.createServer as Mock; + fn.mockImplementation((unusedclient, ...args: any[]) => { + return {on, listen}; + }); + + const daemonDecider = new DaemonDecider(["node", "zowe", "--daemon"]); + daemonDecider.init(); + + expect((daemonDecider as any).mSocket).toEqual(`\\\\.\\pipe\\${os.userInfo().username}\\ZoweDaemon`); + }); + + (process.platform !== "win32" ? it : it.skip)("should use the default socket location (not win32)", () => { + const log = jest.fn(() => { + // do nothing + }); + + const on = jest.fn((event, func) => { + // do nothing + }); + + const listen = jest.fn((event, func) => { + // do nothing + }); + + const parse = jest.fn( (data, context) => { + expect(data).toBe(undefined); + expect(context).toBe(undefined); + }); + + (Imperative as any) = { + api: { + appLogger: { + trace: log, + debug: log, + error: log + } + }, + console: { + info: log + }, + parse + }; + + const fn = net.createServer as Mock; + fn.mockImplementation((unusedclient, ...args: any[]) => { + return {on, listen}; + }); + + const daemonDecider = new DaemonDecider(["node", "zowe", "--daemon"]); + daemonDecider.init(); + + expect((daemonDecider as any).mSocket).toEqual(path.join(os.homedir(), ".zowe-daemon.sock")); + }); + + it("should not start a daemon", () => { + const log = jest.fn(() => { + // do nothing + }); + + const on = jest.fn((event, func) => { + // do nothing + }); + + const listen = jest.fn((event, func) => { + // do nothing + }); + + const parse = jest.fn( (data, context) => { + expect(data).toBe(undefined); + expect(context).toBe(undefined); + }); + + (Imperative as any) = { + api: { + appLogger: { + trace: log, + debug: log, + error: log + } + }, + console: { + info: log + }, + parse + }; + + const fn = net.createServer as Mock; + fn.mockImplementation((unusedclient, ...args: any[]) => { + return {on, listen}; + }); + + const daemonDecider = new DaemonDecider(["node", "zowe", "--help"]); + daemonDecider.init(); + + expect((daemonDecider as any).mSocket).toBeUndefined(); + expect((daemonDecider as any).startServer).toBeUndefined(); + }); }); From e4a8676a5e72f81ecd81252381717053b45c5d75 Mon Sep 17 00:00:00 2001 From: "Andrew W. Harn" Date: Tue, 8 Feb 2022 17:28:35 -0500 Subject: [PATCH 19/29] Reset mock after use Signed-off-by: Andrew W. Harn --- .../daemon/__unit__/DaemonDecider.unit.test.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/cli/__tests__/daemon/__unit__/DaemonDecider.unit.test.ts b/packages/cli/__tests__/daemon/__unit__/DaemonDecider.unit.test.ts index 85745f4aa9..bcb4931da7 100644 --- a/packages/cli/__tests__/daemon/__unit__/DaemonDecider.unit.test.ts +++ b/packages/cli/__tests__/daemon/__unit__/DaemonDecider.unit.test.ts @@ -23,6 +23,7 @@ jest.mock("../../../src/daemon//DaemonClient"); describe("DaemonDecider tests", () => { afterEach(() => { delete process.env.ZOWE_DAEMON; + jest.resetAllMocks }); it("should call normal parse method if no daemon keyword", () => { @@ -188,8 +189,14 @@ describe("DaemonDecider tests", () => { daemonDecider.init(); daemonDecider.runOrUseDaemon(); - expect(existsSyncSpy).toHaveBeenCalledTimes(1); - expect(unlinkSyncSpy).toHaveBeenCalledTimes(1); + + try { + expect(existsSyncSpy).toHaveBeenCalledTimes(1); + expect(unlinkSyncSpy).toHaveBeenCalledTimes(1); + } finally { + existsSyncSpy.mockReset(); + unlinkSyncSpy.mockReset(); + } }); (process.platform === "win32" ? it : it.skip)("should use the default socket location (win32)", () => { From f47c0de513340ce4626fce02ffad58c2ef1dc09d Mon Sep 17 00:00:00 2001 From: "Andrew W. Harn" Date: Tue, 8 Feb 2022 17:46:52 -0500 Subject: [PATCH 20/29] Just mock the return value instead of implementation Signed-off-by: Andrew W. Harn --- .../daemon/__unit__/DaemonDecider.unit.test.ts | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/packages/cli/__tests__/daemon/__unit__/DaemonDecider.unit.test.ts b/packages/cli/__tests__/daemon/__unit__/DaemonDecider.unit.test.ts index bcb4931da7..59c6d21a80 100644 --- a/packages/cli/__tests__/daemon/__unit__/DaemonDecider.unit.test.ts +++ b/packages/cli/__tests__/daemon/__unit__/DaemonDecider.unit.test.ts @@ -182,21 +182,16 @@ describe("DaemonDecider tests", () => { process.env.ZOWE_DAEMON = testSocket; const existsSyncSpy = jest.spyOn(fs, "existsSync"); - existsSyncSpy.mockImplementation(() => true); + existsSyncSpy.mockReturnValueOnce(true); const unlinkSyncSpy = jest.spyOn(fs, "unlinkSync"); - unlinkSyncSpy.mockImplementation(() => true); + unlinkSyncSpy.mockReturnValueOnce(true); daemonDecider.init(); daemonDecider.runOrUseDaemon(); - try { - expect(existsSyncSpy).toHaveBeenCalledTimes(1); - expect(unlinkSyncSpy).toHaveBeenCalledTimes(1); - } finally { - existsSyncSpy.mockReset(); - unlinkSyncSpy.mockReset(); - } + expect(existsSyncSpy).toHaveBeenCalledTimes(1); + expect(unlinkSyncSpy).toHaveBeenCalledTimes(1); }); (process.platform === "win32" ? it : it.skip)("should use the default socket location (win32)", () => { From 539f7c07d45c2bd1079590099320b76a28c6cde5 Mon Sep 17 00:00:00 2001 From: "Andrew W. Harn" Date: Wed, 9 Feb 2022 09:37:13 -0500 Subject: [PATCH 21/29] Remove statement causing CI warning Signed-off-by: Andrew W. Harn --- .../cli/__tests__/daemon/__unit__/DaemonDecider.unit.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/cli/__tests__/daemon/__unit__/DaemonDecider.unit.test.ts b/packages/cli/__tests__/daemon/__unit__/DaemonDecider.unit.test.ts index 59c6d21a80..b5c70afcae 100644 --- a/packages/cli/__tests__/daemon/__unit__/DaemonDecider.unit.test.ts +++ b/packages/cli/__tests__/daemon/__unit__/DaemonDecider.unit.test.ts @@ -23,7 +23,6 @@ jest.mock("../../../src/daemon//DaemonClient"); describe("DaemonDecider tests", () => { afterEach(() => { delete process.env.ZOWE_DAEMON; - jest.resetAllMocks }); it("should call normal parse method if no daemon keyword", () => { From cfbcc5d355953c13a288a565a708502730d0882d Mon Sep 17 00:00:00 2001 From: "Andrew W. Harn" Date: Wed, 9 Feb 2022 10:22:54 -0500 Subject: [PATCH 22/29] Use NPM ~8.3.2 because of Win CI error with ^8.4.0 Signed-off-by: Andrew W. Harn --- .github/workflows/zowe-cli.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/zowe-cli.yml b/.github/workflows/zowe-cli.yml index c549d8ba53..a2e11b8f5a 100644 --- a/.github/workflows/zowe-cli.yml +++ b/.github/workflows/zowe-cli.yml @@ -61,7 +61,7 @@ jobs: - name: Use NPM v8 id: npm8 - run: npm install -g npm@^8 + run: npm install -g npm@~8.3.2 - name: Install Node Package Dependencies id: install From eca24aebdfe39aa9460eaa4bafd0484551d1d2cf Mon Sep 17 00:00:00 2001 From: "Andrew W. Harn" Date: Wed, 9 Feb 2022 16:20:06 -0500 Subject: [PATCH 23/29] Make requested changes Signed-off-by: Andrew W. Harn --- .../__unit__/DaemonDecider.unit.test.ts | 276 +++++++++--------- packages/cli/src/daemon/DaemonDecider.ts | 2 +- 2 files changed, 141 insertions(+), 137 deletions(-) diff --git a/packages/cli/__tests__/daemon/__unit__/DaemonDecider.unit.test.ts b/packages/cli/__tests__/daemon/__unit__/DaemonDecider.unit.test.ts index b5c70afcae..55604b7909 100644 --- a/packages/cli/__tests__/daemon/__unit__/DaemonDecider.unit.test.ts +++ b/packages/cli/__tests__/daemon/__unit__/DaemonDecider.unit.test.ts @@ -139,61 +139,7 @@ describe("DaemonDecider tests", () => { }); - (process.platform !== "win32" ? it : it.skip)("should try to delete an existing socket on *nix", () => { - const log = jest.fn(() => { - // do nothing - }); - - const on = jest.fn((event, func) => { - // do nothing - }); - - const listen = jest.fn((event, func) => { - // do nothing - }); - - const parse = jest.fn( (data, context) => { - expect(data).toBe(undefined); - expect(context).toBe(undefined); - }); - - (Imperative as any) = { - api: { - appLogger: { - trace: log, - debug: log, - error: log - } - }, - console: { - info: log - }, - parse - }; - - const fn = net.createServer as Mock; - fn.mockImplementation((unusedclient, ...args: any[]) => { - return {on, listen}; - }); - - const daemonDecider = new DaemonDecider(["node", "zowe", "--daemon"]); - const testSocket = "/fake/pipe/path"; - process.env.ZOWE_DAEMON = testSocket; - - const existsSyncSpy = jest.spyOn(fs, "existsSync"); - existsSyncSpy.mockReturnValueOnce(true); - - const unlinkSyncSpy = jest.spyOn(fs, "unlinkSync"); - unlinkSyncSpy.mockReturnValueOnce(true); - - daemonDecider.init(); - daemonDecider.runOrUseDaemon(); - - expect(existsSyncSpy).toHaveBeenCalledTimes(1); - expect(unlinkSyncSpy).toHaveBeenCalledTimes(1); - }); - - (process.platform === "win32" ? it : it.skip)("should use the default socket location (win32)", () => { + it("should not start a daemon", () => { const log = jest.fn(() => { // do nothing }); @@ -230,96 +176,154 @@ describe("DaemonDecider tests", () => { return {on, listen}; }); - const daemonDecider = new DaemonDecider(["node", "zowe", "--daemon"]); + const daemonDecider = new DaemonDecider(["node", "zowe", "--help"]); daemonDecider.init(); - expect((daemonDecider as any).mSocket).toEqual(`\\\\.\\pipe\\${os.userInfo().username}\\ZoweDaemon`); + expect((daemonDecider as any).mSocket).toBeUndefined(); + expect((daemonDecider as any).startServer).toBeUndefined(); }); - (process.platform !== "win32" ? it : it.skip)("should use the default socket location (not win32)", () => { - const log = jest.fn(() => { - // do nothing - }); - - const on = jest.fn((event, func) => { - // do nothing - }); - - const listen = jest.fn((event, func) => { - // do nothing - }); - - const parse = jest.fn( (data, context) => { - expect(data).toBe(undefined); - expect(context).toBe(undefined); + (process.platform === "win32" ? describe : describe.skip)("win32 tests", () => { + it("should try to delete an existing socket on *nix", () => { + const log = jest.fn(() => { + // do nothing + }); + + const on = jest.fn((event, func) => { + // do nothing + }); + + const listen = jest.fn((event, func) => { + // do nothing + }); + + const parse = jest.fn( (data, context) => { + expect(data).toBe(undefined); + expect(context).toBe(undefined); + }); + + (Imperative as any) = { + api: { + appLogger: { + trace: log, + debug: log, + error: log + } + }, + console: { + info: log + }, + parse + }; + + const fn = net.createServer as Mock; + fn.mockImplementation((unusedclient, ...args: any[]) => { + return {on, listen}; + }); + + const daemonDecider = new DaemonDecider(["node", "zowe", "--daemon"]); + const testSocket = "/fake/pipe/path"; + process.env.ZOWE_DAEMON = testSocket; + + const existsSyncSpy = jest.spyOn(fs, "existsSync"); + existsSyncSpy.mockReturnValueOnce(true); + + const unlinkSyncSpy = jest.spyOn(fs, "unlinkSync"); + unlinkSyncSpy.mockReturnValueOnce(true); + + daemonDecider.init(); + daemonDecider.runOrUseDaemon(); + + expect(existsSyncSpy).toHaveBeenCalledTimes(1); + expect(unlinkSyncSpy).toHaveBeenCalledTimes(1); }); - (Imperative as any) = { - api: { - appLogger: { - trace: log, - debug: log, - error: log - } - }, - console: { - info: log - }, - parse - }; - - const fn = net.createServer as Mock; - fn.mockImplementation((unusedclient, ...args: any[]) => { - return {on, listen}; + it("should use the default socket location (win32)", () => { + const log = jest.fn(() => { + // do nothing + }); + + const on = jest.fn((event, func) => { + // do nothing + }); + + const listen = jest.fn((event, func) => { + // do nothing + }); + + const parse = jest.fn( (data, context) => { + expect(data).toBe(undefined); + expect(context).toBe(undefined); + }); + + (Imperative as any) = { + api: { + appLogger: { + trace: log, + debug: log, + error: log + } + }, + console: { + info: log + }, + parse + }; + + const fn = net.createServer as Mock; + fn.mockImplementation((unusedclient, ...args: any[]) => { + return {on, listen}; + }); + + const daemonDecider = new DaemonDecider(["node", "zowe", "--daemon"]); + daemonDecider.init(); + + expect((daemonDecider as any).mSocket).toEqual(`\\\\.\\pipe\\${os.userInfo().username}\\ZoweDaemon`); }); - - const daemonDecider = new DaemonDecider(["node", "zowe", "--daemon"]); - daemonDecider.init(); - - expect((daemonDecider as any).mSocket).toEqual(path.join(os.homedir(), ".zowe-daemon.sock")); }); - it("should not start a daemon", () => { - const log = jest.fn(() => { - // do nothing - }); - - const on = jest.fn((event, func) => { - // do nothing + (process.platform !== "win32" ? describe : describe.skip)("non-win32 tests", () => { + it("should use the default socket location (not win32)", () => { + const log = jest.fn(() => { + // do nothing + }); + + const on = jest.fn((event, func) => { + // do nothing + }); + + const listen = jest.fn((event, func) => { + // do nothing + }); + + const parse = jest.fn( (data, context) => { + expect(data).toBe(undefined); + expect(context).toBe(undefined); + }); + + (Imperative as any) = { + api: { + appLogger: { + trace: log, + debug: log, + error: log + } + }, + console: { + info: log + }, + parse + }; + + const fn = net.createServer as Mock; + fn.mockImplementation((unusedclient, ...args: any[]) => { + return {on, listen}; + }); + + const daemonDecider = new DaemonDecider(["node", "zowe", "--daemon"]); + daemonDecider.init(); + + expect((daemonDecider as any).mSocket).toEqual(path.join(os.homedir(), ".zowe-daemon.sock")); }); - - const listen = jest.fn((event, func) => { - // do nothing - }); - - const parse = jest.fn( (data, context) => { - expect(data).toBe(undefined); - expect(context).toBe(undefined); - }); - - (Imperative as any) = { - api: { - appLogger: { - trace: log, - debug: log, - error: log - } - }, - console: { - info: log - }, - parse - }; - - const fn = net.createServer as Mock; - fn.mockImplementation((unusedclient, ...args: any[]) => { - return {on, listen}; - }); - - const daemonDecider = new DaemonDecider(["node", "zowe", "--help"]); - daemonDecider.init(); - - expect((daemonDecider as any).mSocket).toBeUndefined(); - expect((daemonDecider as any).startServer).toBeUndefined(); }); }); diff --git a/packages/cli/src/daemon/DaemonDecider.ts b/packages/cli/src/daemon/DaemonDecider.ts index e5e5bd3ae4..3438818e4b 100644 --- a/packages/cli/src/daemon/DaemonDecider.ts +++ b/packages/cli/src/daemon/DaemonDecider.ts @@ -168,7 +168,7 @@ export class DaemonDecider { this.mSocket = `\\\\.\\pipe\\${os.userInfo().username}\\ZoweDaemon`; } - Imperative.api.appLogger.debug(`daemon server socket ${this.mSocket}`); + Imperative.api.appLogger.debug(`daemon server will listen on ${this.mSocket}`); } } } From 60de50dd1b99218ac045e5ef06d8e7c9d6460602 Mon Sep 17 00:00:00 2001 From: "Andrew W. Harn" Date: Wed, 9 Feb 2022 16:31:30 -0500 Subject: [PATCH 24/29] Put test under right describe Signed-off-by: Andrew W. Harn --- .../__unit__/DaemonDecider.unit.test.ts | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/packages/cli/__tests__/daemon/__unit__/DaemonDecider.unit.test.ts b/packages/cli/__tests__/daemon/__unit__/DaemonDecider.unit.test.ts index 55604b7909..17c08a1686 100644 --- a/packages/cli/__tests__/daemon/__unit__/DaemonDecider.unit.test.ts +++ b/packages/cli/__tests__/daemon/__unit__/DaemonDecider.unit.test.ts @@ -184,7 +184,7 @@ describe("DaemonDecider tests", () => { }); (process.platform === "win32" ? describe : describe.skip)("win32 tests", () => { - it("should try to delete an existing socket on *nix", () => { + it("should use the default socket location (win32)", () => { const log = jest.fn(() => { // do nothing }); @@ -222,23 +222,14 @@ describe("DaemonDecider tests", () => { }); const daemonDecider = new DaemonDecider(["node", "zowe", "--daemon"]); - const testSocket = "/fake/pipe/path"; - process.env.ZOWE_DAEMON = testSocket; - - const existsSyncSpy = jest.spyOn(fs, "existsSync"); - existsSyncSpy.mockReturnValueOnce(true); - - const unlinkSyncSpy = jest.spyOn(fs, "unlinkSync"); - unlinkSyncSpy.mockReturnValueOnce(true); - daemonDecider.init(); - daemonDecider.runOrUseDaemon(); - expect(existsSyncSpy).toHaveBeenCalledTimes(1); - expect(unlinkSyncSpy).toHaveBeenCalledTimes(1); + expect((daemonDecider as any).mSocket).toEqual(`\\\\.\\pipe\\${os.userInfo().username}\\ZoweDaemon`); }); + }); - it("should use the default socket location (win32)", () => { + (process.platform !== "win32" ? describe : describe.skip)("non-win32 tests", () => { + it("should use the default socket location (not win32)", () => { const log = jest.fn(() => { // do nothing }); @@ -278,12 +269,10 @@ describe("DaemonDecider tests", () => { const daemonDecider = new DaemonDecider(["node", "zowe", "--daemon"]); daemonDecider.init(); - expect((daemonDecider as any).mSocket).toEqual(`\\\\.\\pipe\\${os.userInfo().username}\\ZoweDaemon`); + expect((daemonDecider as any).mSocket).toEqual(path.join(os.homedir(), ".zowe-daemon.sock")); }); - }); - (process.platform !== "win32" ? describe : describe.skip)("non-win32 tests", () => { - it("should use the default socket location (not win32)", () => { + it("should try to delete an existing socket on *nix", () => { const log = jest.fn(() => { // do nothing }); @@ -321,9 +310,20 @@ describe("DaemonDecider tests", () => { }); const daemonDecider = new DaemonDecider(["node", "zowe", "--daemon"]); + const testSocket = "/fake/pipe/path"; + process.env.ZOWE_DAEMON = testSocket; + + const existsSyncSpy = jest.spyOn(fs, "existsSync"); + existsSyncSpy.mockReturnValueOnce(true); + + const unlinkSyncSpy = jest.spyOn(fs, "unlinkSync"); + unlinkSyncSpy.mockReturnValueOnce(true); + daemonDecider.init(); + daemonDecider.runOrUseDaemon(); - expect((daemonDecider as any).mSocket).toEqual(path.join(os.homedir(), ".zowe-daemon.sock")); + expect(existsSyncSpy).toHaveBeenCalledTimes(1); + expect(unlinkSyncSpy).toHaveBeenCalledTimes(1); }); }); }); From 25b8e7eaf8885cfb324814be61a940160ca62335 Mon Sep 17 00:00:00 2001 From: "Andrew W. Harn" Date: Fri, 11 Feb 2022 16:43:18 -0500 Subject: [PATCH 25/29] Fix *nix bug, limit concurrency to 1, fix pipeline Signed-off-by: Andrew W. Harn --- .github/workflows/zowe-cli.yml | 11 +- packages/cli/src/daemon/DaemonDecider.ts | 1 + zowex/src/main.rs | 200 +++++++++++++---------- 3 files changed, 124 insertions(+), 88 deletions(-) diff --git a/.github/workflows/zowe-cli.yml b/.github/workflows/zowe-cli.yml index a2e11b8f5a..ac7e2a613b 100644 --- a/.github/workflows/zowe-cli.yml +++ b/.github/workflows/zowe-cli.yml @@ -129,11 +129,16 @@ jobs: env: PATH: ${{ github.workspace }}\__tests__\__resources__\application_instances;${{ env.PATH }} - - name: Integration Tests - id: integration - if: ${{ always() && steps.build.outcome == 'success' }} + - name: Integration Tests (Native) + id: integration-native + if: ${{ always() && steps.build.outcome == 'success' && !(github.event.inputs.test-type == 'binary' || github.event_name == 'push') }} run: npm run test:integration >> integration-tests.txt + - name: Integration Tests (Daemon) + id: integration-daemon + if: ${{ always() && steps.build.outcome == 'success' && (github.event.inputs.test-type == 'binary' || github.event_name == 'push') }} + run: npm run test:integration -- --runInBand >> integration-tests.txt + - name: Archive Results id: upload if: ${{ always() && steps.build.outcome == 'success' }} diff --git a/packages/cli/src/daemon/DaemonDecider.ts b/packages/cli/src/daemon/DaemonDecider.ts index 3438818e4b..d191a1d463 100644 --- a/packages/cli/src/daemon/DaemonDecider.ts +++ b/packages/cli/src/daemon/DaemonDecider.ts @@ -108,6 +108,7 @@ export class DaemonDecider { process.on(eventType, this.close.bind(this, true)); }); + this.mServer.maxConnections = 1; this.mServer.listen(this.mSocket, () => { Imperative.api.appLogger.debug(`daemon server bound ${this.mSocket}`); Imperative.console.info(`server bound ${this.mSocket}`); diff --git a/zowex/src/main.rs b/zowex/src/main.rs index 49cf905e67..65477312a2 100644 --- a/zowex/src/main.rs +++ b/zowex/src/main.rs @@ -57,10 +57,11 @@ const EXIT_CODE_CANNOT_CONNECT_TO_RUNNING_DAEMON: i32 = 100; const EXIT_CODE_CANNOT_GET_MY_PATH: i32 = 101; const EXIT_CODE_NO_NODEJS_ZOWE_ON_PATH: i32 = 102; const EXIT_CODE_CANNOT_START_DAEMON: i32 = 103; -const EXIT_CODE_DAEMON_NOT_RUNNING_AFTER_START: i32 = 104; -const EXIT_CODE_DAEMON_FAILED_TO_RUN_CMD: i32 = 105; -const EXIT_CODE_FAILED_TO_RUN_NODEJS_CMD: i32 = 106; -const EXIT_CODE_CANT_RUN_DAEMON_CMD: i32 = 107; +const EXIT_CODE_TIMEOUT_CONNECT_TO_RUNNING_DAEMON: i32 = 104; +const EXIT_CODE_DAEMON_NOT_RUNNING_AFTER_START: i32 = 105; +const EXIT_CODE_DAEMON_FAILED_TO_RUN_CMD: i32 = 106; +const EXIT_CODE_FAILED_TO_RUN_NODEJS_CMD: i32 = 107; +const EXIT_CODE_CANT_RUN_DAEMON_CMD: i32 = 108; struct DaemonProcInfo { is_running: bool, @@ -91,6 +92,9 @@ struct DaemonResponse { user: Option, } +const THREE_SEC_DELAY: u64 = 3; +const THREE_MIN_OF_RETRIES: i32 = 60; + // TODO(Kelosky): performance tests, `time for i in {1..10}; do zowe -h >/dev/null; done` // 0.8225 zowex vs 1.6961 zowe average over 10 run sample = .8736 sec faster on linux @@ -286,9 +290,27 @@ fn run_daemon_command(args: &mut Vec) -> io::Result<()> { _resp.append(&mut stdin); } - let socket_string = get_socket_string(); - let mut stream = establish_connection(socket_string)?; - talk(&_resp, &mut stream) + let mut tries = 0; + loop { + let socket_string = get_socket_string(); + let mut stream = establish_connection(socket_string)?; + match talk(&_resp, &mut stream) { + Ok(result) => { return Ok(result); }, + Err(ref e) if e.kind() == io::ErrorKind::ConnectionReset => { + if tries > THREE_MIN_OF_RETRIES { + println!("Terminating after {} connection retries.", THREE_MIN_OF_RETRIES); + std::process::exit(EXIT_CODE_TIMEOUT_CONNECT_TO_RUNNING_DAEMON); + } + + println!("{} ({} of {})", "The Zowe daemon is in use, retrying", tries, THREE_MIN_OF_RETRIES); + + // pause between attempts to connect + thread::sleep(Duration::from_secs(THREE_SEC_DELAY)); + tries += 1; + }, + Err(e) => { return Err(e); } + } + } } #[cfg(target_family = "unix")] @@ -302,8 +324,6 @@ type DaemonClient = PipeClient; * Iterate to enable a slow system to start the daemon. */ fn establish_connection(daemon_socket: String) -> io::Result { - const THREE_SEC_DELAY: u64 = 3; - const THREE_MIN_OF_RETRIES: i32 = 60; const RETRY_TO_SHOW_DIAG: i32 = 5; let mut conn_retries = 0; @@ -396,86 +416,91 @@ fn talk(message: &[u8], stream: &mut DaemonClient) -> io::Result<()> { let payload: String; // read until form feed (\f) - if reader.read_until(0xC, &mut u_payload).unwrap() > 0 { - // remove form feed and convert to a string - u_payload.pop(); // remove the 0xC - payload = str::from_utf8(&u_payload).unwrap().to_string(); - - let p: DaemonRequest = match serde_json::from_str(&payload) { - Ok(p) => p, - Err(_e) => { - // TODO(Kelosky): handle this only if progress bar mode is active - if atty::is(Stream::Stderr) { - eprint!("{}", payload); - io::stderr().flush().unwrap(); - } - DaemonRequest { - stdout: None, - stderr: None, - exitCode: Some(0i32), - progress: None, - prompt: None, - securePrompt: None, + match reader.read_until(0xC, &mut u_payload) { + Ok(size) => { + if size > 0 { + // remove form feed and convert to a string + u_payload.pop(); // remove the 0xC + payload = str::from_utf8(&u_payload).unwrap().to_string(); + + let p: DaemonRequest = match serde_json::from_str(&payload) { + Ok(p) => p, + Err(_e) => { + // TODO(Kelosky): handle this only if progress bar mode is active + if atty::is(Stream::Stderr) { + eprint!("{}", payload); + io::stderr().flush().unwrap(); + } + DaemonRequest { + stdout: None, + stderr: None, + exitCode: Some(0i32), + progress: None, + prompt: None, + securePrompt: None, + } + } + }; + + if let Some(s) = p.stdout { + print!("{}", s); + io::stdout().flush().unwrap(); } - } - }; - if let Some(s) = p.stdout { - print!("{}", s); - io::stdout().flush().unwrap(); - } - - if let Some(s) = p.stderr { - eprint!("{}", s); - io::stderr().flush().unwrap(); - } + if let Some(s) = p.stderr { + eprint!("{}", s); + io::stderr().flush().unwrap(); + } - if let Some(s) = p.prompt { - print!("{}", s); - io::stdout().flush().unwrap(); - let mut reply = String::new(); - io::stdin().read_line(&mut reply).unwrap(); - let response: DaemonResponse = DaemonResponse { - argv: None, - cwd: None, - env: None, - stdinLength: None, - stdin: Some(reply), - user: Some(encode(username())), - }; - let v = serde_json::to_string(&response)?; - #[cfg(target_family = "unix")] - writer.write_all(v.as_bytes()).unwrap(); - #[cfg(target_family = "windows")] - reader.get_mut().write_all(v.as_bytes()).unwrap(); - } + if let Some(s) = p.prompt { + print!("{}", s); + io::stdout().flush().unwrap(); + let mut reply = String::new(); + io::stdin().read_line(&mut reply).unwrap(); + let response: DaemonResponse = DaemonResponse { + argv: None, + cwd: None, + env: None, + stdinLength: None, + stdin: Some(reply), + user: Some(encode(username())), + }; + let v = serde_json::to_string(&response)?; + #[cfg(target_family = "unix")] + writer.write_all(v.as_bytes()).unwrap(); + #[cfg(target_family = "windows")] + reader.get_mut().write_all(v.as_bytes()).unwrap(); + } - if let Some(s) = p.securePrompt { - print!("{}", s); - io::stdout().flush().unwrap(); - let reply; - reply = read_password().unwrap(); - let response: DaemonResponse = DaemonResponse { - argv: None, - cwd: None, - env: None, - stdinLength: None, - stdin: Some(reply), - user: Some(encode(username())), - }; - let v = serde_json::to_string(&response)?; - #[cfg(target_family = "unix")] - writer.write_all(v.as_bytes()).unwrap(); - #[cfg(target_family = "windows")] - reader.get_mut().write_all(v.as_bytes()).unwrap(); - } + if let Some(s) = p.securePrompt { + print!("{}", s); + io::stdout().flush().unwrap(); + let reply; + reply = read_password().unwrap(); + let response: DaemonResponse = DaemonResponse { + argv: None, + cwd: None, + env: None, + stdinLength: None, + stdin: Some(reply), + user: Some(encode(username())), + }; + let v = serde_json::to_string(&response)?; + #[cfg(target_family = "unix")] + writer.write_all(v.as_bytes()).unwrap(); + #[cfg(target_family = "windows")] + reader.get_mut().write_all(v.as_bytes()).unwrap(); + } - exit_code = p.exitCode.unwrap_or(0); + exit_code = p.exitCode.unwrap_or(0); - _progress = p.progress.unwrap_or(false); - } else { - // end of reading - break; + _progress = p.progress.unwrap_or(false); + } else { + // end of reading + break; + } + }, + Err(e) => { return Err(e); } } } @@ -580,11 +605,16 @@ fn is_daemon_running() -> DaemonProcInfo { let mut sys = System::new_all(); sys.refresh_all(); for (pid, process) in sys.processes() { - if process.name().to_lowercase().contains("node") && + if (process.name().to_lowercase().contains("node") && process.cmd().len() > 2 && process.cmd()[1].to_lowercase().contains("@zowe") && process.cmd()[1].to_lowercase().contains("cli") && - process.cmd()[2].to_lowercase() == "--daemon" + process.cmd()[2].to_lowercase() == "--daemon") || + (process.name().to_lowercase().contains("node") && + process.cmd().len() > 2 && + process.cmd()[1].to_lowercase().contains("bin") && + process.cmd()[1].to_lowercase().contains("zowe") && + process.cmd()[2].to_lowercase() == "--daemon") { // convert the process command from a vector to a string let mut proc_cmd: String = String::new(); From 905267a0834cba3ff8f724195397dd0066016942 Mon Sep 17 00:00:00 2001 From: "Andrew W. Harn" Date: Fri, 11 Feb 2022 16:54:25 -0500 Subject: [PATCH 26/29] Fix error due to response code bump Signed-off-by: Andrew W. Harn --- .../daemon/__integration__/cli.zowe.exe.integration.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/__tests__/daemon/__integration__/cli.zowe.exe.integration.test.ts b/packages/cli/__tests__/daemon/__integration__/cli.zowe.exe.integration.test.ts index 314a679bf3..9a77ec253b 100644 --- a/packages/cli/__tests__/daemon/__integration__/cli.zowe.exe.integration.test.ts +++ b/packages/cli/__tests__/daemon/__integration__/cli.zowe.exe.integration.test.ts @@ -22,7 +22,7 @@ let testEnvironment: ITestEnvironment; describe("Zowe native executable", () => { const exeCantRunDaemonMsg1: string = "You cannot run this 'daemon' command while using the Zowe CLI native executable."; const exeCantRunDaemonMsg2: string = "Copy and paste the following command instead:"; - const EXIT_CODE_CANT_RUN_DAEMON_CMD: number = 107; + const EXIT_CODE_CANT_RUN_DAEMON_CMD: number = 108; let zoweExePath: string; let willRunZoweExe: boolean = true; From 4ef3962c4e4eac2960df2a7369ba07e26df03129 Mon Sep 17 00:00:00 2001 From: "Andrew W. Harn" Date: Tue, 15 Feb 2022 14:24:57 -0500 Subject: [PATCH 27/29] Make requested changes Signed-off-by: Andrew W. Harn --- zowex/src/main.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/zowex/src/main.rs b/zowex/src/main.rs index 65477312a2..e82abefa91 100644 --- a/zowex/src/main.rs +++ b/zowex/src/main.rs @@ -291,24 +291,23 @@ fn run_daemon_command(args: &mut Vec) -> io::Result<()> { } let mut tries = 0; + let socket_string = get_socket_string(); loop { - let socket_string = get_socket_string(); - let mut stream = establish_connection(socket_string)?; + let mut stream = establish_connection(&socket_string)?; match talk(&_resp, &mut stream) { - Ok(result) => { return Ok(result); }, Err(ref e) if e.kind() == io::ErrorKind::ConnectionReset => { if tries > THREE_MIN_OF_RETRIES { println!("Terminating after {} connection retries.", THREE_MIN_OF_RETRIES); std::process::exit(EXIT_CODE_TIMEOUT_CONNECT_TO_RUNNING_DAEMON); } - println!("{} ({} of {})", "The Zowe daemon is in use, retrying", tries, THREE_MIN_OF_RETRIES); + println!("The Zowe daemon is in use, retrying ({} of {})", tries, THREE_MIN_OF_RETRIES); // pause between attempts to connect thread::sleep(Duration::from_secs(THREE_SEC_DELAY)); tries += 1; }, - Err(e) => { return Err(e); } + result => { return result; } } } } @@ -323,7 +322,7 @@ type DaemonClient = PipeClient; * Attempt to make a TCP connection to the daemon. * Iterate to enable a slow system to start the daemon. */ -fn establish_connection(daemon_socket: String) -> io::Result { +fn establish_connection(daemon_socket: &str) -> io::Result { const RETRY_TO_SHOW_DIAG: i32 = 5; let mut conn_retries = 0; From f0aaad352a40b66c986852326b65d93ea36ac7d2 Mon Sep 17 00:00:00 2001 From: "Andrew W. Harn" Date: Thu, 17 Feb 2022 11:57:28 -0500 Subject: [PATCH 28/29] Update daemon version. Signed-off-by: Andrew W. Harn --- zowex/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zowex/Cargo.toml b/zowex/Cargo.toml index 9279ec09ef..fe6deabd5d 100644 --- a/zowex/Cargo.toml +++ b/zowex/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "zowe" -version = "0.6.2" +version = "0.7.0" authors = ["Zowe Project"] edition = "2018" license = "EPL-2.0" From 13f62509442e93ab65a485e214fcea6544ff4139 Mon Sep 17 00:00:00 2001 From: "Andrew W. Harn" Date: Thu, 17 Feb 2022 12:08:30 -0500 Subject: [PATCH 29/29] Update cargo lock Signed-off-by: Andrew W. Harn --- zowex/Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zowex/Cargo.lock b/zowex/Cargo.lock index df42159075..487ba2615d 100644 --- a/zowex/Cargo.lock +++ b/zowex/Cargo.lock @@ -432,7 +432,7 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "zowe" -version = "0.6.2" +version = "0.7.0" dependencies = [ "atty", "base64",