github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/circonus/resource_circonus_check_tcp.go (about) 1 package circonus 2 3 import ( 4 "bytes" 5 "fmt" 6 "log" 7 "strconv" 8 "strings" 9 10 "github.com/circonus-labs/circonus-gometrics/api/config" 11 "github.com/hashicorp/errwrap" 12 "github.com/hashicorp/terraform/helper/hashcode" 13 "github.com/hashicorp/terraform/helper/schema" 14 ) 15 16 const ( 17 // circonus_check.tcp.* resource attribute names 18 checkTCPBannerRegexpAttr = "banner_regexp" 19 checkTCPCAChainAttr = "ca_chain" 20 checkTCPCertFileAttr = "certificate_file" 21 checkTCPCiphersAttr = "ciphers" 22 checkTCPHostAttr = "host" 23 checkTCPKeyFileAttr = "key_file" 24 checkTCPPortAttr = "port" 25 checkTCPTLSAttr = "tls" 26 ) 27 28 var checkTCPDescriptions = attrDescrs{ 29 checkTCPBannerRegexpAttr: `This regular expression is matched against the response banner. If a match is not found, the check will be marked as bad.`, 30 checkTCPCAChainAttr: "A path to a file containing all the certificate authorities that should be loaded to validate the remote certificate (for TLS checks).", 31 checkTCPCertFileAttr: "A path to a file containing the client certificate that will be presented to the remote server (for TLS checks).", 32 checkTCPCiphersAttr: "A list of ciphers to be used when establishing a TLS connection", 33 checkTCPHostAttr: "Specifies the host name or IP address to connect to for this TCP check", 34 checkTCPKeyFileAttr: "A path to a file containing key to be used in conjunction with the cilent certificate (for TLS checks)", 35 checkTCPPortAttr: "Specifies the port on which the management interface can be reached.", 36 checkTCPTLSAttr: "Upgrade TCP connection to use TLS.", 37 } 38 39 var schemaCheckTCP = &schema.Schema{ 40 Type: schema.TypeSet, 41 Optional: true, 42 MaxItems: 1, 43 MinItems: 1, 44 Set: hashCheckTCP, 45 Elem: &schema.Resource{ 46 Schema: convertToHelperSchema(checkTCPDescriptions, map[schemaAttr]*schema.Schema{ 47 checkTCPBannerRegexpAttr: &schema.Schema{ 48 Type: schema.TypeString, 49 Optional: true, 50 ValidateFunc: validateRegexp(checkTCPBannerRegexpAttr, `.+`), 51 }, 52 checkTCPCAChainAttr: &schema.Schema{ 53 Type: schema.TypeString, 54 Optional: true, 55 ValidateFunc: validateRegexp(checkTCPCAChainAttr, `.+`), 56 }, 57 checkTCPCertFileAttr: &schema.Schema{ 58 Type: schema.TypeString, 59 Optional: true, 60 ValidateFunc: validateRegexp(checkTCPCertFileAttr, `.+`), 61 }, 62 checkTCPCiphersAttr: &schema.Schema{ 63 Type: schema.TypeString, 64 Optional: true, 65 ValidateFunc: validateRegexp(checkTCPCiphersAttr, `.+`), 66 }, 67 checkTCPHostAttr: &schema.Schema{ 68 Type: schema.TypeString, 69 Required: true, 70 ValidateFunc: validateRegexp(checkTCPHostAttr, `.+`), 71 }, 72 checkTCPKeyFileAttr: &schema.Schema{ 73 Type: schema.TypeString, 74 Optional: true, 75 ValidateFunc: validateRegexp(checkTCPKeyFileAttr, `.+`), 76 }, 77 checkTCPPortAttr: &schema.Schema{ 78 Type: schema.TypeInt, 79 Required: true, 80 ValidateFunc: validateFuncs( 81 validateIntMin(checkTCPPortAttr, 0), 82 validateIntMax(checkTCPPortAttr, 65535), 83 ), 84 }, 85 checkTCPTLSAttr: &schema.Schema{ 86 Type: schema.TypeBool, 87 Optional: true, 88 Default: false, 89 }, 90 }), 91 }, 92 } 93 94 // checkAPIToStateTCP reads the Config data out of circonusCheck.CheckBundle into the 95 // statefile. 96 func checkAPIToStateTCP(c *circonusCheck, d *schema.ResourceData) error { 97 tcpConfig := make(map[string]interface{}, len(c.Config)) 98 99 // swamp is a sanity check: it must be empty by the time this method returns 100 swamp := make(map[config.Key]string, len(c.Config)) 101 for k, v := range c.Config { 102 swamp[k] = v 103 } 104 105 saveBoolConfigToState := func(apiKey config.Key, attrName schemaAttr) { 106 if s, ok := c.Config[apiKey]; ok { 107 switch strings.ToLower(s) { 108 case "1", "true", "t", "yes", "y": 109 tcpConfig[string(attrName)] = true 110 case "0", "false", "f", "no", "n": 111 tcpConfig[string(attrName)] = false 112 default: 113 log.Printf("PROVIDER BUG: unsupported boolean: %q for API Config Key %q", s, string(apiKey)) 114 return 115 } 116 } 117 118 delete(swamp, apiKey) 119 } 120 121 saveIntConfigToState := func(apiKey config.Key, attrName schemaAttr) { 122 if v, ok := c.Config[apiKey]; ok { 123 i, err := strconv.ParseInt(v, 10, 64) 124 if err != nil { 125 log.Printf("[ERROR]: Unable to convert %s to an integer: %v", apiKey, err) 126 return 127 } 128 tcpConfig[string(attrName)] = int(i) 129 } 130 131 delete(swamp, apiKey) 132 } 133 134 saveStringConfigToState := func(apiKey config.Key, attrName schemaAttr) { 135 if v, ok := c.Config[apiKey]; ok { 136 tcpConfig[string(attrName)] = v 137 } 138 139 delete(swamp, apiKey) 140 } 141 142 saveStringConfigToState(config.BannerMatch, checkTCPBannerRegexpAttr) 143 saveStringConfigToState(config.CAChain, checkTCPCAChainAttr) 144 saveStringConfigToState(config.CertFile, checkTCPCertFileAttr) 145 saveStringConfigToState(config.Ciphers, checkTCPCiphersAttr) 146 tcpConfig[string(checkTCPHostAttr)] = c.Target 147 saveStringConfigToState(config.KeyFile, checkTCPKeyFileAttr) 148 saveIntConfigToState(config.Port, checkTCPPortAttr) 149 saveBoolConfigToState(config.UseSSL, checkTCPTLSAttr) 150 151 whitelistedConfigKeys := map[config.Key]struct{}{ 152 config.ReverseSecretKey: struct{}{}, 153 config.SubmissionURL: struct{}{}, 154 } 155 156 for k := range swamp { 157 if _, ok := whitelistedConfigKeys[k]; ok { 158 delete(c.Config, k) 159 } 160 161 if _, ok := whitelistedConfigKeys[k]; !ok { 162 log.Printf("[ERROR]: PROVIDER BUG: API Config not empty: %#v", swamp) 163 } 164 } 165 166 if err := d.Set(checkTCPAttr, schema.NewSet(hashCheckTCP, []interface{}{tcpConfig})); err != nil { 167 return errwrap.Wrapf(fmt.Sprintf("Unable to store check %q attribute: {{err}}", checkTCPAttr), err) 168 } 169 170 return nil 171 } 172 173 // hashCheckTCP creates a stable hash of the normalized values 174 func hashCheckTCP(v interface{}) int { 175 m := v.(map[string]interface{}) 176 b := &bytes.Buffer{} 177 b.Grow(defaultHashBufSize) 178 179 writeBool := func(attrName schemaAttr) { 180 if v, ok := m[string(attrName)]; ok { 181 fmt.Fprintf(b, "%t", v.(bool)) 182 } 183 } 184 185 writeInt := func(attrName schemaAttr) { 186 if v, ok := m[string(attrName)]; ok { 187 fmt.Fprintf(b, "%x", v.(int)) 188 } 189 } 190 191 writeString := func(attrName schemaAttr) { 192 if v, ok := m[string(attrName)]; ok && v.(string) != "" { 193 fmt.Fprint(b, strings.TrimSpace(v.(string))) 194 } 195 } 196 197 // Order writes to the buffer using lexically sorted list for easy visual 198 // reconciliation with other lists. 199 writeString(checkTCPBannerRegexpAttr) 200 writeString(checkTCPCAChainAttr) 201 writeString(checkTCPCertFileAttr) 202 writeString(checkTCPCiphersAttr) 203 writeString(checkTCPHostAttr) 204 writeString(checkTCPKeyFileAttr) 205 writeInt(checkTCPPortAttr) 206 writeBool(checkTCPTLSAttr) 207 208 s := b.String() 209 return hashcode.String(s) 210 } 211 212 func checkConfigToAPITCP(c *circonusCheck, l interfaceList) error { 213 c.Type = string(apiCheckTypeTCP) 214 215 // Iterate over all `tcp` attributes, even though we have a max of 1 in the 216 // schema. 217 for _, mapRaw := range l { 218 tcpConfig := newInterfaceMap(mapRaw) 219 220 if v, found := tcpConfig[checkTCPBannerRegexpAttr]; found { 221 c.Config[config.BannerMatch] = v.(string) 222 } 223 224 if v, found := tcpConfig[checkTCPCAChainAttr]; found { 225 c.Config[config.CAChain] = v.(string) 226 } 227 228 if v, found := tcpConfig[checkTCPCertFileAttr]; found { 229 c.Config[config.CertFile] = v.(string) 230 } 231 232 if v, found := tcpConfig[checkTCPCiphersAttr]; found { 233 c.Config[config.Ciphers] = v.(string) 234 } 235 236 if v, found := tcpConfig[checkTCPHostAttr]; found { 237 c.Target = v.(string) 238 } 239 240 if v, found := tcpConfig[checkTCPKeyFileAttr]; found { 241 c.Config[config.KeyFile] = v.(string) 242 } 243 244 if v, found := tcpConfig[checkTCPPortAttr]; found { 245 c.Config[config.Port] = fmt.Sprintf("%d", v.(int)) 246 } 247 248 if v, found := tcpConfig[checkTCPTLSAttr]; found { 249 c.Config[config.UseSSL] = fmt.Sprintf("%t", v.(bool)) 250 } 251 } 252 253 return nil 254 }