terraform/vendor/github.com/Ensighten/udnssdk/rrset.go

378 lines
11 KiB
Go

package udnssdk
import (
"encoding/json"
"fmt"
"log"
"time"
)
// RRSetsService provides access to RRSet resources
type RRSetsService struct {
client *Client
}
// Here is the big 'Profile' mess that should get refactored to a more managable place
// StringProfile wraps a Profile string
type StringProfile struct {
Profile string `json:"profile,omitempty"`
}
// Metaprofile is a helper struct for extracting a Context from a StringProfile
type Metaprofile struct {
Context ProfileSchema `json:"@context"`
}
// ProfileSchema are the schema URIs for RRSet Profiles
type ProfileSchema string
const (
// DirPoolSchema is the schema URI for a Directional pool profile
DirPoolSchema ProfileSchema = "http://schemas.ultradns.com/DirPool.jsonschema"
// RDPoolSchema is the schema URI for a Resource Distribution pool profile
RDPoolSchema = "http://schemas.ultradns.com/RDPool.jsonschema"
// SBPoolSchema is the schema URI for a SiteBacker pool profile
SBPoolSchema = "http://schemas.ultradns.com/SBPool.jsonschema"
// TCPoolSchema is the schema URI for a Traffic Controller pool profile
TCPoolSchema = "http://schemas.ultradns.com/TCPool.jsonschema"
)
// DirPoolProfile wraps a Profile for a Directional Pool
type DirPoolProfile struct {
Context ProfileSchema `json:"@context"`
Description string `json:"description"`
ConflictResolve string `json:"conflictResolve,omitempty"`
RDataInfo []DPRDataInfo `json:"rdataInfo"`
NoResponse DPRDataInfo `json:"noResponse"`
}
// DPRDataInfo wraps the rdataInfo object of a DirPoolProfile response
type DPRDataInfo struct {
AllNonConfigured bool `json:"allNonConfigured,omitempty"`
IPInfo IPInfo `json:"ipInfo,omitempty"`
GeoInfo GeoInfo `json:"geoInfo,omitempty"`
}
// IPInfo wraps the ipInfo object of a DPRDataInfo
type IPInfo struct {
Name string `json:"name"`
IsAccountLevel bool `json:"isAccountLevel,omitempty"`
Ips []IPAddrDTO `json:"ips"`
}
// GeoInfo wraps the geoInfo object of a DPRDataInfo
type GeoInfo struct {
Name string `json:"name"`
IsAccountLevel bool `json:"isAccountLevel,omitempty"`
Codes []string `json:"codes"`
}
// RDPoolProfile wraps a Profile for a Resource Distribution pool
type RDPoolProfile struct {
Context ProfileSchema `json:"@context"`
Order string `json:"order"`
Description string `json:"description"`
}
// SBPoolProfile wraps a Profile for a SiteBacker pool
type SBPoolProfile struct {
Context ProfileSchema `json:"@context"`
Description string `json:"description"`
RunProbes bool `json:"runProbes,omitempty"`
ActOnProbes bool `json:"actOnProbes,omitempty"`
Order string `json:"order,omitempty"`
MaxActive int `json:"maxActive,omitempty"`
MaxServed int `json:"maxServed,omitempty"`
RDataInfo []SBRDataInfo `json:"rdataInfo"`
BackupRecords []BackupRecord `json:"backupRecords"`
}
// SBRDataInfo wraps the rdataInfo object of a SBPoolProfile
type SBRDataInfo struct {
State string `json:"state"`
RunProbes bool `json:"runProbes,omitempty"`
Priority int `json:"priority"`
FailoverDelay int `json:"failoverDelay,omitempty"`
Threshold int `json:"threshold"`
Weight int `json:"weight"`
}
// BackupRecord wraps the backupRecord objects of an SBPoolProfile response
type BackupRecord struct {
RData string `json:"rdata"`
FailoverDelay int `json:"failoverDelay,omitempty"`
}
// TCPoolProfile wraps a Profile for a Traffic Controller pool
type TCPoolProfile struct {
Context ProfileSchema `json:"@context"`
Description string `json:"description"`
RunProbes bool `json:"runProbes,omitempty"`
ActOnProbes bool `json:"actOnProbes,omitempty"`
MaxToLB int `json:"maxToLB,omitempty"`
RDataInfo []SBRDataInfo `json:"rdataInfo"`
BackupRecord BackupRecord `json:"backupRecord"`
}
// UnmarshalJSON does what it says on the tin
func (sp *StringProfile) UnmarshalJSON(b []byte) (err error) {
sp.Profile = string(b)
return nil
}
// MarshalJSON does what it says on the tin
func (sp *StringProfile) MarshalJSON() ([]byte, error) {
if sp.Profile != "" {
return []byte(sp.Profile), nil
}
return json.Marshal(nil)
}
// Metaprofile converts a StringProfile to a Metaprofile to extract the context
func (sp *StringProfile) Metaprofile() (Metaprofile, error) {
var mp Metaprofile
if sp.Profile == "" {
return mp, fmt.Errorf("Empty Profile cannot be converted to a Metaprofile")
}
err := json.Unmarshal([]byte(sp.Profile), &mp)
if err != nil {
return mp, fmt.Errorf("Error getting profile type: %+v\n", err)
}
return mp, nil
}
// Context extracts the schema context from a StringProfile
func (sp *StringProfile) Context() ProfileSchema {
mp, err := sp.Metaprofile()
if err != nil {
log.Printf("[ERROR] %+s\n", err)
return ""
}
return mp.Context
}
// GoString returns the StringProfile's Profile.
func (sp *StringProfile) GoString() string {
return sp.Profile
}
// String returns the StringProfile's Profile.
func (sp *StringProfile) String() string {
return sp.Profile
}
// GetProfileObject extracts the full Profile by its schema type
func (sp *StringProfile) GetProfileObject() interface{} {
c := sp.Context()
switch c {
case DirPoolSchema:
var dpp DirPoolProfile
err := json.Unmarshal([]byte(sp.Profile), &dpp)
if err != nil {
log.Printf("Could not Unmarshal the DirPoolProfile.\n")
return nil
}
return dpp
case RDPoolSchema:
var rdp RDPoolProfile
err := json.Unmarshal([]byte(sp.Profile), &rdp)
if err != nil {
log.Printf("Could not Unmarshal the RDPoolProfile.\n")
return nil
}
return rdp
case SBPoolSchema:
var sbp SBPoolProfile
err := json.Unmarshal([]byte(sp.Profile), &sbp)
if err != nil {
log.Printf("Could not Unmarshal the SBPoolProfile.\n")
return nil
}
return sbp
case TCPoolSchema:
var tcp TCPoolProfile
err := json.Unmarshal([]byte(sp.Profile), &tcp)
if err != nil {
log.Printf("Could not Unmarshal the TCPoolProfile.\n")
return nil
}
return tcp
default:
log.Printf("ERROR - Fall through on GetProfileObject - %s.\n", c)
return fmt.Errorf("Fallthrough on GetProfileObject type %s\n", c)
}
}
// RRSet wraps an RRSet resource
type RRSet struct {
OwnerName string `json:"ownerName"`
RRType string `json:"rrtype"`
TTL int `json:"ttl"`
RData []string `json:"rdata"`
Profile *StringProfile `json:"profile,omitempty"`
}
// RRSetListDTO wraps a list of RRSet resources
type RRSetListDTO struct {
ZoneName string `json:"zoneName"`
Rrsets []RRSet `json:"rrsets"`
Queryinfo QueryInfo `json:"queryInfo"`
Resultinfo ResultInfo `json:"resultInfo"`
}
// RRSetKey collects the identifiers of a Zone
type RRSetKey struct {
Zone string
Type string
Name string
}
// URI generates the URI for an RRSet
func (k RRSetKey) URI() string {
uri := fmt.Sprintf("zones/%s/rrsets", k.Zone)
if k.Type != "" {
uri += fmt.Sprintf("/%v", k.Type)
if k.Name != "" {
uri += fmt.Sprintf("/%v", k.Name)
}
}
return uri
}
// QueryURI generates the query URI for an RRSet and offset
func (k RRSetKey) QueryURI(offset int) string {
// TODO: find a more appropriate place to set "" to "ANY"
if k.Type == "" {
k.Type = "ANY"
}
return fmt.Sprintf("%s?offset=%d", k.URI(), offset)
}
// AlertsURI generates the URI for an RRSet
func (k RRSetKey) AlertsURI() string {
return fmt.Sprintf("%s/alerts", k.URI())
}
// AlertsQueryURI generates the alerts query URI for an RRSet with query
func (k RRSetKey) AlertsQueryURI(offset int) string {
uri := k.AlertsURI()
if offset != 0 {
uri = fmt.Sprintf("%s?offset=%d", uri, offset)
}
return uri
}
// EventsURI generates the URI for an RRSet
func (k RRSetKey) EventsURI() string {
return fmt.Sprintf("%s/events", k.URI())
}
// EventsQueryURI generates the events query URI for an RRSet with query
func (k RRSetKey) EventsQueryURI(query string, offset int) string {
uri := k.EventsURI()
if query != "" {
return fmt.Sprintf("%s?sort=NAME&query=%s&offset=%d", uri, query, offset)
}
if offset != 0 {
return fmt.Sprintf("%s?offset=%d", uri, offset)
}
return uri
}
// NotificationsURI generates the notifications URI for an RRSet
func (k RRSetKey) NotificationsURI() string {
return fmt.Sprintf("%s/notifications", k.URI())
}
// NotificationsQueryURI generates the notifications query URI for an RRSet with query
func (k RRSetKey) NotificationsQueryURI(query string, offset int) string {
uri := k.NotificationsURI()
if query != "" {
uri = fmt.Sprintf("%s?sort=NAME&query=%s&offset=%d", uri, query, offset)
} else {
uri = fmt.Sprintf("%s?offset=%d", uri, offset)
}
return uri
}
// ProbesURI generates the probes URI for an RRSet
func (k RRSetKey) ProbesURI() string {
return fmt.Sprintf("%s/probes", k.URI())
}
// ProbesQueryURI generates the probes query URI for an RRSet with query
func (k RRSetKey) ProbesQueryURI(query string) string {
uri := k.ProbesURI()
if query != "" {
uri = fmt.Sprintf("%s?sort=NAME&query=%s", uri, query)
}
return uri
}
// Select will list the zone rrsets, paginating through all available results
func (s *RRSetsService) Select(k RRSetKey) ([]RRSet, error) {
// TODO: Sane Configuration for timeouts / retries
maxerrs := 5
waittime := 5 * time.Second
rrsets := []RRSet{}
errcnt := 0
offset := 0
for {
reqRrsets, ri, res, err := s.SelectWithOffset(k, offset)
if err != nil {
if res.StatusCode >= 500 {
errcnt = errcnt + 1
if errcnt < maxerrs {
time.Sleep(waittime)
continue
}
}
return rrsets, err
}
log.Printf("ResultInfo: %+v\n", ri)
for _, rrset := range reqRrsets {
rrsets = append(rrsets, rrset)
}
if ri.ReturnedCount+ri.Offset >= ri.TotalCount {
return rrsets, nil
}
offset = ri.ReturnedCount + ri.Offset
continue
}
}
// SelectWithOffset requests zone rrsets by RRSetKey & optional offset
func (s *RRSetsService) SelectWithOffset(k RRSetKey, offset int) ([]RRSet, ResultInfo, *Response, error) {
var rrsld RRSetListDTO
uri := k.QueryURI(offset)
res, err := s.client.get(uri, &rrsld)
rrsets := []RRSet{}
for _, rrset := range rrsld.Rrsets {
rrsets = append(rrsets, rrset)
}
return rrsets, rrsld.Resultinfo, res, err
}
// Create creates an rrset with val
func (s *RRSetsService) Create(k RRSetKey, rrset RRSet) (*Response, error) {
var ignored interface{}
return s.client.post(k.URI(), rrset, &ignored)
}
// Update updates a RRSet with the provided val
func (s *RRSetsService) Update(k RRSetKey, val RRSet) (*Response, error) {
var ignored interface{}
return s.client.put(k.URI(), val, &ignored)
}
// Delete deletes an RRSet
func (s *RRSetsService) Delete(k RRSetKey) (*Response, error) {
return s.client.delete(k.URI(), nil)
}