Skip to content
This repository has been archived by the owner on Jul 6, 2023. It is now read-only.

Commit

Permalink
Merge pull request #147 from lpabon/gfs_volume_pr
Browse files Browse the repository at this point in the history
Volume and Brick GlusterFS support
  • Loading branch information
Luis Pabón committed Aug 21, 2015
2 parents 828b116 + ed5cad5 commit 04145e3
Show file tree
Hide file tree
Showing 18 changed files with 1,287 additions and 186 deletions.
31 changes: 23 additions & 8 deletions apps/glusterfs/app_node.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,13 @@ func (a *App) NodeAdd(w http.ResponseWriter, r *http.Request) {
}

// Get a node in the cluster to execute the Gluster peer command
peer_node, err = cluster.PeerNode(tx)
if err != nil {
logger.Err(err)
return err
// only if there is more than one node
if len(cluster.Info.Nodes) > 0 {
peer_node, err = cluster.NodeEntryFromClusterIndex(tx, 0)
if err != nil {
logger.Err(err)
return err
}
}

return nil
Expand Down Expand Up @@ -212,10 +215,22 @@ func (a *App) NodeDelete(w http.ResponseWriter, r *http.Request) {
}

// Get a node in the cluster to execute the Gluster peer command
peer_node, err = cluster.PeerNode(tx)
if err != nil {
logger.Err(err)
return err
// If it only has one in the list, then there is no need to do a
// peer detach.
if len(cluster.Info.Nodes) > 1 {
for index := range cluster.Info.Nodes {
peer_node, err = cluster.NodeEntryFromClusterIndex(tx, index)
if err != nil {
logger.Err(err)
return err
}

// Cannot peer detach from the same node, we need to execute
// the command from another node
if peer_node.Info.Id != node.Info.Id {
break
}
}
}
return nil
})
Expand Down
189 changes: 189 additions & 0 deletions apps/glusterfs/app_node_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,111 @@ func TestNodeAddBadRequests(t *testing.T) {
tests.Assert(t, r.StatusCode == http.StatusNotFound, r.StatusCode)
}

func TestPeerProbe(t *testing.T) {
tmpfile := tests.Tempfile()
defer os.Remove(tmpfile)

// Create the app
app := NewTestApp(tmpfile)
defer app.Close()
router := mux.NewRouter()
app.SetRoutes(router)

// Setup the server
ts := httptest.NewServer(router)
defer ts.Close()

// ClusterCreate JSON Request
request := []byte(`{
}`)

// Post nothing
r, err := http.Post(ts.URL+"/clusters", "application/json", bytes.NewBuffer(request))
tests.Assert(t, err == nil)
tests.Assert(t, r.StatusCode == http.StatusCreated)
tests.Assert(t, r.Header.Get("Content-Type") == "application/json; charset=UTF-8")

// Read cluster information
var clusterinfo ClusterInfoResponse
err = utils.GetJsonFromResponse(r, &clusterinfo)
tests.Assert(t, err == nil)

// Override mock to check if the peer function was called
probe_called := false
app.xo.MockPeerProbe = func(exec_host, newnode string) error {
probe_called = true
return nil
}

// Create node on this cluster
request = []byte(`{
"cluster" : "` + clusterinfo.Id + `",
"hostnames" : {
"storage" : [ "storage0.hostname.com" ],
"manage" : [ "manage0.hostname.com" ]
},
"zone" : 1
}`)

// Create node
r, err = http.Post(ts.URL+"/nodes", "application/json", bytes.NewBuffer(request))
tests.Assert(t, err == nil)
tests.Assert(t, r.StatusCode == http.StatusAccepted)
location, err := r.Location()
tests.Assert(t, err == nil)

// Query queue until finished
for {
r, err = http.Get(location.String())
tests.Assert(t, err == nil)
tests.Assert(t, r.StatusCode == http.StatusOK)
if r.ContentLength <= 0 {
time.Sleep(time.Millisecond * 10)
continue
} else {
// Should have node information here
tests.Assert(t, r.Header.Get("Content-Type") == "application/json; charset=UTF-8")
tests.Assert(t, err == nil)
break
}
}
tests.Assert(t, probe_called == false)

// Now add another and check that probe was called
request = []byte(`{
"cluster" : "` + clusterinfo.Id + `",
"hostnames" : {
"storage" : [ "storage1.hostname.com" ],
"manage" : [ "manage1.hostname.com" ]
},
"zone" : 1
}`)

// Create node
r, err = http.Post(ts.URL+"/nodes", "application/json", bytes.NewBuffer(request))
tests.Assert(t, err == nil)
tests.Assert(t, r.StatusCode == http.StatusAccepted)
location, err = r.Location()
tests.Assert(t, err == nil)

// Query queue until finished
for {
r, err = http.Get(location.String())
tests.Assert(t, err == nil)
tests.Assert(t, r.StatusCode == http.StatusOK)
if r.ContentLength <= 0 {
time.Sleep(time.Millisecond * 10)
continue
} else {
// Should have node information here
tests.Assert(t, r.Header.Get("Content-Type") == "application/json; charset=UTF-8")
tests.Assert(t, err == nil)
break
}
}
tests.Assert(t, probe_called == true)
}

