From b4ea5d31d6e9600539f57788bf2b0e1863b8f845 Mon Sep 17 00:00:00 2001 From: Matt Primrose <47540908+matt-primrose@users.noreply.github.com> Date: Tue, 10 Sep 2024 16:22:58 -0700 Subject: [PATCH] feat: adds centralized wsman error struct and decode for boot and kvm (#401) --- pkg/wsman/amt/boot/decoder_test.go | 4 +- pkg/wsman/amt/boot/settingdata.go | 12 ++++- pkg/wsman/cim/kvm/decoder_test.go | 4 +- pkg/wsman/cim/kvm/redirectionsap.go | 10 ++++ pkg/wsman/common/constants.go | 24 ++++++++++ pkg/wsman/common/constants_test.go | 73 +++++++++++++++++++++++++++++ pkg/wsman/common/types.go | 43 +++++++++++++++++ 7 files changed, 167 insertions(+), 3 deletions(-) create mode 100644 pkg/wsman/common/constants_test.go diff --git a/pkg/wsman/amt/boot/decoder_test.go b/pkg/wsman/amt/boot/decoder_test.go index 63f3333f..d747568b 100644 --- a/pkg/wsman/amt/boot/decoder_test.go +++ b/pkg/wsman/amt/boot/decoder_test.go @@ -5,7 +5,9 @@ package boot -import "testing" +import ( + "testing" +) func TestFirmwareVerbosity_String(t *testing.T) { tests := []struct { diff --git a/pkg/wsman/amt/boot/settingdata.go b/pkg/wsman/amt/boot/settingdata.go index 333e7569..a3a143d2 100644 --- a/pkg/wsman/amt/boot/settingdata.go +++ b/pkg/wsman/amt/boot/settingdata.go @@ -11,6 +11,7 @@ import ( "github.com/open-amt-cloud-toolkit/go-wsman-messages/v2/internal/message" "github.com/open-amt-cloud-toolkit/go-wsman-messages/v2/pkg/wsman/client" + "github.com/open-amt-cloud-toolkit/go-wsman-messages/v2/pkg/wsman/common" ) // Instantiates a new Boot Setting Data service. @@ -147,5 +148,14 @@ func (settingData SettingData) Put(bootSettingData BootSettingDataRequest) (resp return response, err } - return response, nil + checkForErrorResponse := common.ErrorResponse{} + + err = xml.Unmarshal([]byte(response.XMLOutput), &checkForErrorResponse) + if err != nil { + return response, err + } + + err = common.DecodeAMTError(checkForErrorResponse) + + return response, err } diff --git a/pkg/wsman/cim/kvm/decoder_test.go b/pkg/wsman/cim/kvm/decoder_test.go index b5c7b1be..8a2c604b 100644 --- a/pkg/wsman/cim/kvm/decoder_test.go +++ b/pkg/wsman/cim/kvm/decoder_test.go @@ -5,7 +5,9 @@ package kvm -import "testing" +import ( + "testing" +) func TestKVMProtocol_String(t *testing.T) { tests := []struct { diff --git a/pkg/wsman/cim/kvm/redirectionsap.go b/pkg/wsman/cim/kvm/redirectionsap.go index c5854087..6f066446 100644 --- a/pkg/wsman/cim/kvm/redirectionsap.go +++ b/pkg/wsman/cim/kvm/redirectionsap.go @@ -12,6 +12,7 @@ import ( "github.com/open-amt-cloud-toolkit/go-wsman-messages/v2/internal/message" "github.com/open-amt-cloud-toolkit/go-wsman-messages/v2/pkg/wsman/cim/methods" "github.com/open-amt-cloud-toolkit/go-wsman-messages/v2/pkg/wsman/client" + "github.com/open-amt-cloud-toolkit/go-wsman-messages/v2/pkg/wsman/common" ) // NewKVMRedirectionSAP returns a new instance of the KVMRedirectionSAP struct. @@ -102,5 +103,14 @@ func (redirectionSAP RedirectionSAP) Pull(enumerationContext string) (response R return } + checkForErrorResponse := common.ErrorResponse{} + + err = xml.Unmarshal([]byte(response.XMLOutput), &checkForErrorResponse) + if err != nil { + return + } + + err = common.DecodeAMTError(checkForErrorResponse) + return } diff --git a/pkg/wsman/common/constants.go b/pkg/wsman/common/constants.go index 3ca60443..ef421248 100644 --- a/pkg/wsman/common/constants.go +++ b/pkg/wsman/common/constants.go @@ -5,6 +5,10 @@ package common +import ( + "fmt" +) + // TODO: Review if this file is still necessary. const ValueNotFound string = "Value not found in map" @@ -231,3 +235,23 @@ func ConvertPackageTypeToString(value int) string { return ValueNotFound } + +func (e *AMTError) Error() string { + return fmt.Sprintf("Error [SubCode: %s] Message: %s, Detail: %s", e.SubCode, e.Message, e.Detail) +} + +func NewAMTError(subCode, message, detail string) *AMTError { + return &AMTError{ + SubCode: subCode, + Message: message, + Detail: detail, + } +} + +func DecodeAMTError(er ErrorResponse) error { + if er.Body.Fault.Code.SubCode.Value != "" { + return NewAMTError(er.Body.Fault.Code.SubCode.Value, er.Body.Fault.Reason.Text, er.Body.Fault.Detail) + } + + return nil +} diff --git a/pkg/wsman/common/constants_test.go b/pkg/wsman/common/constants_test.go new file mode 100644 index 00000000..d5aaa977 --- /dev/null +++ b/pkg/wsman/common/constants_test.go @@ -0,0 +1,73 @@ +/********************************************************************* + * Copyright (c) Intel Corporation 2024 + * SPDX-License-Identifier: Apache-2.0 + **********************************************************************/ + +package common + +import ( + "testing" +) + +func TestDecodeWSMANError(t *testing.T) { + tests := []struct { + input ErrorResponse + expected error + }{ + { + ErrorResponse{ + Body: ErrorBody{ + Fault: Fault{ + Code: Code{ + SubCode: SubCode{ + Value: "b:AccessDenied", + }, + }, + Reason: Reason{ + Text: "The sender was not authorized to access the resource.", + }, + Detail: "", + }, + }, + }, + &AMTError{ + SubCode: "b:AccessDenied", Message: "The sender was not authorized to access the resource.", Detail: "", + }, + }, { + ErrorResponse{ + Body: ErrorBody{ + Fault: Fault{ + Code: Code{ + SubCode: SubCode{ + Value: "e:DestinationUnreachable", + }, + }, + Reason: Reason{ + Text: "No route can be determined to reach the destination role defined by the WSAddressing To.", + }, + Detail: "", + }, + }, + }, + &AMTError{ + SubCode: "e:DestinationUnreachable", Message: "No route can be determined to reach the destination role defined by the WSAddressing To.", Detail: "", + }, + }, { + ErrorResponse{}, + nil, + }, + } + + for _, test := range tests { + result := DecodeAMTError(test.input) + if result == nil { + if test.expected != nil { + t.Errorf("Expected %s, but got nil", test.expected) + } + } else { + if result.Error() != test.expected.Error() { + t.Errorf("Expected %s, but got %s", test.expected, result) + } + } + } +} diff --git a/pkg/wsman/common/types.go b/pkg/wsman/common/types.go index 16c4096d..d01e699e 100644 --- a/pkg/wsman/common/types.go +++ b/pkg/wsman/common/types.go @@ -30,3 +30,46 @@ type ReturnValue struct { ReturnValue int `xml:"ReturnValue,omitempty"` ReturnValueStr string `xml:"ReturnValueStr,omitempty"` } + +// AMT WSMAN Error Response Types. +type ( + AMTError struct { + SubCode string + Message string + Detail string + } + + ErrorResponse struct { + XMLName xml.Name `xml:"Envelope"` + Header message.Header `xml:"Header"` + Body ErrorBody `xml:"Body"` + } + + ErrorBody struct { + XMLName xml.Name `xml:"Body"` + Fault Fault `xml:"Fault"` + } + + Fault struct { + XMLName xml.Name `xml:"Fault"` + Code Code `xml:"Code"` + Reason Reason `xml:"Reason"` + Detail string `xml:"Detail"` + } + + Code struct { + XMLName xml.Name `xml:"Code"` + Value string `xml:"Value"` + SubCode SubCode `xml:"Subcode"` + } + + SubCode struct { + XMLName xml.Name `xml:"Subcode"` + Value string `xml:"Value"` + } + + Reason struct { + XMLName xml.Name `xml:"Reason"` + Text string `xml:"Text"` + } +)