diff --git a/command.go b/command.go index f7c3551..7aa2e5e 100644 --- a/command.go +++ b/command.go @@ -201,6 +201,11 @@ func (c *Command) ExitCode() int { return c.exitCode } +// Error returns command execution error if any +func (c *Command) Error() error { + return c.err +} + // Wait function will block the current goroutine until the remote command terminates. func (c *Command) Wait() { // block until finished diff --git a/fixture_test.go b/fixture_test.go index 058e7c9..122f151 100644 --- a/fixture_test.go +++ b/fixture_test.go @@ -49,6 +49,40 @@ var ( ` + createShellResponseWithError = ` + + http://schemas.dmtf.org/wbem/wsman/1/wsman/fault + uuid:0A888267-33ED-4F08-98E6-DDEBDE2067DE + http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous + uuid:1893210b-91a7-45dc-aa90-b0c42e0dd740 + + + + + s:Receiver + w:InternalError + + + Illegal operation attempted on a registry key that has been marked for deletion. + + + + + Illegal operation attempted on a registry key that has been marked for deletion. + + + + + + ` + executeCommandResponse = `http://schemas.microsoft.com/wbem/wsman/1/windows/shell/CommandResponseuuid:D9E108AA-E32B-45E3-8601-E9C70999D3BAhttp://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousuuid:F530804C-6D02-4FA9-AE78-1997750594BA1A6DEE6B-EC68-4DD6-87E9-030C0048ECC4` executeCommandResponseWithError = `http://schemas.dmtf.org/wbem/wsman/1/wsman/faultuuid:C85E435B-712E-45E8-AC64-C53F9FEE7164http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousuuid:23d79ab4-f145-4ac5-baa3-084d67265a24s:Receiverw:InternalErrorThe filename or extension is too long. The filename or extension is too long. ` diff --git a/response.go b/response.go index 792ead5..028cdcb 100644 --- a/response.go +++ b/response.go @@ -66,45 +66,48 @@ func xPath(node tree.Node, xpath string) (tree.NodeSet, error) { return nodes, nil } -// ParseOpenShellResponse ParseOpenShellResponse -func ParseOpenShellResponse(response string) (string, error) { - doc, err := xmltree.ParseXML(strings.NewReader(response)) - if err != nil { - return "", err - } - return first(doc, "//w:Selector[@Name='ShellId']") +func newExecuteCommandError(response string, format string, args ...interface{}) *ExecuteCommandError { + return &ExecuteCommandError{fmt.Errorf(format, args...), response} } -// ParseExecuteCommandResponse ParseExecuteCommandResponse -func ParseExecuteCommandResponse(response string) (commandId string, err error) { - defer func() { - if err != nil { - err = &ExecuteCommandError{Inner: err, Body: response} - } - }() - +func parseResponse(response, expectedAction, idXPath string) (string, error) { doc, err := xmltree.ParseXML(strings.NewReader(response)) if err != nil { - return "", fmt.Errorf("parsing xml response: %w", err) + return "", newExecuteCommandError(response, "parsing xml response: %w", err) } action, err := first(doc, "//a:Action") if err != nil { - return "", fmt.Errorf("getting response action: %w", err) + return "", newExecuteCommandError(response, "getting response action: %w", err) } - switch action { - case "http://schemas.microsoft.com/wbem/wsman/1/windows/shell/CommandResponse": - commandId, err = first(doc, "//rsp:CommandId") + if action == "http://schemas.dmtf.org/wbem/wsman/1/wsman/fault" { + return "", newExecuteCommandError(response, "received error response") + } + if action == expectedAction { + id, err := first(doc, idXPath) if err != nil { - return "", fmt.Errorf("finding command id: %w", err) + return "", newExecuteCommandError(response, "finding %v: %w", idXPath, err) } + return id, nil + } + return "", newExecuteCommandError(response, "unsupported action: %v", action) +} - return commandId, nil +func ParseOpenShellResponse(response string) (string, error) { + return parseResponse( + response, + "http://schemas.xmlsoap.org/ws/2004/09/transfer/CreateResponse", + "//rsp:ShellId", + ) +} - default: - return "", fmt.Errorf("unsupported action: %v", action) - } +func ParseExecuteCommandResponse(response string) (string, error) { + return parseResponse( + response, + "http://schemas.microsoft.com/wbem/wsman/1/windows/shell/CommandResponse", + "//rsp:CommandId", + ) } // ParseSlurpOutputErrResponse ParseSlurpOutputErrResponse diff --git a/response_test.go b/response_test.go index 8be28c5..ff3842e 100644 --- a/response_test.go +++ b/response_test.go @@ -17,6 +17,20 @@ func (s *WinRMSuite) TestOpenShellResponse(c *C) { c.Assert("67A74734-DD32-4F10-89DE-49A060483810", Equals, shellID) } +func (s *WinRMSuite) TestOpenShellResponseError(c *C) { + response := createShellResponseWithError + shellId, err := ParseOpenShellResponse(response) + if err == nil { + c.Fatal("expected error") + } + c.Assert(shellId, Equals, "") + + var execCmdRespErr *ExecuteCommandError + if !errors.As(err, &execCmdRespErr) { + c.Fatal("expected err to be of type ExecuteCommandError") + } +} + func (s *WinRMSuite) TestExecuteCommandResponse(c *C) { response := executeCommandResponse