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"
apiCheckTypeJSON circonusCheckType = "json"
apiCheckTypeMySQL circonusCheckType = "mysql"
apiCheckTypeStatsd circonusCheckType = "statsd"
apiCheckTypePostgreSQL circonusCheckType = "postgres"
apiCheckTypeTCP circonusCheckType = "tcp"
)

View File

@ -44,6 +44,7 @@ const (
checkPeriodAttr = "period"
checkPostgreSQLAttr = "postgresql"
checkMetricAttr = "metric"
checkStatsdAttr = "statsd"
checkTagsAttr = "tags"
checkTargetAttr = "target"
checkTCPAttr = "tcp"
@ -79,6 +80,7 @@ const (
apiCheckTypeJSONAttr apiCheckType = "json"
apiCheckTypeMySQLAttr apiCheckType = "mysql"
apiCheckTypePostgreSQLAttr apiCheckType = "postgres"
apiCheckTypeStatsdAttr apiCheckType = "statsd"
apiCheckTypeTCPAttr apiCheckType = "tcp"
)
@ -91,16 +93,17 @@ var checkDescriptions = attrDescrs{
checkHTTPTrapAttr: "HTTP Trap check configuration",
checkICMPPingAttr: "ICMP ping 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)`,
checkMySQLAttr: "MySQL check configuration",
checkNameAttr: "The name of the check bundle that will be displayed in the web interface",
checkNotesAttr: "Notes about this check bundle",
checkPeriodAttr: "The period between each time the check is made",
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",
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",
checkTypeAttr: "The check type",
@ -156,37 +159,6 @@ func resourceCheck() *schema.Resource {
checkHTTPTrapAttr: schemaCheckHTTPTrap,
checkJSONAttr: schemaCheckJSON,
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{
Type: schema.TypeSet,
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{
Type: schema.TypeString,
Optional: true,
@ -564,6 +568,7 @@ func checkConfigToAPI(c *circonusCheck, d *schema.ResourceData) error {
checkJSONAttr: checkConfigToAPIJSON,
checkMySQLAttr: checkConfigToAPIMySQL,
checkPostgreSQLAttr: checkConfigToAPIPostgreSQL,
checkStatsdAttr: checkConfigToAPIStatsd,
checkTCPAttr: checkConfigToAPITCP,
}
@ -590,6 +595,7 @@ func parseCheckTypeConfig(c *circonusCheck, d *schema.ResourceData) error {
apiCheckTypeJSONAttr: checkAPIToStateJSON,
apiCheckTypeMySQLAttr: checkAPIToStateMySQL,
apiCheckTypePostgreSQLAttr: checkAPIToStatePostgreSQL,
apiCheckTypeStatsdAttr: checkAPIToStateStatsd,
apiCheckTypeTCPAttr: checkAPIToStateTCP,
}

View File

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

View File

@ -84,8 +84,8 @@ func hashCheckMySQL(v interface{}) int {
func checkConfigToAPIMySQL(c *circonusCheck, l interfaceList) error {
c.Type = string(apiCheckTypeMySQL)
// Iterate over all `postgres` attributes, even though we have a max of 1 in
// the schema.
// Iterate over all `mysql` attributes, even though we have a max of 1 in the
// schema.
for _, mapRaw := range l {
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
CheckUUIDs []string `json:"_check_uuids,omitempty"` // [] len >= 0
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
DisplayName string `json:"display_name"` // 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"
},
{
"checksumSHA1": "PDusd0EuHz0oKiQKwKxFhbETxd8=",
"checksumSHA1": "6fUPaqXabil0m2nqKONt9lOmo4c=",
"path": "github.com/circonus-labs/circonus-gometrics/api",
"revision": "dbab9a33438e3f8317407ef5d3a51c29340541db",
"revisionTime": "2017-02-21T20:27:28Z"
"revision": "55add91cfb689b0fd6e9fa67c58c7a948310a80e",
"revisionTime": "2017-03-17T00:26:31Z"
},
{
"checksumSHA1": "bQhz/fcyZPmuHSH2qwC4ZtATy5c=",
"path": "github.com/circonus-labs/circonus-gometrics/api/config",
"revision": "dbab9a33438e3f8317407ef5d3a51c29340541db",
"revisionTime": "2017-02-21T20:27:28Z"
"revision": "55add91cfb689b0fd6e9fa67c58c7a948310a80e",
"revisionTime": "2017-03-17T00:26:31Z"
},
{
"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
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
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
@ -122,9 +126,8 @@ resource "circonus_metric" "used" {
* `postgresql` - (Optional) A PostgreSQL check. See below for details on how to
configure the `postgresql` 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.
* `statsd` - (Optional) A statsd check. See below for details on how to
configure the `statsd` 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.
### `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
* `banner_regexp` - (Optional) This regular expression is matched against the