1
0
mirror of https://github.com/gluster/glusterd2.git synced 2026-02-05 12:45:38 +01:00

Refactor cluster options package

* Merge 'glusterd2/cluster' package into `glusterd2/options` package.
* Rename 'glusterd2/commands/global' to 'glusterd2/commands/options'.

Signed-off-by: Prashanth Pai <ppai@redhat.com>
This commit is contained in:
Prashanth Pai
2018-10-09 12:22:26 +05:30
parent 563476d345
commit edda2c5063
14 changed files with 158 additions and 162 deletions

View File

@@ -71,7 +71,7 @@ func volumeOptionJSONHandler(cmd *cobra.Command, volname string, options []strin
}
if volname == "all" {
err := client.GlobalOptionSet(api.GlobalOptionReq{
err := client.ClusterOptionSet(api.ClusterOptionReq{
Options: vopt,
})
return err

View File

@@ -1,31 +0,0 @@
package cluster
import (
"github.com/gluster/glusterd2/glusterd2/gdctx"
"github.com/gluster/glusterd2/glusterd2/options"
"strconv"
)
// GlobalOptMap contains list of supported cluster-wide options, default values and value types
var GlobalOptMap = map[string]GlobalOption{
"cluster.server-quorum-ratio": {"cluster.server-quorum-ratio", "51", options.OptionTypePercent},
"cluster.shared-storage": {"cluster.shared-storage", "disable", options.OptionTypeBool},
"cluster.op-version": {"cluster.op-version", strconv.Itoa(gdctx.OpVersion), options.OptionTypeInt},
"cluster.max-op-version": {"cluster.max-op-version", strconv.Itoa(gdctx.OpVersion), options.OptionTypeInt},
"cluster.brick-multiplex": {"cluster.brick-multiplex", "disable", options.OptionTypeBool},
"cluster.max-bricks-per-process": {"cluster.max-bricks-per-process", "0", options.OptionTypeInt},
"cluster.localtime-logging": {"cluster.localtime-logging", "disable", options.OptionTypeBool},
}
// Cluster contains cluster-wide attributes
type Cluster struct {
Options map[string]string
}
// GlobalOption reperesents cluster wide options
type GlobalOption struct {
Key string
DefaultValue string
Type options.OptionType
}

View File

@@ -1,40 +0,0 @@
package cluster
import (
"context"
"encoding/json"
"github.com/gluster/glusterd2/glusterd2/store"
"github.com/gluster/glusterd2/pkg/errors"
)
const (
// ClusterPrefix represents the etcd end-point for cluster wide attributes
ClusterPrefix string = "cluster/"
)
// GetCluster gets cluster object instace from store
func GetCluster() (*Cluster, error) {
resp, err := store.Get(context.TODO(), ClusterPrefix)
if err != nil {
return nil, err
}
if resp.Count != 1 {
return nil, errors.ErrClusterNotFound
}
var c Cluster
if err = json.Unmarshal(resp.Kvs[0].Value, &c); err != nil {
return nil, err
}
return &c, nil
}
// UpdateCluster updates cluster instance in etcd store
func UpdateCluster(c *Cluster) error {
data, _ := json.Marshal(c)
_, err := store.Put(context.TODO(), ClusterPrefix, string(data))
return err
}

View File

@@ -2,7 +2,7 @@
package commands
import (
"github.com/gluster/glusterd2/glusterd2/commands/global"
"github.com/gluster/glusterd2/glusterd2/commands/options"
"github.com/gluster/glusterd2/glusterd2/commands/peers"
"github.com/gluster/glusterd2/glusterd2/commands/snapshot"
"github.com/gluster/glusterd2/glusterd2/commands/version"
@@ -24,5 +24,5 @@ var Commands = []Command{
&volumecommands.Command{},
&snapshotcommands.Command{},
&peercommands.Command{},
&globalcommands.Command{},
&optionscommands.Command{},
}

View File

@@ -1,52 +0,0 @@
package globalcommands
import (
"fmt"
"net/http"
"github.com/gluster/glusterd2/glusterd2/cluster"
restutils "github.com/gluster/glusterd2/glusterd2/servers/rest/utils"
"github.com/gluster/glusterd2/pkg/api"
"github.com/gluster/glusterd2/pkg/errors"
)
func getGlobalOptionsHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
c, err := cluster.GetCluster()
// ErrClusterNotFound here implies that no global option has yet been explicitly set. Ignoring it.
if err != nil && err != errors.ErrClusterNotFound {
restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, fmt.Sprintf("Problem retrieving cluster information from etcd store: %s", err.Error()))
return
}
resp := createGlobalOptionsGetResp(c)
restutils.SendHTTPResponse(ctx, w, http.StatusOK, resp)
}
func createGlobalOptionsGetResp(c *cluster.Cluster) []api.GlobalOptionsGetResp {
var resp []api.GlobalOptionsGetResp
for k, v := range cluster.GlobalOptMap {
var val string
var found bool
if c == nil {
val = v.DefaultValue
found = false
} else {
val, found = c.Options[k]
if !found {
val = v.DefaultValue
}
}
resp = append(resp, api.GlobalOptionsGetResp{
Key: k,
Value: val,
DefaultValue: v.DefaultValue,
Modified: found,
})
}
return resp
}

View File

@@ -1,5 +1,5 @@
// Package globalcommands implements the commands to get and set cluster level options
package globalcommands
// Package optionscommands implements the commands to get and set cluster level options
package optionscommands
import (
"github.com/gluster/glusterd2/glusterd2/servers/rest/route"
@@ -13,18 +13,18 @@ type Command struct {
func (c *Command) Routes() route.Routes {
return route.Routes{
route.Route{
Name: "SetGlobalOptions",
Name: "SetClusterOptions",
Method: "POST",
Pattern: "/cluster/options",
Version: 1,
HandlerFunc: setGlobalOptionsHandler,
HandlerFunc: setClusterOptionsHandler,
},
route.Route{
Name: "GetGlobalOptions",
Name: "GetClusterOptions",
Method: "GET",
Pattern: "/cluster/options",
Version: 1,
HandlerFunc: getGlobalOptionsHandler,
HandlerFunc: getClusterOptionsHandler,
},
}
}

View File

@@ -0,0 +1,50 @@
package optionscommands
import (
"net/http"
"github.com/gluster/glusterd2/glusterd2/options"
restutils "github.com/gluster/glusterd2/glusterd2/servers/rest/utils"
"github.com/gluster/glusterd2/pkg/api"
"github.com/gluster/glusterd2/pkg/errors"
)
func getClusterOptionsHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
c, err := options.GetClusterOptions()
if err != nil && err != errors.ErrClusterOptionsNotFound {
restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err)
return
}
resp := createClusterOptionsResp(c)
restutils.SendHTTPResponse(ctx, w, http.StatusOK, resp)
}
func createClusterOptionsResp(c *options.ClusterOptions) []api.ClusterOptionsResp {
var resp []api.ClusterOptionsResp
for k, v := range options.ClusterOptMap {
var val string
var found bool
if c == nil {
val = v.DefaultValue
found = false
} else {
val, found = c.Options[k]
if !found {
val = v.DefaultValue
}
}
resp = append(resp, api.ClusterOptionsResp{
Key: k,
Value: val,
DefaultValue: v.DefaultValue,
Modified: found,
})
}
return resp
}

View File

@@ -1,47 +1,48 @@
package globalcommands
package optionscommands
import (
"fmt"
"net/http"
"github.com/gluster/glusterd2/glusterd2/cluster"
"github.com/gluster/glusterd2/glusterd2/options"
restutils "github.com/gluster/glusterd2/glusterd2/servers/rest/utils"
"github.com/gluster/glusterd2/pkg/api"
"github.com/gluster/glusterd2/pkg/errors"
)
func setGlobalOptionsHandler(w http.ResponseWriter, r *http.Request) {
func setClusterOptionsHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var req api.GlobalOptionReq
var req api.ClusterOptionReq
if err := restutils.UnmarshalRequest(r, &req); err != nil {
restutils.SendHTTPError(ctx, w, http.StatusBadRequest, errors.ErrJSONParsingFailed)
return
}
c, err := cluster.GetCluster()
// ErrClusterNotFound here implies that no global option has yet been explicitly set. Ignoring it.
if err != nil && err != errors.ErrClusterNotFound {
restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, fmt.Sprintf("Problem retrieving cluster information from etcd store: %s", err.Error()))
// TODO: Take lock here
c, err := options.GetClusterOptions()
if err != nil && err != errors.ErrClusterOptionsNotFound {
restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err)
return
}
for k, v := range req.Options {
if _, found := cluster.GlobalOptMap[k]; found {
if _, found := options.ClusterOptMap[k]; found {
// TODO validate the value type for global option
if c == nil {
c = new(cluster.Cluster)
c = new(options.ClusterOptions)
c.Options = make(map[string]string)
}
c.Options[k] = v
} else {
restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, fmt.Sprintf("Invalid global option: %s", k))
continue
return
}
}
if err := cluster.UpdateCluster(c); err != nil {
if err := options.UpdateClusterOptions(c); err != nil {
restutils.SendHTTPError(ctx, w, http.StatusInternalServerError,
fmt.Sprintf("Failed to update store with cluster attributes %s", err.Error()))
return

View File

@@ -0,0 +1,69 @@
package options
import (
"context"
"encoding/json"
"github.com/gluster/glusterd2/glusterd2/gdctx"
"github.com/gluster/glusterd2/glusterd2/store"
"github.com/gluster/glusterd2/pkg/errors"
"strconv"
)
const (
clusterOptionsKey string = "clusteroptions"
)
// ClusterOption reperesents a single cluster wide option
type ClusterOption struct {
Key string
DefaultValue string
Type OptionType
}
// ClusterOptMap contains list of supported cluster-wide options, default values and value types
var ClusterOptMap = map[string]ClusterOption{
"cluster.server-quorum-ratio": {"cluster.server-quorum-ratio", "51", OptionTypePercent},
"cluster.shared-storage": {"cluster.shared-storage", "disable", OptionTypeBool},
"cluster.op-version": {"cluster.op-version", strconv.Itoa(gdctx.OpVersion), OptionTypeInt},
"cluster.max-op-version": {"cluster.max-op-version", strconv.Itoa(gdctx.OpVersion), OptionTypeInt},
"cluster.brick-multiplex": {"cluster.brick-multiplex", "disable", OptionTypeBool},
"cluster.max-bricks-per-process": {"cluster.max-bricks-per-process", "0", OptionTypeInt},
"cluster.localtime-logging": {"cluster.localtime-logging", "disable", OptionTypeBool},
}
// ClusterOptions contains cluster-wide attributes
type ClusterOptions struct {
Options map[string]string
}
// GetClusterOptions gets cluster options from store.
func GetClusterOptions() (*ClusterOptions, error) {
resp, err := store.Get(context.TODO(), clusterOptionsKey)
if err != nil {
return nil, err
}
if resp.Count != 1 {
return nil, errors.ErrClusterOptionsNotFound
}
var c ClusterOptions
if err = json.Unmarshal(resp.Kvs[0].Value, &c); err != nil {
return nil, err
}
return &c, nil
}
// UpdateClusterOptions stores cluster options in store.
func UpdateClusterOptions(c *ClusterOptions) error {
b, err := json.Marshal(c)
if err != nil {
return err
}
_, err = store.Put(context.TODO(), clusterOptionsKey, string(b))
return err
}

View File

@@ -0,0 +1,14 @@
package api
// ClusterOptionReq represents an incoming request to set cluster level options
type ClusterOptionReq struct {
Options map[string]string `json:"options"`
}
// ClusterOptionsResp contains details for global options
type ClusterOptionsResp struct {
Key string `json:"key"`
Value string `json:"value"`
DefaultValue string `json:"default"`
Modified bool `json:"modified"`
}

View File

@@ -1,6 +0,0 @@
package api
// GlobalOptionReq represents an incoming request to set cluster level options
type GlobalOptionReq struct {
Options map[string]string `json:"options"`
}

View File

@@ -1,9 +0,0 @@
package api
// GlobalOptionsGetResp contains details for global options
type GlobalOptionsGetResp struct {
Key string `json:"key"`
Value string `json:"value"`
DefaultValue string `json:"default"`
Modified bool `json:"modified"`
}

View File

@@ -41,7 +41,7 @@ var (
ErrUnknownValue = errors.New("unknown value specified")
ErrGetFailed = errors.New("failed to get value from the store")
ErrUnmarshallFailed = errors.New("failed to unmarshall from json")
ErrClusterNotFound = errors.New("cluster instance not found in store")
ErrClusterOptionsNotFound = errors.New("cluster options not found in store")
ErrDuplicateBrickPath = errors.New("duplicate brick entry")
ErrRestrictedKeyFound = errors.New("key names starting with '_' are restricted in metadata field")
ErrVolFileNotFound = errors.New("volume file not found")

View File

@@ -117,8 +117,8 @@ func (c *Client) VolumeSet(volname string, req api.VolOptionReq) error {
return err
}
// GlobalOptionSet sets cluster level options
func (c *Client) GlobalOptionSet(req api.GlobalOptionReq) error {
// ClusterOptionSet sets cluster level options
func (c *Client) ClusterOptionSet(req api.ClusterOptionReq) error {
url := fmt.Sprintf("/v1/cluster/options")
return c.post(url, req, http.StatusOK, nil)
}