mirror of
				https://github.com/StackExchange/dnscontrol.git
				synced 2024-05-11 05:55:12 +00:00 
			
		
		
		
	HETZNER: handle a 404 from listing zones gracefully (#1371)
The API docs do not mention this, but we saw a case in the wild (1370). Signed-off-by: Jakob Ackermann <das7pad@outlook.com>
This commit is contained in:
		@@ -78,7 +78,7 @@ func (api *hetznerProvider) bulkCreateRecords(records []record) error {
 | 
			
		||||
	request := bulkCreateRecordsRequest{
 | 
			
		||||
		Records: records,
 | 
			
		||||
	}
 | 
			
		||||
	return api.request("/records/bulk", "POST", request, nil)
 | 
			
		||||
	return api.request("/records/bulk", "POST", request, nil, nil)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (api *hetznerProvider) bulkUpdateRecords(records []record) error {
 | 
			
		||||
@@ -91,7 +91,7 @@ func (api *hetznerProvider) bulkUpdateRecords(records []record) error {
 | 
			
		||||
	request := bulkUpdateRecordsRequest{
 | 
			
		||||
		Records: records,
 | 
			
		||||
	}
 | 
			
		||||
	return api.request("/records/bulk", "PUT", request, nil)
 | 
			
		||||
	return api.request("/records/bulk", "PUT", request, nil, nil)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (api *hetznerProvider) createRecord(record record) error {
 | 
			
		||||
@@ -106,14 +106,14 @@ func (api *hetznerProvider) createRecord(record record) error {
 | 
			
		||||
		Value:  record.Value,
 | 
			
		||||
		ZoneID: record.ZoneID,
 | 
			
		||||
	}
 | 
			
		||||
	return api.request("/records", "POST", request, nil)
 | 
			
		||||
	return api.request("/records", "POST", request, nil, nil)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (api *hetznerProvider) createZone(name string) error {
 | 
			
		||||
	request := createZoneRequest{
 | 
			
		||||
		Name: name,
 | 
			
		||||
	}
 | 
			
		||||
	return api.request("/zones", "POST", request, nil)
 | 
			
		||||
	return api.request("/zones", "POST", request, nil, nil)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (api *hetznerProvider) deleteRecord(record record) error {
 | 
			
		||||
@@ -122,7 +122,7 @@ func (api *hetznerProvider) deleteRecord(record record) error {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	url := fmt.Sprintf("/records/%s", record.ID)
 | 
			
		||||
	return api.request(url, "DELETE", nil, nil)
 | 
			
		||||
	return api.request(url, "DELETE", nil, nil, nil)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (api *hetznerProvider) getAllRecords(domain string) ([]record, error) {
 | 
			
		||||
@@ -135,7 +135,7 @@ func (api *hetznerProvider) getAllRecords(domain string) ([]record, error) {
 | 
			
		||||
	for {
 | 
			
		||||
		response := &getAllRecordsResponse{}
 | 
			
		||||
		url := fmt.Sprintf("/records?zone_id=%s&per_page=100&page=%d", zone.ID, page)
 | 
			
		||||
		if err := api.request(url, "GET", nil, response); err != nil {
 | 
			
		||||
		if err := api.request(url, "GET", nil, response, nil); err != nil {
 | 
			
		||||
			return nil, fmt.Errorf("failed fetching zone records for %q: %w", domain, err)
 | 
			
		||||
		}
 | 
			
		||||
		for _, record := range response.Records {
 | 
			
		||||
@@ -165,10 +165,21 @@ func (api *hetznerProvider) getAllZones() error {
 | 
			
		||||
	}
 | 
			
		||||
	zones := map[string]zone{}
 | 
			
		||||
	page := 1
 | 
			
		||||
	statusOK := func(code int) bool {
 | 
			
		||||
		switch code {
 | 
			
		||||
		case http.StatusOK:
 | 
			
		||||
			return true
 | 
			
		||||
		case http.StatusNotFound:
 | 
			
		||||
			// Accept a 404 when requesting the first page
 | 
			
		||||
			return page == 1
 | 
			
		||||
		default:
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for {
 | 
			
		||||
		response := &getAllZonesResponse{}
 | 
			
		||||
		url := fmt.Sprintf("/zones?per_page=100&page=%d", page)
 | 
			
		||||
		if err := api.request(url, "GET", nil, response); err != nil {
 | 
			
		||||
		if err := api.request(url, "GET", nil, response, statusOK); err != nil {
 | 
			
		||||
			return fmt.Errorf("failed fetching zones: %w", err)
 | 
			
		||||
		}
 | 
			
		||||
		for _, zone := range response.Zones {
 | 
			
		||||
@@ -195,7 +206,12 @@ func (api *hetznerProvider) getZone(name string) (*zone, error) {
 | 
			
		||||
	return &zone, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (api *hetznerProvider) request(endpoint string, method string, request interface{}, target interface{}) error {
 | 
			
		||||
func (api *hetznerProvider) request(endpoint string, method string, request interface{}, target interface{}, statusOK func(code int) bool) error {
 | 
			
		||||
	if statusOK == nil {
 | 
			
		||||
		statusOK = func(code int) bool {
 | 
			
		||||
			return code == http.StatusOK
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for {
 | 
			
		||||
		var requestBody io.Reader
 | 
			
		||||
		if request != nil {
 | 
			
		||||
@@ -233,7 +249,7 @@ func (api *hetznerProvider) request(endpoint string, method string, request inte
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		defer cleanupResponseBody()
 | 
			
		||||
		if resp.StatusCode != 200 {
 | 
			
		||||
		if !statusOK(resp.StatusCode) {
 | 
			
		||||
			data, _ := ioutil.ReadAll(resp.Body)
 | 
			
		||||
			fmt.Println(string(data))
 | 
			
		||||
			return fmt.Errorf("bad status code from HETZNER: %d not 200", resp.StatusCode)
 | 
			
		||||
@@ -261,7 +277,7 @@ func (api *hetznerProvider) updateRecord(record record) error {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	url := fmt.Sprintf("/records/%s", record.ID)
 | 
			
		||||
	return api.request(url, "PUT", record, nil)
 | 
			
		||||
	return api.request(url, "PUT", record, nil, nil)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type requestRateLimiter struct {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user