From f5fca2f118660f2f9dd1e4a2df31c2385a4fc125 Mon Sep 17 00:00:00 2001 From: akutz Date: Wed, 2 Dec 2015 21:01:49 -0600 Subject: [PATCH] Added /libStorage/config This patch adds the path /libstorage/config for querying the active server configuration. Additionally, the configuration properties have been altered somewhat. What was once "libstorage.service" is now "libstorage.server". --- client/client.go | 11 ++--- libstorage.go | 20 ++++----- libstorage_test.go | 71 ++++++++++++++++++------------ service/server/handlers/logging.go | 63 +++++++++----------------- service/server/server.go | 64 +++++++++++++++++++++------ service/service.go | 14 +++--- 6 files changed, 135 insertions(+), 108 deletions(-) diff --git a/client/client.go b/client/client.go index 5147a4fd..8f6de947 100644 --- a/client/client.go +++ b/client/client.go @@ -168,11 +168,12 @@ func Dial( } log.WithField("host", host).Debug("got libStorage host") - serverName := config.GetString("libstorage.server") - if serverName == "" { - return nil, goof.New("libstorage.server is required") + serviceName := config.GetString("libstorage.service.name") + if serviceName == "" { + return nil, goof.New("libstorage.service.name is required") } - log.WithField("server", serverName).Debug("got libStorage server name") + log.WithField( + "serviceName", serviceName).Debug("got libStorage serviceName name") if ctx == nil { log.Debug("created empty context for dialer") @@ -188,7 +189,7 @@ func Dial( return nil, goof.WithField("netProto", netProto, "tcp protocol only") } - c.url = fmt.Sprintf("http://%s/libStorage/servers/%s", laddr, serverName) + c.url = fmt.Sprintf("http://%s/libStorage/services/%s", laddr, serviceName) log.WithField("url", c.url).Debug("got libStorage service URL") if err := c.initClientTool(ctx); err != nil { diff --git a/libstorage.go b/libstorage.go index 1cb840bf..eba25c12 100644 --- a/libstorage.go +++ b/libstorage.go @@ -74,16 +74,12 @@ func Dial(ctx context.Context, config gofig.Config) (client.Client, error) { func registerGofigDefaults() { r := gofig.NewRegistration("libStorage") r.Key(gofig.String, "", "", "", "libstorage.host") - r.Key(gofig.String, "", "", "", "libstorage.server") - r.Key(gofig.String, "", "", "", "libstorage.drivers") - + r.Key(gofig.String, "", "", "", "libstorage.service") + r.Key(gofig.String, "", "", "", "libstorage.driver") r.Key(gofig.Bool, "", false, "", "libstorage.profiles.enabled") r.Key(gofig.Bool, "", false, "", "libstorage.profiles.client") r.Key(gofig.String, "", "local=127.0.0.1", "", "libstorage.profiles.groups") - r.Key(gofig.Int, "", 60, "", "libstorage.service.readtimeout") - r.Key(gofig.Int, "", 60, "", "libstorage.service.writetimeout") - r.Key(gofig.String, "", "/proc/partitions", "", "libstorage.client.localdevicesfile") @@ -96,14 +92,16 @@ func registerGofigDefaults() { r.Key(gofig.Bool, "", false, "", "libstorage.client.http.logging.logresponse") - r.Key(gofig.Bool, "", false, "", "libstorage.service.http.logging.enabled") - r.Key(gofig.String, "", "", "", "libstorage.service.http.logging.out") - r.Key(gofig.String, "", "", "", "libstorage.service.http.logging.err") + r.Key(gofig.Int, "", 60, "", "libstorage.server.readtimeout") + r.Key(gofig.Int, "", 60, "", "libstorage.server.writetimeout") + r.Key(gofig.Bool, "", false, "", "libstorage.server.http.logging.enabled") + r.Key(gofig.String, "", "", "", "libstorage.server.http.logging.out") + r.Key(gofig.String, "", "", "", "libstorage.server.http.logging.err") r.Key(gofig.Bool, "", - false, "", "libstorage.service.http.logging.logrequest") + false, "", "libstorage.server.http.logging.logrequest") r.Key(gofig.Bool, "", - false, "", "libstorage.service.http.logging.logresponse") + false, "", "libstorage.server.http.logging.logresponse") gofig.Register(r) } diff --git a/libstorage_test.go b/libstorage_test.go index d150a788..cb381639 100644 --- a/libstorage_test.go +++ b/libstorage_test.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "io/ioutil" + "net/http" "os" "testing" @@ -23,9 +24,9 @@ const ( localDevicesFile = "/tmp/libstorage/partitions" clientToolDir = "/tmp/libstorage/bin" - testServer1Name = "testServer1" - testServer2Name = "testServer2" - testServer3Name = "testServer3" + testServer1Name = "testService1" + testServer2Name = "testService2" + testServer3Name = "testService3" mockDriver1Name = "mockDriver1" mockDriver2Name = "mockDriver2" @@ -54,18 +55,19 @@ func newMockDriver3(config gofig.Config) driver.Driver { return d } -func getConfig(host, server string, t *testing.T) gofig.Config { +func getConfig(host, service string, t *testing.T) gofig.Config { if host == "" { host = "tcp://127.0.0.1:0" } - if server == "" { - server = "testServer2" + if service == "" { + service = testServer2Name } config := gofig.New() configYaml := fmt.Sprintf(` libstorage: host: %s - server: %s + service: %s + driver: invalidDriverName profiles: enabled: true groups: @@ -73,18 +75,8 @@ libstorage: client: tooldir: %s localdevicesfile: %s - http: - logging: - enabled: false - logrequest: false - logresponse: false - service: - http: - logging: - enabled: false - logrequest: false - logresponse: false - servers: + server: + services: %s: libstorage: driver: %s @@ -99,13 +91,12 @@ libstorage: libstorage: driver: %s `, - host, server, + host, service, clientToolDir, localDevicesFile, testServer1Name, mockDriver1Name, testServer2Name, mockDriver2Name, testServer3Name, mockDriver3Name) - t.Log(configYaml) configYamlBuf := []byte(configYaml) if err := config.ReadConfig(bytes.NewReader(configYamlBuf)); err != nil { panic(err) @@ -155,21 +146,45 @@ func TestMain(m *testing.M) { os.Exit(exitCode) } +func TestGetServiceConfig(t *testing.T) { + config := getConfig("", "", t) + if err := Serve(config); err != nil { + t.Fatalf("error serving libStorage service %v", err) + } + + host := config.GetString("libstorage.host") + _, laddr, err := gotil.ParseAddress(host) + if err != nil { + t.Fatal(err) + } + + url := fmt.Sprintf("http://%s/libStorage/config", laddr) + res, err := http.Get(url) + if err != nil { + t.Fatal(err) + } + b, err := ioutil.ReadAll(res.Body) + if err != nil { + t.Fatal(err) + } + t.Log(string(b)) +} + func TestGetServiceInfo(t *testing.T) { testGetServiceInfo(testServer1Name, mockDriver1Name, t) testGetServiceInfo(testServer2Name, mockDriver2Name, t) testGetServiceInfo(testServer3Name, mockDriver3Name, t) } -func testGetServiceInfo(server, driver string, t *testing.T) { - config := getConfig("", server, t) +func testGetServiceInfo(service, driver string, t *testing.T) { + config := getConfig("", service, t) ctx, c := mustGetClient(config, t) args := &api.GetServiceInfoArgs{} info, err := c.GetServiceInfo(ctx, args) if err != nil { t.Fatal(err) } - assert.Equal(t, server, info.Name) + assert.Equal(t, service, info.Name) assert.Equal(t, driver, info.Driver) assert.Equal(t, 3, len(info.RegisteredDrivers)) assert.True(t, gotil.StringInSlice(mockDriver1Name, info.RegisteredDrivers)) @@ -189,8 +204,8 @@ func TestGetVolumeMappingServerAndDriver3(t *testing.T) { testGetVolumeMapping(testServer3Name, mockDriver3Name, t) } -func testGetVolumeMapping(server, driver string, t *testing.T) { - config := getConfig("", server, t) +func testGetVolumeMapping(service, driver string, t *testing.T) { + config := getConfig("", service, t) ctx, c := mustGetClient(config, t) args := &api.GetVolumeMappingArgs{} bds, err := c.GetVolumeMapping(ctx, args) @@ -217,8 +232,8 @@ func TestGetNextAvailableDeviceNameServerAndDriver3(t *testing.T) { testGetNextAvailableDeviceName(testServer3Name, mockDriver3Name, t) } -func testGetNextAvailableDeviceName(server, driver string, t *testing.T) { - config := getConfig("", server, t) +func testGetNextAvailableDeviceName(service, driver string, t *testing.T) { + config := getConfig("", service, t) ctx, c := mustGetClient(config, t) name, err := c.GetNextAvailableDeviceName( ctx, &api.GetNextAvailableDeviceNameArgs{}) diff --git a/service/server/handlers/logging.go b/service/server/handlers/logging.go index 775a8193..b693b312 100644 --- a/service/server/handlers/logging.go +++ b/service/server/handlers/logging.go @@ -26,35 +26,32 @@ const ( // LoggingHandler is an HTTP logging handler for the libStorage service // endpoint. type LoggingHandler struct { - Enabled bool - LogRequests bool - LogResponses bool - StdOut io.WriteCloser - StdErr io.WriteCloser - - handler http.Handler - config gofig.Config + logRequests bool + logResponses bool + stdOut io.WriteCloser + stdErr io.WriteCloser + handler http.Handler + config gofig.Config } // NewLoggingHandler instantiates a new instance of the LoggingHandler type. func NewLoggingHandler( + stdOut, stdErr io.WriteCloser, handler http.Handler, config gofig.Config) *LoggingHandler { h := &LoggingHandler{ handler: handler, config: config, + stdOut: stdOut, + stdErr: stdErr, } - h.Enabled = config.GetBool("libstorage.service.http.logging.enabled") - if h.Enabled { - h.StdOut = GetLogIO( - "libstorage.service.http.logging.out", config) - h.LogRequests = config.GetBool( - "libstorage.service.http.logging.logrequest") - h.LogResponses = config.GetBool( - "libstorage.service.http.logging.logresponse") - } + h.logRequests = config.GetBool( + "libstorage.server.http.logging.logrequest") + h.logResponses = config.GetBool( + "libstorage.server.http.logging.logresponse") + return h } @@ -81,14 +78,9 @@ func GetLogIO( // ServeHTTP serves the HTTP request and writes the response. func (h *LoggingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { - if !h.Enabled { - h.handler.ServeHTTP(w, req) - return - } - var err error var reqDump []byte - if h.LogRequests { + if h.logRequests { if reqDump, err = httputil.DumpRequest(req, true); err != nil { log.Error(err) } @@ -97,11 +89,11 @@ func (h *LoggingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { rec := httptest.NewRecorder() h.handler.ServeHTTP(rec, req) - logRequest(h.LogRequests, h.StdOut, rec, req, reqDump) - if h.LogResponses { - fmt.Fprintln(h.StdOut, "") - logResponse(h.StdOut, rec, req) - fmt.Fprintln(h.StdOut, "") + logRequest(h.logRequests, h.stdOut, rec, req, reqDump) + if h.logResponses { + fmt.Fprintln(h.stdOut, "") + logResponse(h.stdOut, rec, req) + fmt.Fprintln(h.stdOut, "") } w.WriteHeader(rec.Code) @@ -111,21 +103,6 @@ func (h *LoggingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { w.Write(rec.Body.Bytes()) } -// Close closes the resources associated with the handler. -func (h *LoggingHandler) Close() error { - if h.StdOut != nil { - if err := h.StdOut.Close(); err != nil { - return err - } - } - if h.StdErr != nil { - if err := h.StdErr.Close(); err != nil { - return err - } - } - return nil -} - func logRequest( l bool, w io.Writer, diff --git a/service/server/server.go b/service/server/server.go index c52b7752..4cca4d8f 100644 --- a/service/server/server.go +++ b/service/server/server.go @@ -4,6 +4,7 @@ import ( "encoding/base64" "encoding/json" "fmt" + "io" golog "log" "net" "net/http" @@ -31,9 +32,9 @@ var ( // ServiceInfo is information used to serve a service. type ServiceInfo struct { - Name string - Service api.ServiceEndpoint - Config gofig.Config + Name string `json:"name"` + Service api.ServiceEndpoint `json:"-"` + Config gofig.Config `json:"config"` server *rpc.Server } @@ -53,16 +54,47 @@ func Serve( } log.WithField("host", host).Debug("ready to listen") + doLogs := config.GetBool("libstorage.server.http.logging.enabled") + var stdOut, stdErr io.WriteCloser + if doLogs { + stdOut = handlers.GetLogIO( + "libstorage.server.http.logging.out", config) + stdErr = handlers.GetLogIO( + "libstorage.server.http.logging.err", config) + } + r := mux.NewRouter() - httpHandler := http.HandlerFunc( + var configHandler, serversHandler http.Handler + + configHandler = http.HandlerFunc( + func(w http.ResponseWriter, req *http.Request) { + w.WriteHeader(http.StatusOK) + w.Header().Add("Content-Type", "application/json") + + configJSON, _ := json.MarshalIndent(config, "", " ") + w.Write(configJSON) + }) + + serversHandler = http.HandlerFunc( func(w http.ResponseWriter, req *http.Request) { vars := mux.Vars(req) name := vars["name"] serviceInfo[name].server.ServeHTTP(w, req) }) - loggingHandler := handlers.NewLoggingHandler(httpHandler, config) - r.Handle("/libStorage/servers/{name}", - gcontext.ClearHandler(loggingHandler)) + + if doLogs { + configHandler = handlers.NewLoggingHandler( + stdOut, stdErr, configHandler, config) + + serversHandler = handlers.NewLoggingHandler( + stdOut, stdErr, serversHandler, config) + } + + r.Handle("/libStorage/config", + gcontext.ClearHandler(configHandler)) + + r.Handle("/libStorage/services/{name}", + gcontext.ClearHandler(serversHandler)) hs := &http.Server{ Addr: laddr, @@ -72,14 +104,17 @@ func Serve( MaxHeaderBytes: 1 << 20, } - if loggingHandler.Enabled { - hs.ErrorLog = golog.New(loggingHandler.StdErr, "", 0) + if doLogs { + hs.ErrorLog = golog.New(stdErr, "", 0) } go func() { defer func() { - if err := loggingHandler.Close(); err != nil { - log.Error(err) + if stdOut != nil { + stdOut.Close() + } + if stdErr != nil { + stdErr.Close() } r := recover() @@ -101,7 +136,8 @@ func Serve( if updatedHost != host { host = updatedHost - config.Set("libstorage.host", host) + lsmap := config.Get("libstorage").(map[string]interface{}) + lsmap["host"] = host } log.WithField("host", host).Debug("listening") @@ -178,7 +214,7 @@ func initInstanceID(req *http.Request) { } func getReadTimeout(config gofig.Config) time.Duration { - t := config.GetInt("libstorage.service.readtimeout") + t := config.GetInt("libstorage.server.readtimeout") if t == 0 { return 60 } @@ -186,7 +222,7 @@ func getReadTimeout(config gofig.Config) time.Duration { } func getWriteTimeout(config gofig.Config) time.Duration { - t := config.GetInt("libstorage.service.writetimeout") + t := config.GetInt("libstorage.server.writetimeout") if t == 0 { return 60 } diff --git a/service/service.go b/service/service.go index 393aa7f4..93526b5f 100644 --- a/service/service.go +++ b/service/service.go @@ -61,15 +61,15 @@ func Serve(config gofig.Config) error { si := map[string]*server.ServiceInfo{} - servers := config.Get("libstorage.service.servers") - serversMap := servers.(map[string]interface{}) - log.WithField("count", len(serversMap)).Debug("got servers map") + services := config.Get("libstorage.server.services") + servicesMap := services.(map[string]interface{}) + log.WithField("count", len(servicesMap)).Debug("got services map") - for name := range serversMap { - log.WithField("name", name).Debug("processing server config") + for name := range servicesMap { + log.WithField("name", name).Debug("processing service config") - scope := fmt.Sprintf("libstorage.service.servers.%s", name) - log.WithField("scope", scope).Debug("getting scoped config for server") + scope := fmt.Sprintf("libstorage.server.services.%s", name) + log.WithField("scope", scope).Debug("getting scoped config for service") sc := config.Scope(scope) service, err := newService(name, sc)