| /* |
| * 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. |
| */ |
| |
| package tmcheck |
| |
| import ( |
| "fmt" |
| "time" |
| |
| "github.com/apache/trafficcontrol/lib/go-tc" |
| to "github.com/apache/trafficcontrol/traffic_ops/v3-client" |
| |
| "github.com/json-iterator/go" |
| ) |
| |
| // ValidateOfflineStates validates that no OFFLINE or ADMIN_DOWN caches in the given Traffic Ops' CRConfig are marked Available in the given Traffic Monitor's CRStates. |
| func ValidateOfflineStates(tmURI string, toClient *to.Session) error { |
| cdn, err := GetCDN(tmURI) |
| if err != nil { |
| return fmt.Errorf("getting CDN from Traffic Monitor: %v", err) |
| } |
| return ValidateOfflineStatesWithCDN(tmURI, cdn, toClient) |
| } |
| |
| // ValidateOfflineStatesWithCDN validates per ValidateOfflineStates, but saves an additional query if the Traffic Monitor's CDN is known. |
| func ValidateOfflineStatesWithCDN(tmURI string, tmCDN string, toClient *to.Session) error { |
| crConfigBytes, _, err := toClient.GetCRConfig(tmCDN) |
| if err != nil { |
| return fmt.Errorf("getting CRConfig: %v", err) |
| } |
| |
| crConfig := tc.CRConfig{} |
| json := jsoniter.ConfigFastest |
| if err := json.Unmarshal(crConfigBytes, &crConfig); err != nil { |
| return fmt.Errorf("unmarshalling CRConfig JSON: %v", err) |
| } |
| |
| return ValidateOfflineStatesWithCRConfig(tmURI, &crConfig, toClient) |
| } |
| |
| // ValidateOfflineStatesWithCRConfig validates per ValidateOfflineStates, but saves querying the CRconfig if it's already fetched. |
| func ValidateOfflineStatesWithCRConfig(tmURI string, crConfig *tc.CRConfig, toClient *to.Session) error { |
| crStates, err := GetCRStates(tmURI + TrafficMonitorCRStatesPath) |
| if err != nil { |
| return fmt.Errorf("getting CRStates: %v", err) |
| } |
| |
| return ValidateCRStates(crStates, crConfig) |
| } |
| |
| // ValidateCRStates validates that no OFFLINE or ADMIN_DOWN caches in the given CRConfig are marked Available in the given CRStates. |
| func ValidateCRStates(crstates *tc.CRStates, crconfig *tc.CRConfig) error { |
| for cacheName, cacheInfo := range crconfig.ContentServers { |
| status := tc.CacheStatusFromString(string(*cacheInfo.ServerStatus)) |
| if status != tc.CacheStatusAdminDown && status != tc.CacheStatusOffline { |
| continue |
| } |
| |
| available, ok := crstates.Caches[tc.CacheName(cacheName)] |
| if !ok { |
| return fmt.Errorf("Cache %v in CRConfig but not CRStates", cacheName) |
| } |
| |
| if available.IsAvailable { |
| return fmt.Errorf("Cache %v is %v in CRConfig, but available in CRStates", cacheName, status) |
| } |
| |
| } |
| return nil |
| } |
| |
| // CRStatesOfflineValidator is designed to be run as a goroutine, and does not return. It continously validates every `interval`, and calls `onErr` on failure, `onResumeSuccess` when a failure ceases, and `onCheck` on every poll. |
| func CRStatesOfflineValidator( |
| tmURI string, |
| toClient *to.Session, |
| interval time.Duration, |
| grace time.Duration, |
| onErr func(error), |
| onResumeSuccess func(), |
| onCheck func(error), |
| ) { |
| Validator(tmURI, toClient, interval, grace, onErr, onResumeSuccess, onCheck, ValidateOfflineStates) |
| } |
| |
| // AllMonitorsCRStatesOfflineValidator is designed to be run as a goroutine, and does not return. It continously validates every `interval`, and calls `onErr` on failure, `onResumeSuccess` when a failure ceases, and `onCheck` on every poll. Note the error passed to `onErr` may be a general validation error not associated with any monitor, in which case the passed `tc.TrafficMonitorName` will be empty. |
| func AllMonitorsCRStatesOfflineValidator( |
| toClient *to.Session, |
| interval time.Duration, |
| includeOffline bool, |
| grace time.Duration, |
| onErr func(tc.TrafficMonitorName, error), |
| onResumeSuccess func(tc.TrafficMonitorName), |
| onCheck func(tc.TrafficMonitorName, error), |
| ) { |
| AllValidator(toClient, interval, includeOffline, grace, onErr, onResumeSuccess, onCheck, ValidateAllMonitorsOfflineStates) |
| } |
| |
| // ValidateOfflineStates validates that no OFFLINE or ADMIN_DOWN caches in the given Traffic Ops' CRConfig are marked Available in the given Traffic Monitor's CRStates. |
| func ValidateAllMonitorsOfflineStates(toClient *to.Session, includeOffline bool) (map[tc.TrafficMonitorName]error, error) { |
| servers, err := GetMonitors(toClient, includeOffline) |
| if err != nil { |
| return nil, err |
| } |
| |
| crConfigs := GetCRConfigs(GetCDNs(servers), toClient) |
| |
| errs := map[tc.TrafficMonitorName]error{} |
| for _, server := range servers { |
| crConfig := crConfigs[tc.CDNName(server.CDNName)] |
| if err := crConfig.Err; err != nil { |
| errs[tc.TrafficMonitorName(server.HostName)] = fmt.Errorf("getting CRConfig: %v", err) |
| continue |
| } |
| |
| uri := fmt.Sprintf("http://%s.%s", server.HostName, server.DomainName) |
| errs[tc.TrafficMonitorName(server.HostName)] = ValidateOfflineStatesWithCRConfig(uri, crConfig.CRConfig, toClient) |
| } |
| return errs, nil |
| } |