func TestNodeAddDelete(t *testing.T) {
tmpfile := tests.Tempfile()
defer os.Remove(tmpfile)
Expand Down Expand Up @@ -619,3 +724,87 @@ func TestNodePeerDetachFailure(t *testing.T) {
})
tests.Assert(t, err == nil)
}

func TestNodePeerDetach(t *testing.T) {
tmpfile := tests.Tempfile()
defer os.Remove(tmpfile)

// Create the app
app := NewTestApp(tmpfile)
defer app.Close()
router := mux.NewRouter()
app.SetRoutes(router)

// Setup the server
ts := httptest.NewServer(router)
defer ts.Close()

// Create a cluster. We do not want
// any drives in the node so we can delete easily
err := setupSampleDbWithTopology(app.db,
1, // clusters
4, // nodes_per_cluster
0, // devices_per_node,
50*GB, // disksize)
)
tests.Assert(t, err == nil)

// Setup the mock peer probe to fail
peer_called := false
app.xo.MockPeerDetach = func(exec_host, newnode string) error {
peer_called = true
return nil
}

// get list of nodes
var nodes []string
err = app.db.View(func(tx *bolt.Tx) error {
clusters, err := ClusterList(tx)
if err != nil {
return err
}

cluster, err := NewClusterEntryFromId(tx, clusters[0])
if err != nil {
return err
}

nodes = cluster.Info.Nodes
return nil
})
tests.Assert(t, err == nil)

// Delete nodes, peer detach should be called for each except the last one
for index, node := range nodes {
peer_called = false

// Delete node
req, err := http.NewRequest("DELETE", ts.URL+"/nodes/"+node, nil)
tests.Assert(t, err == nil)
r, err := http.DefaultClient.Do(req)
tests.Assert(t, err == nil)
tests.Assert(t, r.StatusCode == http.StatusAccepted)
location, err := r.Location()
tests.Assert(t, err == nil)

for {
r, err = http.Get(location.String())
tests.Assert(t, err == nil)
if r.Header.Get("X-Pending") == "true" {
tests.Assert(t, r.StatusCode == http.StatusOK)
time.Sleep(time.Millisecond * 10)
} else {
tests.Assert(t, r.StatusCode == http.StatusNoContent)
tests.Assert(t, err == nil)
break
}
}

// Check if detach was called
if index == len(nodes)-1 {
tests.Assert(t, peer_called == false)
} else {
tests.Assert(t, peer_called == true)
}
}
}
8 changes: 4 additions & 4 deletions apps/glusterfs/app_volume.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,9 @@ func (a *App) VolumeCreate(w http.ResponseWriter, r *http.Request) {
a.asyncManager.AsyncHttpRedirectFunc(w, r, func() (string, error) {

logger.Info("Creating volume %v", vol.Info.Id)
err := vol.Create(a.db)
err := vol.Create(a.db, a.executor)
if err != nil {
logger.LogError("Failed to create volume %v", vol.Info.Id)
logger.LogError("Failed to create volume: %v", err)
return "", err
}

Expand Down Expand Up @@ -200,7 +200,7 @@ func (a *App) VolumeDelete(w http.ResponseWriter, r *http.Request) {
a.asyncManager.AsyncHttpRedirectFunc(w, r, func() (string, error) {

// Actually destroy the Volume here
err := volume.Destroy(a.db)
err := volume.Destroy(a.db, a.executor)

// If it fails for some reason, we will need to add to the DB again
// or hold state on the entry "DELETING"
Expand Down Expand Up @@ -266,7 +266,7 @@ func (a *App) VolumeExpand(w http.ResponseWriter, r *http.Request) {
a.asyncManager.AsyncHttpRedirectFunc(w, r, func() (string, error) {

logger.Info("Expanding volume %v", volume.Info.Id)
err := volume.Expand(a.db, msg.Size)
err := volume.Expand(a.db, a.executor, msg.Size)
if err != nil {
logger.LogError("Failed to expand volume %v", volume.Info.Id)
return "", err
Expand Down
6 changes: 3 additions & 3 deletions apps/glusterfs/app_volume_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ func TestVolumeInfo(t *testing.T) {
return v.Save(tx)
})
tests.Assert(t, err == nil)
err = v.Create(app.db)
err = v.Create(app.db, app.executor)
tests.Assert(t, err == nil)

// Now that we have some data in the database, we can
Expand Down Expand Up @@ -502,7 +502,7 @@ func TestVolumeDelete(t *testing.T) {
// Create a volume
v := createSampleVolumeEntry(100)
tests.Assert(t, v != nil)
err = v.Create(app.db)
err = v.Create(app.db, app.executor)
tests.Assert(t, err == nil)

// Delete the volume
Expand Down Expand Up @@ -647,7 +647,7 @@ func TestVolumeExpand(t *testing.T) {
// Create a volume
v := createSampleVolumeEntry(100)
tests.Assert(t, v != nil)
err = v.Create(app.db)
err = v.Create(app.db, app.executor)
tests.Assert(t, err == nil)

// Keep a copy
Expand Down
Loading

0 comments on commit 04145e3

Please sign in to comment.