1279 lines
38 KiB
Go
1279 lines
38 KiB
Go
|
package circonus
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"encoding/json"
|
||
|
"fmt"
|
||
|
"log"
|
||
|
"strings"
|
||
|
"time"
|
||
|
|
||
|
"github.com/circonus-labs/circonus-gometrics/api"
|
||
|
"github.com/circonus-labs/circonus-gometrics/api/config"
|
||
|
"github.com/hashicorp/errwrap"
|
||
|
"github.com/hashicorp/terraform/helper/hashcode"
|
||
|
"github.com/hashicorp/terraform/helper/schema"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
// circonus_contact attributes
|
||
|
contactAggregationWindowAttr = "aggregation_window"
|
||
|
contactAlertOptionAttr = "alert_option"
|
||
|
contactEmailAttr = "email"
|
||
|
contactHTTPAttr = "http"
|
||
|
contactIRCAttr = "irc"
|
||
|
contactLongMessageAttr = "long_message"
|
||
|
contactLongSubjectAttr = "long_subject"
|
||
|
contactLongSummaryAttr = "long_summary"
|
||
|
contactNameAttr = "name"
|
||
|
contactPagerDutyAttr = "pager_duty"
|
||
|
contactSMSAttr = "sms"
|
||
|
contactShortMessageAttr = "short_message"
|
||
|
contactShortSummaryAttr = "short_summary"
|
||
|
contactSlackAttr = "slack"
|
||
|
contactTagsAttr = "tags"
|
||
|
contactVictorOpsAttr = "victorops"
|
||
|
contactXMPPAttr = "xmpp"
|
||
|
|
||
|
// circonus_contact.alert_option attributes
|
||
|
contactEscalateAfterAttr = "escalate_after"
|
||
|
contactEscalateToAttr = "escalate_to"
|
||
|
contactReminderAttr = "reminder"
|
||
|
contactSeverityAttr = "severity"
|
||
|
|
||
|
// circonus_contact.email attributes
|
||
|
contactEmailAddressAttr = "address"
|
||
|
//contactUserCIDAttr
|
||
|
|
||
|
// circonus_contact.http attributes
|
||
|
contactHTTPAddressAttr schemaAttr = "address"
|
||
|
contactHTTPFormatAttr = "format"
|
||
|
contactHTTPMethodAttr = "method"
|
||
|
|
||
|
// circonus_contact.irc attributes
|
||
|
//contactUserCIDAttr
|
||
|
|
||
|
// circonus_contact.pager_duty attributes
|
||
|
//contactContactGroupFallbackAttr
|
||
|
contactPagerDutyIntegrationKeyAttr schemaAttr = "integration_key"
|
||
|
contactPagerDutyWebhookURLAttr schemaAttr = "webook_url"
|
||
|
|
||
|
// circonus_contact.slack attributes
|
||
|
//contactContactGroupFallbackAttr
|
||
|
contactSlackButtonsAttr = "buttons"
|
||
|
contactSlackChannelAttr = "channel"
|
||
|
contactSlackTeamAttr = "team"
|
||
|
contactSlackUsernameAttr = "username"
|
||
|
|
||
|
// circonus_contact.sms attributes
|
||
|
contactSMSAddressAttr = "address"
|
||
|
//contactUserCIDAttr
|
||
|
|
||
|
// circonus_contact.victorops attributes
|
||
|
//contactContactGroupFallbackAttr
|
||
|
contactVictorOpsAPIKeyAttr = "api_key"
|
||
|
contactVictorOpsCriticalAttr = "critical"
|
||
|
contactVictorOpsInfoAttr = "info"
|
||
|
contactVictorOpsTeamAttr = "team"
|
||
|
contactVictorOpsWarningAttr = "warning"
|
||
|
|
||
|
// circonus_contact.victorops attributes
|
||
|
//contactUserCIDAttr
|
||
|
contactXMPPAddressAttr = "address"
|
||
|
|
||
|
// circonus_contact read-only attributes
|
||
|
contactLastModifiedAttr = "last_modified"
|
||
|
contactLastModifiedByAttr = "last_modified_by"
|
||
|
|
||
|
// circonus_contact.* shared attributes
|
||
|
contactContactGroupFallbackAttr = "contact_group_fallback"
|
||
|
contactUserCIDAttr = "user"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
// Contact methods from Circonus
|
||
|
circonusMethodEmail = "email"
|
||
|
circonusMethodHTTP = "http"
|
||
|
circonusMethodIRC = "irc"
|
||
|
circonusMethodPagerDuty = "pagerduty"
|
||
|
circonusMethodSlack = "slack"
|
||
|
circonusMethodSMS = "sms"
|
||
|
circonusMethodVictorOps = "victorops"
|
||
|
circonusMethodXMPP = "xmpp"
|
||
|
)
|
||
|
|
||
|
type contactHTTPInfo struct {
|
||
|
Address string `json:"url"`
|
||
|
Format string `json:"params"`
|
||
|
Method string `json:"method"`
|
||
|
}
|
||
|
|
||
|
type contactPagerDutyInfo struct {
|
||
|
FallbackGroupCID int `json:"failover_group,string"`
|
||
|
IntegrationKey string `json:"service_key"`
|
||
|
WebookURL string `json:"webook_url"`
|
||
|
}
|
||
|
|
||
|
type contactSlackInfo struct {
|
||
|
Buttons int `json:"buttons,string"`
|
||
|
Channel string `json:"channel"`
|
||
|
FallbackGroupCID int `json:"failover_group,string"`
|
||
|
Team string `json:"team"`
|
||
|
Username string `json:"username"`
|
||
|
}
|
||
|
|
||
|
type contactVictorOpsInfo struct {
|
||
|
APIKey string `json:"api_key"`
|
||
|
Critical int `json:"critical,string"`
|
||
|
FallbackGroupCID int `json:"failover_group,string"`
|
||
|
Info int `json:"info,string"`
|
||
|
Team string `json:"team"`
|
||
|
Warning int `json:"warning,string"`
|
||
|
}
|
||
|
|
||
|
var contactGroupDescriptions = attrDescrs{
|
||
|
contactAggregationWindowAttr: "",
|
||
|
contactAlertOptionAttr: "",
|
||
|
contactContactGroupFallbackAttr: "",
|
||
|
contactEmailAttr: "",
|
||
|
contactHTTPAttr: "",
|
||
|
contactIRCAttr: "",
|
||
|
contactLastModifiedAttr: "",
|
||
|
contactLastModifiedByAttr: "",
|
||
|
contactLongMessageAttr: "",
|
||
|
contactLongSubjectAttr: "",
|
||
|
contactLongSummaryAttr: "",
|
||
|
contactNameAttr: "",
|
||
|
contactPagerDutyAttr: "",
|
||
|
contactSMSAttr: "",
|
||
|
contactShortMessageAttr: "",
|
||
|
contactShortSummaryAttr: "",
|
||
|
contactSlackAttr: "",
|
||
|
contactTagsAttr: "",
|
||
|
contactVictorOpsAttr: "",
|
||
|
contactXMPPAttr: "",
|
||
|
}
|
||
|
|
||
|
var contactAlertDescriptions = attrDescrs{
|
||
|
contactEscalateAfterAttr: "",
|
||
|
contactEscalateToAttr: "",
|
||
|
contactReminderAttr: "",
|
||
|
contactSeverityAttr: "",
|
||
|
}
|
||
|
|
||
|
var contactEmailDescriptions = attrDescrs{
|
||
|
contactEmailAddressAttr: "",
|
||
|
contactUserCIDAttr: "",
|
||
|
}
|
||
|
|
||
|
var contactHTTPDescriptions = attrDescrs{
|
||
|
contactHTTPAddressAttr: "",
|
||
|
contactHTTPFormatAttr: "",
|
||
|
contactHTTPMethodAttr: "",
|
||
|
}
|
||
|
|
||
|
var contactPagerDutyDescriptions = attrDescrs{
|
||
|
contactContactGroupFallbackAttr: "",
|
||
|
contactPagerDutyIntegrationKeyAttr: "",
|
||
|
contactPagerDutyWebhookURLAttr: "",
|
||
|
}
|
||
|
|
||
|
var contactSlackDescriptions = attrDescrs{
|
||
|
contactContactGroupFallbackAttr: "",
|
||
|
contactSlackButtonsAttr: "",
|
||
|
contactSlackChannelAttr: "",
|
||
|
contactSlackTeamAttr: "",
|
||
|
contactSlackUsernameAttr: "Username Slackbot uses in Slack to deliver a notification",
|
||
|
}
|
||
|
|
||
|
var contactSMSDescriptions = attrDescrs{
|
||
|
contactSMSAddressAttr: "",
|
||
|
contactUserCIDAttr: "",
|
||
|
}
|
||
|
|
||
|
var contactVictorOpsDescriptions = attrDescrs{
|
||
|
contactContactGroupFallbackAttr: "",
|
||
|
contactVictorOpsAPIKeyAttr: "",
|
||
|
contactVictorOpsCriticalAttr: "",
|
||
|
contactVictorOpsInfoAttr: "",
|
||
|
contactVictorOpsTeamAttr: "",
|
||
|
contactVictorOpsWarningAttr: "",
|
||
|
}
|
||
|
|
||
|
var contactXMPPDescriptions = attrDescrs{
|
||
|
contactUserCIDAttr: "",
|
||
|
contactXMPPAddressAttr: "",
|
||
|
}
|
||
|
|
||
|
func resourceContactGroup() *schema.Resource {
|
||
|
return &schema.Resource{
|
||
|
Create: contactGroupCreate,
|
||
|
Read: contactGroupRead,
|
||
|
Update: contactGroupUpdate,
|
||
|
Delete: contactGroupDelete,
|
||
|
Exists: contactGroupExists,
|
||
|
Importer: &schema.ResourceImporter{
|
||
|
State: schema.ImportStatePassthrough,
|
||
|
},
|
||
|
|
||
|
Schema: convertToHelperSchema(contactGroupDescriptions, map[schemaAttr]*schema.Schema{
|
||
|
contactAggregationWindowAttr: &schema.Schema{
|
||
|
Type: schema.TypeString,
|
||
|
Optional: true,
|
||
|
Default: defaultCirconusAggregationWindow,
|
||
|
DiffSuppressFunc: suppressEquivalentTimeDurations,
|
||
|
StateFunc: normalizeTimeDurationStringToSeconds,
|
||
|
ValidateFunc: validateFuncs(
|
||
|
validateDurationMin(contactAggregationWindowAttr, "0s"),
|
||
|
),
|
||
|
},
|
||
|
contactAlertOptionAttr: &schema.Schema{
|
||
|
Type: schema.TypeSet,
|
||
|
Optional: true,
|
||
|
Set: contactGroupAlertOptionsChecksum,
|
||
|
Elem: &schema.Resource{
|
||
|
Schema: convertToHelperSchema(contactAlertDescriptions, map[schemaAttr]*schema.Schema{
|
||
|
contactEscalateAfterAttr: &schema.Schema{
|
||
|
Type: schema.TypeString,
|
||
|
Optional: true,
|
||
|
DiffSuppressFunc: suppressEquivalentTimeDurations,
|
||
|
StateFunc: normalizeTimeDurationStringToSeconds,
|
||
|
ValidateFunc: validateFuncs(
|
||
|
validateDurationMin(contactEscalateAfterAttr, defaultCirconusAlertMinEscalateAfter),
|
||
|
),
|
||
|
},
|
||
|
contactEscalateToAttr: &schema.Schema{
|
||
|
Type: schema.TypeString,
|
||
|
Optional: true,
|
||
|
ValidateFunc: validateContactGroupCID(contactEscalateToAttr),
|
||
|
},
|
||
|
contactReminderAttr: &schema.Schema{
|
||
|
Type: schema.TypeString,
|
||
|
Optional: true,
|
||
|
DiffSuppressFunc: suppressEquivalentTimeDurations,
|
||
|
StateFunc: normalizeTimeDurationStringToSeconds,
|
||
|
ValidateFunc: validateFuncs(
|
||
|
validateDurationMin(contactReminderAttr, "0s"),
|
||
|
),
|
||
|
},
|
||
|
contactSeverityAttr: &schema.Schema{
|
||
|
Type: schema.TypeInt,
|
||
|
Required: true,
|
||
|
ValidateFunc: validateFuncs(
|
||
|
validateIntMin(contactSeverityAttr, minSeverity),
|
||
|
validateIntMax(contactSeverityAttr, maxSeverity),
|
||
|
),
|
||
|
},
|
||
|
}),
|
||
|
},
|
||
|
},
|
||
|
contactEmailAttr: &schema.Schema{
|
||
|
Type: schema.TypeSet,
|
||
|
Optional: true,
|
||
|
Elem: &schema.Resource{
|
||
|
Schema: convertToHelperSchema(contactEmailDescriptions, map[schemaAttr]*schema.Schema{
|
||
|
contactEmailAddressAttr: &schema.Schema{
|
||
|
Type: schema.TypeString,
|
||
|
Optional: true,
|
||
|
ConflictsWith: []string{contactEmailAttr + "." + contactUserCIDAttr},
|
||
|
},
|
||
|
contactUserCIDAttr: &schema.Schema{
|
||
|
Type: schema.TypeString,
|
||
|
Optional: true,
|
||
|
ValidateFunc: validateUserCID(contactUserCIDAttr),
|
||
|
ConflictsWith: []string{contactEmailAttr + "." + contactEmailAddressAttr},
|
||
|
},
|
||
|
}),
|
||
|
},
|
||
|
},
|
||
|
contactHTTPAttr: &schema.Schema{
|
||
|
Type: schema.TypeSet,
|
||
|
Optional: true,
|
||
|
Elem: &schema.Resource{
|
||
|
Schema: convertToHelperSchema(contactHTTPDescriptions, map[schemaAttr]*schema.Schema{
|
||
|
contactHTTPAddressAttr: &schema.Schema{
|
||
|
Type: schema.TypeString,
|
||
|
Required: true,
|
||
|
ValidateFunc: validateHTTPURL(contactHTTPAddressAttr, urlBasicCheck),
|
||
|
},
|
||
|
contactHTTPFormatAttr: &schema.Schema{
|
||
|
Type: schema.TypeString,
|
||
|
Optional: true,
|
||
|
Default: defaultCirconusHTTPFormat,
|
||
|
ValidateFunc: validateStringIn(contactHTTPFormatAttr, validContactHTTPFormats),
|
||
|
},
|
||
|
contactHTTPMethodAttr: &schema.Schema{
|
||
|
Type: schema.TypeString,
|
||
|
Optional: true,
|
||
|
Default: defaultCirconusHTTPMethod,
|
||
|
ValidateFunc: validateStringIn(contactHTTPMethodAttr, validContactHTTPMethods),
|
||
|
},
|
||
|
}),
|
||
|
},
|
||
|
},
|
||
|
contactIRCAttr: &schema.Schema{
|
||
|
Type: schema.TypeSet,
|
||
|
Optional: true,
|
||
|
Elem: &schema.Resource{
|
||
|
Schema: map[string]*schema.Schema{
|
||
|
contactUserCIDAttr: &schema.Schema{
|
||
|
Type: schema.TypeString,
|
||
|
Required: true,
|
||
|
ValidateFunc: validateUserCID(contactUserCIDAttr),
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
contactLongMessageAttr: &schema.Schema{
|
||
|
Type: schema.TypeString,
|
||
|
Optional: true,
|
||
|
StateFunc: suppressWhitespace,
|
||
|
},
|
||
|
contactLongSubjectAttr: &schema.Schema{
|
||
|
Type: schema.TypeString,
|
||
|
Optional: true,
|
||
|
StateFunc: suppressWhitespace,
|
||
|
},
|
||
|
contactLongSummaryAttr: &schema.Schema{
|
||
|
Type: schema.TypeString,
|
||
|
Optional: true,
|
||
|
StateFunc: suppressWhitespace,
|
||
|
},
|
||
|
contactNameAttr: &schema.Schema{
|
||
|
Type: schema.TypeString,
|
||
|
Required: true,
|
||
|
},
|
||
|
contactPagerDutyAttr: &schema.Schema{
|
||
|
Type: schema.TypeSet,
|
||
|
Optional: true,
|
||
|
Elem: &schema.Resource{
|
||
|
Schema: convertToHelperSchema(contactPagerDutyDescriptions, map[schemaAttr]*schema.Schema{
|
||
|
contactContactGroupFallbackAttr: &schema.Schema{
|
||
|
Type: schema.TypeString,
|
||
|
Optional: true,
|
||
|
ValidateFunc: validateContactGroupCID(contactContactGroupFallbackAttr),
|
||
|
},
|
||
|
contactPagerDutyIntegrationKeyAttr: &schema.Schema{
|
||
|
Type: schema.TypeString,
|
||
|
Required: true,
|
||
|
Sensitive: true,
|
||
|
ValidateFunc: validateHTTPURL(contactPagerDutyIntegrationKeyAttr, urlIsAbs),
|
||
|
},
|
||
|
contactPagerDutyWebhookURLAttr: &schema.Schema{
|
||
|
Type: schema.TypeString,
|
||
|
Required: true,
|
||
|
ValidateFunc: validateHTTPURL(contactPagerDutyWebhookURLAttr, urlIsAbs),
|
||
|
},
|
||
|
}),
|
||
|
},
|
||
|
},
|
||
|
contactShortMessageAttr: &schema.Schema{
|
||
|
Type: schema.TypeString,
|
||
|
Optional: true,
|
||
|
StateFunc: suppressWhitespace,
|
||
|
},
|
||
|
contactShortSummaryAttr: &schema.Schema{
|
||
|
Type: schema.TypeString,
|
||
|
Optional: true,
|
||
|
StateFunc: suppressWhitespace,
|
||
|
},
|
||
|
contactSlackAttr: &schema.Schema{
|
||
|
Type: schema.TypeSet,
|
||
|
Optional: true,
|
||
|
Elem: &schema.Resource{
|
||
|
Schema: convertToHelperSchema(contactSlackDescriptions, map[schemaAttr]*schema.Schema{
|
||
|
contactContactGroupFallbackAttr: &schema.Schema{
|
||
|
Type: schema.TypeString,
|
||
|
Optional: true,
|
||
|
ValidateFunc: validateContactGroupCID(contactContactGroupFallbackAttr),
|
||
|
},
|
||
|
contactSlackButtonsAttr: &schema.Schema{
|
||
|
Type: schema.TypeBool,
|
||
|
Optional: true,
|
||
|
Default: true,
|
||
|
},
|
||
|
contactSlackChannelAttr: &schema.Schema{
|
||
|
Type: schema.TypeString,
|
||
|
Required: true,
|
||
|
ValidateFunc: validateFuncs(
|
||
|
validateRegexp(contactSlackChannelAttr, `^#[\S]+$`),
|
||
|
),
|
||
|
},
|
||
|
contactSlackTeamAttr: &schema.Schema{
|
||
|
Type: schema.TypeString,
|
||
|
Required: true,
|
||
|
},
|
||
|
contactSlackUsernameAttr: &schema.Schema{
|
||
|
Type: schema.TypeString,
|
||
|
Optional: true,
|
||
|
Default: defaultCirconusSlackUsername,
|
||
|
ValidateFunc: validateFuncs(
|
||
|
validateRegexp(contactSlackChannelAttr, `^[\S]+$`),
|
||
|
),
|
||
|
},
|
||
|
}),
|
||
|
},
|
||
|
},
|
||
|
contactSMSAttr: &schema.Schema{
|
||
|
Type: schema.TypeSet,
|
||
|
Optional: true,
|
||
|
Elem: &schema.Resource{
|
||
|
Schema: convertToHelperSchema(contactSMSDescriptions, map[schemaAttr]*schema.Schema{
|
||
|
contactSMSAddressAttr: &schema.Schema{
|
||
|
Type: schema.TypeString,
|
||
|
Optional: true,
|
||
|
ConflictsWith: []string{contactSMSAttr + "." + contactUserCIDAttr},
|
||
|
},
|
||
|
contactUserCIDAttr: &schema.Schema{
|
||
|
Type: schema.TypeString,
|
||
|
Optional: true,
|
||
|
ValidateFunc: validateUserCID(contactUserCIDAttr),
|
||
|
ConflictsWith: []string{contactSMSAttr + "." + contactSMSAddressAttr},
|
||
|
},
|
||
|
}),
|
||
|
},
|
||
|
},
|
||
|
contactTagsAttr: tagMakeConfigSchema(contactTagsAttr),
|
||
|
contactVictorOpsAttr: &schema.Schema{
|
||
|
Type: schema.TypeSet,
|
||
|
Optional: true,
|
||
|
Elem: &schema.Resource{
|
||
|
Schema: convertToHelperSchema(contactVictorOpsDescriptions, map[schemaAttr]*schema.Schema{
|
||
|
contactContactGroupFallbackAttr: &schema.Schema{
|
||
|
Type: schema.TypeString,
|
||
|
Optional: true,
|
||
|
ValidateFunc: validateContactGroupCID(contactContactGroupFallbackAttr),
|
||
|
},
|
||
|
contactVictorOpsAPIKeyAttr: &schema.Schema{
|
||
|
Type: schema.TypeString,
|
||
|
Required: true,
|
||
|
Sensitive: true,
|
||
|
},
|
||
|
contactVictorOpsCriticalAttr: &schema.Schema{
|
||
|
Type: schema.TypeInt,
|
||
|
Required: true,
|
||
|
ValidateFunc: validateFuncs(
|
||
|
validateIntMin(contactVictorOpsCriticalAttr, 1),
|
||
|
validateIntMax(contactVictorOpsCriticalAttr, 5),
|
||
|
),
|
||
|
},
|
||
|
contactVictorOpsInfoAttr: &schema.Schema{
|
||
|
Type: schema.TypeInt,
|
||
|
Required: true,
|
||
|
ValidateFunc: validateFuncs(
|
||
|
validateIntMin(contactVictorOpsInfoAttr, 1),
|
||
|
validateIntMax(contactVictorOpsInfoAttr, 5),
|
||
|
),
|
||
|
},
|
||
|
contactVictorOpsTeamAttr: &schema.Schema{
|
||
|
Type: schema.TypeString,
|
||
|
Required: true,
|
||
|
},
|
||
|
contactVictorOpsWarningAttr: &schema.Schema{
|
||
|
Type: schema.TypeInt,
|
||
|
Required: true,
|
||
|
ValidateFunc: validateFuncs(
|
||
|
validateIntMin(contactVictorOpsWarningAttr, 1),
|
||
|
validateIntMax(contactVictorOpsWarningAttr, 5),
|
||
|
),
|
||
|
},
|
||
|
}),
|
||
|
},
|
||
|
},
|
||
|
contactXMPPAttr: &schema.Schema{
|
||
|
Type: schema.TypeSet,
|
||
|
Optional: true,
|
||
|
Elem: &schema.Resource{
|
||
|
Schema: convertToHelperSchema(contactXMPPDescriptions, map[schemaAttr]*schema.Schema{
|
||
|
contactXMPPAddressAttr: &schema.Schema{
|
||
|
Type: schema.TypeString,
|
||
|
Optional: true,
|
||
|
ConflictsWith: []string{contactXMPPAttr + "." + contactUserCIDAttr},
|
||
|
},
|
||
|
contactUserCIDAttr: &schema.Schema{
|
||
|
Type: schema.TypeString,
|
||
|
Optional: true,
|
||
|
ValidateFunc: validateUserCID(contactUserCIDAttr),
|
||
|
ConflictsWith: []string{contactXMPPAttr + "." + contactXMPPAddressAttr},
|
||
|
},
|
||
|
}),
|
||
|
},
|
||
|
},
|
||
|
|
||
|
// OUT parameters
|
||
|
contactLastModifiedAttr: &schema.Schema{
|
||
|
Type: schema.TypeInt,
|
||
|
Computed: true,
|
||
|
},
|
||
|
contactLastModifiedByAttr: &schema.Schema{
|
||
|
Type: schema.TypeString,
|
||
|
Computed: true,
|
||
|
},
|
||
|
}),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func contactGroupCreate(d *schema.ResourceData, meta interface{}) error {
|
||
|
ctxt := meta.(*providerContext)
|
||
|
|
||
|
in, err := getContactGroupInput(d)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
cg, err := ctxt.client.CreateContactGroup(in)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
d.SetId(cg.CID)
|
||
|
|
||
|
return contactGroupRead(d, meta)
|
||
|
}
|
||
|
|
||
|
func contactGroupExists(d *schema.ResourceData, meta interface{}) (bool, error) {
|
||
|
c := meta.(*providerContext)
|
||
|
|
||
|
cid := d.Id()
|
||
|
cg, err := c.client.FetchContactGroup(api.CIDType(&cid))
|
||
|
if err != nil {
|
||
|
if strings.Contains(err.Error(), defaultCirconus404ErrorString) {
|
||
|
return false, nil
|
||
|
}
|
||
|
|
||
|
return false, err
|
||
|
}
|
||
|
|
||
|
if cg.CID == "" {
|
||
|
return false, nil
|
||
|
}
|
||
|
|
||
|
return true, nil
|
||
|
}
|
||
|
|
||
|
func contactGroupRead(d *schema.ResourceData, meta interface{}) error {
|
||
|
c := meta.(*providerContext)
|
||
|
|
||
|
cid := d.Id()
|
||
|
|
||
|
cg, err := c.client.FetchContactGroup(api.CIDType(&cid))
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
if cg.CID == "" {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
d.SetId(cg.CID)
|
||
|
|
||
|
httpState, err := contactGroupHTTPToState(cg)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
pagerDutyState, err := contactGroupPagerDutyToState(cg)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
slackState, err := contactGroupSlackToState(cg)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
smsState, err := contactGroupSMSToState(cg)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
victorOpsState, err := contactGroupVictorOpsToState(cg)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
xmppState, err := contactGroupXMPPToState(cg)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
d.Set(contactAggregationWindowAttr, fmt.Sprintf("%ds", cg.AggregationWindow))
|
||
|
|
||
|
if err := d.Set(contactAlertOptionAttr, contactGroupAlertOptionsToState(cg)); err != nil {
|
||
|
return errwrap.Wrapf(fmt.Sprintf("Unable to store contact %q attribute: {{err}}", contactAlertOptionAttr), err)
|
||
|
}
|
||
|
|
||
|
if err := d.Set(contactEmailAttr, contactGroupEmailToState(cg)); err != nil {
|
||
|
return errwrap.Wrapf(fmt.Sprintf("Unable to store contact %q attribute: {{err}}", contactEmailAttr), err)
|
||
|
}
|
||
|
|
||
|
if err := d.Set(contactHTTPAttr, httpState); err != nil {
|
||
|
return errwrap.Wrapf(fmt.Sprintf("Unable to store contact %q attribute: {{err}}", contactHTTPAttr), err)
|
||
|
}
|
||
|
|
||
|
if err := d.Set(contactIRCAttr, contactGroupIRCToState(cg)); err != nil {
|
||
|
return errwrap.Wrapf(fmt.Sprintf("Unable to store contact %q attribute: {{err}}", contactIRCAttr), err)
|
||
|
}
|
||
|
|
||
|
d.Set(contactLongMessageAttr, cg.AlertFormats.LongMessage)
|
||
|
d.Set(contactLongSubjectAttr, cg.AlertFormats.LongSubject)
|
||
|
d.Set(contactLongSummaryAttr, cg.AlertFormats.LongSummary)
|
||
|
d.Set(contactNameAttr, cg.Name)
|
||
|
|
||
|
if err := d.Set(contactPagerDutyAttr, pagerDutyState); err != nil {
|
||
|
return errwrap.Wrapf(fmt.Sprintf("Unable to store contact %q attribute: {{err}}", contactPagerDutyAttr), err)
|
||
|
}
|
||
|
|
||
|
d.Set(contactShortMessageAttr, cg.AlertFormats.ShortMessage)
|
||
|
d.Set(contactShortSummaryAttr, cg.AlertFormats.ShortSummary)
|
||
|
|
||
|
if err := d.Set(contactSlackAttr, slackState); err != nil {
|
||
|
return errwrap.Wrapf(fmt.Sprintf("Unable to store contact %q attribute: {{err}}", contactSlackAttr), err)
|
||
|
}
|
||
|
|
||
|
if err := d.Set(contactSMSAttr, smsState); err != nil {
|
||
|
return errwrap.Wrapf(fmt.Sprintf("Unable to store contact %q attribute: {{err}}", contactSMSAttr), err)
|
||
|
}
|
||
|
|
||
|
if err := d.Set(contactTagsAttr, cg.Tags); err != nil {
|
||
|
return errwrap.Wrapf(fmt.Sprintf("Unable to store contact %q attribute: {{err}}", contactTagsAttr), err)
|
||
|
}
|
||
|
|
||
|
if err := d.Set(contactVictorOpsAttr, victorOpsState); err != nil {
|
||
|
return errwrap.Wrapf(fmt.Sprintf("Unable to store contact %q attribute: {{err}}", contactVictorOpsAttr), err)
|
||
|
}
|
||
|
|
||
|
if err := d.Set(contactXMPPAttr, xmppState); err != nil {
|
||
|
return errwrap.Wrapf(fmt.Sprintf("Unable to store contact %q attribute: {{err}}", contactXMPPAttr), err)
|
||
|
}
|
||
|
|
||
|
// Out parameters
|
||
|
d.Set(contactLastModifiedAttr, cg.LastModified)
|
||
|
d.Set(contactLastModifiedByAttr, cg.LastModifiedBy)
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func contactGroupUpdate(d *schema.ResourceData, meta interface{}) error {
|
||
|
c := meta.(*providerContext)
|
||
|
|
||
|
in, err := getContactGroupInput(d)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
in.CID = d.Id()
|
||
|
|
||
|
if _, err := c.client.UpdateContactGroup(in); err != nil {
|
||
|
return errwrap.Wrapf(fmt.Sprintf("unable to update contact group %q: {{err}}", d.Id()), err)
|
||
|
}
|
||
|
|
||
|
return contactGroupRead(d, meta)
|
||
|
}
|
||
|
|
||
|
func contactGroupDelete(d *schema.ResourceData, meta interface{}) error {
|
||
|
c := meta.(*providerContext)
|
||
|
|
||
|
cid := d.Id()
|
||
|
if _, err := c.client.DeleteContactGroupByCID(api.CIDType(&cid)); err != nil {
|
||
|
return errwrap.Wrapf(fmt.Sprintf("unable to delete contact group %q: {{err}}", d.Id()), err)
|
||
|
}
|
||
|
|
||
|
d.SetId("")
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func contactGroupAlertOptionsToState(cg *api.ContactGroup) []interface{} {
|
||
|
if config.NumSeverityLevels != len(cg.Reminders) {
|
||
|
log.Printf("[FATAL] PROVIDER BUG: Need to update constants in contactGroupAlertOptionsToState re: reminders")
|
||
|
return nil
|
||
|
}
|
||
|
if config.NumSeverityLevels != len(cg.Escalations) {
|
||
|
log.Printf("[FATAL] PROVIDER BUG: Need to update constants in contactGroupAlertOptionsToState re: escalations")
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// Populate all alert options for every severity level. We'll prune empty
|
||
|
// values at the end of this function.
|
||
|
const defaultNumAlertOptions = 4
|
||
|
alertOptions := make([]*map[string]interface{}, config.NumSeverityLevels)
|
||
|
for severityIndex := 0; severityIndex < config.NumSeverityLevels; severityIndex++ {
|
||
|
sevAction := make(map[string]interface{}, defaultNumAlertOptions)
|
||
|
sevAction[string(contactSeverityAttr)] = severityIndex + 1
|
||
|
alertOptions[severityIndex] = &sevAction
|
||
|
}
|
||
|
|
||
|
for severityIndex, reminder := range cg.Reminders {
|
||
|
if reminder != 0 {
|
||
|
(*alertOptions[severityIndex])[string(contactReminderAttr)] = fmt.Sprintf("%ds", reminder)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for severityIndex, escalate := range cg.Escalations {
|
||
|
if escalate == nil {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
(*alertOptions[severityIndex])[string(contactEscalateAfterAttr)] = fmt.Sprintf("%ds", escalate.After)
|
||
|
(*alertOptions[severityIndex])[string(contactEscalateToAttr)] = escalate.ContactGroupCID
|
||
|
}
|
||
|
|
||
|
alertOptionsList := make([]interface{}, 0, config.NumSeverityLevels)
|
||
|
for i := 0; i < config.NumSeverityLevels; i++ {
|
||
|
// NOTE: the 1 is from the always-populated contactSeverityAttr which is
|
||
|
// always set.
|
||
|
if len(*alertOptions[i]) > 1 {
|
||
|
alertOptionsList = append(alertOptionsList, *alertOptions[i])
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return alertOptionsList
|
||
|
}
|
||
|
|
||
|
func contactGroupEmailToState(cg *api.ContactGroup) []interface{} {
|
||
|
emailContacts := make([]interface{}, 0, len(cg.Contacts.Users)+len(cg.Contacts.External))
|
||
|
|
||
|
for _, ext := range cg.Contacts.External {
|
||
|
switch ext.Method {
|
||
|
case circonusMethodEmail:
|
||
|
emailContacts = append(emailContacts, map[string]interface{}{
|
||
|
contactEmailAddressAttr: ext.Info,
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for _, user := range cg.Contacts.Users {
|
||
|
switch user.Method {
|
||
|
case circonusMethodEmail:
|
||
|
emailContacts = append(emailContacts, map[string]interface{}{
|
||
|
contactUserCIDAttr: user.UserCID,
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return emailContacts
|
||
|
}
|
||
|
|
||
|
func contactGroupHTTPToState(cg *api.ContactGroup) ([]interface{}, error) {
|
||
|
httpContacts := make([]interface{}, 0, len(cg.Contacts.External))
|
||
|
|
||
|
for _, ext := range cg.Contacts.External {
|
||
|
switch ext.Method {
|
||
|
case contactHTTPAttr:
|
||
|
url := contactHTTPInfo{}
|
||
|
if err := json.Unmarshal([]byte(ext.Info), &url); err != nil {
|
||
|
return nil, errwrap.Wrapf(fmt.Sprintf("unable to decode external %s JSON (%q): {{err}}", contactHTTPAttr, ext.Info), err)
|
||
|
}
|
||
|
|
||
|
httpContacts = append(httpContacts, map[string]interface{}{
|
||
|
string(contactHTTPAddressAttr): url.Address,
|
||
|
string(contactHTTPFormatAttr): url.Format,
|
||
|
string(contactHTTPMethodAttr): url.Method,
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return httpContacts, nil
|
||
|
}
|
||
|
|
||
|
func getContactGroupInput(d *schema.ResourceData) (*api.ContactGroup, error) {
|
||
|
cg := api.NewContactGroup()
|
||
|
if v, ok := d.GetOk(contactAggregationWindowAttr); ok {
|
||
|
aggWindow, _ := time.ParseDuration(v.(string))
|
||
|
cg.AggregationWindow = uint(aggWindow.Seconds())
|
||
|
}
|
||
|
|
||
|
if v, ok := d.GetOk(contactAlertOptionAttr); ok {
|
||
|
alertOptionsRaw := v.(*schema.Set).List()
|
||
|
|
||
|
ensureEscalationSeverity := func(severity int) {
|
||
|
if cg.Escalations[severity] == nil {
|
||
|
cg.Escalations[severity] = &api.ContactGroupEscalation{}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for _, alertOptionRaw := range alertOptionsRaw {
|
||
|
alertOptionsMap := alertOptionRaw.(map[string]interface{})
|
||
|
|
||
|
severityIndex := -1
|
||
|
|
||
|
if optRaw, ok := alertOptionsMap[contactSeverityAttr]; ok {
|
||
|
severityIndex = optRaw.(int) - 1
|
||
|
}
|
||
|
|
||
|
if optRaw, ok := alertOptionsMap[contactEscalateAfterAttr]; ok {
|
||
|
if optRaw.(string) != "" {
|
||
|
d, _ := time.ParseDuration(optRaw.(string))
|
||
|
if d != 0 {
|
||
|
ensureEscalationSeverity(severityIndex)
|
||
|
cg.Escalations[severityIndex].After = uint(d.Seconds())
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if optRaw, ok := alertOptionsMap[contactEscalateToAttr]; ok && optRaw.(string) != "" {
|
||
|
ensureEscalationSeverity(severityIndex)
|
||
|
cg.Escalations[severityIndex].ContactGroupCID = optRaw.(string)
|
||
|
}
|
||
|
|
||
|
if optRaw, ok := alertOptionsMap[contactReminderAttr]; ok {
|
||
|
if optRaw.(string) == "" {
|
||
|
optRaw = "0s"
|
||
|
}
|
||
|
|
||
|
d, _ := time.ParseDuration(optRaw.(string))
|
||
|
cg.Reminders[severityIndex] = uint(d.Seconds())
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if v, ok := d.GetOk(contactNameAttr); ok {
|
||
|
cg.Name = v.(string)
|
||
|
}
|
||
|
|
||
|
if v, ok := d.GetOk(contactEmailAttr); ok {
|
||
|
emailListRaw := v.(*schema.Set).List()
|
||
|
for _, emailMapRaw := range emailListRaw {
|
||
|
emailMap := emailMapRaw.(map[string]interface{})
|
||
|
|
||
|
var requiredAttrFound bool
|
||
|
if v, ok := emailMap[contactEmailAddressAttr]; ok && v.(string) != "" {
|
||
|
requiredAttrFound = true
|
||
|
cg.Contacts.External = append(cg.Contacts.External, api.ContactGroupContactsExternal{
|
||
|
Info: v.(string),
|
||
|
Method: circonusMethodEmail,
|
||
|
})
|
||
|
}
|
||
|
|
||
|
if v, ok := emailMap[contactUserCIDAttr]; ok && v.(string) != "" {
|
||
|
requiredAttrFound = true
|
||
|
cg.Contacts.Users = append(cg.Contacts.Users, api.ContactGroupContactsUser{
|
||
|
Method: circonusMethodEmail,
|
||
|
UserCID: v.(string),
|
||
|
})
|
||
|
}
|
||
|
|
||
|
// Can't mark two attributes that are conflicting as required so we do our
|
||
|
// own validation check here.
|
||
|
if !requiredAttrFound {
|
||
|
return nil, fmt.Errorf("In type %s, either %s or %s must be specified", contactEmailAttr, contactEmailAddressAttr, contactUserCIDAttr)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if v, ok := d.GetOk(contactHTTPAttr); ok {
|
||
|
httpListRaw := v.(*schema.Set).List()
|
||
|
for _, httpMapRaw := range httpListRaw {
|
||
|
httpMap := httpMapRaw.(map[string]interface{})
|
||
|
|
||
|
httpInfo := contactHTTPInfo{}
|
||
|
|
||
|
if v, ok := httpMap[string(contactHTTPAddressAttr)]; ok {
|
||
|
httpInfo.Address = v.(string)
|
||
|
}
|
||
|
|
||
|
if v, ok := httpMap[string(contactHTTPFormatAttr)]; ok {
|
||
|
httpInfo.Format = v.(string)
|
||
|
}
|
||
|
|
||
|
if v, ok := httpMap[string(contactHTTPMethodAttr)]; ok {
|
||
|
httpInfo.Method = v.(string)
|
||
|
}
|
||
|
|
||
|
js, err := json.Marshal(httpInfo)
|
||
|
if err != nil {
|
||
|
return nil, errwrap.Wrapf(fmt.Sprintf("error marshalling %s JSON config string: {{err}}", contactHTTPAttr), err)
|
||
|
}
|
||
|
|
||
|
cg.Contacts.External = append(cg.Contacts.External, api.ContactGroupContactsExternal{
|
||
|
Info: string(js),
|
||
|
Method: circonusMethodHTTP,
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if v, ok := d.GetOk(contactIRCAttr); ok {
|
||
|
ircListRaw := v.(*schema.Set).List()
|
||
|
for _, ircMapRaw := range ircListRaw {
|
||
|
ircMap := ircMapRaw.(map[string]interface{})
|
||
|
|
||
|
if v, ok := ircMap[contactUserCIDAttr]; ok && v.(string) != "" {
|
||
|
cg.Contacts.Users = append(cg.Contacts.Users, api.ContactGroupContactsUser{
|
||
|
Method: circonusMethodIRC,
|
||
|
UserCID: v.(string),
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if v, ok := d.GetOk(contactPagerDutyAttr); ok {
|
||
|
pagerDutyListRaw := v.(*schema.Set).List()
|
||
|
for _, pagerDutyMapRaw := range pagerDutyListRaw {
|
||
|
pagerDutyMap := pagerDutyMapRaw.(map[string]interface{})
|
||
|
|
||
|
pagerDutyInfo := contactPagerDutyInfo{}
|
||
|
|
||
|
if v, ok := pagerDutyMap[contactContactGroupFallbackAttr]; ok && v.(string) != "" {
|
||
|
cid := v.(string)
|
||
|
contactGroupID, err := failoverGroupCIDToID(api.CIDType(&cid))
|
||
|
if err != nil {
|
||
|
return nil, errwrap.Wrapf("error reading contact group CID: {{err}}", err)
|
||
|
}
|
||
|
pagerDutyInfo.FallbackGroupCID = contactGroupID
|
||
|
}
|
||
|
|
||
|
if v, ok := pagerDutyMap[string(contactPagerDutyIntegrationKeyAttr)]; ok {
|
||
|
pagerDutyInfo.IntegrationKey = v.(string)
|
||
|
}
|
||
|
|
||
|
if v, ok := pagerDutyMap[string(contactPagerDutyWebhookURLAttr)]; ok {
|
||
|
pagerDutyInfo.WebookURL = v.(string)
|
||
|
}
|
||
|
|
||
|
js, err := json.Marshal(pagerDutyInfo)
|
||
|
if err != nil {
|
||
|
return nil, errwrap.Wrapf(fmt.Sprintf("error marshalling %s JSON config string: {{err}}", contactPagerDutyAttr), err)
|
||
|
}
|
||
|
|
||
|
cg.Contacts.External = append(cg.Contacts.External, api.ContactGroupContactsExternal{
|
||
|
Info: string(js),
|
||
|
Method: circonusMethodPagerDuty,
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if v, ok := d.GetOk(contactSlackAttr); ok {
|
||
|
slackListRaw := v.(*schema.Set).List()
|
||
|
for _, slackMapRaw := range slackListRaw {
|
||
|
slackMap := slackMapRaw.(map[string]interface{})
|
||
|
|
||
|
slackInfo := contactSlackInfo{}
|
||
|
|
||
|
var buttons int
|
||
|
if v, ok := slackMap[contactSlackButtonsAttr]; ok {
|
||
|
if v.(bool) {
|
||
|
buttons = 1
|
||
|
}
|
||
|
slackInfo.Buttons = buttons
|
||
|
}
|
||
|
|
||
|
if v, ok := slackMap[contactSlackChannelAttr]; ok {
|
||
|
slackInfo.Channel = v.(string)
|
||
|
}
|
||
|
|
||
|
if v, ok := slackMap[contactContactGroupFallbackAttr]; ok && v.(string) != "" {
|
||
|
cid := v.(string)
|
||
|
contactGroupID, err := failoverGroupCIDToID(api.CIDType(&cid))
|
||
|
if err != nil {
|
||
|
return nil, errwrap.Wrapf("error reading contact group CID: {{err}}", err)
|
||
|
}
|
||
|
slackInfo.FallbackGroupCID = contactGroupID
|
||
|
}
|
||
|
|
||
|
if v, ok := slackMap[contactSlackTeamAttr]; ok {
|
||
|
slackInfo.Team = v.(string)
|
||
|
}
|
||
|
|
||
|
if v, ok := slackMap[contactSlackUsernameAttr]; ok {
|
||
|
slackInfo.Username = v.(string)
|
||
|
}
|
||
|
|
||
|
js, err := json.Marshal(slackInfo)
|
||
|
if err != nil {
|
||
|
return nil, errwrap.Wrapf(fmt.Sprintf("error marshalling %s JSON config string: {{err}}", contactSlackAttr), err)
|
||
|
}
|
||
|
|
||
|
cg.Contacts.External = append(cg.Contacts.External, api.ContactGroupContactsExternal{
|
||
|
Info: string(js),
|
||
|
Method: circonusMethodSlack,
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if v, ok := d.GetOk(contactSMSAttr); ok {
|
||
|
smsListRaw := v.(*schema.Set).List()
|
||
|
for _, smsMapRaw := range smsListRaw {
|
||
|
smsMap := smsMapRaw.(map[string]interface{})
|
||
|
|
||
|
var requiredAttrFound bool
|
||
|
if v, ok := smsMap[contactSMSAddressAttr]; ok && v.(string) != "" {
|
||
|
requiredAttrFound = true
|
||
|
cg.Contacts.External = append(cg.Contacts.External, api.ContactGroupContactsExternal{
|
||
|
Info: v.(string),
|
||
|
Method: circonusMethodSMS,
|
||
|
})
|
||
|
}
|
||
|
|
||
|
if v, ok := smsMap[contactUserCIDAttr]; ok && v.(string) != "" {
|
||
|
requiredAttrFound = true
|
||
|
cg.Contacts.Users = append(cg.Contacts.Users, api.ContactGroupContactsUser{
|
||
|
Method: circonusMethodSMS,
|
||
|
UserCID: v.(string),
|
||
|
})
|
||
|
}
|
||
|
|
||
|
// Can't mark two attributes that are conflicting as required so we do our
|
||
|
// own validation check here.
|
||
|
if !requiredAttrFound {
|
||
|
return nil, fmt.Errorf("In type %s, either %s or %s must be specified", contactEmailAttr, contactEmailAddressAttr, contactUserCIDAttr)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if v, ok := d.GetOk(contactVictorOpsAttr); ok {
|
||
|
victorOpsListRaw := v.(*schema.Set).List()
|
||
|
for _, victorOpsMapRaw := range victorOpsListRaw {
|
||
|
victorOpsMap := victorOpsMapRaw.(map[string]interface{})
|
||
|
|
||
|
victorOpsInfo := contactVictorOpsInfo{}
|
||
|
|
||
|
if v, ok := victorOpsMap[contactContactGroupFallbackAttr]; ok && v.(string) != "" {
|
||
|
cid := v.(string)
|
||
|
contactGroupID, err := failoverGroupCIDToID(api.CIDType(&cid))
|
||
|
if err != nil {
|
||
|
return nil, errwrap.Wrapf("error reading contact group CID: {{err}}", err)
|
||
|
}
|
||
|
victorOpsInfo.FallbackGroupCID = contactGroupID
|
||
|
}
|
||
|
|
||
|
if v, ok := victorOpsMap[contactVictorOpsAPIKeyAttr]; ok {
|
||
|
victorOpsInfo.APIKey = v.(string)
|
||
|
}
|
||
|
|
||
|
if v, ok := victorOpsMap[contactVictorOpsCriticalAttr]; ok {
|
||
|
victorOpsInfo.Critical = v.(int)
|
||
|
}
|
||
|
|
||
|
if v, ok := victorOpsMap[contactVictorOpsInfoAttr]; ok {
|
||
|
victorOpsInfo.Info = v.(int)
|
||
|
}
|
||
|
|
||
|
if v, ok := victorOpsMap[contactVictorOpsTeamAttr]; ok {
|
||
|
victorOpsInfo.Team = v.(string)
|
||
|
}
|
||
|
|
||
|
if v, ok := victorOpsMap[contactVictorOpsWarningAttr]; ok {
|
||
|
victorOpsInfo.Warning = v.(int)
|
||
|
}
|
||
|
|
||
|
js, err := json.Marshal(victorOpsInfo)
|
||
|
if err != nil {
|
||
|
return nil, errwrap.Wrapf(fmt.Sprintf("error marshalling %s JSON config string: {{err}}", contactVictorOpsAttr), err)
|
||
|
}
|
||
|
|
||
|
cg.Contacts.External = append(cg.Contacts.External, api.ContactGroupContactsExternal{
|
||
|
Info: string(js),
|
||
|
Method: circonusMethodVictorOps,
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if v, ok := d.GetOk(contactXMPPAttr); ok {
|
||
|
xmppListRaw := v.(*schema.Set).List()
|
||
|
for _, xmppMapRaw := range xmppListRaw {
|
||
|
xmppMap := xmppMapRaw.(map[string]interface{})
|
||
|
|
||
|
if v, ok := xmppMap[contactXMPPAddressAttr]; ok && v.(string) != "" {
|
||
|
cg.Contacts.External = append(cg.Contacts.External, api.ContactGroupContactsExternal{
|
||
|
Info: v.(string),
|
||
|
Method: circonusMethodXMPP,
|
||
|
})
|
||
|
}
|
||
|
|
||
|
if v, ok := xmppMap[contactUserCIDAttr]; ok && v.(string) != "" {
|
||
|
cg.Contacts.Users = append(cg.Contacts.Users, api.ContactGroupContactsUser{
|
||
|
Method: circonusMethodXMPP,
|
||
|
UserCID: v.(string),
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if v, ok := d.GetOk(contactLongMessageAttr); ok {
|
||
|
msg := v.(string)
|
||
|
cg.AlertFormats.LongMessage = &msg
|
||
|
}
|
||
|
|
||
|
if v, ok := d.GetOk(contactLongSubjectAttr); ok {
|
||
|
msg := v.(string)
|
||
|
cg.AlertFormats.LongSubject = &msg
|
||
|
}
|
||
|
|
||
|
if v, ok := d.GetOk(contactLongSummaryAttr); ok {
|
||
|
msg := v.(string)
|
||
|
cg.AlertFormats.LongSummary = &msg
|
||
|
}
|
||
|
|
||
|
if v, ok := d.GetOk(contactShortMessageAttr); ok {
|
||
|
msg := v.(string)
|
||
|
cg.AlertFormats.ShortMessage = &msg
|
||
|
}
|
||
|
|
||
|
if v, ok := d.GetOk(contactShortSummaryAttr); ok {
|
||
|
msg := v.(string)
|
||
|
cg.AlertFormats.ShortSummary = &msg
|
||
|
}
|
||
|
|
||
|
if v, ok := d.GetOk(contactShortMessageAttr); ok {
|
||
|
msg := v.(string)
|
||
|
cg.AlertFormats.ShortMessage = &msg
|
||
|
}
|
||
|
|
||
|
if v, found := d.GetOk(checkTagsAttr); found {
|
||
|
cg.Tags = derefStringList(flattenSet(v.(*schema.Set)))
|
||
|
}
|
||
|
|
||
|
if err := validateContactGroup(cg); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return cg, nil
|
||
|
}
|
||
|
|
||
|
func contactGroupIRCToState(cg *api.ContactGroup) []interface{} {
|
||
|
ircContacts := make([]interface{}, 0, len(cg.Contacts.Users))
|
||
|
|
||
|
for _, user := range cg.Contacts.Users {
|
||
|
switch user.Method {
|
||
|
case contactIRCAttr:
|
||
|
ircContacts = append(ircContacts, map[string]interface{}{
|
||
|
contactUserCIDAttr: user.UserCID,
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ircContacts
|
||
|
}
|
||
|
|
||
|
func contactGroupPagerDutyToState(cg *api.ContactGroup) ([]interface{}, error) {
|
||
|
pdContacts := make([]interface{}, 0, len(cg.Contacts.External))
|
||
|
|
||
|
for _, ext := range cg.Contacts.External {
|
||
|
switch ext.Method {
|
||
|
case contactPagerDutyAttr:
|
||
|
pdInfo := contactPagerDutyInfo{}
|
||
|
if err := json.Unmarshal([]byte(ext.Info), &pdInfo); err != nil {
|
||
|
return nil, errwrap.Wrapf(fmt.Sprintf("unable to decode external %s JSON (%q): {{err}}", contactPagerDutyAttr, ext.Info), err)
|
||
|
}
|
||
|
|
||
|
pdContacts = append(pdContacts, map[string]interface{}{
|
||
|
string(contactContactGroupFallbackAttr): failoverGroupIDToCID(pdInfo.FallbackGroupCID),
|
||
|
string(contactPagerDutyIntegrationKeyAttr): pdInfo.IntegrationKey,
|
||
|
string(contactPagerDutyWebhookURLAttr): pdInfo.WebookURL,
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return pdContacts, nil
|
||
|
}
|
||
|
|
||
|
func contactGroupSlackToState(cg *api.ContactGroup) ([]interface{}, error) {
|
||
|
slackContacts := make([]interface{}, 0, len(cg.Contacts.External))
|
||
|
|
||
|
for _, ext := range cg.Contacts.External {
|
||
|
switch ext.Method {
|
||
|
case contactSlackAttr:
|
||
|
slackInfo := contactSlackInfo{}
|
||
|
if err := json.Unmarshal([]byte(ext.Info), &slackInfo); err != nil {
|
||
|
return nil, errwrap.Wrapf(fmt.Sprintf("unable to decode external %s JSON (%q): {{err}}", contactSlackAttr, ext.Info), err)
|
||
|
}
|
||
|
|
||
|
slackContacts = append(slackContacts, map[string]interface{}{
|
||
|
contactContactGroupFallbackAttr: failoverGroupIDToCID(slackInfo.FallbackGroupCID),
|
||
|
contactSlackButtonsAttr: int(slackInfo.Buttons) == int(1),
|
||
|
contactSlackChannelAttr: slackInfo.Channel,
|
||
|
contactSlackTeamAttr: slackInfo.Team,
|
||
|
contactSlackUsernameAttr: slackInfo.Username,
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return slackContacts, nil
|
||
|
}
|
||
|
|
||
|
func contactGroupSMSToState(cg *api.ContactGroup) ([]interface{}, error) {
|
||
|
smsContacts := make([]interface{}, 0, len(cg.Contacts.Users)+len(cg.Contacts.External))
|
||
|
|
||
|
for _, ext := range cg.Contacts.External {
|
||
|
switch ext.Method {
|
||
|
case contactSMSAttr:
|
||
|
smsContacts = append(smsContacts, map[string]interface{}{
|
||
|
contactSMSAddressAttr: ext.Info,
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for _, user := range cg.Contacts.Users {
|
||
|
switch user.Method {
|
||
|
case contactSMSAttr:
|
||
|
smsContacts = append(smsContacts, map[string]interface{}{
|
||
|
contactUserCIDAttr: user.UserCID,
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return smsContacts, nil
|
||
|
}
|
||
|
|
||
|
func contactGroupVictorOpsToState(cg *api.ContactGroup) ([]interface{}, error) {
|
||
|
victorOpsContacts := make([]interface{}, 0, len(cg.Contacts.External))
|
||
|
|
||
|
for _, ext := range cg.Contacts.External {
|
||
|
switch ext.Method {
|
||
|
case contactVictorOpsAttr:
|
||
|
victorOpsInfo := contactVictorOpsInfo{}
|
||
|
if err := json.Unmarshal([]byte(ext.Info), &victorOpsInfo); err != nil {
|
||
|
return nil, errwrap.Wrapf(fmt.Sprintf("unable to decode external %s JSON (%q): {{err}}", contactVictorOpsInfoAttr, ext.Info), err)
|
||
|
}
|
||
|
|
||
|
victorOpsContacts = append(victorOpsContacts, map[string]interface{}{
|
||
|
contactContactGroupFallbackAttr: failoverGroupIDToCID(victorOpsInfo.FallbackGroupCID),
|
||
|
contactVictorOpsAPIKeyAttr: victorOpsInfo.APIKey,
|
||
|
contactVictorOpsCriticalAttr: victorOpsInfo.Critical,
|
||
|
contactVictorOpsInfoAttr: victorOpsInfo.Info,
|
||
|
contactVictorOpsTeamAttr: victorOpsInfo.Team,
|
||
|
contactVictorOpsWarningAttr: victorOpsInfo.Warning,
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return victorOpsContacts, nil
|
||
|
}
|
||
|
|
||
|
func contactGroupXMPPToState(cg *api.ContactGroup) ([]interface{}, error) {
|
||
|
xmppContacts := make([]interface{}, 0, len(cg.Contacts.Users)+len(cg.Contacts.External))
|
||
|
|
||
|
for _, ext := range cg.Contacts.External {
|
||
|
switch ext.Method {
|
||
|
case contactXMPPAttr:
|
||
|
xmppContacts = append(xmppContacts, map[string]interface{}{
|
||
|
contactXMPPAddressAttr: ext.Info,
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for _, user := range cg.Contacts.Users {
|
||
|
switch user.Method {
|
||
|
case contactXMPPAttr:
|
||
|
xmppContacts = append(xmppContacts, map[string]interface{}{
|
||
|
contactUserCIDAttr: user.UserCID,
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return xmppContacts, nil
|
||
|
}
|
||
|
|
||
|
// contactGroupAlertOptionsChecksum creates a stable hash of the normalized values
|
||
|
func contactGroupAlertOptionsChecksum(v interface{}) int {
|
||
|
m := v.(map[string]interface{})
|
||
|
b := &bytes.Buffer{}
|
||
|
b.Grow(defaultHashBufSize)
|
||
|
fmt.Fprintf(b, "%x", m[contactSeverityAttr].(int))
|
||
|
fmt.Fprint(b, normalizeTimeDurationStringToSeconds(m[contactEscalateAfterAttr]))
|
||
|
fmt.Fprint(b, m[contactEscalateToAttr])
|
||
|
fmt.Fprint(b, normalizeTimeDurationStringToSeconds(m[contactReminderAttr]))
|
||
|
return hashcode.String(b.String())
|
||
|
}
|