// Initialize CirconusMetrics instance. Attempt to find a check otherwise create one. // use cases: // // check [bundle] by submission url // check [bundle] by *check* id (note, not check_bundle id) // check [bundle] by search // create check [bundle] func (cm *CheckManager) initializeTrapURL() error { if cm.trapURL != "" { return nil } cm.trapmu.Lock() defer cm.trapmu.Unlock() // special case short-circuit: just send to a url, no check management // up to user to ensure that if url is https that it will work (e.g. not self-signed) if cm.checkSubmissionURL != "" { if !cm.enabled { cm.trapURL = cm.checkSubmissionURL cm.trapLastUpdate = time.Now() return nil } } if !cm.enabled { return errors.New("Unable to initialize trap, check manager is disabled.") } var err error var check *api.Check var checkBundle *api.CheckBundle var broker *api.Broker if cm.checkSubmissionURL != "" { check, err = cm.apih.FetchCheckBySubmissionURL(cm.checkSubmissionURL) if err != nil { return err } if !check.Active { return fmt.Errorf("[ERROR] Check ID %v is not active", check.Cid) } // extract check id from check object returned from looking up using submission url // set m.CheckId to the id // set m.SubmissionUrl to "" to prevent trying to search on it going forward // use case: if the broker is changed in the UI metrics would stop flowing // unless the new submission url can be fetched with the API (which is no // longer possible using the original submission url) var id int id, err = strconv.Atoi(strings.Replace(check.Cid, "/check/", "", -1)) if err == nil { cm.checkID = api.IDType(id) cm.checkSubmissionURL = "" } else { cm.Log.Printf( "[WARN] SubmissionUrl check to Check ID: unable to convert %s to int %q\n", check.Cid, err) } } else if cm.checkID > 0 { check, err = cm.apih.FetchCheckByID(cm.checkID) if err != nil { return err } if !check.Active { return fmt.Errorf("[ERROR] Check ID %v is not active", check.Cid) } } else { searchCriteria := fmt.Sprintf( "(active:1)(host:\"%s\")(type:\"%s\")(tags:%s)", cm.checkInstanceID, cm.checkType, strings.Join(cm.checkSearchTag, ",")) checkBundle, err = cm.checkBundleSearch(searchCriteria) if err != nil { return err } if checkBundle == nil { // err==nil && checkBundle==nil is "no check bundles matched" // an error *should* be returned for any other invalid scenario checkBundle, broker, err = cm.createNewCheck() if err != nil { return err } } } if checkBundle == nil { if check != nil { checkBundle, err = cm.apih.FetchCheckBundleByCID(api.CIDType(check.CheckBundleCid)) if err != nil { return err } } else { return fmt.Errorf("[ERROR] Unable to retrieve, find, or create check") } } if broker == nil { broker, err = cm.apih.FetchBrokerByCID(api.CIDType(checkBundle.Brokers[0])) if err != nil { return err } } // retain to facilitate metric management (adding new metrics specifically) cm.checkBundle = checkBundle cm.inventoryMetrics() // determine the trap url to which metrics should be PUT if checkBundle.Type == "httptrap" { cm.trapURL = api.URLType(checkBundle.Config.SubmissionURL) } else { // build a submission_url for non-httptrap checks out of mtev_reverse url if len(checkBundle.ReverseConnectURLs) == 0 { return fmt.Errorf("%s is not an HTTPTRAP check and no reverse connection urls found", checkBundle.Checks[0]) } mtevURL := checkBundle.ReverseConnectURLs[0] mtevURL = strings.Replace(mtevURL, "mtev_reverse", "https", 1) mtevURL = strings.Replace(mtevURL, "check", "module/httptrap", 1) cm.trapURL = api.URLType(fmt.Sprintf("%s/%s", mtevURL, checkBundle.Config.ReverseSecret)) } // used when sending as "ServerName" get around certs not having IP SANS // (cert created with server name as CN but IP used in trap url) cn, err := cm.getBrokerCN(broker, cm.trapURL) if err != nil { return err } cm.trapCN = BrokerCNType(cn) cm.trapLastUpdate = time.Now() return nil }
// NewCheckManager returns a new check manager func NewCheckManager(cfg *Config) (*CheckManager, error) { if cfg == nil { return nil, errors.New("Invalid Check Manager configuration (nil).") } cm := &CheckManager{ enabled: false, } cm.Debug = cfg.Debug cm.Log = cfg.Log if cm.Log == nil { if cm.Debug { cm.Log = log.New(os.Stderr, "", log.LstdFlags) } else { cm.Log = log.New(ioutil.Discard, "", log.LstdFlags) } } if cfg.Check.SubmissionURL != "" { cm.checkSubmissionURL = api.URLType(cfg.Check.SubmissionURL) } // Blank API Token *disables* check management if cfg.API.TokenKey == "" { if cm.checkSubmissionURL == "" { return nil, errors.New("Invalid check manager configuration (no API token AND no submission url).") } if err := cm.initializeTrapURL(); err != nil { return nil, err } return cm, nil } // enable check manager cm.enabled = true // initialize api handle cfg.API.Debug = cm.Debug cfg.API.Log = cm.Log apih, err := api.NewAPI(&cfg.API) if err != nil { return nil, err } cm.apih = apih // initialize check related data cm.checkType = defaultCheckType idSetting := "0" if cfg.Check.ID != "" { idSetting = cfg.Check.ID } id, err := strconv.Atoi(idSetting) if err != nil { return nil, err } cm.checkID = api.IDType(id) cm.checkInstanceID = CheckInstanceIDType(cfg.Check.InstanceID) cm.checkDisplayName = CheckDisplayNameType(cfg.Check.DisplayName) cm.checkSearchTag = api.SearchTagType(cfg.Check.SearchTag) cm.checkSecret = CheckSecretType(cfg.Check.Secret) cm.checkTags = cfg.Check.Tags fma := defaultForceMetricActivation if cfg.Check.ForceMetricActivation != "" { fma = cfg.Check.ForceMetricActivation } fm, err := strconv.ParseBool(fma) if err != nil { return nil, err } cm.forceMetricActivation = fm _, an := path.Split(os.Args[0]) hn, err := os.Hostname() if err != nil { hn = "unknown" } if cm.checkInstanceID == "" { cm.checkInstanceID = CheckInstanceIDType(fmt.Sprintf("%s:%s", hn, an)) } if cm.checkSearchTag == "" { cm.checkSearchTag = api.SearchTagType(fmt.Sprintf("service:%s", an)) } if cm.checkDisplayName == "" { cm.checkDisplayName = CheckDisplayNameType(fmt.Sprintf("%s /cgm", string(cm.checkInstanceID))) } dur := cfg.Check.MaxURLAge if dur == "" { dur = defaultTrapMaxURLAge } maxDur, err := time.ParseDuration(dur) if err != nil { return nil, err } cm.trapMaxURLAge = maxDur // setup broker idSetting = "0" if cfg.Broker.ID != "" { idSetting = cfg.Broker.ID } id, err = strconv.Atoi(idSetting) if err != nil { return nil, err } cm.brokerID = api.IDType(id) cm.brokerSelectTag = api.SearchTagType(cfg.Broker.SelectTag) dur = cfg.Broker.MaxResponseTime if dur == "" { dur = defaultBrokerMaxResponseTime } maxDur, err = time.ParseDuration(dur) if err != nil { return nil, err } cm.brokerMaxResponseTime = maxDur // metrics cm.availableMetrics = make(map[string]bool) if err := cm.initializeTrapURL(); err != nil { return nil, err } return cm, nil }
// Initialize CirconusMetrics instance. Attempt to find a check otherwise create one. // use cases: // // check [bundle] by submission url // check [bundle] by *check* id (note, not check_bundle id) // check [bundle] by search // create check [bundle] func (cm *CheckManager) initializeTrapURL() error { if cm.trapURL != "" { return nil } cm.trapmu.Lock() defer cm.trapmu.Unlock() if cm.checkSubmissionURL != "" { if !cm.enabled { cm.trapURL = cm.checkSubmissionURL cm.trapLastUpdate = time.Now() return nil } } if !cm.enabled { return errors.New("Unable to initialize trap, check manager is disabled.") } var err error var check *api.Check var checkBundle *api.CheckBundle var broker *api.Broker if cm.checkSubmissionURL != "" { check, err = cm.apih.FetchCheckBySubmissionURL(cm.checkSubmissionURL) if err != nil { return err } // extract check id from check object returned from looking up using submission url // set m.CheckId to the id // set m.SubmissionUrl to "" to prevent trying to search on it going forward // use case: if the broker is changed in the UI metrics would stop flowing // unless the new submission url can be fetched with the API (which is no // longer possible using the original submission url) var id int id, err = strconv.Atoi(strings.Replace(check.Cid, "/check/", "", -1)) if err == nil { cm.checkID = api.IDType(id) cm.checkSubmissionURL = "" } else { cm.Log.Printf( "[WARN] SubmissionUrl check to Check ID: unable to convert %s to int %q\n", check.Cid, err) } } else if cm.checkID > 0 { check, err = cm.apih.FetchCheckByID(cm.checkID) if err != nil { return err } } else { searchCriteria := fmt.Sprintf( "(active:1)(host:\"%s\")(type:\"%s\")(tags:%s)", cm.checkInstanceID, cm.checkType, cm.checkSearchTag) checkBundle, err = cm.checkBundleSearch(searchCriteria) if err != nil { return err } if checkBundle == nil { // err==nil && checkBundle==nil is "no check bundles matched" // an error *should* be returned for any other invalid scenario checkBundle, broker, err = cm.createNewCheck() if err != nil { return err } } } if checkBundle == nil { if check != nil { checkBundle, err = cm.apih.FetchCheckBundleByCID(api.CIDType(check.CheckBundleCid)) if err != nil { return err } } else { return fmt.Errorf("[ERROR] Unable to retrieve, find, or create check") } } if broker == nil { broker, err = cm.apih.FetchBrokerByCID(api.CIDType(checkBundle.Brokers[0])) if err != nil { return err } } // retain to facilitate metric management (adding new metrics specifically) cm.checkBundle = checkBundle cm.inventoryMetrics() // url to which metrics should be PUT cm.trapURL = api.URLType(checkBundle.Config.SubmissionURL) // used when sending as "ServerName" get around certs not having IP SANS // (cert created with server name as CN but IP used in trap url) cn, err := cm.getBrokerCN(broker, cm.trapURL) if err != nil { return err } cm.trapCN = BrokerCNType(cn) cm.trapLastUpdate = time.Now() return nil }