Skip to content

Commit 161550f

Browse files
author
Oshank Kumar
committed
gd2 plugin: added a plugin for block volume management
- added APIs for creation,deleting and listing block volumes. - added pluggable interface for block volume providers. Refer Design Doc: gluster#1319 Signed-off-by: Oshank Kumar <[email protected]>
1 parent d996927 commit 161550f

File tree

14 files changed

+1372
-50
lines changed

14 files changed

+1372
-50
lines changed

glusterd2/commands/volumes/volume-create.go

Lines changed: 57 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package volumecommands
22

33
import (
4+
"context"
45
"errors"
56
"net/http"
67
"path/filepath"
@@ -99,67 +100,93 @@ func registerVolCreateStepFuncs() {
99100
}
100101

101102
func volumeCreateHandler(w http.ResponseWriter, r *http.Request) {
103+
var (
104+
err error
105+
req api.VolCreateReq
106+
ctx = r.Context()
107+
logger = gdctx.GetReqLogger(ctx)
108+
)
102109

103-
ctx := r.Context()
104-
ctx, span := trace.StartSpan(ctx, "/volumeCreateHandler")
105-
defer span.End()
106-
107-
logger := gdctx.GetReqLogger(ctx)
108-
var err error
109-
110-
var req api.VolCreateReq
111110
if err := restutils.UnmarshalRequest(r, &req); err != nil {
112111
restutils.SendHTTPError(ctx, w, http.StatusBadRequest, gderrors.ErrJSONParsingFailed)
113112
return
114113
}
115114

116-
if err := validateVolCreateReq(&req); err != nil {
117-
restutils.SendHTTPError(ctx, w, http.StatusBadRequest, err)
115+
if status, err := CreateVolume(ctx, req); err != nil {
116+
restutils.SendHTTPError(ctx, w, status, err)
117+
return
118+
}
119+
120+
volinfo, err := volume.GetVolume(req.Name)
121+
if err != nil {
122+
// FIXME: If volume was created successfully in the txn above and
123+
// then the store goes down by the time we reach here, what do
124+
// we return to the client ?
125+
restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err)
118126
return
119127
}
120128

129+
logger.WithField("volume-name", volinfo.Name).Info("new volume created")
130+
events.Broadcast(volume.NewEvent(volume.EventVolumeCreated, volinfo))
131+
132+
resp := createVolumeCreateResp(volinfo)
133+
restutils.SetLocationHeader(r, w, volinfo.Name)
134+
restutils.SendHTTPResponse(ctx, w, http.StatusCreated, resp)
135+
}
136+
137+
func createVolumeCreateResp(v *volume.Volinfo) *api.VolumeCreateResp {
138+
return (*api.VolumeCreateResp)(volume.CreateVolumeInfoResp(v))
139+
}
140+
141+
// CreateVolume will create a volume. It returns http StatusCode to be sent to client
142+
// and any error if occurred.
143+
func CreateVolume(ctx context.Context, req api.VolCreateReq) (status int, err error) {
144+
ctx, span := trace.StartSpan(ctx, "/volumeCreateHandler")
145+
defer span.End()
146+
147+
if err := validateVolCreateReq(&req); err != nil {
148+
return http.StatusBadRequest, err
149+
}
150+
121151
if req.Size > 0 {
122152
applyDefaults(&req)
123153

124154
if req.SnapshotReserveFactor < 1 {
125-
restutils.SendHTTPError(ctx, w, http.StatusBadRequest,
126-
errors.New("invalid snapshot reserve factor"))
127-
return
155+
return http.StatusBadRequest, errors.New("invalid snapshot reserve factor")
156+
128157
}
129158

130159
if err := bricksplanner.PlanBricks(&req); err != nil {
131-
restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err)
132-
return
160+
return http.StatusInternalServerError, err
161+
133162
}
134163
} else {
135164
if err := checkDupBrickEntryVolCreate(req); err != nil {
136-
restutils.SendHTTPError(ctx, w, http.StatusBadRequest, err)
137-
return
165+
return http.StatusBadRequest, err
166+
138167
}
139168
}
140169

141170
req.Options, err = expandGroupOptions(req.Options)
142171
if err != nil {
143-
restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err)
144-
return
172+
return http.StatusInternalServerError, err
173+
145174
}
146175

147176
if err := validateOptions(req.Options, req.VolOptionFlags); err != nil {
148-
restutils.SendHTTPError(ctx, w, http.StatusBadRequest, err)
149-
return
177+
return http.StatusBadRequest, err
178+
150179
}
151180

152181
nodes, err := req.Nodes()
153182
if err != nil {
154-
restutils.SendHTTPError(ctx, w, http.StatusBadRequest, err)
155-
return
183+
return http.StatusBadRequest, err
184+
156185
}
157186

