github.com/peterbale/terraform@v0.9.0-beta2.0.20170315142748-5723acd55547/builtin/providers/circonus/resource_circonus_metric_cluster.go (about)

     1  package circonus
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"strings"
     7  
     8  	"github.com/circonus-labs/circonus-gometrics/api"
     9  	"github.com/circonus-labs/circonus-gometrics/api/config"
    10  	"github.com/hashicorp/errwrap"
    11  	"github.com/hashicorp/terraform/helper/hashcode"
    12  	"github.com/hashicorp/terraform/helper/schema"
    13  )
    14  
    15  const (
    16  	// circonus_metric_cluster.* resource attribute names
    17  	metricClusterDescriptionAttr = "description"
    18  	metricClusterNameAttr        = "name"
    19  	metricClusterQueryAttr       = "query"
    20  	metricClusterTagsAttr        = "tags"
    21  
    22  	// circonus_metric_cluster.* out parameters
    23  	metricClusterIDAttr = "id"
    24  
    25  	// circonus_metric_cluster.query.* resource attribute names
    26  	metricClusterDefinitionAttr = "definition"
    27  	metricClusterTypeAttr       = "type"
    28  )
    29  
    30  var metricClusterDescriptions = attrDescrs{
    31  	metricClusterDescriptionAttr: "A description of the metric cluster",
    32  	metricClusterIDAttr:          "The ID of this metric cluster",
    33  	metricClusterNameAttr:        "The name of the metric cluster",
    34  	metricClusterQueryAttr:       "A metric cluster query definition",
    35  	metricClusterTagsAttr:        "A list of tags assigned to the metric cluster",
    36  }
    37  
    38  var metricClusterQueryDescriptions = attrDescrs{
    39  	metricClusterDefinitionAttr: "A query to select a collection of metric streams",
    40  	metricClusterTypeAttr:       "The operation to perform on the matching metric streams",
    41  }
    42  
    43  func resourceMetricCluster() *schema.Resource {
    44  	return &schema.Resource{
    45  		Create: metricClusterCreate,
    46  		Read:   metricClusterRead,
    47  		Update: metricClusterUpdate,
    48  		Delete: metricClusterDelete,
    49  		Exists: metricClusterExists,
    50  		Importer: &schema.ResourceImporter{
    51  			State: schema.ImportStatePassthrough,
    52  		},
    53  
    54  		Schema: convertToHelperSchema(metricClusterDescriptions, map[schemaAttr]*schema.Schema{
    55  			metricClusterDescriptionAttr: &schema.Schema{
    56  				Type:      schema.TypeString,
    57  				Optional:  true,
    58  				Computed:  true,
    59  				StateFunc: suppressWhitespace,
    60  			},
    61  			metricClusterNameAttr: &schema.Schema{
    62  				Type:     schema.TypeString,
    63  				Required: true,
    64  			},
    65  			metricClusterQueryAttr: &schema.Schema{
    66  				Type:     schema.TypeSet,
    67  				Optional: true,
    68  				MinItems: 1,
    69  				Elem: &schema.Resource{
    70  					Schema: convertToHelperSchema(metricClusterQueryDescriptions, map[schemaAttr]*schema.Schema{
    71  						metricClusterDefinitionAttr: &schema.Schema{
    72  							Type:         schema.TypeString,
    73  							Required:     true,
    74  							ValidateFunc: validateRegexp(metricClusterDefinitionAttr, `.+`),
    75  						},
    76  						metricClusterTypeAttr: &schema.Schema{
    77  							Type:         schema.TypeString,
    78  							Required:     true,
    79  							ValidateFunc: validateStringIn(metricClusterTypeAttr, supportedMetricClusterTypes),
    80  						},
    81  					}),
    82  				},
    83  			},
    84  			metricClusterTagsAttr: tagMakeConfigSchema(metricClusterTagsAttr),
    85  
    86  			// Out parameters
    87  			metricClusterIDAttr: &schema.Schema{
    88  				Computed:     true,
    89  				Type:         schema.TypeString,
    90  				ValidateFunc: validateRegexp(metricClusterIDAttr, config.MetricClusterCIDRegex),
    91  			},
    92  		}),
    93  	}
    94  }
    95  
    96  func metricClusterCreate(d *schema.ResourceData, meta interface{}) error {
    97  	ctxt := meta.(*providerContext)
    98  	mc := newMetricCluster()
    99  
   100  	if err := mc.ParseConfig(d); err != nil {
   101  		return errwrap.Wrapf("error parsing metric cluster schema during create: {{err}}", err)
   102  	}
   103  
   104  	if err := mc.Create(ctxt); err != nil {
   105  		return errwrap.Wrapf("error creating metric cluster: {{err}}", err)
   106  	}
   107  
   108  	d.SetId(mc.CID)
   109  
   110  	return metricClusterRead(d, meta)
   111  }
   112  
   113  func metricClusterExists(d *schema.ResourceData, meta interface{}) (bool, error) {
   114  	ctxt := meta.(*providerContext)
   115  
   116  	cid := d.Id()
   117  	mc, err := ctxt.client.FetchMetricCluster(api.CIDType(&cid), "")
   118  	if err != nil {
   119  		if strings.Contains(err.Error(), defaultCirconus404ErrorString) {
   120  			return false, nil
   121  		}
   122  
   123  		return false, err
   124  	}
   125  
   126  	if mc.CID == "" {
   127  		return false, nil
   128  	}
   129  
   130  	return true, nil
   131  }
   132  
   133  // metricClusterRead pulls data out of the MetricCluster object and stores it
   134  // into the appropriate place in the statefile.
   135  func metricClusterRead(d *schema.ResourceData, meta interface{}) error {
   136  	ctxt := meta.(*providerContext)
   137  
   138  	cid := d.Id()
   139  	mc, err := loadMetricCluster(ctxt, api.CIDType(&cid))
   140  	if err != nil {
   141  		return err
   142  	}
   143  
   144  	d.SetId(mc.CID)
   145  
   146  	queries := schema.NewSet(metricClusterQueryChecksum, nil)
   147  	for _, query := range mc.Queries {
   148  		queryAttrs := map[string]interface{}{
   149  			string(metricClusterDefinitionAttr): query.Query,
   150  			string(metricClusterTypeAttr):       query.Type,
   151  		}
   152  
   153  		queries.Add(queryAttrs)
   154  	}
   155  
   156  	d.Set(metricClusterDescriptionAttr, mc.Description)
   157  	d.Set(metricClusterNameAttr, mc.Name)
   158  
   159  	if err := d.Set(metricClusterTagsAttr, tagsToState(apiToTags(mc.Tags))); err != nil {
   160  		return errwrap.Wrapf(fmt.Sprintf("Unable to store metric cluster %q attribute: {{err}}", metricClusterTagsAttr), err)
   161  	}
   162  
   163  	d.Set(metricClusterIDAttr, mc.CID)
   164  
   165  	return nil
   166  }
   167  
   168  func metricClusterUpdate(d *schema.ResourceData, meta interface{}) error {
   169  	ctxt := meta.(*providerContext)
   170  	mc := newMetricCluster()
   171  
   172  	if err := mc.ParseConfig(d); err != nil {
   173  		return err
   174  	}
   175  
   176  	mc.CID = d.Id()
   177  	if err := mc.Update(ctxt); err != nil {
   178  		return errwrap.Wrapf(fmt.Sprintf("unable to update metric cluster %q: {{err}}", d.Id()), err)
   179  	}
   180  
   181  	return metricClusterRead(d, meta)
   182  }
   183  
   184  func metricClusterDelete(d *schema.ResourceData, meta interface{}) error {
   185  	ctxt := meta.(*providerContext)
   186  
   187  	cid := d.Id()
   188  	if _, err := ctxt.client.DeleteMetricClusterByCID(api.CIDType(&cid)); err != nil {
   189  		return errwrap.Wrapf(fmt.Sprintf("unable to delete metric cluster %q: {{err}}", d.Id()), err)
   190  	}
   191  
   192  	d.SetId("")
   193  
   194  	return nil
   195  }
   196  
   197  func metricClusterQueryChecksum(v interface{}) int {
   198  	m := v.(map[string]interface{})
   199  
   200  	b := &bytes.Buffer{}
   201  	b.Grow(defaultHashBufSize)
   202  
   203  	// Order writes to the buffer using lexically sorted list for easy visual
   204  	// reconciliation with other lists.
   205  	if v, found := m[metricClusterDefinitionAttr]; found {
   206  		fmt.Fprint(b, v.(string))
   207  	}
   208  
   209  	if v, found := m[metricClusterTypeAttr]; found {
   210  		fmt.Fprint(b, v.(string))
   211  	}
   212  
   213  	s := b.String()
   214  	return hashcode.String(s)
   215  }
   216  
   217  // ParseConfig reads Terraform config data and stores the information into a
   218  // Circonus MetricCluster object.
   219  func (mc *circonusMetricCluster) ParseConfig(d *schema.ResourceData) error {
   220  	if v, found := d.GetOk(metricClusterDescriptionAttr); found {
   221  		mc.Description = v.(string)
   222  	}
   223  
   224  	if v, found := d.GetOk(metricClusterNameAttr); found {
   225  		mc.Name = v.(string)
   226  	}
   227  
   228  	if queryListRaw, found := d.GetOk(metricClusterQueryAttr); found {
   229  		queryList := queryListRaw.(*schema.Set).List()
   230  
   231  		mc.Queries = make([]api.MetricQuery, 0, len(queryList))
   232  
   233  		for _, queryRaw := range queryList {
   234  			queryAttrs := newInterfaceMap(queryRaw)
   235  
   236  			var query string
   237  			if v, found := queryAttrs[metricClusterDefinitionAttr]; found {
   238  				query = v.(string)
   239  			}
   240  
   241  			var queryType string
   242  			if v, found := queryAttrs[metricClusterTypeAttr]; found {
   243  				queryType = v.(string)
   244  			}
   245  
   246  			mc.Queries = append(mc.Queries, api.MetricQuery{
   247  				Query: query,
   248  				Type:  queryType,
   249  			})
   250  		}
   251  	}
   252  
   253  	if v, found := d.GetOk(metricClusterTagsAttr); found {
   254  		mc.Tags = derefStringList(flattenSet(v.(*schema.Set)))
   255  	}
   256  
   257  	if err := mc.Validate(); err != nil {
   258  		return err
   259  	}
   260  
   261  	return nil
   262  }