Add statsd support to the `circonus_check` resource. (#12820)

* Vendor update `github.com/circonus-labs/circonus-gometrics`

* Add the `statsd` check type to the `circonus_check` resource.

* Noop change: Alpha-sort members of maps, variables, and docs.
This commit is contained in:
Sean Chittenden 2017-03-17 15:34:00 -07:00 committed by Jake Champlin
parent 14e07b136e
commit d3225296a2
9 changed files with 204 additions and 47 deletions

View File

@ -29,6 +29,7 @@ const (
apiCheckTypeHTTP circonusCheckType = "http" apiCheckTypeHTTP circonusCheckType = "http"
apiCheckTypeJSON circonusCheckType = "json" apiCheckTypeJSON circonusCheckType = "json"
apiCheckTypeMySQL circonusCheckType = "mysql" apiCheckTypeMySQL circonusCheckType = "mysql"
apiCheckTypeStatsd circonusCheckType = "statsd"
apiCheckTypePostgreSQL circonusCheckType = "postgres" apiCheckTypePostgreSQL circonusCheckType = "postgres"
apiCheckTypeTCP circonusCheckType = "tcp" apiCheckTypeTCP circonusCheckType = "tcp"
) )

View File

@ -44,6 +44,7 @@ const (
checkPeriodAttr = "period" checkPeriodAttr = "period"
checkPostgreSQLAttr = "postgresql" checkPostgreSQLAttr = "postgresql"
checkMetricAttr = "metric" checkMetricAttr = "metric"
checkStatsdAttr = "statsd"
checkTagsAttr = "tags" checkTagsAttr = "tags"
checkTargetAttr = "target" checkTargetAttr = "target"
checkTCPAttr = "tcp" checkTCPAttr = "tcp"
@ -79,6 +80,7 @@ const (
apiCheckTypeJSONAttr apiCheckType = "json" apiCheckTypeJSONAttr apiCheckType = "json"
apiCheckTypeMySQLAttr apiCheckType = "mysql" apiCheckTypeMySQLAttr apiCheckType = "mysql"
apiCheckTypePostgreSQLAttr apiCheckType = "postgres" apiCheckTypePostgreSQLAttr apiCheckType = "postgres"
apiCheckTypeStatsdAttr apiCheckType = "statsd"
apiCheckTypeTCPAttr apiCheckType = "tcp" apiCheckTypeTCPAttr apiCheckType = "tcp"
) )
@ -91,16 +93,17 @@ var checkDescriptions = attrDescrs{
checkHTTPTrapAttr: "HTTP Trap check configuration", checkHTTPTrapAttr: "HTTP Trap check configuration",
checkICMPPingAttr: "ICMP ping check configuration", checkICMPPingAttr: "ICMP ping check configuration",
checkJSONAttr: "JSON check configuration", checkJSONAttr: "JSON check configuration",
checkMetricAttr: "Configuration for a stream of metrics",
checkMetricLimitAttr: `Setting a metric_limit will enable all (-1), disable (0), or allow up to the specified limit of metrics for this check ("N+", where N is a positive integer)`, checkMetricLimitAttr: `Setting a metric_limit will enable all (-1), disable (0), or allow up to the specified limit of metrics for this check ("N+", where N is a positive integer)`,
checkMySQLAttr: "MySQL check configuration", checkMySQLAttr: "MySQL check configuration",
checkNameAttr: "The name of the check bundle that will be displayed in the web interface", checkNameAttr: "The name of the check bundle that will be displayed in the web interface",
checkNotesAttr: "Notes about this check bundle", checkNotesAttr: "Notes about this check bundle",
checkPeriodAttr: "The period between each time the check is made", checkPeriodAttr: "The period between each time the check is made",
checkPostgreSQLAttr: "PostgreSQL check configuration", checkPostgreSQLAttr: "PostgreSQL check configuration",
checkMetricAttr: "Configuration for a stream of metrics", checkStatsdAttr: "statsd check configuration",
checkTCPAttr: "TCP check configuration",
checkTagsAttr: "A list of tags assigned to the check", checkTagsAttr: "A list of tags assigned to the check",
checkTargetAttr: "The target of the check (e.g. hostname, URL, IP, etc)", checkTargetAttr: "The target of the check (e.g. hostname, URL, IP, etc)",
checkTCPAttr: "TCP check configuration",
checkTimeoutAttr: "The length of time in seconds (and fractions of a second) before the check will timeout if no response is returned to the collector", checkTimeoutAttr: "The length of time in seconds (and fractions of a second) before the check will timeout if no response is returned to the collector",
checkTypeAttr: "The check type", checkTypeAttr: "The check type",
@ -156,37 +159,6 @@ func resourceCheck() *schema.Resource {
checkHTTPTrapAttr: schemaCheckHTTPTrap, checkHTTPTrapAttr: schemaCheckHTTPTrap,
checkJSONAttr: schemaCheckJSON, checkJSONAttr: schemaCheckJSON,
checkICMPPingAttr: schemaCheckICMPPing, checkICMPPingAttr: schemaCheckICMPPing,
checkMetricLimitAttr: &schema.Schema{
Type: schema.TypeInt,
Optional: true,
Computed: true,
ValidateFunc: validateFuncs(
validateIntMin(checkMetricLimitAttr, -1),
),
},
checkMySQLAttr: schemaCheckMySQL,
checkNameAttr: &schema.Schema{
Type: schema.TypeString,
Optional: true,
Computed: true,
},
checkNotesAttr: &schema.Schema{
Type: schema.TypeString,
Optional: true,
Computed: true,
StateFunc: suppressWhitespace,
},
checkPeriodAttr: &schema.Schema{
Type: schema.TypeString,
Optional: true,
Computed: true,
StateFunc: normalizeTimeDurationStringToSeconds,
ValidateFunc: validateFuncs(
validateDurationMin(checkPeriodAttr, defaultCirconusCheckPeriodMin),
validateDurationMax(checkPeriodAttr, defaultCirconusCheckPeriodMax),
),
},
checkPostgreSQLAttr: schemaCheckPostgreSQL,
checkMetricAttr: &schema.Schema{ checkMetricAttr: &schema.Schema{
Type: schema.TypeSet, Type: schema.TypeSet,
Optional: true, Optional: true,
@ -219,7 +191,39 @@ func resourceCheck() *schema.Resource {
}), }),
}, },
}, },
checkTagsAttr: tagMakeConfigSchema(checkTagsAttr), checkMetricLimitAttr: &schema.Schema{
Type: schema.TypeInt,
Optional: true,
Computed: true,
ValidateFunc: validateFuncs(
validateIntMin(checkMetricLimitAttr, -1),
),
},
checkMySQLAttr: schemaCheckMySQL,
checkNameAttr: &schema.Schema{
Type: schema.TypeString,
Optional: true,
Computed: true,
},
checkNotesAttr: &schema.Schema{
Type: schema.TypeString,
Optional: true,
Computed: true,
StateFunc: suppressWhitespace,
},
checkPeriodAttr: &schema.Schema{
Type: schema.TypeString,
Optional: true,
Computed: true,
StateFunc: normalizeTimeDurationStringToSeconds,
ValidateFunc: validateFuncs(
validateDurationMin(checkPeriodAttr, defaultCirconusCheckPeriodMin),
validateDurationMax(checkPeriodAttr, defaultCirconusCheckPeriodMax),
),
},
checkPostgreSQLAttr: schemaCheckPostgreSQL,
checkStatsdAttr: schemaCheckStatsd,
checkTagsAttr: tagMakeConfigSchema(checkTagsAttr),
checkTargetAttr: &schema.Schema{ checkTargetAttr: &schema.Schema{
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
@ -564,6 +568,7 @@ func checkConfigToAPI(c *circonusCheck, d *schema.ResourceData) error {
checkJSONAttr: checkConfigToAPIJSON, checkJSONAttr: checkConfigToAPIJSON,
checkMySQLAttr: checkConfigToAPIMySQL, checkMySQLAttr: checkConfigToAPIMySQL,
checkPostgreSQLAttr: checkConfigToAPIPostgreSQL, checkPostgreSQLAttr: checkConfigToAPIPostgreSQL,
checkStatsdAttr: checkConfigToAPIStatsd,
checkTCPAttr: checkConfigToAPITCP, checkTCPAttr: checkConfigToAPITCP,
} }
@ -590,6 +595,7 @@ func parseCheckTypeConfig(c *circonusCheck, d *schema.ResourceData) error {
apiCheckTypeJSONAttr: checkAPIToStateJSON, apiCheckTypeJSONAttr: checkAPIToStateJSON,
apiCheckTypeMySQLAttr: checkAPIToStateMySQL, apiCheckTypeMySQLAttr: checkAPIToStateMySQL,
apiCheckTypePostgreSQLAttr: checkAPIToStatePostgreSQL, apiCheckTypePostgreSQLAttr: checkAPIToStatePostgreSQL,
apiCheckTypeStatsdAttr: checkAPIToStateStatsd,
apiCheckTypeTCPAttr: checkAPIToStateTCP, apiCheckTypeTCPAttr: checkAPIToStateTCP,
} }

