Skip to content

Commit

Permalink
Merge pull request #71 from ehaligow/ehaligow-patch-chassis-power
Browse files Browse the repository at this point in the history
PATCH on Chassis/Power
  • Loading branch information
Maciej Miś authored Jan 23, 2024
2 parents 5ec96ea + b2e64c7 commit 3f4660c
Show file tree
Hide file tree
Showing 9 changed files with 258 additions and 1 deletion.
7 changes: 7 additions & 0 deletions lib-utilities/proto/chassis/chassis.proto
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ syntax = "proto3";
rpc CreateChassis(CreateChassisRequest) returns (GetChassisResponse){}
rpc DeleteChassis(DeleteChassisRequest) returns (GetChassisResponse){}
rpc UpdateChassis(UpdateChassisRequest) returns (GetChassisResponse){}
rpc UpdateChassisResource(UpdateChassisResourceRequest) returns (GetChassisResponse){}
}

message GetChassisRequest{
Expand Down Expand Up @@ -53,3 +54,9 @@ syntax = "proto3";
string URL=2;
bytes RequestBody = 3;
}

message UpdateChassisResourceRequest{
string sessionToken=1;
string URL=2;
bytes RequestBody = 3;
}
33 changes: 33 additions & 0 deletions svc-api/handle/chassis.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ type ChassisRPCs struct {
CreateChassisRPC func(req chassisproto.CreateChassisRequest) (*chassisproto.GetChassisResponse, error)
DeleteChassisRPC func(req chassisproto.DeleteChassisRequest) (*chassisproto.GetChassisResponse, error)
UpdateChassisRPC func(req chassisproto.UpdateChassisRequest) (*chassisproto.GetChassisResponse, error)
UpdateChassisResourceRPC func(req chassisproto.UpdateChassisResourceRequest) (*chassisproto.GetChassisResponse, error)
}

//CreateChassis creates a new chassis
Expand Down Expand Up @@ -229,3 +230,35 @@ func (chassis *ChassisRPCs) DeleteChassis(ctx iris.Context) {

writeResponse(ctx, rpcResp.Header, rpcResp.StatusCode, rpcResp.Body)
}


// UpdateChassisResource updates an existing resource under chassis
func (chassis *ChassisRPCs) UpdateChassisResource(ctx iris.Context) {
defer ctx.Next()
requestBody := new(json.RawMessage)
e := ctx.ReadJSON(requestBody)
if e != nil {
errorMessage := "error while trying to read obligatory json body: " + e.Error()
log.Warn(errorMessage)
response := common.GeneralError(http.StatusBadRequest, response.MalformedJSON, errorMessage, nil, nil)
common.SetResponseHeader(ctx, response.Header)
ctx.StatusCode(http.StatusBadRequest)
ctx.JSON(&response.Body)
return
}
rpcResponse, err := chassis.UpdateChassisResourceRPC(chassisproto.UpdateChassisResourceRequest{
SessionToken: ctx.Request().Header.Get("X-Auth-Token"),
URL: ctx.Request().RequestURI,
RequestBody: *requestBody,
})

if err != nil {
log.Println("RPC error:" + err.Error())
re := common.GeneralError(http.StatusInternalServerError, response.InternalError, err.Error(), nil, nil)
writeResponse(ctx, re.Header, re.StatusCode, re.Body)
return
}

writeResponse(ctx, rpcResponse.Header, rpcResponse.StatusCode, rpcResponse.Body)

}
2 changes: 2 additions & 0 deletions svc-api/router/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ func Router() *iris.Application {
CreateChassisRPC: rpc.CreateChassis,
DeleteChassisRPC: rpc.DeleteChassis,
UpdateChassisRPC: rpc.UpdateChassis,
UpdateChassisResourceRPC: rpc.UpdateChassisResource,
}

