github.com/akamai/AkamaiOPEN-edgegrid-golang/v8@v8.1.0/pkg/dns/recordsets.go (about) 1 package dns 2 3 import ( 4 "context" 5 "fmt" 6 "net/http" 7 8 validation "github.com/go-ozzo/ozzo-validation/v4" 9 10 "strconv" 11 "sync" 12 ) 13 14 var ( 15 zoneRecordSetsWriteLock sync.Mutex 16 ) 17 18 // Recordsets contains operations available on a record sets. 19 type Recordsets interface { 20 // GetRecordSets retrieves record sets with Query Args. No formatting of arg values. 21 // 22 // See: https://techdocs.akamai.com/edge-dns/reference/get-zones-zone-recordsets 23 GetRecordSets(context.Context, string, ...RecordSetQueryArgs) (*RecordSetResponse, error) 24 // CreateRecordSets creates multiple record sets. 25 // 26 // See: https://techdocs.akamai.com/edge-dns/reference/post-zones-zone-recordsets 27 CreateRecordSets(context.Context, *RecordSets, string, ...bool) error 28 // UpdateRecordSets replaces list of record sets. 29 // 30 // See: https://techdocs.akamai.com/edge-dns/reference/put-zones-zone-recordsets 31 UpdateRecordSets(context.Context, *RecordSets, string, ...bool) error 32 } 33 34 // RecordSetQueryArgs contains query parameters for recordset request 35 type RecordSetQueryArgs struct { 36 Page int 37 PageSize int 38 Search string 39 ShowAll bool 40 SortBy string 41 Types string 42 } 43 44 // RecordSets Struct. Used for Create and Update record sets. Contains a list of RecordSet objects 45 type RecordSets struct { 46 RecordSets []RecordSet `json:"recordsets"` 47 } 48 49 // RecordSet contains record set metadata 50 type RecordSet struct { 51 Name string `json:"name"` 52 Type string `json:"type"` 53 TTL int `json:"ttl"` 54 Rdata []string `json:"rdata"` 55 } 56 57 // Metadata contains metadata of RecordSet response 58 type Metadata struct { 59 LastPage int `json:"lastPage"` 60 Page int `json:"page"` 61 PageSize int `json:"pageSize"` 62 ShowAll bool `json:"showAll"` 63 TotalElements int `json:"totalElements"` 64 } 65 66 // RecordSetResponse contains a response with a list of record sets 67 type RecordSetResponse struct { 68 Metadata Metadata `json:"metadata"` 69 RecordSets []RecordSet `json:"recordsets"` 70 } 71 72 // Validate validates RecordSets 73 func (rs *RecordSets) Validate() error { 74 if len(rs.RecordSets) < 1 { 75 return fmt.Errorf("request initiated with empty recordsets list") 76 } 77 for _, rec := range rs.RecordSets { 78 err := validation.Errors{ 79 "Name": validation.Validate(rec.Name, validation.Required), 80 "Type": validation.Validate(rec.Type, validation.Required), 81 "TTL": validation.Validate(rec.TTL, validation.Required), 82 "Rdata": validation.Validate(rec.Rdata, validation.Required), 83 }.Filter() 84 if err != nil { 85 return err 86 } 87 } 88 return nil 89 } 90 91 func (d *dns) GetRecordSets(ctx context.Context, zone string, queryArgs ...RecordSetQueryArgs) (*RecordSetResponse, error) { 92 logger := d.Log(ctx) 93 logger.Debug("GetRecordSets") 94 95 if len(queryArgs) > 1 { 96 return nil, fmt.Errorf("invalid arguments GetRecordSets QueryArgs") 97 } 98 99 getURL := fmt.Sprintf("/config-dns/v2/zones/%s/recordsets", zone) 100 101 req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) 102 if err != nil { 103 return nil, fmt.Errorf("failed to create GetRecordsets request: %w", err) 104 } 105 106 q := req.URL.Query() 107 if len(queryArgs) > 0 { 108 if queryArgs[0].Page > 0 { 109 q.Add("page", strconv.Itoa(queryArgs[0].Page)) 110 } 111 if queryArgs[0].PageSize > 0 { 112 q.Add("pageSize", strconv.Itoa(queryArgs[0].PageSize)) 113 } 114 if queryArgs[0].Search != "" { 115 q.Add("search", queryArgs[0].Search) 116 } 117 q.Add("showAll", strconv.FormatBool(queryArgs[0].ShowAll)) 118 if queryArgs[0].SortBy != "" { 119 q.Add("sortBy", queryArgs[0].SortBy) 120 } 121 if queryArgs[0].Types != "" { 122 q.Add("types", queryArgs[0].Types) 123 } 124 req.URL.RawQuery = q.Encode() 125 } 126 127 var result RecordSetResponse 128 resp, err := d.Exec(req, &result) 129 if err != nil { 130 return nil, fmt.Errorf("GetRecordsets request failed: %w", err) 131 } 132 133 if resp.StatusCode != http.StatusOK { 134 return nil, d.Error(resp) 135 } 136 137 return &result, nil 138 } 139 140 func (d *dns) CreateRecordSets(ctx context.Context, recordSets *RecordSets, zone string, recLock ...bool) error { 141 // This lock will restrict the concurrency of API calls 142 // to 1 save request at a time. This is needed for the Soa.Serial value which 143 // is required to be incremented for every subsequent update to a zone 144 // so we have to save just one request at a time to ensure this is always 145 // incremented properly 146 147 if localLock(recLock) { 148 zoneRecordSetsWriteLock.Lock() 149 defer zoneRecordSetsWriteLock.Unlock() 150 } 151 152 logger := d.Log(ctx) 153 logger.Debug("CreateRecordSets") 154 155 if err := recordSets.Validate(); err != nil { 156 return err 157 } 158 159 reqBody, err := convertStructToReqBody(recordSets) 160 if err != nil { 161 return fmt.Errorf("failed to generate request body: %w", err) 162 } 163 164 postURL := fmt.Sprintf("/config-dns/v2/zones/%s/recordsets", zone) 165 req, err := http.NewRequestWithContext(ctx, http.MethodPost, postURL, reqBody) 166 if err != nil { 167 return fmt.Errorf("failed to create CreateRecordsets request: %w", err) 168 } 169 170 resp, err := d.Exec(req, nil) 171 if err != nil { 172 return fmt.Errorf("CreateRecordsets request failed: %w", err) 173 } 174 175 if resp.StatusCode != http.StatusNoContent { 176 return d.Error(resp) 177 } 178 179 return nil 180 } 181 182 func (d *dns) UpdateRecordSets(ctx context.Context, recordSets *RecordSets, zone string, recLock ...bool) error { 183 // This lock will restrict the concurrency of API calls 184 // to 1 save request at a time. This is needed for the Soa.Serial value which 185 // is required to be incremented for every subsequent update to a zone 186 // so we have to save just one request at a time to ensure this is always 187 // incremented properly 188 189 if localLock(recLock) { 190 zoneRecordSetsWriteLock.Lock() 191 defer zoneRecordSetsWriteLock.Unlock() 192 } 193 194 logger := d.Log(ctx) 195 logger.Debug("UpdateRecordsets") 196 197 if err := recordSets.Validate(); err != nil { 198 return err 199 } 200 201 reqBody, err := convertStructToReqBody(recordSets) 202 if err != nil { 203 return fmt.Errorf("failed to generate request body: %w", err) 204 } 205 206 putURL := fmt.Sprintf("/config-dns/v2/zones/%s/recordsets", zone) 207 req, err := http.NewRequestWithContext(ctx, http.MethodPut, putURL, reqBody) 208 if err != nil { 209 return fmt.Errorf("failed to create UpdateRecordsets request: %w", err) 210 } 211 212 resp, err := d.Exec(req, nil) 213 if err != nil { 214 return fmt.Errorf("UpdateRecordsets request failed: %w", err) 215 } 216 217 if resp.StatusCode != http.StatusNoContent { 218 return d.Error(resp) 219 } 220 221 return nil 222 }