View File

@ -75,8 +75,8 @@ func checkConfigToAPICAQL(c *circonusCheck, l interfaceList) error {
c.Type = string(apiCheckTypeCAQL) c.Type = string(apiCheckTypeCAQL)
c.Target = defaultCheckCAQLTarget c.Target = defaultCheckCAQLTarget
// Iterate over all `icmp_ping` attributes, even though we have a max of 1 in // Iterate over all `caql` attributes, even though we have a max of 1 in the
// the schema. // schema.
for _, mapRaw := range l { for _, mapRaw := range l {
caqlConfig := newInterfaceMap(mapRaw) caqlConfig := newInterfaceMap(mapRaw)

View File

@ -84,8 +84,8 @@ func hashCheckMySQL(v interface{}) int {
func checkConfigToAPIMySQL(c *circonusCheck, l interfaceList) error { func checkConfigToAPIMySQL(c *circonusCheck, l interfaceList) error {
c.Type = string(apiCheckTypeMySQL) c.Type = string(apiCheckTypeMySQL)
// Iterate over all `postgres` attributes, even though we have a max of 1 in // Iterate over all `mysql` attributes, even though we have a max of 1 in the
// the schema. // schema.
for _, mapRaw := range l { for _, mapRaw := range l {
mysqlConfig := newInterfaceMap(mapRaw) mysqlConfig := newInterfaceMap(mapRaw)

View File

@ -0,0 +1,69 @@
package circonus
import (
"fmt"
"github.com/hashicorp/errwrap"
"github.com/hashicorp/terraform/helper/schema"
)
const (
// circonus_check.statsd.* resource attribute names
checkStatsdSourceIPAttr = "source_ip"
)
var checkStatsdDescriptions = attrDescrs{
checkStatsdSourceIPAttr: "The source IP of the statsd metrics stream",
}
var schemaCheckStatsd = &schema.Schema{
Type: schema.TypeSet,
Optional: true,
MaxItems: 1,
MinItems: 1,
Elem: &schema.Resource{
Schema: convertToHelperSchema(checkStatsdDescriptions, map[schemaAttr]*schema.Schema{
checkStatsdSourceIPAttr: &schema.Schema{
Type: schema.TypeString,
Required: true,
ValidateFunc: validateRegexp(checkStatsdSourceIPAttr, `.+`),
},
}),
},
}
// checkAPIToStateStatsd reads the Config data out of circonusCheck.CheckBundle
// into the statefile.
func checkAPIToStateStatsd(c *circonusCheck, d *schema.ResourceData) error {
statsdConfig := make(map[string]interface{}, len(c.Config))
// Unconditionally map the target to the source_ip config attribute
statsdConfig[string(checkStatsdSourceIPAttr)] = c.Target
if err := d.Set(checkStatsdAttr, []interface{}{statsdConfig}); err != nil {
return errwrap.Wrapf(fmt.Sprintf("Unable to store check %q attribute: {{err}}", checkStatsdAttr), err)
}
return nil
}
func checkConfigToAPIStatsd(c *circonusCheck, l interfaceList) error {
c.Type = string(apiCheckTypeStatsd)
// Iterate over all `statsd` attributes, even though we have a max of 1 in the
// schema.
for _, mapRaw := range l {
statsdConfig := newInterfaceMap(mapRaw)
if v, found := statsdConfig[checkStatsdSourceIPAttr]; found {
switch {
case c.Target == "":
c.Target = v.(string)
case c.Target != v.(string):
return fmt.Errorf("Target (%q) must match %s (%q)", c.Target, checkStatsdSourceIPAttr, v.(string))
}
}
}
return nil
}

View File

@ -0,0 +1,71 @@
package circonus
import (
"fmt"
"testing"
"github.com/hashicorp/terraform/helper/acctest"
"github.com/hashicorp/terraform/helper/resource"
)
func TestAccCirconusCheckStatsd_basic(t *testing.T) {
checkName := fmt.Sprintf("statsd test check - %s", acctest.RandString(5))
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckDestroyCirconusCheckBundle,
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(testAccCirconusCheckStatsdConfigFmt, checkName),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("circonus_check.statsd_dump", "active", "true"),
resource.TestCheckResourceAttr("circonus_check.statsd_dump", "collector.#", "1"),
resource.TestCheckResourceAttr("circonus_check.statsd_dump", "collector.2084916526.id", "/broker/2110"),
resource.TestCheckResourceAttr("circonus_check.statsd_dump", "statsd.#", "1"),
resource.TestCheckResourceAttr("circonus_check.statsd_dump", "statsd.3733287963.source_ip", `127.0.0.2`),
resource.TestCheckResourceAttr("circonus_check.statsd_dump", "name", checkName),
resource.TestCheckResourceAttr("circonus_check.statsd_dump", "period", "60s"),
resource.TestCheckResourceAttr("circonus_check.statsd_dump", "metric.#", "1"),
resource.TestCheckResourceAttr("circonus_check.statsd_dump", "tags.#", "4"),
resource.TestCheckResourceAttr("circonus_check.statsd_dump", "tags.3728194417", "app:consul"),
resource.TestCheckResourceAttr("circonus_check.statsd_dump", "tags.2087084518", "author:terraform"),
resource.TestCheckResourceAttr("circonus_check.statsd_dump", "tags.1401442048", "lifecycle:unittest"),
resource.TestCheckResourceAttr("circonus_check.statsd_dump", "tags.2812916752", "source:statsd"),
resource.TestCheckResourceAttr("circonus_check.statsd_dump", "target", "127.0.0.2"),
resource.TestCheckResourceAttr("circonus_check.statsd_dump", "type", "statsd"),
),
},
},
})
}
const testAccCirconusCheckStatsdConfigFmt = `
variable "test_tags" {
type = "list"
default = [ "app:consul", "author:terraform", "lifecycle:unittest", "source:statsd" ]
}
resource "circonus_check" "statsd_dump" {
active = true
name = "%s"
period = "60s"
collector {
id = "/broker/2110"
}
statsd {
source_ip = "127.0.0.2"
}
metric {
name = "rando_metric"
tags = [ "${var.test_tags}" ]
type = "histogram"
}
tags = [ "${var.test_tags}" ]
}
`

View File

@ -38,7 +38,7 @@ type CheckBundle struct {
Checks []string `json:"_checks,omitempty"` // [] len >= 0 Checks []string `json:"_checks,omitempty"` // [] len >= 0
CheckUUIDs []string `json:"_check_uuids,omitempty"` // [] len >= 0 CheckUUIDs []string `json:"_check_uuids,omitempty"` // [] len >= 0
CID string `json:"_cid,omitempty"` // string CID string `json:"_cid,omitempty"` // string
Config CheckBundleConfig `json:"config,omitempty"` // NOTE contents of config are check type specific, map len >= 0 Config CheckBundleConfig `json:"config"` // NOTE contents of config are check type specific, map len >= 0
Created uint `json:"_created,omitempty"` // uint Created uint `json:"_created,omitempty"` // uint
DisplayName string `json:"display_name"` // string DisplayName string `json:"display_name"` // string
LastModifedBy string `json:"_last_modifed_by,omitempty"` // string LastModifedBy string `json:"_last_modifed_by,omitempty"` // string

10
vendor/vendor.json vendored
View File

@ -1178,16 +1178,16 @@
"revisionTime": "2017-01-10T09:44:45Z" "revisionTime": "2017-01-10T09:44:45Z"
}, },
{ {
"checksumSHA1": "PDusd0EuHz0oKiQKwKxFhbETxd8=", "checksumSHA1": "6fUPaqXabil0m2nqKONt9lOmo4c=",
"path": "github.com/circonus-labs/circonus-gometrics/api", "path": "github.com/circonus-labs/circonus-gometrics/api",
"revision": "dbab9a33438e3f8317407ef5d3a51c29340541db", "revision": "55add91cfb689b0fd6e9fa67c58c7a948310a80e",
"revisionTime": "2017-02-21T20:27:28Z" "revisionTime": "2017-03-17T00:26:31Z"
}, },
{ {
"checksumSHA1": "bQhz/fcyZPmuHSH2qwC4ZtATy5c=", "checksumSHA1": "bQhz/fcyZPmuHSH2qwC4ZtATy5c=",
"path": "github.com/circonus-labs/circonus-gometrics/api/config", "path": "github.com/circonus-labs/circonus-gometrics/api/config",
"revision": "dbab9a33438e3f8317407ef5d3a51c29340541db", "revision": "55add91cfb689b0fd6e9fa67c58c7a948310a80e",
"revisionTime": "2017-02-21T20:27:28Z" "revisionTime": "2017-03-17T00:26:31Z"
}, },
{ {
"checksumSHA1": "QhYMdplKQJAMptRaHZBB8CF6HdM=", "checksumSHA1": "QhYMdplKQJAMptRaHZBB8CF6HdM=",

View File

@ -101,6 +101,10 @@ resource "circonus_metric" "used" {
* `json` - (Optional) A JSON check. See below for details on how to configure * `json` - (Optional) A JSON check. See below for details on how to configure
the `json` check. the `json` check.
* `metric` - (Required) A list of one or more `metric` configurations. All
metrics obtained from this check instance will be available as individual
metric streams. See below for a list of supported `metric` attrbutes.
* `metric_limit` - (Optional) Setting a metric limit will tell the Circonus * `metric_limit` - (Optional) Setting a metric limit will tell the Circonus
backend to periodically look at the check to see if there are additional backend to periodically look at the check to see if there are additional
metrics the collector has seen that we should collect. It will not reactivate metrics the collector has seen that we should collect. It will not reactivate
@ -122,9 +126,8 @@ resource "circonus_metric" "used" {
* `postgresql` - (Optional) A PostgreSQL check. See below for details on how to * `postgresql` - (Optional) A PostgreSQL check. See below for details on how to
configure the `postgresql` check. configure the `postgresql` check.
* `metric` - (Required) A list of one or more `metric` configurations. All * `statsd` - (Optional) A statsd check. See below for details on how to
metrics obtained from this check instance will be available as individual configure the `statsd` check.
metric streams. See below for a list of supported `metric` attrbutes.
* `tags` - (Optional) A list of tags assigned to this check. * `tags` - (Optional) A list of tags assigned to this check.
@ -399,6 +402,13 @@ The `postgresql` check requires the `target` top-level attribute to be set.
Available metric names are dependent on the output of the `query` being run. Available metric names are dependent on the output of the `query` being run.
### `statsd` Check Type Attributes
* `source_ip` - (Required) Any statsd messages from this IP address (IPv4 or
IPv6) will be associated with this check.
Available metrics depend on the metrics sent to the `statsd` check.
### `tcp` Check Type Attributes ### `tcp` Check Type Attributes
* `banner_regexp` - (Optional) This regular expression is matched against the * `banner_regexp` - (Optional) This regular expression is matched against the