Compare commits

...

38 Commits

Author SHA1 Message Date
pb
387785b40c reimported logs without import cycle 2025-06-04 10:33:00 +02:00
pb
03dea55131 added another error log when the status is dead 2025-06-03 10:00:47 +02:00
pb
7b8aa989f6 added a log when an API is not reachable 2025-06-02 18:22:08 +02:00
pb
6ab6383144 corrected an use of the original http caller instead of the deep copy 2025-05-27 18:07:00 +02:00
pb
690d60f9d6 corrected the getBooking function parameters 2025-05-27 16:13:46 +02:00
pb
da0de80afd Booking check and booking post have been transformed in goroutine to improve performance when booking several execution with cron expressions 2025-05-27 15:38:24 +02:00
pb
cd7ae788b1 didn't put the blocking loop in the right place for post booking 2025-05-27 12:06:10 +02:00
pb
0d96cc53bf transformed the loop that posted the booking on oc-datacenter to a threaded operation where each call is done in a goroutine 2025-05-27 11:58:55 +02:00
pb
66fc3c5b35 added the passing of the request.Caller's URL to the deep copy 2025-05-27 11:34:44 +02:00
pb
5ab3eb8a38 forgot to pass the mutex as pointer and unlock it 2025-05-27 11:17:10 +02:00
pb
fec23b4acd modified HTTP caller to have a DeepCopy() method in order to parallelize calls without race conditions 2025-05-27 11:08:35 +02:00
pb
901622fee0 logging on the booking uuid before the post booking 2025-05-27 09:51:41 +02:00
pb
527e622774 correct the error channel 2025-05-26 19:21:28 +02:00
pb
7223b79fe8 correct the error channel 2025-05-26 19:16:39 +02:00
pb
1ade41aeae moved the code that execute the booking into a separated function so that it can be launched as goroutine and parallelize get booking$ 2025-05-26 19:05:17 +02:00
pb
58dc579255 added debug logging 2025-05-26 18:30:56 +02:00
pb
370dac201b In CheckBooking mooved the loop on bookings outside of the loop of execs, which seems to repeat the Peer execution on booking an exponential number of time 2025-05-26 17:55:45 +02:00
pb
2a763006db counting round in exec 2025-05-26 17:41:26 +02:00
pb
522c66653b Added logging for debug 2025-05-26 17:22:09 +02:00
pb
b57f050b81 increased the limit of returns by Mongo find() 2025-05-22 14:41:38 +02:00
pb
41ebcf150a added logging when booking 2025-05-07 18:16:38 +02:00
pb
1499def6ad added booking on the computing and data resource's peers 2025-05-07 14:54:31 +02:00
pb
adbab0f5d7 added more info on error returned by LaunchPeerExecution() 2025-04-30 16:13:49 +02:00
pb
88c88cac5b testing simplyfied urlFormat() method which works thanks to traefik 2025-03-13 16:57:27 +01:00
pb
1ae38c98ad correct path for ADMIRALTY_NODESAPI 2025-03-13 11:58:57 +01:00
pb
2d517cc594 Correcting an error in CallGet() 2025-03-12 15:41:10 +01:00
pb
a9c82bd261 Replaced the return of Call[Method]() by the stored value of the resp.Body 2025-03-12 15:37:03 +01:00
pb
79aec86f5f Replaced the return of Call[Method]() by the stored value of the resp.Body 2025-03-12 15:26:00 +01:00
pb
9b3dfc7576 fixing how last result in stored in httpcaller 2025-03-12 12:13:55 +01:00
pb
037ae74782 modified the way HTTPCaller store last resposne 2025-03-12 12:09:55 +01:00
pb
b81c60a3ce modified the way HTTPCaller store last resposne 2025-03-12 12:00:32 +01:00
pb
363ac94c47 debug instructions 2025-03-12 11:35:25 +01:00
pb
378f9e5095 Added a new http.Response field to HTTPCaller to store results for each call 2025-03-12 10:39:20 +01:00
pb
659b494ee4 Added a new field to HTTPCaller to store results for each call 2025-03-12 09:45:17 +01:00
pb
92965c6af2 Added more information in error when LaunchPeerExecution method doesn't match caller's 2025-03-11 16:48:05 +01:00
pb
70cb5aec9f changed some variable name for better understanding of process in LaunchPeerExecution 2025-03-11 12:03:35 +01:00
pb
d59e77d5a2 changed how url is consructed in LaunchPeerExecution by placing meth after peer url + dt 2025-03-05 16:42:22 +01:00
pb
ff1b857ab0 removed caller from checkPeerStatus() parameters by adding the path to url 2025-03-05 11:54:14 +01:00
7 changed files with 176 additions and 48 deletions

