github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/circonus/resource_circonus_check.go (about)

     1  package circonus
     2  
     3  /*
     4   * Note to future readers: The `circonus_check` resource is actually a facade for
     5   * the check_bundle call.  check_bundle is an implementation detail that we mask
     6   * over and expose just a "check" even though the "check" is actually a
     7   * check_bundle.
     8   *
     9   * Style note: There are three directions that information flows:
    10   *
    11   * 1) Terraform Config file into API Objects.  *Attr named objects are Config or
    12   *    Schema attribute names.  In this file, all config constants should be
    13   *     named check*Attr.
    14   *
    15   * 2) API Objects into Statefile data.  api*Attr named constants are parameters
    16   *    that originate from the API and need to be mapped into the provider's
    17   *    vernacular.
    18   */
    19  
    20  import (
    21  	"fmt"
    22  	"time"
    23  
    24  	"github.com/circonus-labs/circonus-gometrics/api"
    25  	"github.com/circonus-labs/circonus-gometrics/api/config"
    26  	"github.com/hashicorp/errwrap"
    27  	"github.com/hashicorp/terraform/helper/schema"
    28  )
    29  
    30  const (
    31  	// circonus_check.* global resource attribute names
    32  	checkActiveAttr      = "active"
    33  	checkCAQLAttr        = "caql"
    34  	checkCloudWatchAttr  = "cloudwatch"
    35  	checkCollectorAttr   = "collector"
    36  	checkConsulAttr      = "consul"
    37  	checkHTTPAttr        = "http"
    38  	checkHTTPTrapAttr    = "httptrap"
    39  	checkICMPPingAttr    = "icmp_ping"
    40  	checkJSONAttr        = "json"
    41  	checkMetricAttr      = "metric"
    42  	checkMetricLimitAttr = "metric_limit"
    43  	checkMySQLAttr       = "mysql"
    44  	checkNameAttr        = "name"
    45  	checkNotesAttr       = "notes"
    46  	checkPeriodAttr      = "period"
    47  	checkPostgreSQLAttr  = "postgresql"
    48  	checkStatsdAttr      = "statsd"
    49  	checkTCPAttr         = "tcp"
    50  	checkTagsAttr        = "tags"
    51  	checkTargetAttr      = "target"
    52  	checkTimeoutAttr     = "timeout"
    53  	checkTypeAttr        = "type"
    54  
    55  	// circonus_check.collector.* resource attribute names
    56  	checkCollectorIDAttr = "id"
    57  
    58  	// circonus_check.metric.* resource attribute names are aliased to
    59  	// circonus_metric.* resource attributes.
    60  
    61  	// circonus_check.metric.* resource attribute names
    62  	// metricIDAttr  = "id"
    63  
    64  	// Out parameters for circonus_check
    65  	checkOutByCollectorAttr        = "check_by_collector"
    66  	checkOutIDAttr                 = "check_id"
    67  	checkOutChecksAttr             = "checks"
    68  	checkOutCreatedAttr            = "created"
    69  	checkOutLastModifiedAttr       = "last_modified"
    70  	checkOutLastModifiedByAttr     = "last_modified_by"
    71  	checkOutReverseConnectURLsAttr = "reverse_connect_urls"
    72  	checkOutCheckUUIDsAttr         = "uuids"
    73  )
    74  
    75  const (
    76  	// Circonus API constants from their API endpoints
    77  	apiCheckTypeCAQLAttr       apiCheckType = "caql"
    78  	apiCheckTypeCloudWatchAttr apiCheckType = "cloudwatch"
    79  	apiCheckTypeConsulAttr     apiCheckType = "consul"
    80  	apiCheckTypeHTTPAttr       apiCheckType = "http"
    81  	apiCheckTypeHTTPTrapAttr   apiCheckType = "httptrap"
    82  	apiCheckTypeICMPPingAttr   apiCheckType = "ping_icmp"
    83  	apiCheckTypeJSONAttr       apiCheckType = "json"
    84  	apiCheckTypeMySQLAttr      apiCheckType = "mysql"
    85  	apiCheckTypePostgreSQLAttr apiCheckType = "postgres"
    86  	apiCheckTypeStatsdAttr     apiCheckType = "statsd"
    87  	apiCheckTypeTCPAttr        apiCheckType = "tcp"
    88  )
    89  
    90  var checkDescriptions = attrDescrs{
    91  	checkActiveAttr:      "If the check is activate or disabled",
    92  	checkCAQLAttr:        "CAQL check configuration",
    93  	checkCloudWatchAttr:  "CloudWatch check configuration",
    94  	checkCollectorAttr:   "The collector(s) that are responsible for gathering the metrics",
    95  	checkConsulAttr:      "Consul check configuration",
    96  	checkHTTPAttr:        "HTTP check configuration",
    97  	checkHTTPTrapAttr:    "HTTP Trap check configuration",
    98  	checkICMPPingAttr:    "ICMP ping check configuration",
    99  	checkJSONAttr:        "JSON check configuration",
   100  	checkMetricAttr:      "Configuration for a stream of metrics",
   101  	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)`,
   102  	checkMySQLAttr:       "MySQL check configuration",
   103  	checkNameAttr:        "The name of the check bundle that will be displayed in the web interface",
   104  	checkNotesAttr:       "Notes about this check bundle",
   105  	checkPeriodAttr:      "The period between each time the check is made",
   106  	checkPostgreSQLAttr:  "PostgreSQL check configuration",
   107  	checkStatsdAttr:      "statsd check configuration",
   108  	checkTCPAttr:         "TCP check configuration",
   109  	checkTagsAttr:        "A list of tags assigned to the check",
   110  	checkTargetAttr:      "The target of the check (e.g. hostname, URL, IP, etc)",
   111  	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",
   112  	checkTypeAttr:        "The check type",
   113  
   114  	checkOutByCollectorAttr:        "",
   115  	checkOutCheckUUIDsAttr:         "",
   116  	checkOutChecksAttr:             "",
   117  	checkOutCreatedAttr:            "",
   118  	checkOutIDAttr:                 "",
   119  	checkOutLastModifiedAttr:       "",
   120  	checkOutLastModifiedByAttr:     "",
   121  	checkOutReverseConnectURLsAttr: "",
   122  }
   123  
   124  var checkCollectorDescriptions = attrDescrs{
   125  	checkCollectorIDAttr: "The ID of the collector",
   126  }
   127  
   128  var checkMetricDescriptions = metricDescriptions
   129  
   130  func resourceCheck() *schema.Resource {
   131  	return &schema.Resource{
   132  		Create: checkCreate,
   133  		Read:   checkRead,
   134  		Update: checkUpdate,
   135  		Delete: checkDelete,
   136  		Exists: checkExists,
   137  		Importer: &schema.ResourceImporter{
   138  			State: schema.ImportStatePassthrough,
   139  		},
   140  
   141  		Schema: convertToHelperSchema(checkDescriptions, map[schemaAttr]*schema.Schema{
   142  			checkActiveAttr: &schema.Schema{
   143  				Type:     schema.TypeBool,
   144  				Optional: true,
   145  				Default:  true,
   146  			},
   147  			checkCAQLAttr:       schemaCheckCAQL,
   148  			checkCloudWatchAttr: schemaCheckCloudWatch,
   149  			checkCollectorAttr: &schema.Schema{
   150  				Type:     schema.TypeSet,
   151  				Optional: true,
   152  				MinItems: 1,
   153  				Elem: &schema.Resource{
   154  					Schema: convertToHelperSchema(checkCollectorDescriptions, map[schemaAttr]*schema.Schema{
   155  						checkCollectorIDAttr: &schema.Schema{
   156  							Type:         schema.TypeString,
   157  							Required:     true,
   158  							ValidateFunc: validateRegexp(checkCollectorIDAttr, config.BrokerCIDRegex),
   159  						},
   160  					}),
   161  				},
   162  			},
   163  			checkConsulAttr:   schemaCheckConsul,
   164  			checkHTTPAttr:     schemaCheckHTTP,
   165  			checkHTTPTrapAttr: schemaCheckHTTPTrap,
   166  			checkJSONAttr:     schemaCheckJSON,
   167  			checkICMPPingAttr: schemaCheckICMPPing,
   168  			checkMetricAttr: &schema.Schema{
   169  				Type:     schema.TypeSet,
   170  				Optional: true,
   171  				Set:      checkMetricChecksum,
   172  				MinItems: 1,
   173  				Elem: &schema.Resource{
   174  					Schema: convertToHelperSchema(checkMetricDescriptions, map[schemaAttr]*schema.Schema{
   175  						metricActiveAttr: &schema.Schema{
   176  							Type:     schema.TypeBool,
   177  							Optional: true,
   178  							Default:  true,
   179  						},
   180  						metricNameAttr: &schema.Schema{
   181  							Type:         schema.TypeString,
   182  							Required:     true,
   183  							ValidateFunc: validateRegexp(metricNameAttr, `[\S]+`),
   184  						},
   185  						metricTagsAttr: tagMakeConfigSchema(metricTagsAttr),
   186  						metricTypeAttr: &schema.Schema{
   187  							Type:         schema.TypeString,
   188  							Required:     true,
   189  							ValidateFunc: validateMetricType,
   190  						},
   191  						metricUnitAttr: &schema.Schema{
   192  							Type:         schema.TypeString,
   193  							Optional:     true,
   194  							Default:      metricUnit,
   195  							ValidateFunc: validateRegexp(metricUnitAttr, metricUnitRegexp),
   196  						},
   197  					}),
   198  				},
   199  			},
   200  			checkMetricLimitAttr: &schema.Schema{
   201  				Type:     schema.TypeInt,
   202  				Optional: true,
   203  				Computed: true,
   204  				ValidateFunc: validateFuncs(
   205  					validateIntMin(checkMetricLimitAttr, -1),
   206  				),
   207  			},
   208  			checkMySQLAttr: schemaCheckMySQL,
   209  			checkNameAttr: &schema.Schema{
   210  				Type:     schema.TypeString,
   211  				Optional: true,
   212  				Computed: true,
   213  			},
   214  			checkNotesAttr: &schema.Schema{
   215  				Type:      schema.TypeString,
   216  				Optional:  true,
   217  				Computed:  true,
   218  				StateFunc: suppressWhitespace,
   219  			},
   220  			checkPeriodAttr: &schema.Schema{
   221  				Type:      schema.TypeString,
   222  				Optional:  true,
   223  				Computed:  true,
   224  				StateFunc: normalizeTimeDurationStringToSeconds,
   225  				ValidateFunc: validateFuncs(
   226  					validateDurationMin(checkPeriodAttr, defaultCirconusCheckPeriodMin),
   227  					validateDurationMax(checkPeriodAttr, defaultCirconusCheckPeriodMax),
   228  				),
   229  			},
   230  			checkPostgreSQLAttr: schemaCheckPostgreSQL,
   231  			checkStatsdAttr:     schemaCheckStatsd,
   232  			checkTagsAttr:       tagMakeConfigSchema(checkTagsAttr),
   233  			checkTargetAttr: &schema.Schema{
   234  				Type:         schema.TypeString,
   235  				Optional:     true,
   236  				Computed:     true,
   237  				ValidateFunc: validateRegexp(checkTagsAttr, `.+`),
   238  			},
   239  			checkTCPAttr: schemaCheckTCP,
   240  			checkTimeoutAttr: &schema.Schema{
   241  				Type:      schema.TypeString,
   242  				Optional:  true,
   243  				Computed:  true,
   244  				StateFunc: normalizeTimeDurationStringToSeconds,
   245  				ValidateFunc: validateFuncs(
   246  					validateDurationMin(checkTimeoutAttr, defaultCirconusTimeoutMin),
   247  					validateDurationMax(checkTimeoutAttr, defaultCirconusTimeoutMax),
   248  				),
   249  			},
   250  			checkTypeAttr: &schema.Schema{
   251  				Type:         schema.TypeString,
   252  				Computed:     true,
   253  				Optional:     true,
   254  				ForceNew:     true,
   255  				ValidateFunc: validateCheckType,
   256  			},
   257  
   258  			// Out parameters
   259  			checkOutIDAttr: &schema.Schema{
   260  				Type:     schema.TypeString,
   261  				Computed: true,
   262  			},
   263  			checkOutByCollectorAttr: &schema.Schema{
   264  				Type:     schema.TypeMap,
   265  				Computed: true,
   266  				Elem: &schema.Schema{
   267  					Type: schema.TypeString,
   268  				},
   269  			},
   270  			checkOutCheckUUIDsAttr: &schema.Schema{
   271  				Type:     schema.TypeList,
   272  				Computed: true,
   273  				Elem: &schema.Schema{
   274  					Type: schema.TypeString,
   275  				},
   276  			},
   277  			checkOutChecksAttr: &schema.Schema{
   278  				Type:     schema.TypeList,
   279  				Computed: true,
   280  				Elem: &schema.Schema{
   281  					Type: schema.TypeString,
   282  				},
   283  			},
   284  			checkOutCreatedAttr: &schema.Schema{
   285  				Type:     schema.TypeInt,
   286  				Computed: true,
   287  			},
   288  			checkOutLastModifiedAttr: &schema.Schema{
   289  				Type:     schema.TypeInt,
   290  				Computed: true,
   291  			},
   292  			checkOutLastModifiedByAttr: &schema.Schema{
   293  				Type:     schema.TypeString,
   294  				Computed: true,
   295  			},
   296  			checkOutReverseConnectURLsAttr: &schema.Schema{
   297  				Type:     schema.TypeList,
   298  				Computed: true,
   299  				Elem: &schema.Schema{
   300  					Type: schema.TypeString,
   301  				},
   302  			},
   303  		}),
   304  	}
   305  }
   306  
   307  func checkCreate(d *schema.ResourceData, meta interface{}) error {
   308  	ctxt := meta.(*providerContext)
   309  	c := newCheck()
   310  	if err := c.ParseConfig(d); err != nil {
   311  		return errwrap.Wrapf("error parsing check schema during create: {{err}}", err)
   312  	}
   313  
   314  	if err := c.Create(ctxt); err != nil {
   315  		return errwrap.Wrapf("error creating check: {{err}}", err)
   316  	}
   317  
   318  	d.SetId(c.CID)
   319  
   320  	return checkRead(d, meta)
   321  }
   322  
   323  func checkExists(d *schema.ResourceData, meta interface{}) (bool, error) {
   324  	ctxt := meta.(*providerContext)
   325  
   326  	cid := d.Id()
   327  	cb, err := ctxt.client.FetchCheckBundle(api.CIDType(&cid))
   328  	if err != nil {
   329  		return false, err
   330  	}
   331  
   332  	if cb.CID == "" {
   333  		return false, nil
   334  	}
   335  
   336  	return true, nil
   337  }
   338  
   339  // checkRead pulls data out of the CheckBundle object and stores it into the
   340  // appropriate place in the statefile.
   341  func checkRead(d *schema.ResourceData, meta interface{}) error {
   342  	ctxt := meta.(*providerContext)
   343  
   344  	cid := d.Id()
   345  	c, err := loadCheck(ctxt, api.CIDType(&cid))
   346  	if err != nil {
   347  		return err
   348  	}
   349  
   350  	d.SetId(c.CID)
   351  
   352  	// Global circonus_check attributes are saved first, followed by the check
   353  	// type specific attributes handled below in their respective checkRead*().
   354  
   355  	checkIDsByCollector := make(map[string]interface{}, len(c.Checks))
   356  	for i, b := range c.Brokers {
   357  		checkIDsByCollector[b] = c.Checks[i]
   358  	}
   359  
   360  	var checkID string
   361  	if len(c.Checks) == 1 {
   362  		checkID = c.Checks[0]
   363  	}
   364  
   365  	metrics := schema.NewSet(checkMetricChecksum, nil)
   366  	for _, m := range c.Metrics {
   367  		metricAttrs := map[string]interface{}{
   368  			string(metricActiveAttr): metricAPIStatusToBool(m.Status),
   369  			string(metricNameAttr):   m.Name,
   370  			string(metricTagsAttr):   tagsToState(apiToTags(m.Tags)),
   371  			string(metricTypeAttr):   m.Type,
   372  			string(metricUnitAttr):   indirect(m.Units),
   373  		}
   374  
   375  		metrics.Add(metricAttrs)
   376  	}
   377  
   378  	// Write the global circonus_check parameters followed by the check
   379  	// type-specific parameters.
   380  
   381  	d.Set(checkActiveAttr, checkAPIStatusToBool(c.Status))
   382  
   383  	if err := d.Set(checkCollectorAttr, stringListToSet(c.Brokers, checkCollectorIDAttr)); err != nil {
   384  		return errwrap.Wrapf(fmt.Sprintf("Unable to store check %q attribute: {{err}}", checkCollectorAttr), err)
   385  	}
   386  
   387  	d.Set(checkMetricLimitAttr, c.MetricLimit)
   388  	d.Set(checkNameAttr, c.DisplayName)
   389  	d.Set(checkNotesAttr, c.Notes)
   390  	d.Set(checkPeriodAttr, fmt.Sprintf("%ds", c.Period))
   391  
   392  	if err := d.Set(checkMetricAttr, metrics); err != nil {
   393  		return errwrap.Wrapf(fmt.Sprintf("Unable to store check %q attribute: {{err}}", checkMetricAttr), err)
   394  	}
   395  
   396  	if err := d.Set(checkTagsAttr, c.Tags); err != nil {
   397  		return errwrap.Wrapf(fmt.Sprintf("Unable to store check %q attribute: {{err}}", checkTagsAttr), err)
   398  	}
   399  
   400  	d.Set(checkTargetAttr, c.Target)
   401  
   402  	{
   403  		t, _ := time.ParseDuration(fmt.Sprintf("%fs", c.Timeout))
   404  		d.Set(checkTimeoutAttr, t.String())
   405  	}
   406  
   407  	d.Set(checkTypeAttr, c.Type)
   408  
   409  	// Last step: parse a check_bundle's config into the statefile.
   410  	if err := parseCheckTypeConfig(&c, d); err != nil {
   411  		return errwrap.Wrapf("Unable to parse check config: {{err}}", err)
   412  	}
   413  
   414  	// Out parameters
   415  	if err := d.Set(checkOutByCollectorAttr, checkIDsByCollector); err != nil {
   416  		return errwrap.Wrapf(fmt.Sprintf("Unable to store check %q attribute: {{err}}", checkOutByCollectorAttr), err)
   417  	}
   418  
   419  	if err := d.Set(checkOutCheckUUIDsAttr, c.CheckUUIDs); err != nil {
   420  		return errwrap.Wrapf(fmt.Sprintf("Unable to store check %q attribute: {{err}}", checkOutCheckUUIDsAttr), err)
   421  	}
   422  
   423  	if err := d.Set(checkOutChecksAttr, c.Checks); err != nil {
   424  		return errwrap.Wrapf(fmt.Sprintf("Unable to store check %q attribute: {{err}}", checkOutChecksAttr), err)
   425  	}
   426  
   427  	if checkID != "" {
   428  		d.Set(checkOutIDAttr, checkID)
   429  	}
   430  
   431  	d.Set(checkOutCreatedAttr, c.Created)
   432  	d.Set(checkOutLastModifiedAttr, c.LastModified)
   433  	d.Set(checkOutLastModifiedByAttr, c.LastModifedBy)
   434  
   435  	if err := d.Set(checkOutReverseConnectURLsAttr, c.ReverseConnectURLs); err != nil {
   436  		return errwrap.Wrapf(fmt.Sprintf("Unable to store check %q attribute: {{err}}", checkOutReverseConnectURLsAttr), err)
   437  	}
   438  
   439  	return nil
   440  }
   441  
   442  func checkUpdate(d *schema.ResourceData, meta interface{}) error {
   443  	ctxt := meta.(*providerContext)
   444  	c := newCheck()
   445  	if err := c.ParseConfig(d); err != nil {
   446  		return err
   447  	}
   448  
   449  	c.CID = d.Id()
   450  	if err := c.Update(ctxt); err != nil {
   451  		return errwrap.Wrapf(fmt.Sprintf("unable to update check %q: {{err}}", d.Id()), err)
   452  	}
   453  
   454  	return checkRead(d, meta)
   455  }
   456  
   457  func checkDelete(d *schema.ResourceData, meta interface{}) error {
   458  	ctxt := meta.(*providerContext)
   459  
   460  	if _, err := ctxt.client.Delete(d.Id()); err != nil {
   461  		return errwrap.Wrapf(fmt.Sprintf("unable to delete check %q: {{err}}", d.Id()), err)
   462  	}
   463  
   464  	d.SetId("")
   465  
   466  	return nil
   467  }
   468  
   469  func checkMetricChecksum(v interface{}) int {
   470  	m := v.(map[string]interface{})
   471  	csum := metricChecksum(m)
   472  	return csum
   473  }
   474  
   475  // ParseConfig reads Terraform config data and stores the information into a
   476  // Circonus CheckBundle object.
   477  func (c *circonusCheck) ParseConfig(d *schema.ResourceData) error {
   478  	if v, found := d.GetOk(checkActiveAttr); found {
   479  		c.Status = checkActiveToAPIStatus(v.(bool))
   480  	}
   481  
   482  	if v, found := d.GetOk(checkCollectorAttr); found {
   483  		l := v.(*schema.Set).List()
   484  		c.Brokers = make([]string, 0, len(l))
   485  
   486  		for _, mapRaw := range l {
   487  			mapAttrs := mapRaw.(map[string]interface{})
   488  
   489  			if mv, mapFound := mapAttrs[checkCollectorIDAttr]; mapFound {
   490  				c.Brokers = append(c.Brokers, mv.(string))
   491  			}
   492  		}
   493  	}
   494  
   495  	if v, found := d.GetOk(checkMetricLimitAttr); found {
   496  		c.MetricLimit = v.(int)
   497  	}
   498  
   499  	if v, found := d.GetOk(checkNameAttr); found {
   500  		c.DisplayName = v.(string)
   501  	}
   502  
   503  	if v, found := d.GetOk(checkNotesAttr); found {
   504  		s := v.(string)
   505  		c.Notes = &s
   506  	}
   507  
   508  	if v, found := d.GetOk(checkPeriodAttr); found {
   509  		d, err := time.ParseDuration(v.(string))
   510  		if err != nil {
   511  			return errwrap.Wrapf(fmt.Sprintf("unable to parse %q as a duration: {{err}}", checkPeriodAttr), err)
   512  		}
   513  
   514  		c.Period = uint(d.Seconds())
   515  	}
   516  
   517  	if v, found := d.GetOk(checkMetricAttr); found {
   518  		metricList := v.(*schema.Set).List()
   519  		c.Metrics = make([]api.CheckBundleMetric, 0, len(metricList))
   520  
   521  		for _, metricListRaw := range metricList {
   522  			metricAttrs := metricListRaw.(map[string]interface{})
   523  
   524  			var id string
   525  			if av, found := metricAttrs[metricIDAttr]; found {
   526  				id = av.(string)
   527  			} else {
   528  				var err error
   529  				id, err = newMetricID()
   530  				if err != nil {
   531  					return errwrap.Wrapf("unable to create a new metric ID: {{err}}", err)
   532  				}
   533  			}
   534  
   535  			m := newMetric()
   536  			if err := m.ParseConfigMap(id, metricAttrs); err != nil {
   537  				return errwrap.Wrapf("unable to parse config: {{err}}", err)
   538  			}
   539  
   540  			c.Metrics = append(c.Metrics, m.CheckBundleMetric)
   541  		}
   542  	}
   543  
   544  	if v, found := d.GetOk(checkTagsAttr); found {
   545  		c.Tags = derefStringList(flattenSet(v.(*schema.Set)))
   546  	}
   547  
   548  	if v, found := d.GetOk(checkTargetAttr); found {
   549  		c.Target = v.(string)
   550  	}
   551  
   552  	if v, found := d.GetOk(checkTimeoutAttr); found {
   553  		d, err := time.ParseDuration(v.(string))
   554  		if err != nil {
   555  			return errwrap.Wrapf(fmt.Sprintf("unable to parse %q as a duration: {{err}}", checkTimeoutAttr), err)
   556  		}
   557  
   558  		t := float32(d.Seconds())
   559  		c.Timeout = t
   560  	}
   561  
   562  	// Last step: parse the individual check types
   563  	if err := checkConfigToAPI(c, d); err != nil {
   564  		return errwrap.Wrapf("unable to parse check type: {{err}}", err)
   565  	}
   566  
   567  	if err := c.Fixup(); err != nil {
   568  		return err
   569  	}
   570  
   571  	if err := c.Validate(); err != nil {
   572  		return err
   573  	}
   574  
   575  	return nil
   576  }
   577  
   578  // checkConfigToAPI parses the Terraform config into the respective per-check
   579  // type api.Config attributes.
   580  func checkConfigToAPI(c *circonusCheck, d *schema.ResourceData) error {
   581  	checkTypeParseMap := map[string]func(*circonusCheck, interfaceList) error{
   582  		checkCAQLAttr:       checkConfigToAPICAQL,
   583  		checkCloudWatchAttr: checkConfigToAPICloudWatch,
   584  		checkConsulAttr:     checkConfigToAPIConsul,
   585  		checkHTTPAttr:       checkConfigToAPIHTTP,
   586  		checkHTTPTrapAttr:   checkConfigToAPIHTTPTrap,
   587  		checkICMPPingAttr:   checkConfigToAPIICMPPing,
   588  		checkJSONAttr:       checkConfigToAPIJSON,
   589  		checkMySQLAttr:      checkConfigToAPIMySQL,
   590  		checkPostgreSQLAttr: checkConfigToAPIPostgreSQL,
   591  		checkStatsdAttr:     checkConfigToAPIStatsd,
   592  		checkTCPAttr:        checkConfigToAPITCP,
   593  	}
   594  
   595  	for checkType, fn := range checkTypeParseMap {
   596  		if listRaw, found := d.GetOk(checkType); found {
   597  			switch u := listRaw.(type) {
   598  			case []interface{}:
   599  				if err := fn(c, u); err != nil {
   600  					return errwrap.Wrapf(fmt.Sprintf("Unable to parse type %q: {{err}}", string(checkType)), err)
   601  				}
   602  			case *schema.Set:
   603  				if err := fn(c, u.List()); err != nil {
   604  					return errwrap.Wrapf(fmt.Sprintf("Unable to parse type %q: {{err}}", string(checkType)), err)
   605  				}
   606  			default:
   607  				return fmt.Errorf("PROVIDER BUG: unsupported check type interface: %q", checkType)
   608  			}
   609  		}
   610  	}
   611  
   612  	return nil
   613  }
   614  
   615  // parseCheckTypeConfig parses an API Config object and stores the result in the
   616  // statefile.
   617  func parseCheckTypeConfig(c *circonusCheck, d *schema.ResourceData) error {
   618  	checkTypeConfigHandlers := map[apiCheckType]func(*circonusCheck, *schema.ResourceData) error{
   619  		apiCheckTypeCAQLAttr:       checkAPIToStateCAQL,
   620  		apiCheckTypeCloudWatchAttr: checkAPIToStateCloudWatch,
   621  		apiCheckTypeConsulAttr:     checkAPIToStateConsul,
   622  		apiCheckTypeHTTPAttr:       checkAPIToStateHTTP,
   623  		apiCheckTypeHTTPTrapAttr:   checkAPIToStateHTTPTrap,
   624  		apiCheckTypeICMPPingAttr:   checkAPIToStateICMPPing,
   625  		apiCheckTypeJSONAttr:       checkAPIToStateJSON,
   626  		apiCheckTypeMySQLAttr:      checkAPIToStateMySQL,
   627  		apiCheckTypePostgreSQLAttr: checkAPIToStatePostgreSQL,
   628  		apiCheckTypeStatsdAttr:     checkAPIToStateStatsd,
   629  		apiCheckTypeTCPAttr:        checkAPIToStateTCP,
   630  	}
   631  
   632  	var checkType apiCheckType = apiCheckType(c.Type)
   633  	fn, ok := checkTypeConfigHandlers[checkType]
   634  	if !ok {
   635  		return fmt.Errorf("check type %q not supported", c.Type)
   636  	}
   637  
   638  	if err := fn(c, d); err != nil {
   639  		return errwrap.Wrapf(fmt.Sprintf("unable to parse the API config for %q: {{err}}", c.Type), err)
   640  	}
   641  
   642  	return nil
   643  }