diff --git a/go.mod b/go.mod index 66def3213e37c475bb9967f3b12a3ba8e3573895..c215a3ec313d0f5440d707709baeb136bb44a78a 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,5 @@ module git.fsmpi.rwth-aachen.de/thomas/go-rwthdns go 1.18 + +require github.com/go-logr/logr v1.2.3 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000000000000000000000000000000000000..6da913857d049bc485b993e3e1e862acb2da182a --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= diff --git a/rwthdns.go b/rwthdns.go index 4c9af7ac47e33744f679aeaa673ea3d46ad1fbfb..ea632338bccd99b788751328a14a71bc795ebb92 100644 --- a/rwthdns.go +++ b/rwthdns.go @@ -8,6 +8,8 @@ import ( "net/url" "strings" "time" + + "github.com/go-logr/logr" ) const ApiBase = "https://noc-portal.rz.rwth-aachen.de/dns-admin/api/v1/" @@ -76,16 +78,29 @@ type Record struct { type Client struct { ApiToken string Client *http.Client + Log *logr.Logger +} + +func (c *Client) log() logr.Logger { + if c.Log != nil { + return c.Log.WithName("rwthdns") + } + return logr.Discard() } func (c *Client) do(method string, endpoint string, params url.Values) (*http.Response, error) { + logger := c.log().WithValues("function", "do") if c.Client == nil { c.Client = http.DefaultClient } + logger.V(6).Info("arguments", "method", method, "endpoint", endpoint, "params", params) + r, err := http.NewRequest(method, ApiBase+endpoint, strings.NewReader(params.Encode())) if err != nil { + logger.Error(err, "NewRequest", "method", method, "url", ApiBase+endpoint, + "params", params.Encode()) return nil, err } r.Header.Set("Content-Type", "application/x-www-form-urlencoded") @@ -96,6 +111,8 @@ func (c *Client) do(method string, endpoint string, params url.Values) (*http.Re } func (c *Client) ListZones(search *string) ([]Zone, error) { + logger := c.log().WithValues("function", "ListZones") + logger.V(6).Info("arguments", "search", search) q := url.Values{} if search != nil { q.Set("search", *search) @@ -103,16 +120,32 @@ func (c *Client) ListZones(search *string) ([]Zone, error) { res, err := c.do("GET", "list_zones", q) if err != nil { + logger.Error(err, "(*Client).do()", + "method", "GET", "endpoint", "list_zones", "params", q) return nil, err } - dec := json.NewDecoder(res.Body) + b, err := io.ReadAll(res.Body) + if err != nil { + logger.Error(err, "io.ReadAll(res.Body)") + return nil, err + } + bs := string(b) + logger.V(6).Info("response", "content", bs, "response", responseInfo(res)) + + dec := json.NewDecoder(strings.NewReader(bs)) var zones []Zone err = dec.Decode(&zones) + if err != nil { + logger.Error(err, "json.Decoder.Decode()", "zones", zones, "content", bs) + err = fmt.Errorf("Decode: %w (%s)", err, bs) + } return zones, err } func (c *Client) ListRecords(zone *int, search *string) ([]Record, error) { + logger := c.log().WithValues("function", "ListRecords") + logger.V(6).Info("arguments", "zone", zone, "search", search) q := url.Values{} if zone != nil { q.Add("zone_id", fmt.Sprintf("%d", *zone)) @@ -123,50 +156,76 @@ func (c *Client) ListRecords(zone *int, search *string) ([]Record, error) { res, err := c.do("GET", "list_records", q) if err != nil { + logger.Error(err, "(*Client).do()", + "method", "GET", "endpoint", "list_records", "params", q) return nil, err } - dec := json.NewDecoder(res.Body) + b, err := io.ReadAll(res.Body) + if err != nil { + logger.Error(err, "io.ReadAll(res.Body)") + return nil, err + } + bs := string(b) + logger.V(6).Info("response", "content", bs, "response", responseInfo(res)) + + dec := json.NewDecoder(strings.NewReader(bs)) var records []Record err = dec.Decode(&records) + if err != nil { + logger.Error(err, "json.Decoder.Decode()", "records", records, "content", bs) + err = fmt.Errorf("Decode: %w (%s)", err, bs) + } return records, err } func (c *Client) DeployZone(zone int) (Zone, error) { + logger := c.log().WithValues("function", "DeployZone") + logger.V(6).Info("arguments", "zone", zone) q := url.Values{} q.Set("zone_id", fmt.Sprintf("%d", zone)) res, err := c.do("POST", "deploy_zone", q) if err != nil { + logger.Error(err, "(*Client).do()", + "method", "POST", "endpoint", "deploy_zone", "params", q) return Zone{}, err } b, err := io.ReadAll(res.Body) if err != nil { + logger.Error(err, "io.ReadAll(res.Body)") return Zone{}, err } bs := string(b) + logger.V(6).Info("response", "content", bs, "response", responseInfo(res)) dec := json.NewDecoder(strings.NewReader(bs)) var z Zone err = dec.Decode(&z) if err != nil { + logger.Error(err, "json.Decoder.Decode()", "zone", z, "content", bs) err = fmt.Errorf("Decode: %w (%s)", err, bs) } return z, err } func (c *Client) CreateRecord(content string) (Record, error) { + logger := c.log().WithValues("function", "CreateRecord") + logger.V(6).Info("arguments", "content", content) q := url.Values{} q.Set("record_content", content) res, err := c.do("POST", "create_record", q) if err != nil { + logger.Error(err, "(*Client).do()", + "method", "POST", "endpoint", "create_record", "params", q) return Record{}, err } b, err := io.ReadAll(res.Body) if err != nil { + logger.Error(err, "io.ReadAll(res.Body)") return Record{}, err } bs := string(b) @@ -175,53 +234,111 @@ func (c *Client) CreateRecord(content string) (Record, error) { var r Record err = dec.Decode(&r) if err != nil { + logger.Error(err, "json.Decoder.Decode()", "record", r, "content", bs) err = fmt.Errorf("Decode: %w (%s)", err, bs) } return r, err } func (c *Client) UpdateRecord(record int, content string) (Record, error) { + logger := c.log().WithValues("function", "UpdateRecord") + logger.V(6).Info("arguments", "record", record, "content", content) q := url.Values{} q.Set("record_id", fmt.Sprintf("%d", record)) q.Set("record_content", content) res, err := c.do("POST", "update_record", q) if err != nil { + logger.Error(err, "(*Client).do()", + "method", "POST", "endpoint", "update_record", "params", q) + return Record{}, err + } + + b, err := io.ReadAll(res.Body) + if err != nil { + logger.Error(err, "io.ReadAll(res.Body)") return Record{}, err } + bs := string(b) + logger.V(6).Info("response", "content", bs, "response", responseInfo(res)) - dec := json.NewDecoder(res.Body) + dec := json.NewDecoder(strings.NewReader(bs)) var r Record err = dec.Decode(&r) + if err != nil { + logger.Error(err, "json.Decoder.Decode()", "record", r, "content", bs) + err = fmt.Errorf("Decode: %w (%s)", err, bs) + } return r, err } func (c *Client) DestroyRecord(record int) (Record, error) { + logger := c.log().WithValues("function", "DestroyRecord") + logger.V(6).Info("arguments", "record", record) q := url.Values{} q.Set("record_id", fmt.Sprintf("%d", record)) res, err := c.do("DELETE", "destroy_record", q) if err != nil { + logger.Error(err, "(*Client).do()", + "method", "DELETE", "endpoint", "destroy_record", "params", q) return Record{}, err } - dec := json.NewDecoder(res.Body) + b, err := io.ReadAll(res.Body) + if err != nil { + logger.Error(err, "io.ReadAll(res.Body)") + return Record{}, err + } + bs := string(b) + logger.V(6).Info("response", "content", bs, "response", responseInfo(res)) + + dec := json.NewDecoder(strings.NewReader(bs)) var r Record err = dec.Decode(&r) + if err != nil { + logger.Error(err, "json.Decoder.Decode()", "record", r, "content", bs) + err = fmt.Errorf("Decode: %w (%s)", err, bs) + } return r, err } func (c *Client) RestoreRecord(record int) (Record, error) { + logger := c.log().WithValues("function", "RestoreRecord") + logger.V(6).Info("arguments", "record", record) q := url.Values{} q.Set("record_id", fmt.Sprintf("%d", record)) res, err := c.do("POST", "restore_record", q) if err != nil { + logger.Error(err, "(*Client).do()", + "method", "POST", "endpoint", "restore_record", "params", q) return Record{}, err } - dec := json.NewDecoder(res.Body) + b, err := io.ReadAll(res.Body) + if err != nil { + logger.Error(err, "io.ReadAll(res.Body)") + return Record{}, err + } + bs := string(b) + logger.V(6).Info("response", "content", bs, "response", responseInfo(res)) + + dec := json.NewDecoder(strings.NewReader(bs)) var r Record err = dec.Decode(&r) + if err != nil { + logger.Error(err, "json.Decoder.Decode()", "record", r, "content", bs) + err = fmt.Errorf("Decode: %w (%s)", err, bs) + } return r, err } + +func responseInfo(res *http.Response) map[string]interface{} { + r := make(map[string]interface{}) + r["status"] = res.Status + r["proto"] = res.Proto + r["headers"] = res.Header + + return r +}