github.com/akamai/AkamaiOPEN-edgegrid-golang/v8@v8.1.0/pkg/dns/tsig.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 "reflect" 11 "strings" 12 ) 13 14 type ( 15 // TSIGKeys contains operations available on TSIKeyG resource. 16 TSIGKeys interface { 17 // ListTSIGKeys lists the TSIG keys used by zones that you are allowed to manage. 18 // 19 // See: https://techdocs.akamai.com/edge-dns/reference/get-keys 20 ListTSIGKeys(context.Context, *TSIGQueryString) (*TSIGReportResponse, error) 21 // GetTSIGKeyZones retrieves DNS Zones using TSIG key. 22 // 23 // See: https://techdocs.akamai.com/edge-dns/reference/post-keys-used-by 24 GetTSIGKeyZones(context.Context, *TSIGKey) (*ZoneNameListResponse, error) 25 // GetTSIGKeyAliases retrieves a DNS Zone's aliases. 26 // 27 // See: https://techdocs.akamai.com/edge-dns/reference/get-zones-zone-key-used-by 28 GetTSIGKeyAliases(context.Context, string) (*ZoneNameListResponse, error) 29 // TSIGKeyBulkUpdate updates Bulk Zones TSIG key. 30 // 31 // See: https://techdocs.akamai.com/edge-dns/reference/post-keys-bulk-update 32 TSIGKeyBulkUpdate(context.Context, *TSIGKeyBulkPost) error 33 // GetTSIGKey retrieves a TSIG key for zone. 34 // 35 // See: https://techdocs.akamai.com/edge-dns/reference/get-zones-zone-key 36 GetTSIGKey(context.Context, string) (*TSIGKeyResponse, error) 37 // DeleteTSIGKey deletes TSIG key for zone. 38 // 39 // See: https://techdocs.akamai.com/edge-dns/reference/delete-zones-zone-key 40 DeleteTSIGKey(context.Context, string) error 41 // UpdateTSIGKey updates TSIG key for zone. 42 // 43 // See: https://techdocs.akamai.com/edge-dns/reference/put-zones-zone-key 44 UpdateTSIGKey(context.Context, *TSIGKey, string) error 45 } 46 47 // TSIGQueryString contains TSIG query parameters 48 TSIGQueryString struct { 49 ContractIDs []string `json:"contractIds,omitempty"` 50 Search string `json:"search,omitempty"` 51 SortBy []string `json:"sortBy,omitempty"` 52 GID int64 `json:"gid,omitempty"` 53 } 54 55 // TSIGKey contains TSIG key POST response 56 TSIGKey struct { 57 Name string `json:"name"` 58 Algorithm string `json:"algorithm,omitempty"` 59 Secret string `json:"secret,omitempty"` 60 } 61 // TSIGKeyResponse contains TSIG key GET response 62 TSIGKeyResponse struct { 63 TSIGKey 64 ZoneCount int64 `json:"zonesCount,omitempty"` 65 } 66 67 // TSIGKeyBulkPost contains TSIG key and a list of names of zones that should use the key. Used with update function. 68 TSIGKeyBulkPost struct { 69 Key *TSIGKey `json:"key"` 70 Zones []string `json:"zones"` 71 } 72 73 // TSIGZoneAliases contains list of zone aliases 74 TSIGZoneAliases struct { 75 Aliases []string `json:"aliases"` 76 } 77 78 // TSIGReportMeta contains metadata for TSIGReport response 79 TSIGReportMeta struct { 80 TotalElements int64 `json:"totalElements"` 81 Search string `json:"search,omitempty"` 82 Contracts []string `json:"contracts,omitempty"` 83 GID int64 `json:"gid,omitempty"` 84 SortBy []string `json:"sortBy,omitempty"` 85 } 86 87 // TSIGReportResponse contains response with a list of the TSIG keys used by zones. 88 TSIGReportResponse struct { 89 Metadata *TSIGReportMeta `json:"metadata"` 90 Keys []*TSIGKeyResponse `json:"keys,omitempty"` 91 } 92 ) 93 94 // Validate validates TSIGKey 95 func (key *TSIGKey) Validate() error { 96 return validation.Errors{ 97 "Name": validation.Validate(key.Name, validation.Required), 98 "Algorithm": validation.Validate(key.Algorithm, validation.Required), 99 "Secret": validation.Validate(key.Secret, validation.Required), 100 }.Filter() 101 } 102 103 // Validate validates TSIGKeyBulkPost 104 func (bulk *TSIGKeyBulkPost) Validate() error { 105 return validation.Errors{ 106 "Key": validation.Validate(bulk.Key, validation.Required), 107 "Zones": validation.Validate(bulk.Zones, validation.Required), 108 }.Filter() 109 } 110 111 func constructTSIGQueryString(tsigQueryString *TSIGQueryString) string { 112 queryString := "" 113 qsElems := reflect.ValueOf(tsigQueryString).Elem() 114 for i := 0; i < qsElems.NumField(); i++ { 115 varName := qsElems.Type().Field(i).Name 116 varValue := qsElems.Field(i).Interface() 117 keyVal := fmt.Sprint(varValue) 118 switch varName { 119 case "ContractIDs": 120 contractList := "" 121 for j, id := range varValue.([]string) { 122 contractList += id 123 if j < len(varValue.([]string))-1 { 124 contractList += "%2C" 125 } 126 } 127 if len(varValue.([]string)) > 0 { 128 queryString += "contractIds=" + contractList 129 } 130 case "SortBy": 131 sortByList := "" 132 for j, sb := range varValue.([]string) { 133 sortByList += sb 134 if j < len(varValue.([]string))-1 { 135 sortByList += "%2C" 136 } 137 } 138 if len(varValue.([]string)) > 0 { 139 queryString += "sortBy=" + sortByList 140 } 141 case "Search": 142 if keyVal != "" { 143 queryString += "search=" + keyVal 144 } 145 case "GID": 146 if varValue.(int64) != 0 { 147 queryString += "gid=" + keyVal 148 } 149 } 150 if i < qsElems.NumField()-1 { 151 queryString += "&" 152 } 153 } 154 queryString = strings.TrimRight(queryString, "&") 155 if len(queryString) > 0 { 156 return "?" + queryString 157 } 158 return "" 159 } 160 161 func (d *dns) ListTSIGKeys(ctx context.Context, tsigQueryString *TSIGQueryString) (*TSIGReportResponse, error) { 162 logger := d.Log(ctx) 163 logger.Debug("ListTSIGKeys") 164 165 getURL := fmt.Sprintf("/config-dns/v2/keys%s", constructTSIGQueryString(tsigQueryString)) 166 req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) 167 if err != nil { 168 return nil, fmt.Errorf("failed to create ListTsigKeyss request: %w", err) 169 } 170 171 var result TSIGReportResponse 172 resp, err := d.Exec(req, &result) 173 if err != nil { 174 return nil, fmt.Errorf(" ListTsigKeys request failed: %w", err) 175 } 176 177 if resp.StatusCode != http.StatusOK { 178 return nil, d.Error(resp) 179 } 180 181 return &result, nil 182 } 183 184 func (d *dns) GetTSIGKeyZones(ctx context.Context, tsigKey *TSIGKey) (*ZoneNameListResponse, error) { 185 logger := d.Log(ctx) 186 logger.Debug("GetTSIGKeyZones") 187 188 if err := tsigKey.Validate(); err != nil { 189 return nil, err 190 } 191 192 reqBody, err := convertStructToReqBody(tsigKey) 193 if err != nil { 194 return nil, fmt.Errorf("failed to generate request body: %w", err) 195 } 196 197 postURL := "/config-dns/v2/keys/used-by" 198 req, err := http.NewRequestWithContext(ctx, http.MethodPost, postURL, reqBody) 199 if err != nil { 200 return nil, fmt.Errorf("failed to create GetTsigKeyZones request: %w", err) 201 } 202 203 var result ZoneNameListResponse 204 resp, err := d.Exec(req, &result) 205 if err != nil { 206 return nil, fmt.Errorf("GetTsigKeyZones request failed: %w", err) 207 } 208 209 if resp.StatusCode != http.StatusOK { 210 return nil, d.Error(resp) 211 } 212 213 return &result, nil 214 } 215 216 func (d *dns) GetTSIGKeyAliases(ctx context.Context, zone string) (*ZoneNameListResponse, error) { 217 logger := d.Log(ctx) 218 logger.Debug("GetTSIGKeyAliases") 219 220 getURL := fmt.Sprintf("/config-dns/v2/zones/%s/key/used-by", zone) 221 req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) 222 if err != nil { 223 return nil, fmt.Errorf("failed to create GetTsigKeyAliases request: %w", err) 224 } 225 226 var result ZoneNameListResponse 227 resp, err := d.Exec(req, &result) 228 if err != nil { 229 return nil, fmt.Errorf("GetTsigKeyAliases request failed: %w", err) 230 } 231 232 if resp.StatusCode != http.StatusOK { 233 return nil, d.Error(resp) 234 } 235 236 return &result, nil 237 } 238 239 func (d *dns) TSIGKeyBulkUpdate(ctx context.Context, tsigBulk *TSIGKeyBulkPost) error { 240 logger := d.Log(ctx) 241 logger.Debug("TSIGKeyBulkUpdate") 242 243 if err := tsigBulk.Validate(); err != nil { 244 return err 245 } 246 247 reqBody, err := convertStructToReqBody(tsigBulk) 248 if err != nil { 249 return fmt.Errorf("failed to generate request body: %w", err) 250 } 251 252 postURL := "/config-dns/v2/keys/bulk-update" 253 req, err := http.NewRequestWithContext(ctx, http.MethodPost, postURL, reqBody) 254 if err != nil { 255 return fmt.Errorf("failed to create TsigKeyBulkUpdate request: %w", err) 256 } 257 258 resp, err := d.Exec(req, nil) 259 if err != nil { 260 return fmt.Errorf("TsigKeyBulkUpdate request failed: %w", err) 261 } 262 263 if resp.StatusCode != http.StatusNoContent { 264 return d.Error(resp) 265 } 266 267 return nil 268 } 269 270 func (d *dns) GetTSIGKey(ctx context.Context, zone string) (*TSIGKeyResponse, error) { 271 logger := d.Log(ctx) 272 logger.Debug("GetTSIGKey") 273 274 getURL := fmt.Sprintf("/config-dns/v2/zones/%s/key", zone) 275 req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) 276 if err != nil { 277 return nil, fmt.Errorf("failed to create GetTsigKey request: %w", err) 278 } 279 280 var result TSIGKeyResponse 281 resp, err := d.Exec(req, &result) 282 if err != nil { 283 return nil, fmt.Errorf("GetTsigKey request failed: %w", err) 284 } 285 286 if resp.StatusCode != http.StatusOK { 287 return nil, d.Error(resp) 288 } 289 290 return &result, nil 291 } 292 293 func (d *dns) DeleteTSIGKey(ctx context.Context, zone string) error { 294 logger := d.Log(ctx) 295 logger.Debug("DeleteTSIGKey") 296 297 delURL := fmt.Sprintf("/config-dns/v2/zones/%s/key", zone) 298 req, err := http.NewRequestWithContext(ctx, http.MethodDelete, delURL, nil) 299 if err != nil { 300 return fmt.Errorf("failed to create DeleteTsigKey request: %w", err) 301 } 302 303 resp, err := d.Exec(req, nil) 304 if err != nil { 305 return fmt.Errorf("DeleteTsigKey request failed: %w", err) 306 } 307 308 if resp.StatusCode != http.StatusNoContent { 309 return d.Error(resp) 310 } 311 312 return nil 313 } 314 315 func (d *dns) UpdateTSIGKey(ctx context.Context, tsigKey *TSIGKey, zone string) error { 316 logger := d.Log(ctx) 317 logger.Debug("UpdateTSIGKey") 318 319 if err := tsigKey.Validate(); err != nil { 320 return err 321 } 322 323 reqBody, err := convertStructToReqBody(tsigKey) 324 if err != nil { 325 return fmt.Errorf("failed to generate request body: %w", err) 326 } 327 328 putURL := fmt.Sprintf("/config-dns/v2/zones/%s/key", zone) 329 req, err := http.NewRequestWithContext(ctx, http.MethodPut, putURL, reqBody) 330 if err != nil { 331 return fmt.Errorf("failed to create UpdateTsigKey request: %w", err) 332 } 333 334 resp, err := d.Exec(req, nil) 335 if err != nil { 336 return fmt.Errorf("UpdateTsigKey request failed: %w", err) 337 } 338 339 if resp.StatusCode != http.StatusNoContent { 340 return d.Error(resp) 341 } 342 343 return nil 344 }