View File

@ -287,7 +287,7 @@ func (m *MongoDB) Search(filters *dbs.Filters, collection_name string) (*mongo.C
return nil, 503, err return nil, 503, err
} }
opts := options.Find() opts := options.Find()
opts.SetLimit(100) opts.SetLimit(1000)
targetDBCollection := CollectionMap[collection_name] targetDBCollection := CollectionMap[collection_name]
orList := bson.A{} orList := bson.A{}
andList := bson.A{} andList := bson.A{}

View File

@ -4,7 +4,6 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"regexp"
"strings" "strings"
"cloud.o-forge.io/core/oc-lib/tools" "cloud.o-forge.io/core/oc-lib/tools"
@ -29,28 +28,29 @@ type PeerCache struct {
} }
// urlFormat formats the URL of the peer with the data type API function // urlFormat formats the URL of the peer with the data type API function
func (p *PeerCache) urlFormat(url string, dt tools.DataType) string { func (p *PeerCache) urlFormat(hostUrl string, dt tools.DataType) string {
// localhost is replaced by the local peer URL // localhost is replaced by the local peer URL
// because localhost must collide on a web request security protocol // because localhost must collide on a web request security protocol
localhost := "" /*localhost := ""
if strings.Contains(url, "localhost") { if strings.Contains(hostUrl, "localhost") {
localhost = "localhost" localhost = "localhost"
} }
if strings.Contains(url, "127.0.0.1") { if strings.Contains(hostUrl, "127.0.0.1") {
localhost = "127.0.0.1" localhost = "127.0.0.1"
} }
if localhost != "" { if localhost != "" {
r := regexp.MustCompile("(" + localhost + ":[0-9]+)") r := regexp.MustCompile("(" + localhost + ":[0-9]+)")
t := r.FindString(url) t := r.FindString(hostUrl)
if t != "" { if t != "" {
url = strings.Replace(url, t, dt.API()+":8080/oc", -1) hostUrl = strings.Replace(hostUrl, t, dt.API()+":8080/oc", -1)
} else { } else {
url = strings.ReplaceAll(url, localhost, dt.API()+":8080/oc") hostUrl = strings.ReplaceAll(hostUrl, localhost, dt.API()+":8080/oc")
} }
} else { } else {*/
url = dt.API() + "/" + url hostUrl = hostUrl + "/" + strings.ReplaceAll(dt.API(), "oc-", "")
} //}
return url fmt.Println("Contacting", hostUrl)
return hostUrl
} }
// checkPeerStatus checks the status of a peer // checkPeerStatus checks the status of a peer
@ -65,22 +65,20 @@ func (p *PeerCache) checkPeerStatus(peerID string, appName string) (*Peer, bool)
state, services := api.CheckRemotePeer(url) state, services := api.CheckRemotePeer(url)
res.(*Peer).ServicesState = services // Update the services states of the peer res.(*Peer).ServicesState = services // Update the services states of the peer
access.UpdateOne(res, peerID) // Update the peer in the db access.UpdateOne(res, peerID) // Update the peer in the db
fmt.Println("URL peer : ", url)
fmt.Println("State : ", state)
fmt.Println("Services : ", services)
return res.(*Peer), state != tools.DEAD && services[appName] == 0 // Return the peer and its status return res.(*Peer), state != tools.DEAD && services[appName] == 0 // Return the peer and its status
} }
// LaunchPeerExecution launches an execution on a peer // LaunchPeerExecution launches an execution on a peer
// The method contacts the path described by : peer.Url + datatype path (from enums) + replacement of id by dataID
func (p *PeerCache) LaunchPeerExecution(peerID string, dataID string, func (p *PeerCache) LaunchPeerExecution(peerID string, dataID string,
dt tools.DataType, method tools.METHOD, body interface{}, caller *tools.HTTPCaller) (*PeerExecution, error) { dt tools.DataType, method tools.METHOD, body interface{}, caller *tools.HTTPCaller) (*PeerExecution, error) {
fmt.Println("Launching peer execution on", caller.URLS, dt, method) fmt.Println("Launching peer execution on", caller.URLS, dt, method)
methods := caller.URLS[dt] // Get the methods url of the data type methods := caller.URLS[dt] // Get the methods url of the data type
if m, ok := methods[method]; !ok || m == "" { if m, ok := methods[method]; !ok || m == "" {
return nil, errors.New("no path found") return nil, errors.New("Requested method " + method.String() + " not declared in HTTPCaller")
} }
meth := methods[method] // Get the method url to execute path := methods[method] // Get the path corresponding to the action we want to execute
meth = strings.ReplaceAll(meth, ":id", dataID) // Replace the id in the url in case of a DELETE / UPDATE method (it's a standard naming in OC) path = strings.ReplaceAll(path, ":id", dataID) // Replace the id in the path in case of a DELETE / UPDATE method (it's a standard naming in OC)
url := "" url := ""
// Check the status of the peer // Check the status of the peer
@ -88,20 +86,20 @@ func (p *PeerCache) LaunchPeerExecution(peerID string, dataID string,
// If the peer is not reachable, add the execution to the failed executions list // If the peer is not reachable, add the execution to the failed executions list
pexec := &PeerExecution{ pexec := &PeerExecution{
Method: method.String(), Method: method.String(),
Url: p.urlFormat((mypeer.Url)+meth, dt), Url: p.urlFormat((mypeer.Url), dt) + path, // the url is constitued of : host URL + resource path + action path (ex : mypeer.com/datacenter/resourcetype/path/to/action)
Body: body, Body: body,
DataType: dt.EnumIndex(), DataType: dt.EnumIndex(),
DataID: dataID, DataID: dataID,
} }
mypeer.AddExecution(*pexec) mypeer.AddExecution(*pexec)
NewShallowAccessor().UpdateOne(mypeer, peerID) // Update the peer in the db NewShallowAccessor().UpdateOne(mypeer, peerID) // Update the peer in the db
return nil, errors.New("peer is not reachable") return nil, errors.New("peer is " + peerID + " not reachable")
} else { } else {
if mypeer == nil { if mypeer == nil {
return nil, errors.New("peer not found") return nil, errors.New("peer " + peerID + " not found")
} }
// If the peer is reachable, launch the execution // If the peer is reachable, launch the execution
url = p.urlFormat((mypeer.Url)+meth, dt) // Format the URL url = p.urlFormat((mypeer.Url), dt) + path // Format the URL
tmp := mypeer.FailedExecution // Get the failed executions list tmp := mypeer.FailedExecution // Get the failed executions list
mypeer.FailedExecution = []PeerExecution{} // Reset the failed executions list mypeer.FailedExecution = []PeerExecution{} // Reset the failed executions list
NewShallowAccessor().UpdateOne(mypeer, peerID) // Update the peer in the db NewShallowAccessor().UpdateOne(mypeer, peerID) // Update the peer in the db

View File

@ -112,6 +112,8 @@ func (d *WorkflowExecution) VerifyAuth(request *tools.APIRequest) bool {
func (d *WorkflowExecution) Book(executionsID string, wfID string, priceds map[tools.DataType]map[string]pricing.PricedItemITF) []*booking.Booking { func (d *WorkflowExecution) Book(executionsID string, wfID string, priceds map[tools.DataType]map[string]pricing.PricedItemITF) []*booking.Booking {
booking := d.bookEach(executionsID, wfID, tools.STORAGE_RESOURCE, priceds[tools.STORAGE_RESOURCE]) booking := d.bookEach(executionsID, wfID, tools.STORAGE_RESOURCE, priceds[tools.STORAGE_RESOURCE])
booking = append(booking, d.bookEach(executionsID, wfID, tools.PROCESSING_RESOURCE, priceds[tools.PROCESSING_RESOURCE])...) booking = append(booking, d.bookEach(executionsID, wfID, tools.PROCESSING_RESOURCE, priceds[tools.PROCESSING_RESOURCE])...)
booking = append(booking,d.bookEach(executionsID, wfID, tools.COMPUTE_RESOURCE, priceds[tools.COMPUTE_RESOURCE])...)
booking = append(booking,d.bookEach(executionsID, wfID, tools.DATA_RESOURCE, priceds[tools.DATA_RESOURCE])...)
return booking return booking
} }

View File

@ -4,6 +4,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"strings" "strings"
"sync"
"time" "time"
"cloud.o-forge.io/core/oc-lib/models/booking" "cloud.o-forge.io/core/oc-lib/models/booking"
@ -77,22 +78,60 @@ func (ws *WorkflowSchedule) CheckBooking(wfID string, request *tools.APIRequest)
bookings := []*booking.Booking{} bookings := []*booking.Booking{}
for _, exec := range execs { for _, exec := range execs {
bookings = append(bookings, exec.Book(ws.UUID, wfID, priceds)...) bookings = append(bookings, exec.Book(ws.UUID, wfID, priceds)...)
for _, b := range bookings {
meth := request.Caller.URLS[tools.BOOKING][tools.GET]
meth = strings.ReplaceAll(meth, ":id", b.ResourceID)
meth = strings.ReplaceAll(meth, ":start_date", b.ExpectedStartDate.Format("2006-01-02T15:04:05"))
meth = strings.ReplaceAll(meth, ":end_date", b.ExpectedEndDate.Format("2006-01-02T15:04:05"))
request.Caller.URLS[tools.BOOKING][tools.GET] = meth
_, err := (&peer.Peer{}).LaunchPeerExecution(b.DestPeerID, b.ResourceID, tools.BOOKING, tools.GET, nil, request.Caller)
if err != nil {
return false, wf, execs, bookings, err
}
}
} }
errCh := make(chan error, len(bookings))
var m sync.Mutex
for _, b := range bookings {
go getBooking(b, request, wf, execs, bookings, errCh, &m)
}
for i := 0; i < len(bookings); i++ {
if err := <-errCh; err != nil {
return false, wf, execs, bookings, err
}
}
return true, wf, execs, bookings, nil return true, wf, execs, bookings, nil
} }
func getBooking( b *booking.Booking, request *tools.APIRequest, wf *workflow.Workflow, execs []*WorkflowExecution, bookings []*booking.Booking, errCh chan error, m *sync.Mutex) {
m.Lock()
c, err := getCallerCopy(request, errCh)
if err != nil {
errCh <- err
return
}
m.Unlock()
meth := c.URLS[tools.BOOKING][tools.GET]
meth = strings.ReplaceAll(meth, ":id", b.ResourceID)
meth = strings.ReplaceAll(meth, ":start_date", b.ExpectedStartDate.Format("2006-01-02T15:04:05"))
meth = strings.ReplaceAll(meth, ":end_date", b.ExpectedEndDate.Format("2006-01-02T15:04:05"))
c.URLS[tools.BOOKING][tools.GET] = meth
_, err = (&peer.Peer{}).LaunchPeerExecution(b.DestPeerID, b.ResourceID, tools.BOOKING, tools.GET, nil, &c)
if err != nil {
errCh <- err
return
}
errCh <- nil
}
func getCallerCopy(request *tools.APIRequest, errCh chan error) (tools.HTTPCaller, error) {
var c tools.HTTPCaller
err := request.Caller.DeepCopy(c)
if err != nil {
errCh <- err
return tools.HTTPCaller{}, nil
}
c.URLS = request.Caller.URLS
return c, err
}
func (ws *WorkflowSchedule) Schedules(wfID string, request *tools.APIRequest) (*WorkflowSchedule, *workflow.Workflow, []*WorkflowExecution, error) { func (ws *WorkflowSchedule) Schedules(wfID string, request *tools.APIRequest) (*WorkflowSchedule, *workflow.Workflow, []*WorkflowExecution, error) {
if request == nil { if request == nil {
return ws, nil, []*WorkflowExecution{}, errors.New("no request found") return ws, nil, []*WorkflowExecution{}, errors.New("no request found")
@ -111,13 +150,20 @@ func (ws *WorkflowSchedule) Schedules(wfID string, request *tools.APIRequest) (*
return ws, nil, executions, errors.New("could not book the workflow : " + fmt.Sprintf("%v", err)) return ws, nil, executions, errors.New("could not book the workflow : " + fmt.Sprintf("%v", err))
} }
ws.Workflow = wf ws.Workflow = wf
var errCh = make(chan error, len(bookings))
var m sync.Mutex
for _, booking := range bookings { for _, booking := range bookings {
_, err := (&peer.Peer{}).LaunchPeerExecution(booking.DestPeerID, "", go ws.BookExecs(booking, request, errCh, &m)
tools.BOOKING, tools.POST, booking.Serialize(booking), request.Caller) }
if err != nil {
for i := 0; i < len(bookings); i++ {
if err := <- errCh ; err != nil {
return ws, wf, executions, errors.New("could not launch the peer execution : " + fmt.Sprintf("%v", err)) return ws, wf, executions, errors.New("could not launch the peer execution : " + fmt.Sprintf("%v", err))
} }
} }
fmt.Println("Schedules") fmt.Println("Schedules")
for _, exec := range executions { for _, exec := range executions {
err := exec.PurgeDraft(request) err := exec.PurgeDraft(request)
@ -131,6 +177,27 @@ func (ws *WorkflowSchedule) Schedules(wfID string, request *tools.APIRequest) (*
return ws, wf, executions, nil return ws, wf, executions, nil
} }
func (ws *WorkflowSchedule) BookExecs(booking *booking.Booking, request *tools.APIRequest, errCh chan error, m *sync.Mutex) {
m.Lock()
c, err := getCallerCopy(request, errCh)
if err != nil {
errCh <- err
return
}
m.Unlock()
_, err = (&peer.Peer{}).LaunchPeerExecution(booking.DestPeerID, "",
tools.BOOKING, tools.POST, booking.Serialize(booking), &c)
if err != nil {
errCh <- err
return
}
errCh <- nil
}
/* /*
BOOKING IMPLIED TIME, not of subscription but of execution BOOKING IMPLIED TIME, not of subscription but of execution
so is processing time execution time applied on computes so is processing time execution time applied on computes

View File

@ -7,6 +7,7 @@ import (
"cloud.o-forge.io/core/oc-lib/config" "cloud.o-forge.io/core/oc-lib/config"
"cloud.o-forge.io/core/oc-lib/dbs/mongo" "cloud.o-forge.io/core/oc-lib/dbs/mongo"
"cloud.o-forge.io/core/oc-lib/logs"
beego "github.com/beego/beego/v2/server/web" beego "github.com/beego/beego/v2/server/web"
) )
@ -135,6 +136,7 @@ func (a *API) CheckRemotePeer(url string) (State, map[string]int) {
// CheckRemoteAPIs checks the state of remote APIs from your proper OC // CheckRemoteAPIs checks the state of remote APIs from your proper OC
func (a *API) CheckRemoteAPIs(apis []DataType) (State, map[string]string, error) { func (a *API) CheckRemoteAPIs(apis []DataType) (State, map[string]string, error) {
// Check if the database is up // Check if the database is up
l := logs.GetLogger()
new := map[string]string{} new := map[string]string{}
caller := NewHTTPCaller(map[DataType]map[METHOD]string{}) // Create a new http caller caller := NewHTTPCaller(map[DataType]map[METHOD]string{}) // Create a new http caller
code := 0 code := 0
@ -145,6 +147,7 @@ func (a *API) CheckRemoteAPIs(apis []DataType) (State, map[string]string, error)
var resp APIStatusResponse var resp APIStatusResponse
b, err := caller.CallGet("http://"+api.API()+":8080", "/oc/version/status") // Call the status endpoint of the remote API (standard OC status endpoint) b, err := caller.CallGet("http://"+api.API()+":8080", "/oc/version/status") // Call the status endpoint of the remote API (standard OC status endpoint)
if err != nil { if err != nil {
l.Error().Msg(api.String() + " not reachable")
state = REDUCED_SERVICE // If a remote API is not reachable, return reduced service state = REDUCED_SERVICE // If a remote API is not reachable, return reduced service
continue continue
} }
@ -161,6 +164,7 @@ func (a *API) CheckRemoteAPIs(apis []DataType) (State, map[string]string, error)
reachable = true // If the remote API is reachable, set reachable to true cause we are not dead reachable = true // If the remote API is reachable, set reachable to true cause we are not dead
} }
if !reachable { if !reachable {
l.Error().Msg("Peer check returned no answers")
state = DEAD // If no remote API is reachable, return dead, nobody is alive state = DEAD // If no remote API is reachable, return dead, nobody is alive
} }
if code > 0 { if code > 0 {

View File

@ -39,7 +39,7 @@ var ADMIRALTY_SOURCEAPI = DATACENTERAPI+"/admiralty/source"
var ADMIRALTY_TARGETAPI = DATACENTERAPI+"/admiralty/target" var ADMIRALTY_TARGETAPI = DATACENTERAPI+"/admiralty/target"
var ADMIRALTY_SECRETAPI = DATACENTERAPI+"/admiralty/secret" var ADMIRALTY_SECRETAPI = DATACENTERAPI+"/admiralty/secret"
var ADMIRALTY_KUBECONFIGAPI = DATACENTERAPI+"/admiralty/kubeconfig" var ADMIRALTY_KUBECONFIGAPI = DATACENTERAPI+"/admiralty/kubeconfig"
var ADMIRALTY_NODESAPI = DATACENTERAPI+"/admiralty/nodes" var ADMIRALTY_NODESAPI = DATACENTERAPI+"/admiralty/node"
// Bind the standard API name to the data type // Bind the standard API name to the data type
var DefaultAPI = [...]string{ var DefaultAPI = [...]string{

View File

@ -3,6 +3,7 @@ package tools
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt"
"io" "io"
"net/http" "net/http"
"net/url" "net/url"
@ -49,8 +50,9 @@ func ToMethod(str string) METHOD {
var HTTPCallerInstance = &HTTPCaller{} // Singleton instance of the HTTPCaller var HTTPCallerInstance = &HTTPCaller{} // Singleton instance of the HTTPCaller
type HTTPCaller struct { type HTTPCaller struct {
URLS map[DataType]map[METHOD]string // Map of the different methods and their urls URLS map[DataType]map[METHOD]string // Map of the different methods and their urls
Disabled bool // Disabled flag Disabled bool // Disabled flag
LastResults map[string]interface{} // Used to store information regarding the last execution of a given method on a given data type
} }
// NewHTTPCaller creates a new instance of the HTTP Caller // NewHTTPCaller creates a new instance of the HTTP Caller
@ -61,6 +63,16 @@ func NewHTTPCaller(urls map[DataType]map[METHOD]string) *HTTPCaller {
} }
} }
// Creates a copy of the current caller, in order to have parallelized executions without race condition
func (c* HTTPCaller) DeepCopy(dst HTTPCaller) error {
bytes, err := json.Marshal(c)
if err != nil {
return err
}
return json.Unmarshal(bytes, &dst)
}
// CallGet calls the GET method on the HTTP server // CallGet calls the GET method on the HTTP server
func (caller *HTTPCaller) CallGet(url string, subpath string, types ...string) ([]byte, error) { func (caller *HTTPCaller) CallGet(url string, subpath string, types ...string) ([]byte, error) {
req, err := http.NewRequest(http.MethodGet, url+subpath, bytes.NewBuffer([]byte(""))) req, err := http.NewRequest(http.MethodGet, url+subpath, bytes.NewBuffer([]byte("")))
@ -76,17 +88,33 @@ func (caller *HTTPCaller) CallGet(url string, subpath string, types ...string) (
return nil, err return nil, err
} }
defer resp.Body.Close() defer resp.Body.Close()
return io.ReadAll(resp.Body) err = caller.StoreResp(resp)
if err != nil {
return nil, err
}
return caller.LastResults["body"].([]byte), nil
} }
// CallPut calls the DELETE method on the HTTP server // CallPut calls the DELETE method on the HTTP server
func (caller *HTTPCaller) CallDelete(url string, subpath string) ([]byte, error) { func (caller *HTTPCaller) CallDelete(url string, subpath string) ([]byte, error) {
resp, err := http.NewRequest("DELETE", url+subpath, nil) req, err := http.NewRequest("DELETE", url+subpath, nil)
if err != nil || resp == nil || resp.Body == nil { if err != nil {
return nil, err
}
client := &http.Client{}
resp, err := client.Do(req)
if err != nil || req == nil || req.Body == nil {
return nil, err return nil, err
} }
defer resp.Body.Close() defer resp.Body.Close()
return io.ReadAll(resp.Body)
err = caller.StoreResp(resp)
if err != nil {
return nil, err
}
return caller.LastResults["body"].([]byte), nil
} }
// CallPost calls the POST method on the HTTP server // CallPost calls the POST method on the HTTP server
@ -105,7 +133,12 @@ func (caller *HTTPCaller) CallPost(url string, subpath string, body interface{},
return nil, err return nil, err
} }
defer resp.Body.Close() defer resp.Body.Close()
return io.ReadAll(resp.Body) err = caller.StoreResp(resp)
if err != nil {
return nil, err
}
return caller.LastResults["body"].([]byte), nil
} }
// CallPost calls the POST method on the HTTP server // CallPost calls the POST method on the HTTP server
@ -123,7 +156,12 @@ func (caller *HTTPCaller) CallPut(url string, subpath string, body map[string]in
return nil, err return nil, err
} }
defer resp.Body.Close() defer resp.Body.Close()
return io.ReadAll(resp.Body) err = caller.StoreResp(resp)
if err != nil {
return nil, err
}
return caller.LastResults["body"].([]byte), nil
} }
// CallRaw calls the Raw method on the HTTP server // CallRaw calls the Raw method on the HTTP server
@ -143,7 +181,12 @@ func (caller *HTTPCaller) CallRaw(method string, url string, subpath string,
req.AddCookie(c) req.AddCookie(c)
} }
client := &http.Client{} client := &http.Client{}
return client.Do(req) resp, err := client.Do(req)
if err != nil {
return nil, err
}
return resp, nil
} }
// CallRaw calls the Raw method on the HTTP server // CallRaw calls the Raw method on the HTTP server
@ -163,3 +206,17 @@ func (caller *HTTPCaller) CallForm(method string, url string, subpath string,
client := &http.Client{} client := &http.Client{}
return client.Do(req) return client.Do(req)
} }
func (caller *HTTPCaller) StoreResp(resp *http.Response) error {
caller.LastResults = make(map[string]interface{})
caller.LastResults["header"] = resp.Header
caller.LastResults["code"] = resp.StatusCode
data, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Println("Error reading the body of the last request")
return err
}
caller.LastResults["body"] = data
return nil
}