I'm currently experiencing a problem that really frustrates me and where i absolutely can't see anny issues with my code.
What i'm trying to achieve is to send a http POST message to a mockup of an iDrac i wrote (both softwares written in golang) to control the mockup's powerstate, but no matter what i configure for the request, the mockup always receives get requests with an empty body.
The function i create and send the request with:
func (iDrac *IDrac) SetPowerstate(powerstate string) error {
//Create reset type json string
var jsonStr = `{"ResetType":"` powerstate `"}`
//Create the request with auth header
req, reqErr := iDrac.buildHttpRequestWithAuthorizationHeader(http.MethodPost, "https://" iDrac.hostAddress apiBaseURL apiChassisURL apiChassisResetAction, jsonStr)
if reqErr != nil {
return fmt.Errorf("COULD_NOT_CREATE_REQUEST: " reqErr.Error())
}
req.Header.Set("Content-Type", "application/json; charset=UTF-8")
//Make the request
resp, doErr := http.DefaultClient.Do(req)
if doErr != nil {
return fmt.Errorf("COULD_NOT_SEND_POST_REQUEST_TO_IDRAC_API" doErr.Error())
}
//Check if the request was successful
if resp.StatusCode != 200 {
return fmt.Errorf("COULD_NOT_CHANGE_SERVER_POWER_STATUS_OVER_IDRAC HTTP:" resp.Status)
}
return nil
}
The helper function i use to build the request with:
func (iDrac *IDrac) buildHttpRequestWithAuthorizationHeader(method string, url string, content string) (*http.Request, error) {
req, err := http.NewRequest(method, url, bytes.NewBuffer([]byte(content)))
if err != nil {
return nil, err
}
req.Header.Add("Authorization", "Basic " iDrac.hashedCredentials)
return req, nil
}
And finally the function where the mockup proccesses the request:
func handlePerformReset(w http.ResponseWriter, r *http.Request) {
garbagelog.Log("Handling reset perform request from " r.RemoteAddr)
if r.Method != http.MethodPost {
garbagelog.Log("Invalid http method! Got " r.Method " expected POST")
w.WriteHeader(405)
return
}
if !checkAuthorization(r.BasicAuth()) {
w.WriteHeader(401)
return
}
var resetType nidrac.ResetType
err := json.NewDecoder(r.Body).Decode(&resetType)
if err != nil {
garbagelog.Log("Could not decode reset type: " err.Error())
w.WriteHeader(422)
return
}
iDracMock.PerformResetAction(resetType.ResetType)
garbagelog.Log(">>>>SEVERSTATE: " iDracMock.PowerState().PowerState "<<<<")
w.WriteHeader(200)
}
The type the iDrac mock tries to convert the body to:
type ResetType struct {
ResetType string
}
It works flawlessly when i try to reach the endpoint with postman: iDrac mockup log confirming the successful request
Postnam request configuration: Postman request configuration
But it somehow does not work when i try making the request with go code: iDrac mockup log saying that the http method is invalid (because it's get instead of post)
I spent two hours trying to find a solution but i somehow did not find a post with someone having the same problem that i have.
Edit: Corrected old code. The problem remains even with the silly mistake fixed:
//Create the request with auth header
req, reqErr := iDrac.buildHttpRequestWithAuthorizationHeader(http.MethodPost, "https://" iDrac.hostAddress apiBaseURL apiChassisURL apiChassisResetAction, jsonStr)
if reqErr != nil {
return fmt.Errorf("COULD_NOT_CREATE_REQUEST: " reqErr.Error())
}
How i build the routes in the iDrac mockup:
http.Handle("/", http.HandlerFunc(handleDefault))
http.Handle("/reset", http.HandlerFunc(handleReset))
http.Handle("/redfish/v1/Systems/System.Embedded.1", http.HandlerFunc(handlePowerStateGet))
http.Handle("/redfish/v1/Systems/System.Embedded.1/Actions/ComputerSystem.Reset", http.HandlerFunc(handlePerformReset))
garbagelog.Log("Starting webserver")
err := http.ListenAndServeTLS(":443", currentConfig.CertFile, currentConfig.PrivKeyFile, nil)
if err != nil {
garbagelog.Log("Could not serve TLS: " err.Error())
}
In both requests, the one created in my iDrac comms module and the one received by the iDrac mockup, did confirm that the requested path is:
r.URL.Path = /redfish/v1/Systems/System.Embedded.1/Actions/ComputerSystem.Reset
CodePudding user response:
based on your screenshot, I can see you are using a "POST" request in your postman, but in your code is "GET".
I think nothing wrong with the code but the method only :)
CodePudding user response:
I found the problem:
The constants i built the urls with were defined like this:
const (
apiBaseURL = "/redfish/v1/"
apiChassisURL = "/Systems/System.Embedded.1"
apiChassisResetAction = "/Actions/ComputerSystem.Reset"
)
Leading to a url that looks like this:
https://host/redfish/v1//Systems/System.Embedded.1/Actions/ComputerSystem.Reset
(Notice the double // between v1 and Systems)
So i've fixed it:
const (
apiBaseURL = "/redfish/v1"
apiChassisURL = "/Systems/System.Embedded.1"
apiChassisResetAction = "/Actions/ComputerSystem.Reset"
)
And everything works correctly: Test results showing that every test was successful
I thank everyone for their input for helping me not lose my mind completely.