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 #139 from lpabon/gfs_device_add_pr
Browse files Browse the repository at this point in the history
Device Add and Delete supported on GlusterFS
  • Loading branch information
Luis Pabón committed Aug 16, 2015
2 parents 742a280 + cbedd96 commit 66cb026
Show file tree
Hide file tree
Showing 15 changed files with 484 additions and 208 deletions.
30 changes: 1 addition & 29 deletions apps/glusterfs/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
package glusterfs

import (
"encoding/json"
"fmt"
"github.com/boltdb/bolt"
"github.com/gorilla/mux"
Expand All @@ -41,20 +40,10 @@ const (
)

var (
logger = utils.NewLogger("[heketi]", utils.LEVEL_DEBUG)
logger = utils.NewLogger("[heketi]", utils.LEVEL_INFO)
dbfilename = "heketi.db"
)

type GlusterFSConfig struct {
DBfile string `json:"db"`
Executor string `json:"executor"`
SshConfig sshexec.SshConfig `json:"sshexec"`
}

type ConfigFile struct {
GlusterFS GlusterFSConfig `json:"glusterfs"`
}

type App struct {
asyncManager *rest.AsyncHttpManager
db *bolt.DB
Expand All @@ -66,19 +55,6 @@ type App struct {
xo *mockexec.MockExecutor
}

func loadConfiguration(configIo io.Reader) *GlusterFSConfig {
configParser := json.NewDecoder(configIo)

var config ConfigFile
if err := configParser.Decode(&config); err != nil {
logger.LogError("Unable to parse config file: %v\n",
err.Error())
return nil
}

return &config.GlusterFS
}

func NewApp(configIo io.Reader) *App {
app := &App{}

Expand Down Expand Up @@ -296,7 +272,3 @@ func (a *App) Hello(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
fmt.Fprint(w, "HelloWorld from GlusterFS Application")
}

func (a *App) NotImplemented(w http.ResponseWriter, r *http.Request) {
http.Error(w, "Function not yet supported", http.StatusNotImplemented)
}
46 changes: 46 additions & 0 deletions apps/glusterfs/app_config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//
// Copyright (c) 2015 The heketi Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

package glusterfs

import (
"encoding/json"
"github.com/heketi/heketi/executors/sshexec"
"io"
)

type GlusterFSConfig struct {
DBfile string `json:"db"`
Executor string `json:"executor"`
SshConfig sshexec.SshConfig `json:"sshexec"`
}

type ConfigFile struct {
GlusterFS GlusterFSConfig `json:"glusterfs"`
}

func loadConfiguration(configIo io.Reader) *GlusterFSConfig {
configParser := json.NewDecoder(configIo)

var config ConfigFile
if err := configParser.Decode(&config); err != nil {
logger.LogError("Unable to parse config file: %v\n",
err.Error())
return nil
}

return &config.GlusterFS
}
185 changes: 109 additions & 76 deletions apps/glusterfs/app_device.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import (
"github.com/gorilla/mux"
"github.com/heketi/heketi/utils"
"net/http"
"time"
)

func (a *App) DeviceAdd(w http.ResponseWriter, r *http.Request) {
Expand All @@ -35,14 +34,16 @@ func (a *App) DeviceAdd(w http.ResponseWriter, r *http.Request) {
}

// Check the message has devices
if len(msg.Devices) <= 0 {
if msg.Name == "" {
http.Error(w, "no devices added", http.StatusBadRequest)
return
}

// Check the node is in the db
var node *NodeEntry
err = a.db.View(func(tx *bolt.Tx) error {
_, err := NewNodeEntryFromId(tx, msg.NodeId)
var err error
node, err = NewNodeEntryFromId(tx, msg.NodeId)
if err == ErrNotFound {
http.Error(w, "Node id does not exist", http.StatusNotFound)
return err
Expand All @@ -58,63 +59,59 @@ func (a *App) DeviceAdd(w http.ResponseWriter, r *http.Request) {
}

// Log the devices are being added
logger.Info("Adding devices %+v to node %v", msg.Devices, msg.NodeId)
logger.Info("Adding device %v to node %v", msg.Name, msg.NodeId)

// Add device in an asynchronous function
a.asyncManager.AsyncHttpRedirectFunc(w, r, func() (string, error) {

sg := utils.NewStatusGroup()
for index := range msg.Devices {
sg.Add(1)
// Create device entry
device := NewDeviceEntryFromRequest(&msg)

// Add each drive
go func(dev *Device) {
defer sg.Done()

device := NewDeviceEntryFromRequest(dev, msg.NodeId)

// Pretend work
time.Sleep(1 * time.Second)
// :TODO: Fake work
device.StorageSet(10 * TB)

err := a.db.Update(func(tx *bolt.Tx) error {
node, err := NewNodeEntryFromId(tx, msg.NodeId)
if err != nil {
return err
}
// Setup device on node
info, err := a.executor.DeviceSetup(node.ManageHostName(),
device.Info.Name, device.Info.Id)
if err != nil {
return "", err
}

// Add device to node
node.DeviceAdd(device.Info.Id)
// Create an entry for the device and set the size
device.StorageSet(info.Size)

// Commit
err = node.Save(tx)
if err != nil {
return err
}
// Save on db
err = a.db.Update(func(tx *bolt.Tx) error {
node, err := NewNodeEntryFromId(tx, msg.NodeId)
if err != nil {
return err
}

// Save drive
err = device.Save(tx)
if err != nil {
return err
}
// Add device to node
node.DeviceAdd(device.Info.Id)

return nil
// Commit
err = node.Save(tx)
if err != nil {
return err
}

})
if err != nil {
sg.Err(err)
}
// Save drive
err = device.Save(tx)
if err != nil {
return err
}

logger.Info("Added device %v", dev.Name)
return nil

}(&msg.Devices[index])
})
if err != nil {
return "", err
}

logger.Info("Added device %v", msg.Name)

// Done
// Returning a null string instructs the async manager
// to return http status of 204 (No Content)
return "", sg.Result()
return "", nil
})

}
Expand Down Expand Up @@ -163,59 +160,95 @@ func (a *App) DeviceDelete(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
id := vars["id"]

// Get info from db
err := a.db.Update(func(tx *bolt.Tx) error {

// Check request
var (
device *DeviceEntry
node *NodeEntry
)
err := a.db.View(func(tx *bolt.Tx) error {
var err error
// Access device entry
device, err := NewDeviceEntryFromId(tx, id)
device, err = NewDeviceEntryFromId(tx, id)
if err == ErrNotFound {
http.Error(w, err.Error(), http.StatusNotFound)
return err
} else if err != nil {
logger.Err(err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return err
}

// Access node entry
node, err := NewNodeEntryFromId(tx, device.NodeId)
if err == ErrNotFound {
http.Error(w, "Node id does not exist", http.StatusInternalServerError)
logger.Critical(
"Node id %v pointed to by device %v, but it is not in the db",
device.NodeId,
device.Info.Id)
return err
} else if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return err
// Check if we can delete the device
if !device.IsDeleteOk() {
http.Error(w, ErrConflict.Error(), http.StatusConflict)
return ErrConflict
}

// Delete device from node
node.DeviceDelete(device.Info.Id)

// Save node
node.Save(tx)

// Delete device from db
err = device.Delete(tx)
if err == ErrConflict {
http.Error(w, err.Error(), http.StatusConflict)
return err
} else if err != nil {
// Access node entry
node, err = NewNodeEntryFromId(tx, device.NodeId)
if err != nil {
logger.Err(err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return err
}

return nil

})
if err != nil {
return
}

// Show that the key has been deleted
logger.Info("Deleted node [%s]", id)
// Delete device
logger.Info("Deleting device %v on node %v", device.Info.Id, device.NodeId)
a.asyncManager.AsyncHttpRedirectFunc(w, r, func() (string, error) {

// Teardown device
err := a.executor.DeviceTeardown(node.ManageHostName(),
device.Info.Name, device.Info.Id)
if err != nil {
return "", err
}

// Get info from db
err = a.db.Update(func(tx *bolt.Tx) error {

// Access node entry
node, err := NewNodeEntryFromId(tx, device.NodeId)
if err == ErrNotFound {
logger.Critical(
"Node id %v pointed to by device %v, but it is not in the db",
device.NodeId,
device.Info.Id)
return err
} else if err != nil {
logger.Err(err)
return err
}

// Delete device from node
node.DeviceDelete(device.Info.Id)

// Save node
node.Save(tx)

// Delete device from db
err = device.Delete(tx)
if err != nil {
logger.Err(err)
return err
}

return nil

})
if err != nil {
return "", err
}

// Show that the key has been deleted
logger.Info("Deleted node [%s]", id)

return "", nil
})

// Write msg
w.WriteHeader(http.StatusOK)
}
Loading

0 comments on commit 66cb026

Please sign in to comment.