From 7a42df2cb55d7766de25b166b3d7daad6d8ccd2e Mon Sep 17 00:00:00 2001 From: Tom McSweeney Date: Fri, 22 Apr 2016 16:26:21 -0700 Subject: [PATCH] Fixes #874: fixed panic in snapd when sections of the configuration file are all commented out (at a top-level) --- control/config.go | 46 +++++++++++++++++++++++++++++++++++++++ mgmt/rest/server.go | 50 +++++++++++++++++++++++++++++++++++++++++++ mgmt/tribe/config.go | 43 +++++++++++++++++++++++++++++++++++++ scheduler/config.go | 32 +++++++++++++++++++++++++++ snapd.go | 51 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 222 insertions(+) diff --git a/control/config.go b/control/config.go index 6b36a3fe4..e88b7ea0b 100644 --- a/control/config.go +++ b/control/config.go @@ -63,6 +63,9 @@ type pluginConfigItem struct { } // holds the configuration passed in through the SNAP config file +// Note: if this struct is modified, then the switch statement in the +// UnmarshalJSON method in this same file needs to be modified to +// match the field mapping that is defined here type Config struct { MaxRunningPlugins int `json:"max_running_plugins,omitempty"yaml:"max_running_plugins,omitempty"` PluginTrust int `json:"plugin_trust_level,omitempty"yaml:"plugin_trust_level,omitempty"` @@ -84,6 +87,49 @@ func GetDefaultConfig() *Config { } } +// UnmarshalJSON unmarshals valid json into a Config. An example Config can be found +// at github.com/intelsdi-x/snap/blob/master/examples/configs/snap-config-sample.json +func (c *Config) UnmarshalJSON(data []byte) error { + // construct a map of strings to json.RawMessages (to defer the parsing of individual + // fields from the unmarshalled interface until later) and unmarshal the input + // byte array into that map + t := make(map[string]json.RawMessage) + if err := json.Unmarshal(data, &t); err != nil { + return err + } + // loop through the individual map elements, parse each in turn, and set + // the appropriate field in this configuration + for k, v := range t { + switch k { + case "max_running_plugins": + if err := json.Unmarshal(v, &(c.MaxRunningPlugins)); err != nil { + return err + } + case "plugin_trust_level": + if err := json.Unmarshal(v, &(c.PluginTrust)); err != nil { + return err + } + case "auto_discover_path": + if err := json.Unmarshal(v, &(c.AutoDiscoverPath)); err != nil { + return err + } + case "keyring_paths": + if err := json.Unmarshal(v, &(c.KeyringPaths)); err != nil { + return err + } + case "cache_expiration": + if err := json.Unmarshal(v, &(c.CacheExpiration)); err != nil { + return err + } + case "plugins": + if err := json.Unmarshal(v, c.Plugins); err != nil { + return err + } + } + } + return nil +} + // NewPluginsConfig returns a map of *pluginConfigItems where the key is the plugin name. func NewPluginsConfig() map[string]*pluginConfigItem { return map[string]*pluginConfigItem{} diff --git a/mgmt/rest/server.go b/mgmt/rest/server.go index d94e1cdec..d70f31856 100644 --- a/mgmt/rest/server.go +++ b/mgmt/rest/server.go @@ -67,6 +67,9 @@ var ( ) // holds the configuration passed in through the SNAP config file +// Note: if this struct is modified, then the switch statement in the +// UnmarshalJSON method in this same file needs to be modified to +// match the field mapping that is defined here type Config struct { Enable bool `json:"enable,omitempty"yaml:"enable,omitempty"` Port int `json:"port,omitempty"yaml:"port,omitempty"` @@ -181,6 +184,53 @@ func GetDefaultConfig() *Config { } } +// UnmarshalJSON unmarshals valid json into a Config. An example Config can be found +// at github.com/intelsdi-x/snap/blob/master/examples/configs/snap-config-sample.json +func (c *Config) UnmarshalJSON(data []byte) error { + // construct a map of strings to json.RawMessages (to defer the parsing of individual + // fields from the unmarshalled interface until later) and unmarshal the input + // byte array into that map + t := make(map[string]json.RawMessage) + if err := json.Unmarshal(data, &t); err != nil { + return err + } + // loop through the individual map elements, parse each in turn, and set + // the appropriate field in this configuration + for k, v := range t { + switch k { + case "enable": + if err := json.Unmarshal(v, &(c.Enable)); err != nil { + return err + } + case "port": + if err := json.Unmarshal(v, &(c.Port)); err != nil { + return err + } + case "https": + if err := json.Unmarshal(v, &(c.HTTPS)); err != nil { + return err + } + case "rest_certificate": + if err := json.Unmarshal(v, &(c.RestCertificate)); err != nil { + return err + } + case "rest_key": + if err := json.Unmarshal(v, &(c.RestKey)); err != nil { + return err + } + case "rest_auth": + if err := json.Unmarshal(v, &(c.RestAuth)); err != nil { + return err + } + case "rest_auth_password": + if err := json.Unmarshal(v, &(c.RestAuthPassword)); err != nil { + return err + } + } + } + return nil +} + // SetAPIAuth sets API authentication to enabled or disabled func (s *Server) SetAPIAuth(auth bool) { s.auth = auth diff --git a/mgmt/tribe/config.go b/mgmt/tribe/config.go index b9121161f..814772c9b 100644 --- a/mgmt/tribe/config.go +++ b/mgmt/tribe/config.go @@ -20,6 +20,7 @@ limitations under the License. package tribe import ( + "encoding/json" "net" "os" "time" @@ -41,6 +42,9 @@ const ( ) // holds the configuration passed in through the SNAP config file +// Note: if this struct is modified, then the switch statement in the +// UnmarshalJSON method in this same file needs to be modified to +// match the field mapping that is defined here type Config struct { Name string `json:"name,omitempty"yaml:"name,omitempty"` Enable bool `json:"enable,omitempty"yaml:"enable,omitempty"` @@ -73,6 +77,45 @@ func GetDefaultConfig() *Config { } } +// UnmarshalJSON unmarshals valid json into a Config. An example Config can be found +// at github.com/intelsdi-x/snap/blob/master/examples/configs/snap-config-sample.json +func (c *Config) UnmarshalJSON(data []byte) error { + // construct a map of strings to json.RawMessages (to defer the parsing of individual + // fields from the unmarshalled interface until later) and unmarshal the input + // byte array into that map + t := make(map[string]json.RawMessage) + if err := json.Unmarshal(data, &t); err != nil { + return err + } + // loop through the individual map elements, parse each in turn, and set + // the appropriate field in this configuration + for k, v := range t { + switch k { + case "name": + if err := json.Unmarshal(v, &(c.Name)); err != nil { + return err + } + case "enable": + if err := json.Unmarshal(v, &(c.Enable)); err != nil { + return err + } + case "bind_addr": + if err := json.Unmarshal(v, &(c.BindAddr)); err != nil { + return err + } + case "bind_port": + if err := json.Unmarshal(v, &(c.BindPort)); err != nil { + return err + } + case "seed": + if err := json.Unmarshal(v, &(c.Seed)); err != nil { + return err + } + } + } + return nil +} + func getHostname() string { hostname, err := os.Hostname() if err != nil { diff --git a/scheduler/config.go b/scheduler/config.go index 958f867e4..243b9c71f 100644 --- a/scheduler/config.go +++ b/scheduler/config.go @@ -19,6 +19,8 @@ limitations under the License. package scheduler +import "encoding/json" + // default configuration values const ( defaultWorkManagerQueueSize uint = 25 @@ -26,6 +28,9 @@ const ( ) // holds the configuration passed in through the SNAP config file +// Note: if this struct is modified, then the switch statement in the +// UnmarshalJSON method in this same file needs to be modified to +// match the field mapping that is defined here type Config struct { WorkManagerQueueSize uint `json:"work_manager_queue_size,omitempty"yaml:"work_manager_queue_size,omitempty"` WorkManagerPoolSize uint `json:"work_manager_pool_size,omitempty"yaml:"work_manager_pool_size,omitempty"` @@ -38,3 +43,30 @@ func GetDefaultConfig() *Config { WorkManagerPoolSize: defaultWorkManagerPoolSize, } } + +// UnmarshalJSON unmarshals valid json into a Config. An example Config can be found +// at github.com/intelsdi-x/snap/blob/master/examples/configs/snap-config-sample.json +func (c *Config) UnmarshalJSON(data []byte) error { + // construct a map of strings to json.RawMessages (to defer the parsing of individual + // fields from the unmarshalled interface until later) and unmarshal the input + // byte array into that map + t := make(map[string]json.RawMessage) + if err := json.Unmarshal(data, &t); err != nil { + return err + } + // loop through the individual map elements, parse each in turn, and set + // the appropriate field in this configuration + for k, v := range t { + switch k { + case "work_manager_queue_size": + if err := json.Unmarshal(v, &(c.WorkManagerQueueSize)); err != nil { + return err + } + case "work_manager_pool_size": + if err := json.Unmarshal(v, &(c.WorkManagerPoolSize)); err != nil { + return err + } + } + } + return nil +} diff --git a/snapd.go b/snapd.go index 2d957139e..99841022e 100644 --- a/snapd.go +++ b/snapd.go @@ -20,6 +20,7 @@ limitations under the License. package main import ( + "encoding/json" "fmt" "io/ioutil" "os" @@ -147,6 +148,9 @@ const ( ) // holds the configuration passed in through the SNAP config file +// Note: if this struct is modified, then the switch statement in the +// UnmarshalJSON method in this same file needs to be modified to +// match the field mapping that is defined here type Config struct { LogLevel int `json:"log_level,omitempty"yaml:"log_level,omitempty"` GoMaxProcs int `json:"gomaxprocs,omitempty"yaml:"gomaxprocs,omitempty"` @@ -702,6 +706,53 @@ func setMaxProcs(maxProcs int) { } } +// UnmarshalJSON unmarshals valid json into a Config. An example Config can be found +// at github.com/intelsdi-x/snap/blob/master/examples/configs/snap-config-sample.json +func (c *Config) UnmarshalJSON(data []byte) error { + // construct a map of strings to json.RawMessages (to defer the parsing of individual + // fields from the unmarshalled interface until later), then unmarshal the input + // byte array into that map + t := make(map[string]json.RawMessage) + if err := json.Unmarshal(data, &t); err != nil { + return err + } + // loop through the individual map elements, parse each in turn, and set + // the appropriate field in this configuration + for k, v := range t { + switch k { + case "log_level": + if err := json.Unmarshal(v, &(c.LogLevel)); err != nil { + return err + } + case "gomaxprocs": + if err := json.Unmarshal(v, &(c.GoMaxProcs)); err != nil { + return err + } + case "log_path": + if err := json.Unmarshal(v, &(c.LogPath)); err != nil { + return err + } + case "control": + if err := json.Unmarshal(v, c.Control); err != nil { + return err + } + case "restapi": + if err := json.Unmarshal(v, c.RestAPI); err != nil { + return err + } + case "scheduler": + if err := json.Unmarshal(v, c.Scheduler); err != nil { + return err + } + case "tribe": + if err := json.Unmarshal(v, c.Tribe); err != nil { + return err + } + } + } + return nil +} + func startModule(m coreModule) error { err := m.Start() if err == nil {