Add `consul` check type to `circonus_check` resource (#13030)
* Add the `consul` check type to the `circonus_check` resource. * Fix a tab-complete fail. `Parse` != `Path`, but lexically close. * Dept of 2nd thoughts: `s/service_name/service/g`
This commit is contained in:
parent
c5935ab1ad
commit
32db4d184f
|
@ -25,6 +25,7 @@ const (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
apiCheckTypeCAQL circonusCheckType = "caql"
|
apiCheckTypeCAQL circonusCheckType = "caql"
|
||||||
|
apiCheckTypeConsul circonusCheckType = "consul"
|
||||||
apiCheckTypeICMPPing circonusCheckType = "ping_icmp"
|
apiCheckTypeICMPPing circonusCheckType = "ping_icmp"
|
||||||
apiCheckTypeHTTP circonusCheckType = "http"
|
apiCheckTypeHTTP circonusCheckType = "http"
|
||||||
apiCheckTypeJSON circonusCheckType = "json"
|
apiCheckTypeJSON circonusCheckType = "json"
|
||||||
|
@ -108,15 +109,24 @@ func (c *circonusCheck) Fixup() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *circonusCheck) Validate() error {
|
func (c *circonusCheck) Validate() error {
|
||||||
|
if len(c.Metrics) == 0 {
|
||||||
|
return fmt.Errorf("At least one %s must be specified", checkMetricAttr)
|
||||||
|
}
|
||||||
|
|
||||||
if c.Timeout > float32(c.Period) {
|
if c.Timeout > float32(c.Period) {
|
||||||
return fmt.Errorf("Timeout (%f) can not exceed period (%d)", c.Timeout, c.Period)
|
return fmt.Errorf("Timeout (%f) can not exceed period (%d)", c.Timeout, c.Period)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check-type specific validation
|
||||||
switch apiCheckType(c.Type) {
|
switch apiCheckType(c.Type) {
|
||||||
case apiCheckTypeCloudWatchAttr:
|
case apiCheckTypeCloudWatchAttr:
|
||||||
if !(c.Period == 60 || c.Period == 300) {
|
if !(c.Period == 60 || c.Period == 300) {
|
||||||
return fmt.Errorf("Period must be either 1m or 5m for a %s check", apiCheckTypeCloudWatchAttr)
|
return fmt.Errorf("Period must be either 1m or 5m for a %s check", apiCheckTypeCloudWatchAttr)
|
||||||
}
|
}
|
||||||
|
case apiCheckTypeConsulAttr:
|
||||||
|
if v, found := c.Config[config.URL]; !found || v == "" {
|
||||||
|
return fmt.Errorf("%s must have at least one check mode set: %s, %s, or %s must be set", checkConsulAttr, checkConsulServiceAttr, checkConsulNodeAttr, checkConsulStateAttr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -17,6 +17,19 @@ const (
|
||||||
providerAutoTagAttr = "auto_tag"
|
providerAutoTagAttr = "auto_tag"
|
||||||
providerKeyAttr = "key"
|
providerKeyAttr = "key"
|
||||||
|
|
||||||
|
apiConsulCheckBlacklist = "check_name_blacklist"
|
||||||
|
apiConsulDatacenterAttr = "dc"
|
||||||
|
apiConsulNodeBlacklist = "node_blacklist"
|
||||||
|
apiConsulServiceBlacklist = "service_blacklist"
|
||||||
|
apiConsulStaleAttr = "stale"
|
||||||
|
checkConsulTokenHeader = `X-Consul-Token`
|
||||||
|
checkConsulV1NodePrefix = "node"
|
||||||
|
checkConsulV1Prefix = "/v1/health"
|
||||||
|
checkConsulV1ServicePrefix = "service"
|
||||||
|
checkConsulV1StatePrefix = "state"
|
||||||
|
defaultCheckConsulHTTPAddr = "http://consul.service.consul"
|
||||||
|
defaultCheckConsulPort = "8500"
|
||||||
|
|
||||||
defaultCheckJSONMethod = "GET"
|
defaultCheckJSONMethod = "GET"
|
||||||
defaultCheckJSONPort = "443"
|
defaultCheckJSONPort = "443"
|
||||||
defaultCheckJSONVersion = "1.1"
|
defaultCheckJSONVersion = "1.1"
|
||||||
|
|
|
@ -33,21 +33,22 @@ const (
|
||||||
checkCAQLAttr = "caql"
|
checkCAQLAttr = "caql"
|
||||||
checkCloudWatchAttr = "cloudwatch"
|
checkCloudWatchAttr = "cloudwatch"
|
||||||
checkCollectorAttr = "collector"
|
checkCollectorAttr = "collector"
|
||||||
|
checkConsulAttr = "consul"
|
||||||
checkHTTPAttr = "http"
|
checkHTTPAttr = "http"
|
||||||
checkHTTPTrapAttr = "httptrap"
|
checkHTTPTrapAttr = "httptrap"
|
||||||
checkICMPPingAttr = "icmp_ping"
|
checkICMPPingAttr = "icmp_ping"
|
||||||
checkJSONAttr = "json"
|
checkJSONAttr = "json"
|
||||||
|
checkMetricAttr = "metric"
|
||||||
checkMetricLimitAttr = "metric_limit"
|
checkMetricLimitAttr = "metric_limit"
|
||||||
checkMySQLAttr = "mysql"
|
checkMySQLAttr = "mysql"
|
||||||
checkNameAttr = "name"
|
checkNameAttr = "name"
|
||||||
checkNotesAttr = "notes"
|
checkNotesAttr = "notes"
|
||||||
checkPeriodAttr = "period"
|
checkPeriodAttr = "period"
|
||||||
checkPostgreSQLAttr = "postgresql"
|
checkPostgreSQLAttr = "postgresql"
|
||||||
checkMetricAttr = "metric"
|
|
||||||
checkStatsdAttr = "statsd"
|
checkStatsdAttr = "statsd"
|
||||||
|
checkTCPAttr = "tcp"
|
||||||
checkTagsAttr = "tags"
|
checkTagsAttr = "tags"
|
||||||
checkTargetAttr = "target"
|
checkTargetAttr = "target"
|
||||||
checkTCPAttr = "tcp"
|
|
||||||
checkTimeoutAttr = "timeout"
|
checkTimeoutAttr = "timeout"
|
||||||
checkTypeAttr = "type"
|
checkTypeAttr = "type"
|
||||||
|
|
||||||
|
@ -75,6 +76,7 @@ const (
|
||||||
// Circonus API constants from their API endpoints
|
// Circonus API constants from their API endpoints
|
||||||
apiCheckTypeCAQLAttr apiCheckType = "caql"
|
apiCheckTypeCAQLAttr apiCheckType = "caql"
|
||||||
apiCheckTypeCloudWatchAttr apiCheckType = "cloudwatch"
|
apiCheckTypeCloudWatchAttr apiCheckType = "cloudwatch"
|
||||||
|
apiCheckTypeConsulAttr apiCheckType = "consul"
|
||||||
apiCheckTypeHTTPAttr apiCheckType = "http"
|
apiCheckTypeHTTPAttr apiCheckType = "http"
|
||||||
apiCheckTypeHTTPTrapAttr apiCheckType = "httptrap"
|
apiCheckTypeHTTPTrapAttr apiCheckType = "httptrap"
|
||||||
apiCheckTypeICMPPingAttr apiCheckType = "ping_icmp"
|
apiCheckTypeICMPPingAttr apiCheckType = "ping_icmp"
|
||||||
|
@ -90,6 +92,7 @@ var checkDescriptions = attrDescrs{
|
||||||
checkCAQLAttr: "CAQL check configuration",
|
checkCAQLAttr: "CAQL check configuration",
|
||||||
checkCloudWatchAttr: "CloudWatch check configuration",
|
checkCloudWatchAttr: "CloudWatch check configuration",
|
||||||
checkCollectorAttr: "The collector(s) that are responsible for gathering the metrics",
|
checkCollectorAttr: "The collector(s) that are responsible for gathering the metrics",
|
||||||
|
checkConsulAttr: "Consul check configuration",
|
||||||
checkHTTPAttr: "HTTP check configuration",
|
checkHTTPAttr: "HTTP check configuration",
|
||||||
checkHTTPTrapAttr: "HTTP Trap check configuration",
|
checkHTTPTrapAttr: "HTTP Trap check configuration",
|
||||||
checkICMPPingAttr: "ICMP ping check configuration",
|
checkICMPPingAttr: "ICMP ping check configuration",
|
||||||
|
@ -157,6 +160,7 @@ func resourceCheck() *schema.Resource {
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
checkConsulAttr: schemaCheckConsul,
|
||||||
checkHTTPAttr: schemaCheckHTTP,
|
checkHTTPAttr: schemaCheckHTTP,
|
||||||
checkHTTPTrapAttr: schemaCheckHTTPTrap,
|
checkHTTPTrapAttr: schemaCheckHTTPTrap,
|
||||||
checkJSONAttr: schemaCheckJSON,
|
checkJSONAttr: schemaCheckJSON,
|
||||||
|
@ -577,6 +581,7 @@ func checkConfigToAPI(c *circonusCheck, d *schema.ResourceData) error {
|
||||||
checkTypeParseMap := map[string]func(*circonusCheck, interfaceList) error{
|
checkTypeParseMap := map[string]func(*circonusCheck, interfaceList) error{
|
||||||
checkCAQLAttr: checkConfigToAPICAQL,
|
checkCAQLAttr: checkConfigToAPICAQL,
|
||||||
checkCloudWatchAttr: checkConfigToAPICloudWatch,
|
checkCloudWatchAttr: checkConfigToAPICloudWatch,
|
||||||
|
checkConsulAttr: checkConfigToAPIConsul,
|
||||||
checkHTTPAttr: checkConfigToAPIHTTP,
|
checkHTTPAttr: checkConfigToAPIHTTP,
|
||||||
checkHTTPTrapAttr: checkConfigToAPIHTTPTrap,
|
checkHTTPTrapAttr: checkConfigToAPIHTTPTrap,
|
||||||
checkICMPPingAttr: checkConfigToAPIICMPPing,
|
checkICMPPingAttr: checkConfigToAPIICMPPing,
|
||||||
|
@ -589,8 +594,17 @@ func checkConfigToAPI(c *circonusCheck, d *schema.ResourceData) error {
|
||||||
|
|
||||||
for checkType, fn := range checkTypeParseMap {
|
for checkType, fn := range checkTypeParseMap {
|
||||||
if listRaw, found := d.GetOk(checkType); found {
|
if listRaw, found := d.GetOk(checkType); found {
|
||||||
if err := fn(c, listRaw.(*schema.Set).List()); err != nil {
|
switch u := listRaw.(type) {
|
||||||
return errwrap.Wrapf(fmt.Sprintf("Unable to parse type %q: {{err}}", string(checkType)), err)
|
case []interface{}:
|
||||||
|
if err := fn(c, u); err != nil {
|
||||||
|
return errwrap.Wrapf(fmt.Sprintf("Unable to parse type %q: {{err}}", string(checkType)), err)
|
||||||
|
}
|
||||||
|
case *schema.Set:
|
||||||
|
if err := fn(c, u.List()); err != nil {
|
||||||
|
return errwrap.Wrapf(fmt.Sprintf("Unable to parse type %q: {{err}}", string(checkType)), err)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("PROVIDER BUG: unsupported check type interface: %q", checkType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -604,6 +618,7 @@ func parseCheckTypeConfig(c *circonusCheck, d *schema.ResourceData) error {
|
||||||
checkTypeConfigHandlers := map[apiCheckType]func(*circonusCheck, *schema.ResourceData) error{
|
checkTypeConfigHandlers := map[apiCheckType]func(*circonusCheck, *schema.ResourceData) error{
|
||||||
apiCheckTypeCAQLAttr: checkAPIToStateCAQL,
|
apiCheckTypeCAQLAttr: checkAPIToStateCAQL,
|
||||||
apiCheckTypeCloudWatchAttr: checkAPIToStateCloudWatch,
|
apiCheckTypeCloudWatchAttr: checkAPIToStateCloudWatch,
|
||||||
|
apiCheckTypeConsulAttr: checkAPIToStateConsul,
|
||||||
apiCheckTypeHTTPAttr: checkAPIToStateHTTP,
|
apiCheckTypeHTTPAttr: checkAPIToStateHTTP,
|
||||||
apiCheckTypeHTTPTrapAttr: checkAPIToStateHTTPTrap,
|
apiCheckTypeHTTPTrapAttr: checkAPIToStateHTTPTrap,
|
||||||
apiCheckTypeICMPPingAttr: checkAPIToStateICMPPing,
|
apiCheckTypeICMPPingAttr: checkAPIToStateICMPPing,
|
||||||
|
|
|
@ -0,0 +1,412 @@
|
||||||
|
package circonus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"net/url"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/circonus-labs/circonus-gometrics/api/config"
|
||||||
|
"github.com/hashicorp/errwrap"
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// circonus_check.consul.* resource attribute names
|
||||||
|
checkConsulACLTokenAttr = "acl_token"
|
||||||
|
checkConsulAllowStaleAttr = "allow_stale"
|
||||||
|
checkConsulCAChainAttr = "ca_chain"
|
||||||
|
checkConsulCertFileAttr = "certificate_file"
|
||||||
|
checkConsulCheckNameBlacklistAttr = "check_blacklist"
|
||||||
|
checkConsulCiphersAttr = "ciphers"
|
||||||
|
checkConsulDatacenterAttr = "dc"
|
||||||
|
checkConsulHTTPAddrAttr = "http_addr"
|
||||||
|
checkConsulHeadersAttr = "headers"
|
||||||
|
checkConsulKeyFileAttr = "key_file"
|
||||||
|
checkConsulNodeAttr = "node"
|
||||||
|
checkConsulNodeBlacklistAttr = "node_blacklist"
|
||||||
|
checkConsulServiceAttr = "service"
|
||||||
|
checkConsulServiceNameBlacklistAttr = "service_blacklist"
|
||||||
|
checkConsulStateAttr = "state"
|
||||||
|
)
|
||||||
|
|
||||||
|
var checkConsulDescriptions = attrDescrs{
|
||||||
|
checkConsulACLTokenAttr: "A Consul ACL token",
|
||||||
|
checkConsulAllowStaleAttr: "Allow Consul to read from a non-leader system",
|
||||||
|
checkConsulCAChainAttr: "A path to a file containing all the certificate authorities that should be loaded to validate the remote certificate (for TLS checks)",
|
||||||
|
checkConsulCertFileAttr: "A path to a file containing the client certificate that will be presented to the remote server (for TLS-enabled checks)",
|
||||||
|
checkConsulCheckNameBlacklistAttr: "A blacklist of check names to exclude from metric results",
|
||||||
|
checkConsulCiphersAttr: "A list of ciphers to be used in the TLS protocol (for HTTPS checks)",
|
||||||
|
checkConsulDatacenterAttr: "The Consul datacenter to extract health information from",
|
||||||
|
checkConsulHeadersAttr: "Map of HTTP Headers to send along with HTTP Requests",
|
||||||
|
checkConsulHTTPAddrAttr: "The HTTP Address of a Consul agent to query",
|
||||||
|
checkConsulKeyFileAttr: "A path to a file containing key to be used in conjunction with the cilent certificate (for TLS checks)",
|
||||||
|
checkConsulNodeAttr: "Node Name or NodeID of a Consul agent",
|
||||||
|
checkConsulNodeBlacklistAttr: "A blacklist of node names or IDs to exclude from metric results",
|
||||||
|
checkConsulServiceAttr: "Name of the Consul service to check",
|
||||||
|
checkConsulServiceNameBlacklistAttr: "A blacklist of service names to exclude from metric results",
|
||||||
|
checkConsulStateAttr: "Check for Consul services in this particular state",
|
||||||
|
}
|
||||||
|
|
||||||
|
var consulHealthCheckRE = regexp.MustCompile(fmt.Sprintf(`^%s/(%s|%s|%s)/(.+)`, checkConsulV1Prefix, checkConsulV1NodePrefix, checkConsulV1ServicePrefix, checkConsulV1StatePrefix))
|
||||||
|
|
||||||
|
var schemaCheckConsul = &schema.Schema{
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
MaxItems: 1,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: convertToHelperSchema(checkConsulDescriptions, map[schemaAttr]*schema.Schema{
|
||||||
|
checkConsulACLTokenAttr: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
ValidateFunc: validateRegexp(checkConsulACLTokenAttr, `^[a-zA-Z0-9\-]+$`),
|
||||||
|
},
|
||||||
|
checkConsulAllowStaleAttr: &schema.Schema{
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Default: true,
|
||||||
|
},
|
||||||
|
checkConsulCAChainAttr: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
ValidateFunc: validateRegexp(checkConsulCAChainAttr, `.+`),
|
||||||
|
},
|
||||||
|
checkConsulCertFileAttr: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
ValidateFunc: validateRegexp(checkConsulCertFileAttr, `.+`),
|
||||||
|
},
|
||||||
|
checkConsulCheckNameBlacklistAttr: &schema.Schema{
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
ValidateFunc: validateRegexp(checkConsulCheckNameBlacklistAttr, `^[A-Za-z0-9_-]+$`),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
checkConsulCiphersAttr: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
ValidateFunc: validateRegexp(checkConsulCiphersAttr, `.+`),
|
||||||
|
},
|
||||||
|
checkConsulDatacenterAttr: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
ValidateFunc: validateRegexp(checkConsulCertFileAttr, `^[a-zA-Z0-9]+$`),
|
||||||
|
},
|
||||||
|
checkConsulHTTPAddrAttr: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Default: defaultCheckConsulHTTPAddr,
|
||||||
|
ValidateFunc: validateHTTPURL(checkConsulHTTPAddrAttr, urlIsAbs|urlWithoutPath),
|
||||||
|
},
|
||||||
|
checkConsulHeadersAttr: &schema.Schema{
|
||||||
|
Type: schema.TypeMap,
|
||||||
|
Elem: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
ValidateFunc: validateHTTPHeaders,
|
||||||
|
},
|
||||||
|
checkConsulKeyFileAttr: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
ValidateFunc: validateRegexp(checkConsulKeyFileAttr, `.+`),
|
||||||
|
},
|
||||||
|
checkConsulNodeAttr: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
ValidateFunc: validateRegexp(checkConsulNodeAttr, `^[a-zA-Z0-9_\-]+$`),
|
||||||
|
ConflictsWith: []string{
|
||||||
|
checkConsulAttr + "." + checkConsulServiceAttr,
|
||||||
|
checkConsulAttr + "." + checkConsulStateAttr,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
checkConsulNodeBlacklistAttr: &schema.Schema{
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
ValidateFunc: validateRegexp(checkConsulNodeBlacklistAttr, `^[A-Za-z0-9_-]+$`),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
checkConsulServiceAttr: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
ValidateFunc: validateRegexp(checkConsulServiceAttr, `^[a-zA-Z0-9_\-]+$`),
|
||||||
|
ConflictsWith: []string{
|
||||||
|
checkConsulAttr + "." + checkConsulNodeAttr,
|
||||||
|
checkConsulAttr + "." + checkConsulStateAttr,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
checkConsulServiceNameBlacklistAttr: &schema.Schema{
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
ValidateFunc: validateRegexp(checkConsulServiceNameBlacklistAttr, `^[A-Za-z0-9_-]+$`),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
checkConsulStateAttr: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
ValidateFunc: validateRegexp(checkConsulStateAttr, `^(any|passing|warning|critical)$`),
|
||||||
|
ConflictsWith: []string{
|
||||||
|
checkConsulAttr + "." + checkConsulNodeAttr,
|
||||||
|
checkConsulAttr + "." + checkConsulServiceAttr,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkAPIToStateConsul reads the Config data out of circonusCheck.CheckBundle into
|
||||||
|
// the statefile.
|
||||||
|
func checkAPIToStateConsul(c *circonusCheck, d *schema.ResourceData) error {
|
||||||
|
consulConfig := make(map[string]interface{}, len(c.Config))
|
||||||
|
|
||||||
|
// swamp is a sanity check: it must be empty by the time this method returns
|
||||||
|
swamp := make(map[config.Key]string, len(c.Config))
|
||||||
|
for k, s := range c.Config {
|
||||||
|
swamp[k] = s
|
||||||
|
}
|
||||||
|
|
||||||
|
saveStringConfigToState := func(apiKey config.Key, attrName schemaAttr) {
|
||||||
|
if s, ok := c.Config[apiKey]; ok && s != "" {
|
||||||
|
consulConfig[string(attrName)] = s
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(swamp, apiKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
saveStringConfigToState(config.CAChain, checkConsulCAChainAttr)
|
||||||
|
saveStringConfigToState(config.CertFile, checkConsulCertFileAttr)
|
||||||
|
saveStringConfigToState(config.Ciphers, checkConsulCiphersAttr)
|
||||||
|
|
||||||
|
// httpAddrURL is used to compose the http_addr value using multiple c.Config
|
||||||
|
// values.
|
||||||
|
var httpAddrURL url.URL
|
||||||
|
|
||||||
|
headers := make(map[string]interface{}, len(c.Config)+1) // +1 is for the ACLToken
|
||||||
|
headerPrefixLen := len(config.HeaderPrefix)
|
||||||
|
|
||||||
|
// Explicitly handle several config parameters in sequence: URL, then port,
|
||||||
|
// then everything else.
|
||||||
|
if v, found := c.Config[config.URL]; found {
|
||||||
|
u, err := url.Parse(v)
|
||||||
|
if err != nil {
|
||||||
|
return errwrap.Wrapf(fmt.Sprintf("unable to parse %q from config: {{err}}", config.URL), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
queryArgs := u.Query()
|
||||||
|
if vals, found := queryArgs[apiConsulStaleAttr]; found && len(vals) > 0 {
|
||||||
|
consulConfig[string(checkConsulAllowStaleAttr)] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if dc := queryArgs.Get(apiConsulDatacenterAttr); dc != "" {
|
||||||
|
consulConfig[string(checkConsulDatacenterAttr)] = dc
|
||||||
|
}
|
||||||
|
|
||||||
|
httpAddrURL.Host = u.Host
|
||||||
|
httpAddrURL.Scheme = u.Scheme
|
||||||
|
|
||||||
|
md := consulHealthCheckRE.FindStringSubmatch(u.EscapedPath())
|
||||||
|
if md == nil {
|
||||||
|
return fmt.Errorf("config %q failed to match the health regexp", config.URL)
|
||||||
|
}
|
||||||
|
|
||||||
|
checkMode := md[1]
|
||||||
|
checkArg := md[2]
|
||||||
|
switch checkMode {
|
||||||
|
case checkConsulV1NodePrefix:
|
||||||
|
consulConfig[string(checkConsulNodeAttr)] = checkArg
|
||||||
|
case checkConsulV1ServicePrefix:
|
||||||
|
consulConfig[string(checkConsulServiceAttr)] = checkArg
|
||||||
|
case checkConsulV1StatePrefix:
|
||||||
|
consulConfig[string(checkConsulStateAttr)] = checkArg
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("PROVIDER BUG: unsupported check mode %q from %q", checkMode, u.EscapedPath())
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(swamp, config.URL)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, found := c.Config[config.Port]; found {
|
||||||
|
hostInfo := strings.SplitN(httpAddrURL.Host, ":", 2)
|
||||||
|
switch {
|
||||||
|
case len(hostInfo) == 1 && v != defaultCheckConsulPort, len(hostInfo) > 1:
|
||||||
|
httpAddrURL.Host = net.JoinHostPort(hostInfo[0], v)
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(swamp, config.Port)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, found := c.Config[apiConsulCheckBlacklist]; found {
|
||||||
|
consulConfig[checkConsulCheckNameBlacklistAttr] = strings.Split(v, ",")
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, found := c.Config[apiConsulNodeBlacklist]; found {
|
||||||
|
consulConfig[checkConsulNodeBlacklistAttr] = strings.Split(v, ",")
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, found := c.Config[apiConsulServiceBlacklist]; found {
|
||||||
|
consulConfig[checkConsulServiceNameBlacklistAttr] = strings.Split(v, ",")
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE(sean@): headers attribute processed last. See below.
|
||||||
|
|
||||||
|
consulConfig[string(checkConsulHTTPAddrAttr)] = httpAddrURL.String()
|
||||||
|
|
||||||
|
saveStringConfigToState(config.KeyFile, checkConsulKeyFileAttr)
|
||||||
|
|
||||||
|
// Process the headers last in order to provide an escape hatch capible of
|
||||||
|
// overriding any other derived value above.
|
||||||
|
for k, v := range c.Config {
|
||||||
|
if len(k) <= headerPrefixLen {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle all of the prefix variable headers, like `header_`
|
||||||
|
if strings.Compare(string(k[:headerPrefixLen]), string(config.HeaderPrefix)) == 0 {
|
||||||
|
key := k[headerPrefixLen:]
|
||||||
|
switch key {
|
||||||
|
case checkConsulTokenHeader:
|
||||||
|
consulConfig[checkConsulACLTokenAttr] = v
|
||||||
|
default:
|
||||||
|
headers[string(key)] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(swamp, k)
|
||||||
|
}
|
||||||
|
consulConfig[string(checkConsulHeadersAttr)] = headers
|
||||||
|
|
||||||
|
whitelistedConfigKeys := map[config.Key]struct{}{
|
||||||
|
config.Port: struct{}{},
|
||||||
|
config.ReverseSecretKey: struct{}{},
|
||||||
|
config.SubmissionURL: struct{}{},
|
||||||
|
config.URL: struct{}{},
|
||||||
|
}
|
||||||
|
|
||||||
|
for k := range swamp {
|
||||||
|
if _, ok := whitelistedConfigKeys[k]; ok {
|
||||||
|
delete(c.Config, k)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := whitelistedConfigKeys[k]; !ok {
|
||||||
|
return fmt.Errorf("PROVIDER BUG: API Config not empty: %#v", swamp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := d.Set(checkConsulAttr, []interface{}{consulConfig}); err != nil {
|
||||||
|
return errwrap.Wrapf(fmt.Sprintf("Unable to store check %q attribute: {{err}}", checkConsulAttr), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkConfigToAPIConsul(c *circonusCheck, l interfaceList) error {
|
||||||
|
c.Type = string(apiCheckTypeConsul)
|
||||||
|
|
||||||
|
// Iterate over all `consul` attributes, even though we have a max of 1 in the
|
||||||
|
// schema.
|
||||||
|
for _, mapRaw := range l {
|
||||||
|
consulConfig := newInterfaceMap(mapRaw)
|
||||||
|
if v, found := consulConfig[checkConsulCAChainAttr]; found {
|
||||||
|
c.Config[config.CAChain] = v.(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, found := consulConfig[checkConsulCertFileAttr]; found {
|
||||||
|
c.Config[config.CertFile] = v.(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, found := consulConfig[checkConsulCheckNameBlacklistAttr]; found {
|
||||||
|
listRaw := v.([]interface{})
|
||||||
|
checks := make([]string, 0, len(listRaw))
|
||||||
|
for _, v := range listRaw {
|
||||||
|
checks = append(checks, v.(string))
|
||||||
|
}
|
||||||
|
c.Config[apiConsulCheckBlacklist] = strings.Join(checks, ",")
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, found := consulConfig[checkConsulCiphersAttr]; found {
|
||||||
|
c.Config[config.Ciphers] = v.(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
if headers := consulConfig.CollectMap(checkConsulHeadersAttr); headers != nil {
|
||||||
|
for k, v := range headers {
|
||||||
|
h := config.HeaderPrefix + config.Key(k)
|
||||||
|
c.Config[h] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, found := consulConfig[checkConsulKeyFileAttr]; found {
|
||||||
|
c.Config[config.KeyFile] = v.(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Extract all of the input attributes necessary to construct the
|
||||||
|
// Consul agent's URL.
|
||||||
|
|
||||||
|
httpAddr := consulConfig[checkConsulHTTPAddrAttr].(string)
|
||||||
|
checkURL, err := url.Parse(httpAddr)
|
||||||
|
if err != nil {
|
||||||
|
return errwrap.Wrapf(fmt.Sprintf("Unable to parse %s's attribute %q: {{err}}", checkConsulAttr, httpAddr), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
hostInfo := strings.SplitN(checkURL.Host, ":", 2)
|
||||||
|
if len(c.Target) == 0 {
|
||||||
|
c.Target = hostInfo[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(hostInfo) > 1 {
|
||||||
|
c.Config[config.Port] = hostInfo[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, found := consulConfig[checkConsulNodeAttr]; found && v.(string) != "" {
|
||||||
|
checkURL.Path = strings.Join([]string{checkConsulV1Prefix, checkConsulV1NodePrefix, v.(string)}, "/")
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, found := consulConfig[checkConsulServiceAttr]; found && v.(string) != "" {
|
||||||
|
checkURL.Path = strings.Join([]string{checkConsulV1Prefix, checkConsulV1ServicePrefix, v.(string)}, "/")
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, found := consulConfig[checkConsulStateAttr]; found && v.(string) != "" {
|
||||||
|
checkURL.Path = strings.Join([]string{checkConsulV1Prefix, checkConsulV1StatePrefix, v.(string)}, "/")
|
||||||
|
}
|
||||||
|
|
||||||
|
q := checkURL.Query()
|
||||||
|
|
||||||
|
if v, found := consulConfig[checkConsulAllowStaleAttr]; found && v.(bool) {
|
||||||
|
q.Set(apiConsulStaleAttr, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, found := consulConfig[checkConsulDatacenterAttr]; found && v.(string) != "" {
|
||||||
|
q.Set(apiConsulDatacenterAttr, v.(string))
|
||||||
|
}
|
||||||
|
|
||||||
|
checkURL.RawQuery = q.Encode()
|
||||||
|
|
||||||
|
c.Config[config.URL] = checkURL.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, found := consulConfig[checkConsulNodeBlacklistAttr]; found {
|
||||||
|
listRaw := v.([]interface{})
|
||||||
|
checks := make([]string, 0, len(listRaw))
|
||||||
|
for _, v := range listRaw {
|
||||||
|
checks = append(checks, v.(string))
|
||||||
|
}
|
||||||
|
c.Config[apiConsulNodeBlacklist] = strings.Join(checks, ",")
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, found := consulConfig[checkConsulServiceNameBlacklistAttr]; found {
|
||||||
|
listRaw := v.([]interface{})
|
||||||
|
checks := make([]string, 0, len(listRaw))
|
||||||
|
for _, v := range listRaw {
|
||||||
|
checks = append(checks, v.(string))
|
||||||
|
}
|
||||||
|
c.Config[apiConsulServiceBlacklist] = strings.Join(checks, ",")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,282 @@
|
||||||
|
package circonus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/circonus-labs/circonus-gometrics/api/config"
|
||||||
|
"github.com/hashicorp/terraform/helper/acctest"
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccCirconusCheckConsul_node(t *testing.T) {
|
||||||
|
checkName := fmt.Sprintf("Terraform test: consul.service.consul mode=state check - %s", acctest.RandString(5))
|
||||||
|
|
||||||
|
checkNode := fmt.Sprintf("my-node-name-or-node-id-%s", acctest.RandString(5))
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckDestroyCirconusCheckBundle,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
{
|
||||||
|
Config: fmt.Sprintf(testAccCirconusCheckConsulConfigV1HealthNodeFmt, checkName, checkNode),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "active", "true"),
|
||||||
|
resource.TestMatchResourceAttr("circonus_check.consul_server", "check_id", regexp.MustCompile(config.CheckCIDRegex)),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "collector.#", "1"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "collector.2084916526.id", "/broker/2110"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "consul.#", "1"),
|
||||||
|
// resource.TestCheckResourceAttr("circonus_check.consul_server", "consul.0.ca_chain", ""),
|
||||||
|
// resource.TestCheckResourceAttr("circonus_check.consul_server", "consul.0.certificate_file", ""),
|
||||||
|
// resource.TestCheckResourceAttr("circonus_check.consul_server", "consul.0.ciphers", ""),
|
||||||
|
// resource.TestCheckResourceAttr("circonus_check.consul_server", "consul.0.key_file", ""),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "consul.0.dc", "dc2"),
|
||||||
|
resource.TestCheckNoResourceAttr("circonus_check.consul_server", "consul.0.headers"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "consul.0.http_addr", "http://consul.service.consul:8501"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "consul.0.node", checkNode),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "consul.0.node_blacklist.#", "3"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "consul.0.node_blacklist.0", "a"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "consul.0.node_blacklist.1", "bad"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "consul.0.node_blacklist.2", "node"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "notes", ""),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "period", "60s"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "metric.#", "2"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "metric.3333874791.active", "true"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "metric.3333874791.name", "KnownLeader"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "metric.3333874791.tags.#", "2"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "metric.3333874791.tags.1401442048", "lifecycle:unittest"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "metric.3333874791.tags.2058715988", "source:consul"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "metric.3333874791.type", "text"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "metric.3148913305.active", "true"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "metric.3148913305.name", "LastContact"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "metric.3148913305.tags.#", "2"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "metric.3148913305.tags.1401442048", "lifecycle:unittest"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "metric.3148913305.tags.2058715988", "source:consul"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "metric.3148913305.type", "numeric"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "metric.3148913305.unit", "seconds"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "tags.#", "2"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "tags.1401442048", "lifecycle:unittest"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "tags.2058715988", "source:consul"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "target", "consul.service.consul"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "type", "consul"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAccCirconusCheckConsul_service(t *testing.T) {
|
||||||
|
checkName := fmt.Sprintf("Terraform test: consul.service.consul mode=service check - %s", acctest.RandString(5))
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckDestroyCirconusCheckBundle,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
{
|
||||||
|
Config: fmt.Sprintf(testAccCirconusCheckConsulConfigV1HealthServiceFmt, checkName),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "active", "true"),
|
||||||
|
resource.TestMatchResourceAttr("circonus_check.consul_server", "check_id", regexp.MustCompile(config.CheckCIDRegex)),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "collector.#", "1"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "collector.2084916526.id", "/broker/2110"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "consul.#", "1"),
|
||||||
|
// resource.TestCheckResourceAttr("circonus_check.consul_server", "consul.0.ca_chain", ""),
|
||||||
|
// resource.TestCheckResourceAttr("circonus_check.consul_server", "consul.0.certificate_file", ""),
|
||||||
|
// resource.TestCheckResourceAttr("circonus_check.consul_server", "consul.0.ciphers", ""),
|
||||||
|
// resource.TestCheckResourceAttr("circonus_check.consul_server", "consul.0.key_file", ""),
|
||||||
|
resource.TestCheckNoResourceAttr("circonus_check.consul_server", "consul.0.headers"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "consul.0.http_addr", "http://consul.service.consul"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "consul.0.service", "consul"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "consul.0.service_blacklist.#", "3"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "consul.0.service_blacklist.0", "bad"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "consul.0.service_blacklist.1", "hombre"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "consul.0.service_blacklist.2", "service"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "name", checkName),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "notes", ""),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "period", "60s"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "metric.#", "2"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "metric.3333874791.active", "true"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "metric.3333874791.name", "KnownLeader"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "metric.3333874791.tags.#", "2"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "metric.3333874791.tags.1401442048", "lifecycle:unittest"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "metric.3333874791.tags.2058715988", "source:consul"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "metric.3333874791.type", "text"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "metric.3148913305.active", "true"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "metric.3148913305.name", "LastContact"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "metric.3148913305.tags.#", "2"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "metric.3148913305.tags.1401442048", "lifecycle:unittest"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "metric.3148913305.tags.2058715988", "source:consul"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "metric.3148913305.type", "numeric"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "metric.3148913305.unit", "seconds"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "tags.#", "2"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "tags.1401442048", "lifecycle:unittest"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "tags.2058715988", "source:consul"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "target", "consul.service.consul"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "type", "consul"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAccCirconusCheckConsul_state(t *testing.T) {
|
||||||
|
checkName := fmt.Sprintf("Terraform test: consul.service.consul mode=state check - %s", acctest.RandString(5))
|
||||||
|
|
||||||
|
checkState := "critical"
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckDestroyCirconusCheckBundle,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
{
|
||||||
|
Config: fmt.Sprintf(testAccCirconusCheckConsulConfigV1HealthStateFmt, checkName, checkState),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "active", "true"),
|
||||||
|
resource.TestMatchResourceAttr("circonus_check.consul_server", "check_id", regexp.MustCompile(config.CheckCIDRegex)),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "collector.#", "1"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "collector.2084916526.id", "/broker/2110"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "consul.#", "1"),
|
||||||
|
// resource.TestCheckResourceAttr("circonus_check.consul_server", "consul.0.ca_chain", ""),
|
||||||
|
// resource.TestCheckResourceAttr("circonus_check.consul_server", "consul.0.certificate_file", ""),
|
||||||
|
// resource.TestCheckResourceAttr("circonus_check.consul_server", "consul.0.ciphers", ""),
|
||||||
|
// resource.TestCheckResourceAttr("circonus_check.consul_server", "consul.0.key_file", ""),
|
||||||
|
resource.TestCheckNoResourceAttr("circonus_check.consul_server", "consul.0.headers"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "consul.0.http_addr", "http://consul.service.consul"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "consul.0.state", checkState),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "consul.0.check_blacklist.#", "2"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "consul.0.check_blacklist.0", "worthless"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "consul.0.check_blacklist.1", "check"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "name", checkName),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "notes", ""),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "period", "60s"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "metric.#", "2"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "metric.3333874791.active", "true"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "metric.3333874791.name", "KnownLeader"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "metric.3333874791.tags.#", "2"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "metric.3333874791.tags.1401442048", "lifecycle:unittest"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "metric.3333874791.tags.2058715988", "source:consul"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "metric.3333874791.type", "text"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "metric.3148913305.active", "true"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "metric.3148913305.name", "LastContact"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "metric.3148913305.tags.#", "2"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "metric.3148913305.tags.1401442048", "lifecycle:unittest"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "metric.3148913305.tags.2058715988", "source:consul"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "metric.3148913305.type", "numeric"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "metric.3148913305.unit", "seconds"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "tags.#", "2"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "tags.1401442048", "lifecycle:unittest"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "tags.2058715988", "source:consul"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "target", "consul.service.consul"),
|
||||||
|
resource.TestCheckResourceAttr("circonus_check.consul_server", "type", "consul"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const testAccCirconusCheckConsulConfigV1HealthNodeFmt = `
|
||||||
|
resource "circonus_check" "consul_server" {
|
||||||
|
active = true
|
||||||
|
name = "%s"
|
||||||
|
period = "60s"
|
||||||
|
|
||||||
|
collector {
|
||||||
|
id = "/broker/2110"
|
||||||
|
}
|
||||||
|
|
||||||
|
consul {
|
||||||
|
dc = "dc2"
|
||||||
|
http_addr = "http://consul.service.consul:8501"
|
||||||
|
node = "%s"
|
||||||
|
node_blacklist = ["a","bad","node"]
|
||||||
|
}
|
||||||
|
|
||||||
|
metric {
|
||||||
|
name = "LastContact"
|
||||||
|
tags = [ "source:consul", "lifecycle:unittest" ]
|
||||||
|
type = "numeric"
|
||||||
|
unit = "seconds"
|
||||||
|
}
|
||||||
|
|
||||||
|
metric {
|
||||||
|
name = "KnownLeader"
|
||||||
|
tags = [ "source:consul", "lifecycle:unittest" ]
|
||||||
|
type = "text"
|
||||||
|
}
|
||||||
|
|
||||||
|
tags = [ "source:consul", "lifecycle:unittest" ]
|
||||||
|
|
||||||
|
target = "consul.service.consul"
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const testAccCirconusCheckConsulConfigV1HealthServiceFmt = `
|
||||||
|
resource "circonus_check" "consul_server" {
|
||||||
|
active = true
|
||||||
|
name = "%s"
|
||||||
|
period = "60s"
|
||||||
|
|
||||||
|
collector {
|
||||||
|
id = "/broker/2110"
|
||||||
|
}
|
||||||
|
|
||||||
|
consul {
|
||||||
|
service = "consul"
|
||||||
|
service_blacklist = ["bad","hombre","service"]
|
||||||
|
}
|
||||||
|
|
||||||
|
metric {
|
||||||
|
name = "LastContact"
|
||||||
|
tags = [ "source:consul", "lifecycle:unittest" ]
|
||||||
|
type = "numeric"
|
||||||
|
unit = "seconds"
|
||||||
|
}
|
||||||
|
|
||||||
|
metric {
|
||||||
|
name = "KnownLeader"
|
||||||
|
tags = [ "source:consul", "lifecycle:unittest" ]
|
||||||
|
type = "text"
|
||||||
|
}
|
||||||
|
|
||||||
|
tags = [ "source:consul", "lifecycle:unittest" ]
|
||||||
|
|
||||||
|
target = "consul.service.consul"
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const testAccCirconusCheckConsulConfigV1HealthStateFmt = `
|
||||||
|
resource "circonus_check" "consul_server" {
|
||||||
|
active = true
|
||||||
|
name = "%s"
|
||||||
|
period = "60s"
|
||||||
|
|
||||||
|
collector {
|
||||||
|
id = "/broker/2110"
|
||||||
|
}
|
||||||
|
|
||||||
|
consul {
|
||||||
|
state = "%s"
|
||||||
|
check_blacklist = ["worthless","check"]
|
||||||
|
}
|
||||||
|
|
||||||
|
metric {
|
||||||
|
name = "LastContact"
|
||||||
|
tags = [ "source:consul", "lifecycle:unittest" ]
|
||||||
|
type = "numeric"
|
||||||
|
unit = "seconds"
|
||||||
|
}
|
||||||
|
|
||||||
|
metric {
|
||||||
|
name = "KnownLeader"
|
||||||
|
tags = [ "source:consul", "lifecycle:unittest" ]
|
||||||
|
type = "text"
|
||||||
|
}
|
||||||
|
|
||||||
|
tags = [ "source:consul", "lifecycle:unittest" ]
|
||||||
|
|
||||||
|
target = "consul.service.consul"
|
||||||
|
}
|
||||||
|
`
|
|
@ -372,6 +372,10 @@ func checkConfigToAPIHTTP(c *circonusCheck, l interfaceList) error {
|
||||||
if len(c.Target) == 0 {
|
if len(c.Target) == 0 {
|
||||||
c.Target = hostInfo[0]
|
c.Target = hostInfo[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(hostInfo) > 1 && c.Config[config.Port] == "" {
|
||||||
|
c.Config[config.Port] = hostInfo[1]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, found := httpConfig[checkHTTPVersionAttr]; found {
|
if v, found := httpConfig[checkHTTPVersionAttr]; found {
|
||||||
|
|
|
@ -355,6 +355,10 @@ func checkConfigToAPIJSON(c *circonusCheck, l interfaceList) error {
|
||||||
if len(c.Target) == 0 {
|
if len(c.Target) == 0 {
|
||||||
c.Target = hostInfo[0]
|
c.Target = hostInfo[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(hostInfo) > 1 && c.Config[config.Port] == "" {
|
||||||
|
c.Config[config.Port] = hostInfo[1]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, found := jsonConfig[checkJSONVersionAttr]; found {
|
if v, found := jsonConfig[checkJSONVersionAttr]; found {
|
||||||
|
|
|
@ -314,6 +314,7 @@ type urlParseFlags int
|
||||||
const (
|
const (
|
||||||
urlIsAbs urlParseFlags = 1 << iota
|
urlIsAbs urlParseFlags = 1 << iota
|
||||||
urlOptional
|
urlOptional
|
||||||
|
urlWithoutPath
|
||||||
urlWithoutPort
|
urlWithoutPort
|
||||||
urlWithoutSchema
|
urlWithoutSchema
|
||||||
)
|
)
|
||||||
|
@ -345,6 +346,10 @@ func validateHTTPURL(attrName schemaAttr, checkFlags urlParseFlags) func(v inter
|
||||||
errors = append(errors, fmt.Errorf("Schema is present on URL %q (HINT: drop the https://%s)", v.(string), v.(string)))
|
errors = append(errors, fmt.Errorf("Schema is present on URL %q (HINT: drop the https://%s)", v.(string), v.(string)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if checkFlags&urlWithoutPath != 0 && u.Path != "" {
|
||||||
|
errors = append(errors, fmt.Errorf("Path is present on URL %q (HINT: drop the %s)", v.(string), u.Path))
|
||||||
|
}
|
||||||
|
|
||||||
if checkFlags&urlWithoutPort != 0 {
|
if checkFlags&urlWithoutPort != 0 {
|
||||||
hostParts := strings.SplitN(u.Host, ":", 2)
|
hostParts := strings.SplitN(u.Host, ":", 2)
|
||||||
if len(hostParts) != 1 {
|
if len(hostParts) != 1 {
|
||||||
|
|
|
@ -88,6 +88,9 @@ resource "circonus_metric" "used" {
|
||||||
enterprise collector running in your datacenter. One collection of metrics
|
enterprise collector running in your datacenter. One collection of metrics
|
||||||
will be automatically created for each `collector` specified.
|
will be automatically created for each `collector` specified.
|
||||||
|
|
||||||
|
* `consul` - (Optional) A native Consul check. See below for details on how to
|
||||||
|
configure a `consul` check.
|
||||||
|
|
||||||
* `http` - (Optional) A poll-based HTTP check. See below for details on how to configure
|
* `http` - (Optional) A poll-based HTTP check. See below for details on how to configure
|
||||||
the `http` check.
|
the `http` check.
|
||||||
|
|
||||||
|
@ -249,6 +252,140 @@ resource "circonus_check" "rds_metrics" {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### `consul` Check Type Attributes
|
||||||
|
|
||||||
|
* `acl_token` - (Optional) An ACL Token authenticate the API request. When an
|
||||||
|
ACL Token is set, this value is transmitted as an HTTP Header in order to not
|
||||||
|
show up in any logs. The default value is an empty string.
|
||||||
|
|
||||||
|
* `allow_stale` - (Optional) A boolean value that indicates whether or not this
|
||||||
|
check should require the health information come from the Consul leader node.
|
||||||
|
For scalability reasons, this value defaults to `false`. See below for
|
||||||
|
details on detecting the staleness of health information.
|
||||||
|
|
||||||
|
* `ca_chain` - (Optional) A path to a file containing all the certificate
|
||||||
|
authorities that should be loaded to validate the remote certificate (required
|
||||||
|
when `http_addr` is a TLS-enabled endpoint).
|
||||||
|
|
||||||
|
* `certificate_file` - (Optional) A path to a file containing the client
|
||||||
|
certificate that will be presented to the remote server (required when
|
||||||
|
`http_addr` is a TLS-enabled endpoint).
|
||||||
|
|
||||||
|
* `check_blacklist` - (Optional) A list of check names to exclude from the
|
||||||
|
result of checks (i.e. no metrics will be generated by whose check name is in
|
||||||
|
the `check_blacklist`). This blacklist is applied to the `node`,
|
||||||
|
`service`, and `state` check modes.
|
||||||
|
|
||||||
|
* `ciphers` - (Optional) A list of ciphers to be used in the TLS protocol
|
||||||
|
(only used when `http_addr` is a TLS-enabled endpoint).
|
||||||
|
|
||||||
|
* `dc` - (Optional) Explicitly name the Consul datacenter to use. The default
|
||||||
|
value is an empty string. When an empty value is specified, the Consul
|
||||||
|
datacenter of the agent at the `http_addr` is implicitly used.
|
||||||
|
|
||||||
|
* `headers` - (Optional) A map of the HTTP headers to be sent when executing the
|
||||||
|
check. NOTE: the `headers` attribute is processed last and will takes
|
||||||
|
precidence over any other derived value that is transmitted as an HTTP header
|
||||||
|
to Consul (i.e. it is possible to override the `acl_token` by setting a
|
||||||
|
headers value).
|
||||||
|
|
||||||
|
* `http_addr` - (Optional) The Consul HTTP endpoint to to query for health
|
||||||
|
information. The default value is `http://consul.service.consul:8500`. The
|
||||||
|
scheme must change from `http` to `https` when the endpoint has been
|
||||||
|
TLS-enabled.
|
||||||
|
|
||||||
|
* `key_file` - (Optional) A path to a file containing key to be used in
|
||||||
|
conjunction with the cilent certificate (required when `http_addr` is a
|
||||||
|
TLS-enabled endpoint).
|
||||||
|
|
||||||
|
* `node` - (Optional) Check the health of this node. The value can be either a
|
||||||
|
Consul Node ID (Consul Version >= 0.7.4) or Node Name. See also the
|
||||||
|
`service_blacklist`, `node_blacklist`, and `check_blacklist` attributes. This
|
||||||
|
attribute conflicts with the `service` and `state` attributes.
|
||||||
|
|
||||||
|
* `node_blacklist` - (Optional) A list of node IDs or node names to exclude from
|
||||||
|
the results of checks (i.e. no metrics will be generated from nodes in the
|
||||||
|
`node_blacklist`). This blacklist is applied to the `node`, `service`, and
|
||||||
|
`state` check modes.
|
||||||
|
|
||||||
|
* `service` - (Optional) Check the cluster-wide health of this named service.
|
||||||
|
See also the `service_blacklist`, `node_blacklist`, and `check_blacklist`
|
||||||
|
attributes. This attribute conflicts with the `node` and `state` attributes.
|
||||||
|
|
||||||
|
* `service_blacklist` - (Optional) A list of service names to exclude from the
|
||||||
|
result of checks (i.e. no metrics will be generated by services whose service
|
||||||
|
name is in the `service_blacklist`). This blacklist is applied to the `node`,
|
||||||
|
`service`, and `state` check modes.
|
||||||
|
|
||||||
|
* `state` - (Optional) A Circonus check to monitor Consul checks across the
|
||||||
|
entire Consul cluster. This value may be either `passing`, `warning`, or
|
||||||
|
`critical`. This `consul` check mode is intended to act as the cluster check
|
||||||
|
of last resort. This check type is useful when first starting and is intended
|
||||||
|
to act as a check of last resort before transitioning to explicitly defined
|
||||||
|
checks for individual services or nodes. The metrics returned from check will
|
||||||
|
be sorted based on the `CreateIndex` of the entry in order to have a stable
|
||||||
|
set of metrics in the array of returned values. See also the
|
||||||
|
`service_blacklist`, `node_blacklist`, and `check_blacklist` attributes. This
|
||||||
|
attribute conflicts with the `node` and `state` attributes.
|
||||||
|
|
||||||
|
Available metrics depend on the consul check being performed (`node`, `service`,
|
||||||
|
or `state`). In addition to the data avilable from the endpoints, the `consul`
|
||||||
|
check also returns a set of metrics that are a variant of:
|
||||||
|
`{Num,Pct}{,Passing,Warning,Critical}{Checks,Nodes,Services}` (see the
|
||||||
|
`GLOB_BRACE` section of your local `glob(3)` documentation).
|
||||||
|
|
||||||
|
Example Consul check (partial metrics collection):
|
||||||
|
|
||||||
|
```
|
||||||
|
resource "circonus_check" "consul_server" {
|
||||||
|
active = true
|
||||||
|
name = "%s"
|
||||||
|
period = "60s"
|
||||||
|
|
||||||
|
collector {
|
||||||
|
# Collector ID must be an Enterprise broker able to reach the Consul agent
|
||||||
|
# listed in `http_addr`.
|
||||||
|
id = "/broker/2110"
|
||||||
|
}
|
||||||
|
|
||||||
|
consul {
|
||||||
|
service = "consul"
|
||||||
|
|
||||||
|
# Other consul check modes:
|
||||||
|
# node = "consul1"
|
||||||
|
# state = "critical"
|
||||||
|
}
|
||||||
|
|
||||||
|
metric {
|
||||||
|
name = "NumNodes"
|
||||||
|
tags = [ "source:consul", "lifecycle:unittest" ]
|
||||||
|
type = "numeric"
|
||||||
|
}
|
||||||
|
|
||||||
|
metric {
|
||||||
|
name = "LastContact"
|
||||||
|
tags = [ "source:consul", "lifecycle:unittest" ]
|
||||||
|
type = "numeric"
|
||||||
|
unit = "seconds"
|
||||||
|
}
|
||||||
|
|
||||||
|
metric {
|
||||||
|
name = "Index"
|
||||||
|
tags = [ "source:consul", "lifecycle:unittest" ]
|
||||||
|
type = "numeric"
|
||||||
|
unit = "transactions"
|
||||||
|
}
|
||||||
|
|
||||||
|
metric {
|
||||||
|
name = "KnownLeader"
|
||||||
|
tags = [ "source:consul", "lifecycle:unittest" ]
|
||||||
|
type = "text"
|
||||||
|
}
|
||||||
|
|
||||||
|
tags = [ "source:consul", "lifecycle:unittest" ]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### `http` Check Type Attributes
|
### `http` Check Type Attributes
|
||||||
|
|
||||||
* `auth_method` - (Optional) HTTP Authentication method to use. When set must
|
* `auth_method` - (Optional) HTTP Authentication method to use. When set must
|
||||||
|
|
Loading…
Reference in New Issue