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 }