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