checkmgr/check.go
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.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 {
		cid := fmt.Sprintf("/check/%d", cm.checkID)
		check, err = cm.apih.FetchCheck(api.CIDType(&cid))
		if err != nil {
			return err
		}
		if !check.Active {
			return fmt.Errorf("[ERROR] Check ID %v is not active", check.CID)
		}
	} else {
		if checkBundle == nil {
			// old search (instanceid as check.target)
			searchCriteria := fmt.Sprintf(
				"(active:1)(type:\"%s\")(host:\"%s\")(tags:%s)", cm.checkType, cm.checkTarget, strings.Join(cm.checkSearchTag, ","))
			checkBundle, err = cm.checkBundleSearch(searchCriteria, map[string][]string{})
			if err != nil {
				return err
			}
		}

		if checkBundle == nil {
			// new search (check.target != instanceid, instanceid encoded in notes field)
			searchCriteria := fmt.Sprintf(
				"(active:1)(type:\"%s\")(tags:%s)", cm.checkType, strings.Join(cm.checkSearchTag, ","))
			filterCriteria := map[string][]string{"f_notes": {*cm.getNotes()}}
			checkBundle, err = cm.checkBundleSearch(searchCriteria, filterCriteria)
			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 {
			cid := check.CheckBundleCID
			checkBundle, err = cm.apih.FetchCheckBundle(api.CIDType(&cid))
			if err != nil {
				return err
			}
		} else {
			return fmt.Errorf("[ERROR] Unable to retrieve, find, or create check")
		}
	}

	if broker == nil {
		cid := checkBundle.Brokers[0]
		broker, err = cm.apih.FetchBroker(api.CIDType(&cid))
		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" {
		if turl, found := checkBundle.Config[config.SubmissionURL]; found {
			cm.trapURL = api.URLType(turl)
		} else {
			if cm.Debug {
				cm.Log.Printf("Missing config.%s %+v", config.SubmissionURL, checkBundle)
			}
			return fmt.Errorf("[ERROR] Unable to use check, no %s in config", 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)
		if rs, found := checkBundle.Config[config.ReverseSecretKey]; found {
			cm.trapURL = api.URLType(fmt.Sprintf("%s/%s", mtevURL, rs))
		} else {
			if cm.Debug {
				cm.Log.Printf("Missing config.%s %+v", config.ReverseSecretKey, checkBundle)
			}
			return fmt.Errorf("[ERROR] Unable to use check, no %s in config", config.ReverseSecretKey)
		}
	}

	// 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)

	if cm.enabled {
		u, err := url.Parse(string(cm.trapURL))
		if err != nil {
			return err
		}
		if u.Scheme == "https" {
			if err := cm.loadCACert(); err != nil {
				return err
			}
		}
	}

	cm.trapLastUpdate = time.Now()

	return nil
}
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.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 {
		cid := fmt.Sprintf("/check/%d", cm.checkID)
		check, err = cm.apih.FetchCheck(api.CIDType(&cid))
		if err != nil {
			return err
		}
		if !check.Active {
			return fmt.Errorf("[ERROR] Check ID %v is not active", check.CID)
		}
	} else {
		if checkBundle == nil {
			// old search (instanceid as check.target)
			searchCriteria := fmt.Sprintf(
				"(active:1)(type:\"%s\")(host:\"%s\")(tags:%s)", cm.checkType, cm.checkTarget, strings.Join(cm.checkSearchTag, ","))
			checkBundle, err = cm.checkBundleSearch(searchCriteria, map[string][]string{})
			if err != nil {
				return err
			}
		}

		if checkBundle == nil {
			// new search (check.target != instanceid, instanceid encoded in notes field)
			searchCriteria := fmt.Sprintf(
				"(active:1)(type:\"%s\")(tags:%s)", cm.checkType, strings.Join(cm.checkSearchTag, ","))
			filterCriteria := map[string][]string{"f_notes": {*cm.getNotes()}}
			checkBundle, err = cm.checkBundleSearch(searchCriteria, filterCriteria)
			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 {
			cid := check.CheckBundleCID
			checkBundle, err = cm.apih.FetchCheckBundle(api.CIDType(&cid))
			if err != nil {
				return err
			}
		} else {
			return fmt.Errorf("[ERROR] Unable to retrieve, find, or create check")
		}
	}

	if broker == nil {
		cid := checkBundle.Brokers[0]
		broker, err = cm.apih.FetchBroker(api.CIDType(&cid))
		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" {
		if turl, found := checkBundle.Config[config.SubmissionURL]; found {
			cm.trapURL = api.URLType(turl)
		} else {
			if cm.Debug {
				cm.Log.Printf("Missing config.%s %+v", config.SubmissionURL, checkBundle)
			}
			return fmt.Errorf("[ERROR] Unable to use check, no %s in config", 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)
		if rs, found := checkBundle.Config[config.ReverseSecretKey]; found {
			cm.trapURL = api.URLType(fmt.Sprintf("%s/%s", mtevURL, rs))
		} else {
			if cm.Debug {
				cm.Log.Printf("Missing config.%s %+v", config.ReverseSecretKey, checkBundle)
			}
			return fmt.Errorf("[ERROR] Unable to use check, no %s in config", config.ReverseSecretKey)
		}
	}

	// 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)

	if cm.enabled {
		u, err := url.Parse(string(cm.trapURL))
		if err != nil {
			return err
		}
		if u.Scheme == "https" {
			if err := cm.loadCACert(); err != nil {
				return err
			}
		}
	}

	cm.trapLastUpdate = time.Now()

	return nil
}
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 ( " " ) } var err error var check * api . Check var checkBundle * api . CheckBundle var broker * api . Broker if cm . checkSubmissionURL != " " { check , err = cm . fetchCheckBySubmissionURL ( cm . checkSubmissionURL ) if err != nil { return err } if ! check . Active { return fmt . Errorf ( " " , 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 , " " , " " , - 1 ) ) if err == nil { cm . checkID = api . IDType ( id ) cm . checkSubmissionURL = " " } else { cm . Log . Printf ( " \n " , check . CID , err ) } } else if cm . checkID > 0 { cid := fmt . Sprintf ( " " , cm . checkID ) check , err = cm . apih . FetchCheck ( api . CIDType ( & cid ) ) if err != nil { return err } if ! check . Active { return fmt . Errorf ( " " , check . CID ) } } else { if checkBundle == nil { // old search (instanceid as check.target) searchCriteria := fmt . Sprintf ( " \" \" \" \" " , cm . checkType , cm . checkTarget , strings . Join ( cm . checkSearchTag , " " ) ) checkBundle , err = cm . checkBundleSearch ( searchCriteria , map [ string ] [ ] string { } ) if err != nil { return err } } if checkBundle == nil { // new search (check.target != instanceid, instanceid encoded in notes field) searchCriteria := fmt . Sprintf ( " \" \" " , cm . checkType , strings . Join ( cm . checkSearchTag , " " ) ) filterCriteria := map [ string ] [ ] string { " " : { * cm . getNotes ( ) } } checkBundle , err = cm . checkBundleSearch ( searchCriteria , filterCriteria ) 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 { cid := check . CheckBundleCID checkBundle , err = cm . apih . FetchCheckBundle ( api . CIDType ( & cid ) ) if err != nil { return err } } else { return fmt . Errorf ( " " ) } } if broker == nil { cid := checkBundle . Brokers [ 0 ] broker , err = cm . apih . FetchBroker ( api . CIDType ( & cid ) ) 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 == " " { if turl , found := checkBundle . Config [ config . SubmissionURL ] ; found { cm . trapURL = api . URLType ( turl ) } else { if cm . Debug { cm . Log . Printf ( " " , config . SubmissionURL , checkBundle ) } return fmt . Errorf ( " " , config . SubmissionURL ) } } else { // build a submission_url for non-httptrap checks out of mtev_reverse url if len ( checkBundle . ReverseConnectURLs ) == 0 { return fmt . Errorf ( " " , checkBundle . Checks [ 0 ] ) } mtevURL := checkBundle . ReverseConnectURLs [ 0 ] mtevURL = strings . Replace ( mtevURL , " " , " " , 1 ) mtevURL = strings . Replace ( mtevURL , " " , " " , 1 ) if rs , found := checkBundle . Config [ config . ReverseSecretKey ] ; found { cm . trapURL = api . URLType ( fmt . Sprintf ( " " , mtevURL , rs ) ) } else { if cm . Debug { cm . Log . Printf ( " " , config . ReverseSecretKey , checkBundle ) } return fmt . Errorf ( " " , config . ReverseSecretKey ) } } // 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 ) if cm . enabled { u , err := url . Parse ( string ( cm . trapURL ) ) if err != nil { return err } if u . Scheme == " " { if err := cm . loadCACert ( ) ; err != nil { return err } } } cm . trapLastUpdate = time . Now ( ) return 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]
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 ]