evt := handle.EventsRPCs{
Expand Down Expand Up @@ -478,6 +479,7 @@ func Router() *iris.Application {
chassis.Any("/{id}/LogServices/{rid}/Actions", handle.ChassisMethodNotAllowed)

chassisPower := chassis.Party("/{id}/Power")
chassisPower.Patch("", cha.UpdateChassisResource)
chassisPower.SetRegisterRule(iris.RouteSkip)
chassisPower.Get("/", cha.GetChassisResource)
chassisPower.Get("#PowerControl/{id1}", cha.GetChassisResource)
Expand Down
18 changes: 17 additions & 1 deletion svc-api/rpc/chassis.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ package rpc
import (
"context"
"fmt"

chassisproto "github.com/ODIM-Project/ODIM/lib-utilities/proto/chassis"
"github.com/ODIM-Project/ODIM/lib-utilities/services"
)
Expand Down Expand Up @@ -113,3 +112,20 @@ func UpdateChassis(req chassisproto.UpdateChassisRequest) (*chassisproto.GetChas
}
return resp, nil
}

//UpdateChassisResource will do the rpc call to update a chassis resource
func UpdateChassisResource(req chassisproto.UpdateChassisResourceRequest) (*chassisproto.GetChassisResponse, error) {
conn, err := services.ODIMService.Client(services.Systems)
if err != nil {
return nil, fmt.Errorf("Failed to create client connection: %v", err)
}
defer conn.Close()
service := chassisproto.NewChassisClient(conn)

resp, err := service.UpdateChassisResource(context.TODO(), &req)
if err != nil && resp == nil {
return nil, fmt.Errorf("Something went wrong with rpc call: %v", err)
}

return resp, err
}
71 changes: 71 additions & 0 deletions svc-device-manager/rest/patchPower.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package rest

import (
"devicemanager/config"
"devicemanager/rest/redfish"
"fmt"
"github.com/kataras/iris/v12"
"github.com/kataras/iris/v12/context"
"github.com/sirupsen/logrus"
"io"
"net/http"
)

type patchPowerHandler struct {
cfg config.Config
}

func (r *patchPowerHandler) handle(ctx iris.Context) {
if ctx.GetHeader("Authorization") == "" {
noValidAuthError := "No valid authorization"
ctx.StatusCode(http.StatusUnauthorized)
logrus.Error(noValidAuthError)
ctx.WriteString(noValidAuthError)
return
}

var reqInfo redfish.RequestInformation

// Get information from the request.
err := ctx.ReadJSON(&reqInfo)
if err != nil {
missingInfoError := "Unable to retrieve information from a request: " + err.Error()
logrus.Error(missingInfoError)
ctx.StatusCode(http.StatusBadRequest)
ctx.WriteString(missingInfoError)
return
}

httpClient := redfish.NewHttpClient(r.cfg).WithBasicAuth(reqInfo.Username, string(reqInfo.Password))
uri := fmt.Sprintf("https://%s%s", reqInfo.Host, ctx.Request().RequestURI)

response, err := httpClient.Patch(uri, reqInfo.Body)
if err != nil {
errorMessage := fmt.Sprintf("PATCH action failed on %s due to: %s", uri, err.Error())
logrus.Error(errorMessage)
if response == nil {
ctx.StatusCode(http.StatusInternalServerError)
ctx.WriteString(errorMessage)
return
}
}

defer response.Body.Close()
body, err := io.ReadAll(response.Body)
if err != nil {
errorMessage := "Error while reading response body: " + err.Error()
logrus.Error(errorMessage)
ctx.StatusCode(http.StatusInternalServerError)
ctx.WriteString(errorMessage)
return
}

ctx.StatusCode(response.StatusCode)
ctx.Write(body)
}

func newPatchPowerHandler(cfg config.Config) context.Handler {
return (&patchPowerHandler{
cfg: cfg,
}).handle
}
34 changes: 34 additions & 0 deletions svc-device-manager/rest/redfish/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,40 @@ func (h *HttpClient) Post(uri string, requestBody []byte) (*http.Response, error
return resp, nil
}

// Patch sends PATCH action to a requested endpoint with requested body.
func (h *HttpClient) Patch(uri string, requestBody []byte) (*http.Response, error) {
requestedUrl, err := url.Parse(uri)
if err != nil {
return nil, err
}

body := io.NopCloser(bytes.NewBuffer(requestBody))
req := &http.Request{
Method: http.MethodPatch,
URL: requestedUrl,
Body: body,
Header: http.Header{},
}
h.addDefaultHeaders(req)

err = translateRequest(req)
if err != nil {
return nil, err
}

resp, err := h.client.Do(req)
if err != nil {
return resp, err
}

err = translateResponse(resp)
if err != nil {
return nil, err
}

return resp, nil
}

func translateRequest(req *http.Request) error {
req.URL, _ = url.Parse(utils.UriConverter.DmToRedfish(req.URL.String()))

Expand Down
7 changes: 7 additions & 0 deletions svc-device-manager/rest/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ func createRouting(app *iris.Application, config config.Config) {

routes := app.Party("/ODIM/v1")
{
chassis := routes.Party("/Chassis", basicAuthHandler)
chassis.Get("", getGenericResourceHandler)
chassis.Get("/{id}", getGenericResourceHandler)
chassis.Get("/{id}/Thermal", getGenericResourceHandler)
chassisPower := chassis.Party("/{id}/Power")
chassisPower.Patch("", newPatchPowerHandler(config))
chassisPower.Get("", getGenericResourceHandler)
systems := routes.Party("/Systems", basicAuthHandler)
systems.Get("", getGenericResourceHandler)
systems.Get("/{id}", getGenericResourceHandler)
Expand Down
69 changes: 69 additions & 0 deletions svc-systems/chassis/updateChassisResource.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package chassis

import (
"encoding/json"
"fmt"
"github.com/ODIM-Project/ODIM/lib-utilities/common"
chassisproto "github.com/ODIM-Project/ODIM/lib-utilities/proto/chassis"
"github.com/ODIM-Project/ODIM/lib-utilities/response"
"github.com/ODIM-Project/ODIM/svc-systems/scommon"
"github.com/ODIM-Project/ODIM/svc-systems/smodel"
"net/http"
"strings"
)

func (p *PluginContact) UpdateChassisResource(req *chassisproto.UpdateChassisResourceRequest) response.RPC {
var resp response.RPC

urlData := strings.Split(req.URL, "/")
var tableName string
if req.URL == "" {
resourceName := urlData[len(urlData)-1]
tableName = common.ChassisResource[resourceName]
} else {
tableName = urlData[len(urlData)-2]
}

uuid := strings.SplitN(tableName, ".", 2)
target, err := smodel.GetTarget(uuid[0])
if err != nil {
return common.GeneralError(http.StatusNotFound, response.ResourceNotFound, err.Error(), []interface{}{"Chassis", uuid[0]}, nil)
}
decryptedPasswordByte, error := p.DecryptPassword(target.Password)
if error != nil {
errorMessage := "error while trying to decrypt device password: " + err.Error()
return common.GeneralError(http.StatusInternalServerError, response.InternalError, errorMessage, []interface{}{"Chassis", urlData}, nil)
}

target.PostBody = req.RequestBody
target.Password = decryptedPasswordByte

plugin, err := smodel.GetPluginData(target.PluginID)
if err != nil {
errorMessage := "error while trying to get plugin data"
return common.GeneralError(http.StatusInternalServerError, response.InternalError, errorMessage, nil, nil)
}

var contactRequest scommon.PluginContactRequest
contactRequest.ContactClient = p.ContactClient
contactRequest.Plugin = plugin
contactRequest.HTTPMethodType = http.MethodPatch
contactRequest.OID = fmt.Sprintf("/ODIM/v1/Chassis/%s/Power", uuid[1])
contactRequest.BasicAuth = map[string]string{
"UserName": plugin.Username,
"Password": string(plugin.Password),
}
contactRequest.DeviceInfo = target

body, _, getResponse, contactErr := scommon.ContactPlugin(contactRequest, "error while trying patch Chassis/Power")
if contactErr != nil {
return common.GeneralError(getResponse.StatusCode, getResponse.StatusMessage, contactErr.Error(), nil, nil)
}

var resource map[string]interface{}
json.Unmarshal(body, &resource)
resp.Body = resource
resp.StatusCode = http.StatusOK
resp.StatusMessage = response.Success
return resp
}
18 changes: 18 additions & 0 deletions svc-systems/rpc/chassis.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,24 @@ type ChassisRPC struct {
CreateHandler *chassis.Create
}

func (cha *ChassisRPC) UpdateChassisResource(_ context.Context, req *chassisproto.UpdateChassisResourceRequest) (*chassisproto.GetChassisResponse, error) {
var resp chassisproto.GetChassisResponse
sessionToken := req.SessionToken
authResp := cha.IsAuthorizedRPC(sessionToken, []string{common.PrivilegeLogin}, []string{})
if authResp.StatusCode != http.StatusOK {
rewrite(authResp, &resp)
return &resp, nil
}
var pc = chassis.PluginContact{
ContactClient: pmbhandle.ContactPlugin,
DecryptPassword: common.DecryptWithPrivateKey,
GetPluginStatus: scommon.GetPluginStatus,
}
data := pc.UpdateChassisResource(req)
rewrite(data, &resp)
return &resp, nil
}

func (cha *ChassisRPC) UpdateChassis(ctx context.Context, req *chassisproto.UpdateChassisRequest) (*chassisproto.GetChassisResponse, error) {
var resp chassisproto.GetChassisResponse
r := auth(cha.IsAuthorizedRPC, req.SessionToken, []string{common.PrivilegeConfigureComponents}, func() response.RPC {
Expand Down

0 comments on commit 3f4660c

Please sign in to comment.