| package tc |
| |
| import ( |
| "encoding/json" |
| "fmt" |
| "strconv" |
| "strings" |
| ) |
| |
| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| // TMConfigResponse ... |
| type TMConfigResponse struct { |
| Response TrafficMonitorConfig `json:"response"` |
| } |
| |
| // TrafficMonitorConfig ... |
| type TrafficMonitorConfig struct { |
| TrafficServers []TrafficServer `json:"trafficServers,omitempty"` |
| CacheGroups []TMCacheGroup `json:"cacheGroups,omitempty"` |
| Config map[string]interface{} `json:"config,omitempty"` |
| TrafficMonitors []TrafficMonitor `json:"trafficMonitors,omitempty"` |
| DeliveryServices []TMDeliveryService `json:"deliveryServices,omitempty"` |
| Profiles []TMProfile `json:"profiles,omitempty"` |
| } |
| |
| // TrafficMonitorConfigMap ... |
| type TrafficMonitorConfigMap struct { |
| TrafficServer map[string]TrafficServer |
| CacheGroup map[string]TMCacheGroup |
| Config map[string]interface{} |
| TrafficMonitor map[string]TrafficMonitor |
| DeliveryService map[string]TMDeliveryService |
| Profile map[string]TMProfile |
| } |
| |
| // TrafficMonitor ... |
| type TrafficMonitor struct { |
| Port int `json:"port"` |
| IP6 string `json:"ip6"` |
| IP string `json:"ip"` |
| HostName string `json:"hostName"` |
| FQDN string `json:"fqdn"` |
| Profile string `json:"profile"` |
| Location string `json:"location"` |
| ServerStatus string `json:"status"` |
| } |
| |
| // TMCacheGroup ... |
| // !!! Note the lowercase!!! this is local to this file, there's a CacheGroup definition in cachegroup.go! |
| type TMCacheGroup struct { |
| Name string `json:"name"` |
| Coordinates MonitoringCoordinates `json:"coordinates"` |
| } |
| |
| // Coordinates ... |
| type MonitoringCoordinates struct { |
| Latitude float64 `json:"latitude"` |
| Longitude float64 `json:"longitude"` |
| } |
| |
| // TMDeliveryService ... |
| type TMDeliveryService struct { |
| XMLID string `json:"xmlId"` |
| TotalTPSThreshold int64 `json:"TotalTpsThreshold"` |
| ServerStatus string `json:"status"` |
| TotalKbpsThreshold int64 `json:"TotalKbpsThreshold"` |
| } |
| |
| // TMProfile ... |
| type TMProfile struct { |
| Parameters TMParameters `json:"parameters"` |
| Name string `json:"name"` |
| Type string `json:"type"` |
| } |
| |
| // TMParameters ... |
| // TODO change TO to return this struct, so a custom UnmarshalJSON isn't necessary. |
| type TMParameters struct { |
| HealthConnectionTimeout int `json:"health.connection.timeout"` |
| HealthPollingURL string `json:"health.polling.url"` |
| HealthPollingFormat string `json:"health.polling.format"` |
| HealthPollingType string `json:"health.polling.type"` |
| HistoryCount int `json:"history.count"` |
| MinFreeKbps int64 |
| Thresholds map[string]HealthThreshold `json:"health_threshold"` |
| } |
| |
| const DefaultHealthThresholdComparator = "<" |
| |
| type HealthThreshold struct { |
| Val float64 |
| Comparator string // TODO change to enum? |
| } |
| |
| // strToThreshold takes a string like ">=42" and returns a HealthThreshold with a Val of `42` and a Comparator of `">="`. If no comparator exists, `DefaultHealthThresholdComparator` is used. If the string is not of the form "(>|<|)(=|)\d+" an error is returned |
| func strToThreshold(s string) (HealthThreshold, error) { |
| comparators := []string{"=", ">", "<", ">=", "<="} |
| for _, comparator := range comparators { |
| if strings.HasPrefix(s, comparator) { |
| valStr := s[len(comparator):] |
| val, err := strconv.ParseFloat(valStr, 64) |
| if err != nil { |
| return HealthThreshold{}, fmt.Errorf("invalid threshold: NaN") |
| } |
| return HealthThreshold{Val: val, Comparator: comparator}, nil |
| } |
| } |
| val, err := strconv.ParseFloat(s, 64) |
| if err != nil { |
| return HealthThreshold{}, fmt.Errorf("invalid threshold: NaN") |
| } |
| return HealthThreshold{Val: val, Comparator: DefaultHealthThresholdComparator}, nil |
| } |
| func (params *TMParameters) UnmarshalJSON(bytes []byte) (err error) { |
| raw := map[string]interface{}{} |
| if err := json.Unmarshal(bytes, &raw); err != nil { |
| return err |
| } |
| |
| if vi, ok := raw["health.connection.timeout"]; ok { |
| if v, ok := vi.(float64); !ok { |
| return fmt.Errorf("Unmarshalling TMParameters health.connection.timeout expected integer, got %v", vi) |
| } else { |
| params.HealthConnectionTimeout = int(v) |
| } |
| } |
| |
| if vi, ok := raw["health.polling.url"]; ok { |
| if v, ok := vi.(string); !ok { |
| return fmt.Errorf("Unmarshalling TMParameters health.polling.url expected string, got %v", vi) |
| } else { |
| params.HealthPollingURL = v |
| } |
| } |
| |
| if vi, ok := raw["health.polling.format"]; ok { |
| if v, ok := vi.(string); !ok { |
| return fmt.Errorf("Unmarshalling TMParameters health.polling.format expected string, got %v", vi) |
| } else { |
| params.HealthPollingFormat = v |
| } |
| } |
| |
| if vi, ok := raw["health.polling.type"]; ok { |
| if v, ok := vi.(string); !ok { |
| return fmt.Errorf("Unmarshalling TMParameters health.polling.type expected string, got %v", vi) |
| } else { |
| params.HealthPollingType = v |
| } |
| } |
| |
| if vi, ok := raw["history.count"]; ok { |
| if v, ok := vi.(float64); !ok { |
| return fmt.Errorf("Unmarshalling TMParameters history.count expected integer, got %v", vi) |
| } else { |
| params.HistoryCount = int(v) |
| } |
| } |
| |
| params.Thresholds = map[string]HealthThreshold{} |
| thresholdPrefix := "health.threshold." |
| for k, v := range raw { |
| if strings.HasPrefix(k, thresholdPrefix) { |
| stat := k[len(thresholdPrefix):] |
| vStr := fmt.Sprintf("%v", v) // allows string or numeric JSON types. TODO check if a type switch is faster. |
| if t, err := strToThreshold(vStr); err != nil { |
| return fmt.Errorf("Unmarshalling TMParameters `health.threshold.` parameter value not of the form `(>|)(=|)\\d+`: stat '%s' value '%v'", k, v) |
| } else { |
| params.Thresholds[stat] = t |
| } |
| } |
| } |
| return nil |
| } |
| |
| func TrafficMonitorTransformToMap(tmConfig *TrafficMonitorConfig) (*TrafficMonitorConfigMap, error) { |
| var tm TrafficMonitorConfigMap |
| |
| tm.TrafficServer = make(map[string]TrafficServer) |
| tm.CacheGroup = make(map[string]TMCacheGroup) |
| tm.Config = make(map[string]interface{}) |
| tm.TrafficMonitor = make(map[string]TrafficMonitor) |
| tm.DeliveryService = make(map[string]TMDeliveryService) |
| tm.Profile = make(map[string]TMProfile) |
| |
| for _, trafficServer := range tmConfig.TrafficServers { |
| tm.TrafficServer[trafficServer.HostName] = trafficServer |
| } |
| |
| for _, cacheGroup := range tmConfig.CacheGroups { |
| tm.CacheGroup[cacheGroup.Name] = cacheGroup |
| } |
| |
| for parameterKey, parameterVal := range tmConfig.Config { |
| tm.Config[parameterKey] = parameterVal |
| } |
| |
| for _, trafficMonitor := range tmConfig.TrafficMonitors { |
| tm.TrafficMonitor[trafficMonitor.HostName] = trafficMonitor |
| } |
| |
| for _, deliveryService := range tmConfig.DeliveryServices { |
| tm.DeliveryService[deliveryService.XMLID] = deliveryService |
| } |
| |
| for _, profile := range tmConfig.Profiles { |
| bwThreshold := profile.Parameters.Thresholds["availableBandwidthInKbps"] |
| profile.Parameters.MinFreeKbps = int64(bwThreshold.Val) |
| tm.Profile[profile.Name] = profile |
| } |
| |
| return &tm, nil |
| } |
| |
| type HealthData struct { |
| TotalOffline uint64 `json:"totalOffline"` |
| TotalOnline uint64 `json:"totalOnline"` |
| CacheGroups []HealthDataCacheGroup `json:"cachegroups"` |
| } |
| |
| type HealthDataCacheGroup struct { |
| Offline int64 `json:"offline"` |
| Online int64 `json:"online"` |
| Name CacheGroupName `json:"name"` |
| } |