github.com/akamai/AkamaiOPEN-edgegrid-golang/v4@v4.1.0/pkg/dns/zone.go (about) 1 package dns 2 3 import ( 4 "context" 5 "fmt" 6 "io" 7 "io/ioutil" 8 "net/http" 9 10 "bytes" 11 "encoding/json" 12 "reflect" 13 "strconv" 14 "strings" 15 "sync" 16 ) 17 18 var ( 19 zoneWriteLock sync.Mutex 20 ) 21 22 type ( 23 // Zones contains operations available on Zone resources. 24 Zones interface { 25 // ListZones retrieves a list of all zones user can access. 26 // 27 // See: https://techdocs.akamai.com/edge-dns/reference/get-zones 28 ListZones(context.Context, ...ZoneListQueryArgs) (*ZoneListResponse, error) 29 // NewZone returns a new ZoneCreate object. 30 NewZone(context.Context, ZoneCreate) *ZoneCreate 31 // NewZoneResponse returns a new ZoneResponse object. 32 NewZoneResponse(context.Context, string) *ZoneResponse 33 // NewChangeListResponse returns a new ChangeListResponse object. 34 NewChangeListResponse(context.Context, string) *ChangeListResponse 35 // NewZoneQueryString returns a new ZoneQueryString object. 36 NewZoneQueryString(context.Context, string, string) *ZoneQueryString 37 // GetZone retrieves Zone metadata. 38 // 39 // See: https://techdocs.akamai.com/edge-dns/reference/get-zone 40 GetZone(context.Context, string) (*ZoneResponse, error) 41 //GetChangeList retrieves Zone changelist. 42 // 43 // See: https://techdocs.akamai.com/edge-dns/reference/get-changelists-zone 44 GetChangeList(context.Context, string) (*ChangeListResponse, error) 45 // GetMasterZoneFile retrieves master zone file. 46 // 47 // See: https://techdocs.akamai.com/edge-dns/reference/get-zones-zone-zone-file 48 GetMasterZoneFile(context.Context, string) (string, error) 49 // PostMasterZoneFile updates master zone file. 50 // 51 // See: https://techdocs.akamai.com/edge-dns/reference/post-zones-zone-zone-file 52 PostMasterZoneFile(context.Context, string, string) error 53 // CreateZone creates new zone. 54 // 55 // See: https://techdocs.akamai.com/edge-dns/reference/post-zone 56 CreateZone(context.Context, *ZoneCreate, ZoneQueryString, ...bool) error 57 // SaveChangelist creates a new Change List based on the most recent version of a zone. 58 // 59 // See: https://techdocs.akamai.com/edge-dns/reference/post-changelists 60 SaveChangelist(context.Context, *ZoneCreate) error 61 // SubmitChangelist submits changelist for the Zone to create default NS SOA records. 62 // 63 // See: https://techdocs.akamai.com/edge-dns/reference/post-changelists-zone-submit 64 SubmitChangelist(context.Context, *ZoneCreate) error 65 // UpdateZone updates zone. 66 // 67 // See: https://techdocs.akamai.com/edge-dns/reference/put-zone 68 UpdateZone(context.Context, *ZoneCreate, ZoneQueryString) error 69 // DeleteZone deletes zone. 70 // 71 // See: N/A 72 DeleteZone(context.Context, *ZoneCreate, ZoneQueryString) error 73 // ValidateZone validates zone metadata based on type. 74 ValidateZone(context.Context, *ZoneCreate) error 75 // GetZoneNames retrieves a list of a zone's record names. 76 // 77 // See: https://techdocs.akamai.com/edge-dns/reference/get-zone-names 78 GetZoneNames(context.Context, string) (*ZoneNamesResponse, error) 79 // GetZoneNameTypes retrieves a zone name's record types. 80 // 81 // See: https://techdocs.akamai.com/edge-dns/reference/get-zone-name-types 82 GetZoneNameTypes(context.Context, string, string) (*ZoneNameTypesResponse, error) 83 // CreateBulkZones submits create bulk zone request. 84 // 85 // See: https://techdocs.akamai.com/edge-dns/reference/post-zones-create-requests 86 CreateBulkZones(context.Context, *BulkZonesCreate, ZoneQueryString) (*BulkZonesResponse, error) 87 // DeleteBulkZones submits delete bulk zone request. 88 // 89 // See: https://techdocs.akamai.com/edge-dns/reference/post-zones-delete-requests 90 DeleteBulkZones(context.Context, *ZoneNameListResponse, ...bool) (*BulkZonesResponse, error) 91 // GetBulkZoneCreateStatus retrieves submit request status. 92 // 93 // See: https://techdocs.akamai.com/edge-dns/reference/get-zones-create-requests-requestid 94 GetBulkZoneCreateStatus(context.Context, string) (*BulkStatusResponse, error) 95 //GetBulkZoneDeleteStatus retrieves submit request status. 96 // 97 // See: https://techdocs.akamai.com/edge-dns/reference/get-zones-delete-requests-requestid 98 GetBulkZoneDeleteStatus(context.Context, string) (*BulkStatusResponse, error) 99 // GetBulkZoneCreateResult retrieves create request result. 100 // 101 // See: https://techdocs.akamai.com/edge-dns/reference/get-zones-create-requests-requestid-result 102 GetBulkZoneCreateResult(ctx context.Context, requestid string) (*BulkCreateResultResponse, error) 103 // GetBulkZoneDeleteResult retrieves delete request result. 104 // 105 // See: https://techdocs.akamai.com/edge-dns/reference/get-zones-delete-requests-requestid-result 106 GetBulkZoneDeleteResult(context.Context, string) (*BulkDeleteResultResponse, error) 107 } 108 109 // ZoneQueryString contains zone query parameters 110 ZoneQueryString struct { 111 Contract string 112 Group string 113 } 114 115 // ZoneCreate contains zone create request 116 ZoneCreate struct { 117 Zone string `json:"zone"` 118 Type string `json:"type"` 119 Masters []string `json:"masters,omitempty"` 120 Comment string `json:"comment,omitempty"` 121 SignAndServe bool `json:"signAndServe"` 122 SignAndServeAlgorithm string `json:"signAndServeAlgorithm,omitempty"` 123 TsigKey *TSIGKey `json:"tsigKey,omitempty"` 124 Target string `json:"target,omitempty"` 125 EndCustomerID string `json:"endCustomerId,omitempty"` 126 ContractID string `json:"contractId,omitempty"` 127 } 128 129 // ZoneResponse contains zone create response 130 ZoneResponse struct { 131 Zone string `json:"zone,omitempty"` 132 Type string `json:"type,omitempty"` 133 Masters []string `json:"masters,omitempty"` 134 Comment string `json:"comment,omitempty"` 135 SignAndServe bool `json:"signAndServe"` 136 SignAndServeAlgorithm string `json:"signAndServeAlgorithm,omitempty"` 137 TsigKey *TSIGKey `json:"tsigKey,omitempty"` 138 Target string `json:"target,omitempty"` 139 EndCustomerID string `json:"endCustomerId,omitempty"` 140 ContractID string `json:"contractId,omitempty"` 141 AliasCount int64 `json:"aliasCount,omitempty"` 142 ActivationState string `json:"activationState,omitempty"` 143 LastActivationDate string `json:"lastActivationDate,omitempty"` 144 LastModifiedBy string `json:"lastModifiedBy,omitempty"` 145 LastModifiedDate string `json:"lastModifiedDate,omitempty"` 146 VersionId string `json:"versionId,omitempty"` 147 } 148 149 // ZoneListQueryArgs contains parameters for List Zones query 150 ZoneListQueryArgs struct { 151 ContractIDs string 152 Page int 153 PageSize int 154 Search string 155 ShowAll bool 156 SortBy string 157 Types string 158 } 159 160 // ListMetadata contains metadata for List Zones request 161 ListMetadata struct { 162 ContractIDs []string `json:"contractIds"` 163 Page int `json:"page"` 164 PageSize int `json:"pageSize"` 165 ShowAll bool `json:"showAll"` 166 TotalElements int `json:"totalElements"` 167 } //`json:"metadata"` 168 169 // ZoneListResponse contains response for List Zones request 170 ZoneListResponse struct { 171 Metadata *ListMetadata `json:"metadata,omitempty"` 172 Zones []*ZoneResponse `json:"zones,omitempty"` 173 } 174 175 // ChangeListResponse contains metadata about a change list 176 ChangeListResponse struct { 177 Zone string `json:"zone,omitempty"` 178 ChangeTag string `json:"changeTag,omitempty"` 179 ZoneVersionID string `json:"zoneVersionId,omitempty"` 180 LastModifiedDate string `json:"lastModifiedDate,omitempty"` 181 Stale bool `json:"stale,omitempty"` 182 } 183 184 // ZoneNameListResponse contains response with a list of zone's names and aliases 185 ZoneNameListResponse struct { 186 Zones []string `json:"zones"` 187 Aliases []string `json:"aliases,omitempty"` 188 } 189 190 // ZoneNamesResponse contains record set names for zone 191 ZoneNamesResponse struct { 192 Names []string `json:"names"` 193 } 194 195 // ZoneNameTypesResponse contains record set types for zone 196 ZoneNameTypesResponse struct { 197 Types []string `json:"types"` 198 } 199 ) 200 201 var zoneStructMap = map[string]string{ 202 "Zone": "zone", 203 "Type": "type", 204 "Masters": "masters", 205 "Comment": "comment", 206 "SignAndServe": "signAndServe", 207 "SignAndServeAlgorithm": "signAndServeAlgorithm", 208 "TsigKey": "tsigKey", 209 "Target": "target", 210 "EndCustomerID": "endCustomerId", 211 "ContractId": "contractId"} 212 213 // Util to convert struct to http request body, eg. io.reader 214 func convertStructToReqBody(srcstruct interface{}) (io.Reader, error) { 215 216 reqbody, err := json.Marshal(srcstruct) 217 if err != nil { 218 return nil, err 219 } 220 return bytes.NewBuffer(reqbody), nil 221 } 222 223 func (p *dns) ListZones(ctx context.Context, queryArgs ...ZoneListQueryArgs) (*ZoneListResponse, error) { 224 225 logger := p.Log(ctx) 226 logger.Debug("ListZones") 227 228 // construct GET url 229 getURL := fmt.Sprintf("/config-dns/v2/zones") 230 if len(queryArgs) > 1 { 231 return nil, fmt.Errorf("ListZones QueryArgs invalid") 232 } 233 234 req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) 235 if err != nil { 236 return nil, fmt.Errorf("failed to create listzones request: %w", err) 237 } 238 239 q := req.URL.Query() 240 if len(queryArgs) > 0 { 241 if queryArgs[0].Page > 0 { 242 q.Add("page", strconv.Itoa(queryArgs[0].Page)) 243 } 244 if queryArgs[0].PageSize > 0 { 245 q.Add("pageSize", strconv.Itoa(queryArgs[0].PageSize)) 246 } 247 if queryArgs[0].Search != "" { 248 q.Add("search", queryArgs[0].Search) 249 } 250 q.Add("showAll", strconv.FormatBool(queryArgs[0].ShowAll)) 251 if queryArgs[0].SortBy != "" { 252 q.Add("sortBy", queryArgs[0].SortBy) 253 } 254 if queryArgs[0].Types != "" { 255 q.Add("types", queryArgs[0].Types) 256 } 257 if queryArgs[0].ContractIDs != "" { 258 q.Add("contractIds", queryArgs[0].ContractIDs) 259 } 260 req.URL.RawQuery = q.Encode() 261 } 262 263 var zonelist ZoneListResponse 264 resp, err := p.Exec(req, &zonelist) 265 if err != nil { 266 return nil, fmt.Errorf("listzones request failed: %w", err) 267 } 268 269 if resp.StatusCode != http.StatusOK { 270 return nil, p.Error(resp) 271 } 272 273 return &zonelist, nil 274 } 275 276 func (p *dns) NewZone(ctx context.Context, params ZoneCreate) *ZoneCreate { 277 278 logger := p.Log(ctx) 279 logger.Debug("NewZone") 280 281 zone := &ZoneCreate{Zone: params.Zone, 282 Type: params.Type, 283 Masters: params.Masters, 284 TsigKey: params.TsigKey, 285 Target: params.Target, 286 EndCustomerID: params.EndCustomerID, 287 ContractID: params.ContractID, 288 Comment: params.Comment, 289 SignAndServe: params.SignAndServe, 290 SignAndServeAlgorithm: params.SignAndServeAlgorithm} 291 292 logger.Debugf("Created zone: %v", zone) 293 return zone 294 } 295 296 func (p *dns) NewZoneResponse(ctx context.Context, zonename string) *ZoneResponse { 297 298 logger := p.Log(ctx) 299 logger.Debug("NewZoneResponse") 300 301 zone := &ZoneResponse{Zone: zonename} 302 return zone 303 } 304 305 func (p *dns) NewChangeListResponse(ctx context.Context, zone string) *ChangeListResponse { 306 307 logger := p.Log(ctx) 308 logger.Debug("NewChangeListResponse") 309 310 changelist := &ChangeListResponse{Zone: zone} 311 return changelist 312 } 313 314 func (p *dns) NewZoneQueryString(ctx context.Context, contract string, group string) *ZoneQueryString { 315 316 logger := p.Log(ctx) 317 logger.Debug("NewZoneQueryString") 318 319 zonequerystring := &ZoneQueryString{Contract: contract, Group: group} 320 return zonequerystring 321 } 322 323 func (p *dns) GetZone(ctx context.Context, zonename string) (*ZoneResponse, error) { 324 325 logger := p.Log(ctx) 326 logger.Debug("GetZone") 327 328 var zone ZoneResponse 329 330 getURL := fmt.Sprintf("/config-dns/v2/zones/%s", zonename) 331 req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) 332 if err != nil { 333 return nil, fmt.Errorf("failed to create GetZone request: %w", err) 334 } 335 336 resp, err := p.Exec(req, &zone) 337 if err != nil { 338 return nil, fmt.Errorf("GetZone request failed: %w", err) 339 } 340 341 if resp.StatusCode != http.StatusOK { 342 return nil, p.Error(resp) 343 } 344 345 return &zone, nil 346 } 347 348 func (p *dns) GetChangeList(ctx context.Context, zone string) (*ChangeListResponse, error) { 349 350 logger := p.Log(ctx) 351 logger.Debug("GetChangeList") 352 353 var changelist ChangeListResponse 354 getURL := fmt.Sprintf("/config-dns/v2/changelists/%s", zone) 355 req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) 356 if err != nil { 357 return nil, fmt.Errorf("failed to create GetChangeList request: %w", err) 358 } 359 360 resp, err := p.Exec(req, &changelist) 361 if err != nil { 362 return nil, fmt.Errorf("GetChangeList request failed: %w", err) 363 } 364 365 if resp.StatusCode != http.StatusOK { 366 return nil, p.Error(resp) 367 } 368 369 return &changelist, nil 370 } 371 372 func (p *dns) GetMasterZoneFile(ctx context.Context, zone string) (string, error) { 373 374 logger := p.Log(ctx) 375 logger.Debug("GetMasterZoneFile") 376 377 getURL := fmt.Sprintf("/config-dns/v2/zones/%s/zone-file", zone) 378 req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) 379 if err != nil { 380 return "", fmt.Errorf("failed to create GetMasterZoneFile request: %w", err) 381 } 382 req.Header.Add("Accept", "text/dns") 383 384 resp, err := p.Exec(req, nil) 385 if err != nil { 386 return "", fmt.Errorf("GetMasterZoneFile request failed: %w", err) 387 } 388 389 if resp.StatusCode != http.StatusOK { 390 return "", p.Error(resp) 391 } 392 393 masterfile, err := ioutil.ReadAll(resp.Body) 394 if err != nil { 395 return "", fmt.Errorf("GetMasterZoneFile request failed: %w", err) 396 } 397 398 return string(masterfile), nil 399 } 400 401 func (p *dns) PostMasterZoneFile(ctx context.Context, zone string, filedata string) error { 402 403 logger := p.Log(ctx) 404 logger.Debug("PostMasterZoneFile") 405 406 mtresp := "" 407 pmzfURL := fmt.Sprintf("/config-dns/v2/zones/%s/zone-file", zone) 408 buf := bytes.NewReader([]byte(filedata)) 409 req, err := http.NewRequestWithContext(ctx, http.MethodPost, pmzfURL, buf) 410 if err != nil { 411 return fmt.Errorf("failed to create PostMasterZoneFile request: %w", err) 412 } 413 414 req.Header.Set("Content-Type", "text/dns") 415 416 resp, err := p.Exec(req, &mtresp) 417 if err != nil { 418 return fmt.Errorf("Create PostMasterZoneFile failed: %w", err) 419 } 420 421 if resp.StatusCode != http.StatusNoContent { 422 return p.Error(resp) 423 } 424 425 return nil 426 } 427 428 func (p *dns) CreateZone(ctx context.Context, zone *ZoneCreate, zonequerystring ZoneQueryString, clearConn ...bool) error { 429 // This lock will restrict the concurrency of API calls 430 // to 1 save request at a time. This is needed for the Soa.Serial value which 431 // is required to be incremented for every subsequent update to a zone 432 // so we have to save just one request at a time to ensure this is always 433 // incremented properly 434 435 zoneWriteLock.Lock() 436 defer zoneWriteLock.Unlock() 437 438 logger := p.Log(ctx) 439 logger.Debug("Zone Create") 440 441 if err := p.ValidateZone(ctx, zone); err != nil { 442 return err 443 } 444 445 zoneMap := filterZoneCreate(zone) 446 447 var zoneresponse ZoneResponse 448 zoneURL := "/config-dns/v2/zones/?contractId=" + zonequerystring.Contract 449 if len(zonequerystring.Group) > 0 { 450 zoneURL += "&gid=" + zonequerystring.Group 451 } 452 453 reqbody, err := convertStructToReqBody(zoneMap) 454 if err != nil { 455 return fmt.Errorf("failed to generate request body: %w", err) 456 } 457 458 req, err := http.NewRequestWithContext(ctx, http.MethodPost, zoneURL, reqbody) 459 if err != nil { 460 return fmt.Errorf("failed to create Zone Create request: %w", err) 461 } 462 463 resp, err := p.Exec(req, &zoneresponse) 464 if err != nil { 465 return fmt.Errorf("Create Zone request failed: %w", err) 466 } 467 468 if resp.StatusCode != http.StatusCreated { 469 return p.Error(resp) 470 } 471 472 if strings.ToUpper(zone.Type) == "PRIMARY" { 473 // Timing issue with Create immediately followed by SaveChangelist 474 for _, clear := range clearConn { 475 // should only be one entry 476 if clear { 477 logger.Info("Clearing Idle Connections") 478 p.Client().CloseIdleConnections() 479 } 480 } 481 } 482 483 return nil 484 } 485 486 func (p *dns) SaveChangelist(ctx context.Context, zone *ZoneCreate) error { 487 // This lock will restrict the concurrency of API calls 488 // to 1 save request at a time. This is needed for the Soa.Serial value which 489 // is required to be incremented for every subsequent update to a zone 490 // so we have to save just one request at a time to ensure this is always 491 // incremented properly 492 493 zoneWriteLock.Lock() 494 defer zoneWriteLock.Unlock() 495 496 logger := p.Log(ctx) 497 logger.Debug("SaveChangeList") 498 499 reqbody, err := convertStructToReqBody("") 500 if err != nil { 501 return fmt.Errorf("failed to generate request body: %w", err) 502 } 503 504 postURL := fmt.Sprintf("/config-dns/v2/changelists/?zone=%s", zone.Zone) 505 req, err := http.NewRequestWithContext(ctx, http.MethodPost, postURL, reqbody) 506 if err != nil { 507 return fmt.Errorf("failed to create SaveChangeList request: %w", err) 508 } 509 510 resp, err := p.Exec(req, nil) 511 if err != nil { 512 return fmt.Errorf("SaveChangeList request failed: %w", err) 513 } 514 515 if resp.StatusCode != http.StatusCreated { 516 return p.Error(resp) 517 } 518 519 return nil 520 } 521 522 func (p *dns) SubmitChangelist(ctx context.Context, zone *ZoneCreate) error { 523 // This lock will restrict the concurrency of API calls 524 // to 1 save request at a time. This is needed for the Soa.Serial value which 525 // is required to be incremented for every subsequent update to a zone 526 // so we have to save just one request at a time to ensure this is always 527 // incremented properly 528 529 zoneWriteLock.Lock() 530 defer zoneWriteLock.Unlock() 531 532 logger := p.Log(ctx) 533 logger.Debug("SubmitChangeList") 534 535 reqbody, err := convertStructToReqBody("") 536 if err != nil { 537 return fmt.Errorf("failed to generate request body: %w", err) 538 } 539 540 postURL := fmt.Sprintf("/config-dns/v2/changelists/%s/submit", zone.Zone) 541 req, err := http.NewRequestWithContext(ctx, http.MethodPost, postURL, reqbody) 542 if err != nil { 543 return fmt.Errorf("failed to create SubmitChangeList request: %w", err) 544 } 545 546 resp, err := p.Exec(req, nil) 547 if err != nil { 548 return fmt.Errorf("SubmitChangeList request failed: %w", err) 549 } 550 551 if resp.StatusCode != http.StatusNoContent { 552 return p.Error(resp) 553 } 554 555 return nil 556 } 557 558 func (p *dns) UpdateZone(ctx context.Context, zone *ZoneCreate, _ ZoneQueryString) error { 559 // This lock will restrict the concurrency of API calls 560 // to 1 save request at a time. This is needed for the Soa.Serial value which 561 // is required to be incremented for every subsequent update to a zone 562 // so we have to save just one request at a time to ensure this is always 563 // incremented properly 564 565 zoneWriteLock.Lock() 566 defer zoneWriteLock.Unlock() 567 568 logger := p.Log(ctx) 569 logger.Debug("Zone Update") 570 571 if err := p.ValidateZone(ctx, zone); err != nil { 572 return err 573 } 574 575 zoneMap := filterZoneCreate(zone) 576 reqbody, err := convertStructToReqBody(zoneMap) 577 if err != nil { 578 return fmt.Errorf("failed to generate request body: %w", err) 579 } 580 581 putURL := fmt.Sprintf("/config-dns/v2/zones/%s", zone.Zone) 582 req, err := http.NewRequestWithContext(ctx, http.MethodPut, putURL, reqbody) 583 if err != nil { 584 return fmt.Errorf("failed to create Get Update request: %w", err) 585 } 586 587 var zoneresp ZoneResponse 588 resp, err := p.Exec(req, &zoneresp) 589 if err != nil { 590 return fmt.Errorf("Zone Update request failed: %w", err) 591 } 592 593 if resp.StatusCode != http.StatusOK { 594 return p.Error(resp) 595 } 596 597 return nil 598 599 } 600 601 func (p *dns) DeleteZone(ctx context.Context, zone *ZoneCreate, _ ZoneQueryString) error { 602 // remove all the records except for SOA 603 // which is required and save the zone 604 605 zoneWriteLock.Lock() 606 defer zoneWriteLock.Unlock() 607 608 logger := p.Log(ctx) 609 logger.Debug("Zone Delete") 610 611 if zone.Zone == "" { 612 return fmt.Errorf("Zone name missing") 613 } 614 615 deleteURL := fmt.Sprintf("/config-dns/v2/zones/%s", zone.Zone) 616 req, err := http.NewRequestWithContext(ctx, http.MethodDelete, deleteURL, nil) 617 if err != nil { 618 return fmt.Errorf("failed to create Zone Delete request: %w", err) 619 } 620 621 resp, err := p.Exec(req, nil) 622 if err != nil { 623 return fmt.Errorf("Zone Delete request failed: %w", err) 624 } 625 626 if resp.StatusCode == http.StatusNotFound { 627 return nil 628 } 629 630 if resp.StatusCode != http.StatusNoContent { 631 return p.Error(resp) 632 } 633 634 return nil 635 636 } 637 638 func filterZoneCreate(zone *ZoneCreate) map[string]interface{} { 639 640 zoneType := strings.ToUpper(zone.Type) 641 filteredZone := make(map[string]interface{}) 642 zoneElems := reflect.ValueOf(zone).Elem() 643 for i := 0; i < zoneElems.NumField(); i++ { 644 varName := zoneElems.Type().Field(i).Name 645 varLower := zoneStructMap[varName] 646 varValue := zoneElems.Field(i).Interface() 647 switch varName { 648 case "Target": 649 if zoneType == "ALIAS" { 650 filteredZone[varLower] = varValue 651 } 652 case "TsigKey": 653 if zoneType == "SECONDARY" { 654 filteredZone[varLower] = varValue 655 } 656 case "Masters": 657 if zoneType == "SECONDARY" { 658 filteredZone[varLower] = varValue 659 } 660 case "SignAndServe": 661 if zoneType != "ALIAS" { 662 filteredZone[varLower] = varValue 663 } 664 case "SignAndServeAlgorithm": 665 if zoneType != "ALIAS" { 666 filteredZone[varLower] = varValue 667 } 668 default: 669 filteredZone[varLower] = varValue 670 } 671 } 672 673 return filteredZone 674 } 675 676 // ValidateZone validates ZoneCreate Object 677 func (p *dns) ValidateZone(ctx context.Context, zone *ZoneCreate) error { 678 679 logger := p.Log(ctx) 680 logger.Debug("ValidateZone") 681 682 if len(zone.Zone) == 0 { 683 return fmt.Errorf("Zone name is required") 684 } 685 ztype := strings.ToUpper(zone.Type) 686 if ztype != "PRIMARY" && ztype != "SECONDARY" && ztype != "ALIAS" { 687 return fmt.Errorf("Invalid zone type") 688 } 689 if ztype != "SECONDARY" && zone.TsigKey != nil { 690 return fmt.Errorf("TsigKey is invalid for %s zone type", ztype) 691 } 692 if ztype == "ALIAS" { 693 if len(zone.Target) == 0 { 694 return fmt.Errorf("Target is required for Alias zone type") 695 } 696 if zone.Masters != nil && len(zone.Masters) > 0 { 697 return fmt.Errorf("Masters is invalid for Alias zone type") 698 } 699 if zone.SignAndServe { 700 return fmt.Errorf("SignAndServe is invalid for Alias zone type") 701 } 702 if len(zone.SignAndServeAlgorithm) > 0 { 703 return fmt.Errorf("SignAndServeAlgorithm is invalid for Alias zone type") 704 } 705 return nil 706 } 707 // Primary or Secondary 708 if len(zone.Target) > 0 { 709 return fmt.Errorf("Target is invalid for %s zone type", ztype) 710 } 711 if zone.Masters != nil && len(zone.Masters) > 0 && ztype == "PRIMARY" { 712 return fmt.Errorf("Masters is invalid for Primary zone type") 713 } 714 715 return nil 716 } 717 718 func (p *dns) GetZoneNames(ctx context.Context, zone string) (*ZoneNamesResponse, error) { 719 720 logger := p.Log(ctx) 721 logger.Debug("GetZoneNames") 722 723 var znresponse ZoneNamesResponse 724 getURL := fmt.Sprintf("/config-dns/v2/zones/%s/names", zone) 725 req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) 726 if err != nil { 727 return nil, fmt.Errorf("failed to create GetZoneNames request: %w", err) 728 } 729 730 resp, err := p.Exec(req, &znresponse) 731 if err != nil { 732 return nil, fmt.Errorf("GetZoneNames request failed: %w", err) 733 } 734 735 if resp.StatusCode != http.StatusOK { 736 return nil, p.Error(resp) 737 } 738 739 return &znresponse, nil 740 } 741 742 func (p *dns) GetZoneNameTypes(ctx context.Context, zname string, zone string) (*ZoneNameTypesResponse, error) { 743 744 logger := p.Log(ctx) 745 logger.Debug(" GetZoneNameTypes") 746 747 var zntypes ZoneNameTypesResponse 748 getURL := fmt.Sprintf("/config-dns/v2/zones/%s/names/%s/types", zone, zname) 749 req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil) 750 if err != nil { 751 return nil, fmt.Errorf("failed to create GetZoneNameTypes request: %w", err) 752 } 753 754 resp, err := p.Exec(req, &zntypes) 755 if err != nil { 756 return nil, fmt.Errorf("GetZoneNameTypes request failed: %w", err) 757 } 758 759 if resp.StatusCode != http.StatusOK { 760 return nil, p.Error(resp) 761 } 762 763 return &zntypes, nil 764 }