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 }