This repository has been archived by the owner on Mar 26, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 82
WIP: Intelligent Volume provisioning #513
Closed
Closed
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package middleware | ||
|
||
import ( | ||
"bytes" | ||
"encoding/json" | ||
"fmt" | ||
"io/ioutil" | ||
"net/http" | ||
"strings" | ||
|
||
"github.com/gluster/glusterd2/glusterd2/commands/volumes" | ||
"github.com/gluster/glusterd2/pkg/utils" | ||
) | ||
|
||
// TODO | ||
// In Go, the idiomatic and recommended way to attach any request scoped | ||
// metadata information across goroutine and process boundaries is to use the | ||
// 'context' package. This is not useful unless we pass down this context | ||
// all through-out the request scope across nodes, and this involves some | ||
// code changes in function signatures at many places | ||
// The following simple implementation is good enough until then... | ||
|
||
// Heketi is a middleware which generates adds bricks to a volume | ||
// request if it has a key asking for auto brick allocation. It modifies the | ||
// HTTP request and adds bricks to it. | ||
func Heketi(next http.Handler) http.Handler { | ||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
|
||
|
||
if r.URL.Path == "/v1/volumes" && r.Method == http.MethodPost { | ||
req := new(volumecommands.VolCreateRequest) | ||
utils.GetJSONFromRequest(r, req) | ||
|
||
//if (len(req.Bricks) <= 0) && (req.Size > 0) { | ||
if req.Size > 0 { | ||
replacer := strings.NewReplacer("export", "testexport") | ||
for i :=0; i < len(req.Bricks); i++ { | ||
req.Bricks[i] = replacer.Replace(req.Bricks[i]) | ||
} | ||
newbody, err := json.Marshal(req) | ||
if err != nil { | ||
fmt.Printf("Marshalling Error %v", err) | ||
} | ||
|
||
r.Body = ioutil.NopCloser(bytes.NewReader(newbody)) | ||
r.ContentLength = int64(len(newbody)) | ||
|
||
} | ||
|
||
} | ||
next.ServeHTTP(w, r) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package utils | ||
|
||
import ( | ||
"encoding/json" | ||
"io" | ||
"io/ioutil" | ||
"net/http" | ||
) | ||
|
||
func jsonFromBody(r io.Reader, v interface{}) error { | ||
|
||
// Check body | ||
body, err := ioutil.ReadAll(r) | ||
if err != nil { | ||
return err | ||
} | ||
if err := json.Unmarshal(body, v); err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// GetJSONFromRequest unmarshals JSON in `r` into `v` | ||
func GetJSONFromRequest(r *http.Request, v interface{}) error { | ||
defer r.Body.Close() | ||
return jsonFromBody(r.Body, v) | ||
} | ||
|
||
// GetJSONFromResponse unmarshals JSON in `r` into `v` | ||
func GetJSONFromResponse(r *http.Response, v interface{}) error { | ||
defer r.Body.Close() | ||
return jsonFromBody(r.Body, v) | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package heketi | ||
|
||
// AddDeviceReq represents REST API request to add device to heketi managed device list | ||
type AddDeviceReq struct { | ||
NodeID string `json:"nodeid"` | ||
DeviceName string `json:"devicename"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package heketi | ||
|
||
import "github.com/pborman/uuid" | ||
|
||
const ( | ||
// HeketiDeviceEnabled represents enabled | ||
HeketiDeviceEnabled = "Enabled" | ||
|
||
// HeketiDeviceFrozen represents frozen | ||
HeketiDeviceFrozen = "Frozen" | ||
|
||
// HeketiDeviceEvacuated represents evacuated | ||
HeketiDeviceEvacuated = "Evacuated" | ||
) | ||
|
||
// DeviceInfo is the added device info | ||
type DeviceInfo struct { | ||
NodeID uuid.UUID `json:"nodeid"` | ||
DeviceName string `json:"devicename"` | ||
State string `json:"devicestate"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package heketi | ||
|
||
// ErrHeketiSingleError only error for now | ||
type ErrHeketiSingleError struct{} | ||
|
||
func (e *ErrHeketiSingleError) Error() string { | ||
return "Single error" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package heketi | ||
|
||
import ( | ||
"github.com/gluster/glusterd2/glusterd2/servers/rest/route" | ||
"github.com/gluster/glusterd2/glusterd2/transaction" | ||
"github.com/prashanthpai/sunrpc" | ||
) | ||
|
||
// Plugin is a structure which implements GlusterdPlugin interface | ||
type Plugin struct { | ||
} | ||
|
||
// Name returns name of plugin | ||
func (p *Plugin) Name() string { | ||
return "heketi" | ||
} | ||
|
||
// SunRPCProgram returns sunrpc program to register with Glusterd | ||
func (p *Plugin) SunRPCProgram() sunrpc.Program { | ||
return nil | ||
} | ||
|
||
// RestRoutes returns list of REST API routes to register with Glusterd | ||
func (p *Plugin) RestRoutes() route.Routes { | ||
return route.Routes{ | ||
route.Route{ | ||
Name: "HeketiDeviceAdd", | ||
Method: "POST", | ||
Pattern: "/heketi/{nodeid}/{devicename}/add", | ||
Version: 1, | ||
HandlerFunc: heketiDeviceAddHandler}, | ||
} | ||
} | ||
|
||
// RegisterStepFuncs registers transaction step functions with | ||
// Glusterd Transaction framework | ||
func (p *Plugin) RegisterStepFuncs() { | ||
transaction.RegisterStepFunc(txnHeketiPrepareDevice, "heketi-prepare-device.Commit") | ||
transaction.RegisterStepFunc(txnHeketiCreateBrick, "heketi-create-brick.Commit") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
package heketi | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"net/http" | ||
|
||
"github.com/pborman/uuid" | ||
|
||
heketiapi "github.com/gluster/glusterd2/plugins/heketi/api" | ||
restutils "github.com/gluster/glusterd2/glusterd2/servers/rest/utils" | ||
"github.com/gluster/glusterd2/glusterd2/store" | ||
"github.com/gluster/glusterd2/pkg/api" | ||
"github.com/gluster/glusterd2/glusterd2/transaction" | ||
|
||
"github.com/gorilla/mux" | ||
log "github.com/sirupsen/logrus" | ||
) | ||
|
||
const ( | ||
heketiPrefix string = store.GlusterPrefix + "heketi/" | ||
) | ||
|
||
func heketiDeviceAddHandler(w http.ResponseWriter, r *http.Request) { | ||
// Collect inputs from URL | ||
p := mux.Vars(r) | ||
nodeIDRaw := p["nodeid"] | ||
deviceName := p["devicename"] | ||
var deviceinfo heketiapi.DeviceInfo | ||
deviceinfo.DeviceName = deviceName | ||
ctx := r.Context() | ||
nodeID := uuid.Parse(nodeIDRaw) | ||
if nodeID == nil { | ||
restutils.SendHTTPError(ctx, w, http.StatusBadRequest, "Invalid Node ID", api.ErrCodeDefault) | ||
return | ||
} | ||
deviceinfo.NodeID = nodeID | ||
|
||
reqID, logger := restutils.GetReqIDandLogger(r) | ||
|
||
_, err := store.Store.Get(context.TODO(), deviceinfo.NodeID.String()) | ||
if err != nil { | ||
restutils.SendHTTPError(ctx,w, http.StatusInternalServerError, err.Error(), api.ErrCodeDefault) | ||
return | ||
} | ||
|
||
txn := transaction.NewTxn(ctx) | ||
defer txn.Cleanup() | ||
|
||
lock, unlock, err := transaction.CreateLockSteps(deviceinfo.NodeID.String()) | ||
if err != nil { | ||
restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err.Error(), api.ErrCodeDefault) | ||
return | ||
} | ||
|
||
nodes := make([]uuid.UUID, 0) | ||
nodes = append(nodes, deviceinfo.NodeID) | ||
|
||
txn.Nodes = nodes | ||
txn.Steps = []*transaction.Step{ | ||
lock, | ||
{ | ||
DoFunc: "heketi-prepare-device.Commit", | ||
Nodes: txn.Nodes, | ||
}, | ||
unlock, | ||
} | ||
txn.Ctx.Set("nodeid", deviceinfo.NodeID.String()) | ||
txn.Ctx.Set("devicename", deviceinfo.DeviceName) | ||
|
||
err = txn.Do() | ||
if err != nil { | ||
logger.WithFields(log.Fields{ | ||
"error": err.Error(), | ||
"nodeid": deviceinfo.NodeID, | ||
"devicename": deviceinfo.DeviceName, | ||
}).Error("Failed to prepare device") | ||
restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err.Error(), api.ErrCodeDefault) | ||
return | ||
} | ||
|
||
// update device state | ||
deviceinfo.State = heketiapi.HeketiDeviceEnabled | ||
|
||
json, err := json.Marshal(deviceinfo) | ||
if err != nil { | ||
log.WithField("error", err).Error("Failed to marshal the DeviceInfo object" + reqID) | ||
restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err.Error(), api.ErrCodeDefault) | ||
return | ||
} | ||
|
||
_, err = store.Store.Put(context.TODO(), heketiPrefix+"/"+deviceinfo.NodeID.String()+"/"+deviceName, string(json)) | ||
if err != nil { | ||
log.WithError(err).Error("Couldn't add deviceinfo to store") | ||
restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err.Error(), api.ErrCodeDefault) | ||
return | ||
} | ||
|
||
restutils.SendHTTPResponse(ctx, w, http.StatusOK, deviceinfo) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
package heketi | ||
|
||
import ( | ||
"fmt" | ||
"os/exec" | ||
|
||
heketi "github.com/gluster/glusterd2/plugins/heketi/api" | ||
"github.com/gluster/glusterd2/glusterd2/transaction" | ||
) | ||
|
||
func txnHeketiPrepareDevice(c transaction.TxnCtx) error { | ||
var deviceinfo heketi.DeviceInfo | ||
|
||
if err := c.Get("nodeid", &deviceinfo.NodeID); err != nil { | ||
return err | ||
} | ||
if err := c.Get("devicename", &deviceinfo.DeviceName); err != nil { | ||
return err | ||
} | ||
|
||
|
||
cmd1 := exec.Command("pvcreate", "--metadatasize=128M", "--dataalignment=256K", "/dev/"+deviceinfo.DeviceName) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is pvcreate and vgcreate enough for making the device ready for brick usage? |
||
if err := cmd1.Run(); err != nil { | ||
fmt.Printf("failed to run pvcreate") | ||
} | ||
cmd2 := exec.Command("vgcreate", deviceinfo.DeviceName, "/dev/"+deviceinfo.DeviceName) | ||
if err := cmd2.Run(); err != nil { | ||
fmt.Printf("failed to run vgcreate") | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func txnHeketiCreateBrick(c transaction.TxnCtx) error { | ||
|
||
return nil | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This patch looks incomplete. Correct ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, I am still working on it |
||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this field represent the targetted size of volume like say 30GB or something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, instead of mentioning the bricks we can directly provide size and then the bricks will be allocated.