diff --git a/src/common/notifier/config_watcher.go b/src/common/notifier/config_watcher.go new file mode 100644 index 000000000..5a1d9eb19 --- /dev/null +++ b/src/common/notifier/config_watcher.go @@ -0,0 +1,47 @@ +package notifier + +import ( + "errors" + "reflect" + + "github.com/vmware/harbor/src/common/models" + "github.com/vmware/harbor/src/common/utils" +) + +//WatchConfigChanges is used to watch the configuration changes. +func WatchConfigChanges(cfg map[string]interface{}) error { + if cfg == nil { + return errors.New("Empty configurations") + } + + //Currently only watch the scan all policy change. + if v, ok := cfg[ScanAllPolicyTopic]; ok { + if reflect.TypeOf(v).Kind() == reflect.Map { + policyCfg := &models.ScanAllPolicy{} + vMap := v.(map[string]interface{}) + //Reset filed name. + if pv, yes := vMap["parameter"]; yes { + vMap["Parm"] = pv + delete(vMap, "parameter") + } + if err := utils.ConvertMapToStruct(policyCfg, vMap); err != nil { + return err + } + + policyNotification := ScanPolicyNotification{ + Type: policyCfg.Type, + DailyTime: 0, + } + + if t, yes := policyCfg.Parm["daily_time"]; yes { + if reflect.TypeOf(t).Kind() == reflect.Int { + policyNotification.DailyTime = (int64)(t.(int)) + } + } + + return Publish(ScanAllPolicyTopic, policyNotification) + } + } + + return nil +} diff --git a/src/common/notifier/config_watcher_test.go b/src/common/notifier/config_watcher_test.go new file mode 100644 index 000000000..1bf22ba93 --- /dev/null +++ b/src/common/notifier/config_watcher_test.go @@ -0,0 +1,57 @@ +package notifier + +import ( + "encoding/json" + "strconv" + "strings" + "testing" + "time" +) + +var jsonText = ` +{ +"scan_all_policy": { + "type": "daily", + "parameter": { + "daily_time": + } + } +} +` + +func TestWatchConfiguration(t *testing.T) { + now := time.Now().UTC() + offset := (now.Hour()+1)*3600 + now.Minute()*60 + jsonT := strings.Replace(jsonText, "", strconv.Itoa(offset), -1) + v := make(map[string]interface{}) + if err := json.Unmarshal([]byte(jsonT), &v); err != nil { + t.Fatal(err) + } + + if err := WatchConfigChanges(v); err != nil { + if !strings.Contains(err.Error(), "No handlers registered") { + t.Fatal(err) + } + } +} + +var jsonText2 = ` +{ +"scan_all_policy": { + "type": "none" + } +} +` + +func TestWatchConfiguration2(t *testing.T) { + v := make(map[string]interface{}) + if err := json.Unmarshal([]byte(jsonText2), &v); err != nil { + t.Fatal(err) + } + + if err := WatchConfigChanges(v); err != nil { + if !strings.Contains(err.Error(), "No handlers registered") { + t.Fatal(err) + } + } +} diff --git a/src/common/utils/utils.go b/src/common/utils/utils.go index 5436e17b3..33e025911 100644 --- a/src/common/utils/utils.go +++ b/src/common/utils/utils.go @@ -129,6 +129,7 @@ func ParseTimeStamp(timestamp string) (*time.Time, error) { } //ConvertMapToStruct is used to fill the specified struct with map. +//Only support the exported fields. func ConvertMapToStruct(object interface{}, valuesInMap map[string]interface{}) error { if object == nil { return fmt.Errorf("nil struct is not supported") @@ -139,7 +140,7 @@ func ConvertMapToStruct(object interface{}, valuesInMap map[string]interface{}) } for k, v := range valuesInMap { - if err := setField(object, k, v); err != nil { + if err := setField(object, strings.Title(strings.ToLower(k)), v); err != nil { return err } } diff --git a/src/ui/api/config.go b/src/ui/api/config.go index e1854d702..4a9e03ad4 100644 --- a/src/ui/api/config.go +++ b/src/ui/api/config.go @@ -192,7 +192,9 @@ func (c *ConfigAPI) Put() { } //Everything is ok, detect the configurations to confirm if the option we are caring is changed. - watchConfigChanges(cfg) + if err := watchConfigChanges(cfg); err != nil { + log.Errorf("Failed to watch configuration change with error: %s\n", err) + } } // Reset system configurations diff --git a/src/ui/api/utils.go b/src/ui/api/utils.go index 0919c31c8..9ec629218 100644 --- a/src/ui/api/utils.go +++ b/src/ui/api/utils.go @@ -17,11 +17,9 @@ package api import ( "bytes" "encoding/json" - "errors" "fmt" "io/ioutil" "net/http" - "reflect" "sort" "strings" @@ -501,33 +499,7 @@ func transformVulnerabilities(layerWithVuln *models.ClairLayerEnvelope) []*model } //Watch the configuration changes. +//Wrap the same method in common utils. func watchConfigChanges(cfg map[string]interface{}) error { - if cfg == nil { - return errors.New("Empty configurations") - } - - //Currently only watch the scan all policy change. - if v, ok := cfg[notifier.ScanAllPolicyTopic]; ok { - if reflect.TypeOf(v).Kind() == reflect.Map { - policyCfg := &models.ScanAllPolicy{} - if err := utils.ConvertMapToStruct(policyCfg, v.(map[string]interface{})); err != nil { - return err - } - - policyNotification := notifier.ScanPolicyNotification{ - Type: policyCfg.Type, - DailyTime: 0, - } - - if t, yes := policyCfg.Parm["daily_time"]; yes { - if reflect.TypeOf(t).Kind() == reflect.Int { - policyNotification.DailyTime = (int64)(t.(int)) - } - } - - return notifier.Publish(notifier.ScanAllPolicyTopic, policyNotification) - } - } - - return nil + return notifier.WatchConfigChanges(cfg) }