158187
txn, err := transaction.NewTxnWithLocks(ctx, req.Name)
159188
if err != nil {
160-
status, err := restutils.ErrToStatusCode(err)
161-
restutils.SendHTTPError(ctx, w, status, err)
162-
return
189+
return restutils.ErrToStatusCode(err)
163190
}
164191
defer txn.Done()
165192

@@ -191,8 +218,8 @@ func volumeCreateHandler(w http.ResponseWriter, r *http.Request) {
191218
}
192219

193220
if err := txn.Ctx.Set("req", &req); err != nil {
194-
restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err)
195-
return
221+
return http.StatusInternalServerError, err
222+
196223
}
197224

198225
// Add attributes to the span with info that can be viewed along with traces.
@@ -203,28 +230,8 @@ func volumeCreateHandler(w http.ResponseWriter, r *http.Request) {
203230
)
204231

205232
if err := txn.Do(); err != nil {
206-
status, err := restutils.ErrToStatusCode(err)
207-
restutils.SendHTTPError(ctx, w, status, err)
208-
return
233+
return restutils.ErrToStatusCode(err)
209234
}
210235

211-
volinfo, err := volume.GetVolume(req.Name)
212-
if err != nil {
213-
// FIXME: If volume was created successfully in the txn above and
214-
// then the store goes down by the time we reach here, what do
215-
// we return to the client ?
216-
restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err)
217-
return
218-
}
219-
220-
logger.WithField("volume-name", volinfo.Name).Info("new volume created")
221-
events.Broadcast(volume.NewEvent(volume.EventVolumeCreated, volinfo))
222-
223-
resp := createVolumeCreateResp(volinfo)
224-
restutils.SetLocationHeader(r, w, volinfo.Name)
225-
restutils.SendHTTPResponse(ctx, w, http.StatusCreated, resp)
226-
}
227-
228-
func createVolumeCreateResp(v *volume.Volinfo) *api.VolumeCreateResp {
229-
return (*api.VolumeCreateResp)(volume.CreateVolumeInfoResp(v))
236+
return http.StatusCreated, nil
230237
}

glusterd2/plugin/plugins.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ package plugin
44

55
import (
66
"github.com/gluster/glusterd2/plugins/bitrot"
7+
"github.com/gluster/glusterd2/plugins/blockvolume"
78
"github.com/gluster/glusterd2/plugins/device"
89
"github.com/gluster/glusterd2/plugins/events"
910
"github.com/gluster/glusterd2/plugins/georeplication"
@@ -25,4 +26,5 @@ var PluginsList = []GlusterdPlugin{
2526
&glustershd.Plugin{},
2627
&device.Plugin{},
2728
&rebalance.Plugin{},
29+
&blockvolume.BlockVolume{},
2830
}

glusterd2/volume/filters.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package volume
2+
3+
const (
4+
// BlockHosted is plugin name for FilterBlockHostedVolumes
5+
BlockHosted = "block-hosted"
6+
)
7+
8+
// Filter will receive a slice of *Volinfo and filters out the undesired one and return slice of desired one only
9+
type Filter func([]*Volinfo) []*Volinfo
10+
11+
var filters = make(map[string]Filter)
12+
13+
// InstallFilter will register a custom Filter
14+
func InstallFilter(name string, f Filter) {
15+
filters[name] = f
16+
}
17+
18+
// ApplyFilters applies all registered filters passed in the args to a slice of *Volinfo
19+
func ApplyFilters(volumes []*Volinfo, names ...string) []*Volinfo {
20+
for _, name := range names {
21+
if filter, found := filters[name]; found {
22+
volumes = filter(volumes)
23+
}
24+
}
25+
return volumes
26+
}
27+
28+
// ApplyCustomFilters applies all custom filter to a slice of *Volinfo
29+
func ApplyCustomFilters(volumes []*Volinfo, filters ...Filter) []*Volinfo {
30+
for _, filter := range filters {
31+
volumes = filter(volumes)
32+
}
33+
34+
return volumes
35+
}
36+
37+
// FilterBlockHostedVolumes filters out volume which are suitable for hosting block volume
38+
func FilterBlockHostedVolumes(volumes []*Volinfo) []*Volinfo {
39+
var volInfos []*Volinfo
40+
for _, volume := range volumes {
41+
val, found := volume.Metadata["_block-hosting"]
42+
if found && val == "yes" {
43+
volInfos = append(volInfos, volume)
44+
}
45+
}
46+
return volInfos
47+
}
48+
49+
func init() {
50+
InstallFilter(BlockHosted, FilterBlockHostedVolumes)
51+
}

0 commit comments

Comments
 (0)