LOOPIA: Linting corrections (#2175)

Co-authored-by: Tom Limoncelli <tlimoncelli@stackoverflow.com>
This commit is contained in:
Tom Limoncelli 2023-03-16 13:57:18 -04:00 committed by GitHub
parent 30646a15f7
commit 31765b0bef
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 103 additions and 89 deletions

View file

@ -5,13 +5,14 @@ import (
"encoding/xml"
"errors"
"fmt"
"golang.org/x/text/cases"
"golang.org/x/text/language"
"io"
"net/http"
"strconv"
"strings"
"time"
"golang.org/x/text/cases"
"golang.org/x/text/language"
)
/*
@ -78,18 +79,23 @@ Loopia available API return (object) types:
*/
// DefaultBaseNOURL and others are RPC end-points.
const (
DefaultBaseNOURL = "https://api.loopia.no/RPCSERV"
DefaultBaseRSURL = "https://api.loopia.rs/RPCSERV"
DefaultBaseSEURL = "https://api.loopia.se/RPCSERV"
defaultNS1 = "ns1.loopia.se."
defaultNS2 = "ns2.loopia.se."
)
// defaultNS1 and defaultNS2 are default NS records.
const (
defaultNS1 = "ns1.loopia.se."
defaultNS2 = "ns2.loopia.se."
)
// Section 2: Define the API client.
// LoopiaClient is the LoopiaClient handle used to store any client-related state.
type LoopiaClient struct {
// APIClient is the APIClient handle used to store any client-related state.
type APIClient struct {
APIUser string
APIPassword string
BaseURL string
@ -101,7 +107,7 @@ type LoopiaClient struct {
}
// NewClient creates a new LoopiaClient.
func NewClient(apiUser, apiPassword string, region string, modifyns bool, fetchns bool, debug bool) *LoopiaClient {
func NewClient(apiUser, apiPassword string, region string, modifyns bool, fetchns bool, debug bool) *APIClient {
// DefaultBaseURL is url to the XML-RPC api.
var DefaultBaseURL string
switch region {
@ -114,7 +120,7 @@ func NewClient(apiUser, apiPassword string, region string, modifyns bool, fetchn
default:
DefaultBaseURL = DefaultBaseSEURL
}
return &LoopiaClient{
return &APIClient{
APIUser: apiUser,
APIPassword: apiPassword,
BaseURL: DefaultBaseURL,
@ -129,7 +135,7 @@ func NewClient(apiUser, apiPassword string, region string, modifyns bool, fetchn
//Create
// CreateRecordSimulate only prints info about a record addition. Used for debugging.
func (c *LoopiaClient) CreateRecordSimulate(domain string, subdomain string, record paramStruct) error {
func (c *APIClient) CreateRecordSimulate(domain string, subdomain string, record paramStruct) error {
if c.Debug {
fmt.Printf("create: domain: %s; subdomain: %s; record: %+v\n", domain, subdomain, record)
}
@ -137,7 +143,7 @@ func (c *LoopiaClient) CreateRecordSimulate(domain string, subdomain string, rec
}
// CreateRecord adds a record.
func (c *LoopiaClient) CreateRecord(domain string, subdomain string, record paramStruct) error {
func (c *APIClient) CreateRecord(domain string, subdomain string, record paramStruct) error {
call := &methodCall{
MethodName: "addZoneRecord",
Params: []param{
@ -161,8 +167,8 @@ func (c *LoopiaClient) CreateRecord(domain string, subdomain string, record para
//CRUD: Create, Read, Update, Delete
//Read
// GetDomains lists all domains.
func (c *LoopiaClient) GetDomains() ([]domainObject, error) {
// getDomains lists all domains.
func (c *APIClient) getDomains() ([]domainObject, error) {
call := &methodCall{
MethodName: "getDomains",
Params: []param{
@ -178,8 +184,8 @@ func (c *LoopiaClient) GetDomains() ([]domainObject, error) {
return resp.Domains, err
}
// GetDomainRecords gets all records for a subdomain
func (c *LoopiaClient) GetDomainRecords(domain string, subdomain string) ([]zoneRecord, error) {
// getDomainRecords gets all records for a subdomain
func (c *APIClient) getDomainRecords(domain string, subdomain string) ([]zoneRecord, error) {
call := &methodCall{
MethodName: "getZoneRecords",
Params: []param{
@ -198,7 +204,7 @@ func (c *LoopiaClient) GetDomainRecords(domain string, subdomain string) ([]zone
}
// GetSubDomains gets all the subdomains within a domain, no records
func (c *LoopiaClient) GetSubDomains(domain string) ([]string, error) {
func (c *APIClient) GetSubDomains(domain string) ([]string, error) {
call := &methodCall{
MethodName: "getSubdomains",
Params: []param{
@ -216,60 +222,59 @@ func (c *LoopiaClient) GetSubDomains(domain string) ([]string, error) {
}
// GetDomainNS gets all NS records for a subdomain, in this case, the apex "@"
func (c *LoopiaClient) GetDomainNS(domain string) ([]string, error) {
func (c *APIClient) GetDomainNS(domain string) ([]string, error) {
if c.ModifyNameServers {
return []string{}, nil
} else {
if c.FetchNSEntries {
return []string{defaultNS1, defaultNS2}, nil
} else {
//fetch from the domain - an extra API call.
call := &methodCall{
MethodName: "getZoneRecords",
Params: []param{
paramString{Value: c.APIUser},
paramString{Value: c.APIPassword},
paramString{Value: domain},
paramString{Value: "@"},
},
}
return nil, nil
}
resp := &zoneRecordsResponse{}
apexNSRecords := []string{}
err := c.rpcCall(call, resp)
if err != nil {
return nil, err
}
if c.FetchNSEntries {
return []string{defaultNS1, defaultNS2}, nil
}
//fetch from the domain - an extra API call.
call := &methodCall{
MethodName: "getZoneRecords",
Params: []param{
paramString{Value: c.APIUser},
paramString{Value: c.APIPassword},
paramString{Value: domain},
paramString{Value: "@"},
},
}
resp := &zoneRecordsResponse{}
apexNSRecords := []string{}
err := c.rpcCall(call, resp)
if err != nil {
return nil, err
}
if c.Debug {
fmt.Printf("DEBUG: getZoneRecords(@) START\n")
}
for i, rec := range resp.ZoneRecords {
ns := rec.GetZR()
if ns.Type == "NS" {
apexNSRecords = append(apexNSRecords, ns.Rdata)
if c.Debug {
fmt.Printf("DEBUG: getZoneRecords(@) START\n")
fmt.Printf("DEBUG: HERE %d: %v\n", i, ns)
}
for i, rec := range resp.ZoneRecords {
ns := rec.GetZR()
if ns.Type == "NS" {
apexNSRecords = append(apexNSRecords, ns.Rdata)
if c.Debug {
fmt.Printf("DEBUG: HERE %d: %v\n", i, ns)
}
}
}
return apexNSRecords, err
}
}
return nil, nil
return apexNSRecords, err
}
//CRUD: Create, Read, Update, Delete
//Update
// UpdateRecordSimulate only prints info about a record update. Used for debugging.
func (c *LoopiaClient) UpdateRecordSimulate(domain string, subdomain string, rec paramStruct) error {
func (c *APIClient) UpdateRecordSimulate(domain string, subdomain string, rec paramStruct) error {
fmt.Printf("got update: domain: %s; subdomain: %s; record: %v\n", domain, subdomain, rec)
return nil
}
// UpdateRecord updates a record.
func (c *LoopiaClient) UpdateRecord(domain string, subdomain string, rec paramStruct) error {
func (c *APIClient) UpdateRecord(domain string, subdomain string, rec paramStruct) error {
call := &methodCall{
MethodName: "updateZoneRecord",
Params: []param{
@ -304,13 +309,13 @@ func (c *LoopiaClient) UpdateRecord(domain string, subdomain string, rec paramSt
//Delete
// DeleteRecordSimulate only prints info about a record deletion. Used for debugging.
func (c *LoopiaClient) DeleteRecordSimulate(domain string, subdomain string, recordID uint32) error {
func (c *APIClient) DeleteRecordSimulate(domain string, subdomain string, recordID uint32) error {
fmt.Printf("delete: domain: %s; subdomain: %s; recordID: %d\n", domain, subdomain, recordID)
return nil
}
// DeleteRecord deletes a record.
func (c *LoopiaClient) DeleteRecord(domain string, subdomain string, recordID uint32) error {
func (c *APIClient) DeleteRecord(domain string, subdomain string, recordID uint32) error {
call := &methodCall{
MethodName: "removeZoneRecord",
Params: []param{
@ -332,7 +337,7 @@ func (c *LoopiaClient) DeleteRecord(domain string, subdomain string, recordID ui
}
// DeleteSubdomain deletes a sub-domain and its child records.
func (c *LoopiaClient) DeleteSubdomain(domain, subdomain string) error {
func (c *APIClient) DeleteSubdomain(domain, subdomain string) error {
call := &methodCall{
MethodName: "removeSubdomain",
Params: []param{
@ -355,7 +360,7 @@ func (c *LoopiaClient) DeleteSubdomain(domain, subdomain string) error {
// rpcCall makes an XML-RPC call to Loopia's RPC endpoint
// by marshaling the data given in the call argument to XML and sending that via HTTP Post to Loopia.
// The response is then unmarshalled into the resp argument.
func (c *LoopiaClient) rpcCall(call *methodCall, resp response) error {
func (c *APIClient) rpcCall(call *methodCall, resp response) error {
callBody, err := xml.MarshalIndent(call, "", " ")
if err != nil {
return fmt.Errorf("error marshalling the API request XML callBody: %w", err)
@ -398,7 +403,7 @@ func (c *LoopiaClient) rpcCall(call *methodCall, resp response) error {
return nil
}
func (c *LoopiaClient) httpPost(url string, bodyType string, body io.Reader) ([]byte, error) {
func (c *APIClient) httpPost(url string, bodyType string, body io.Reader) ([]byte, error) {
c.requestRateLimiter.beforeRequest()
resp, err := c.HTTPClient.Post(url, bodyType, body)
c.requestRateLimiter.afterRequest()

View file

@ -201,7 +201,7 @@ func TestClient_GetDomainRecords(t *testing.T) {
client := NewClient("apiuser", "goodpassword", "", false, true, false)
client.BaseURL = serverURL + "/"
recordObjs, err := client.GetDomainRecords(exampleDomain, exampleSubDomain)
recordObjs, err := client.getDomainRecords(exampleDomain, exampleSubDomain)
require.NoError(t, err)
zr := zRec{

View file

@ -79,7 +79,7 @@ func newReg(conf map[string]string) (providers.Registrar, error) {
}
// newHelper generates a handle.
func newHelper(m map[string]string, metadata json.RawMessage) (*LoopiaClient, error) {
func newHelper(m map[string]string, metadata json.RawMessage) (*APIClient, error) {
if m["username"] == "" {
return nil, fmt.Errorf("missing Loopia API username")
}
@ -87,22 +87,22 @@ func newHelper(m map[string]string, metadata json.RawMessage) (*LoopiaClient, er
return nil, fmt.Errorf("missing Loopia API password")
}
const boolean_string_warn = " setting as a 'string': 't', 'true', 'True' etc"
const booleanStringWarn = " setting as a 'string': 't', 'true', 'True' etc"
var err error
modify_name_servers := false
modifyNameServers := false
if m["modify_name_servers"] != "" { // optional
modify_name_servers, err = strconv.ParseBool(m["modify_name_servers"])
modifyNameServers, err = strconv.ParseBool(m["modify_name_servers"])
if err != nil {
return nil, fmt.Errorf("creds.json requires the modify_name_servers" + boolean_string_warn)
return nil, fmt.Errorf("creds.json requires the modify_name_servers" + booleanStringWarn)
}
}
fetch_apex_ns_entries := false
fetchApexNSEntries := false
if m["fetch_apex_ns_entries"] != "" { // optional
fetch_apex_ns_entries, err = strconv.ParseBool(m["fetch_apex_ns_entries"])
fetchApexNSEntries, err = strconv.ParseBool(m["fetch_apex_ns_entries"])
if err != nil {
return nil, fmt.Errorf("creds.json requires the fetch_apex_ns_entries" + boolean_string_warn)
return nil, fmt.Errorf("creds.json requires the fetch_apex_ns_entries" + booleanStringWarn)
}
}
@ -110,11 +110,11 @@ func newHelper(m map[string]string, metadata json.RawMessage) (*LoopiaClient, er
if m["debug"] != "" { //debug is optional
dbg, err = strconv.ParseBool(m["debug"])
if err != nil {
return nil, fmt.Errorf("creds.json requires the debug" + boolean_string_warn)
return nil, fmt.Errorf("creds.json requires the debug" + booleanStringWarn)
}
}
api := NewClient(m["username"], m["password"], strings.ToLower(m["region"]), modify_name_servers, fetch_apex_ns_entries, dbg)
api := NewClient(m["username"], m["password"], strings.ToLower(m["region"]), modifyNameServers, fetchApexNSEntries, dbg)
quota := m["rate_limit_per"]
err = api.requestRateLimiter.setRateLimitPer(quota)
@ -127,9 +127,9 @@ func newHelper(m map[string]string, metadata json.RawMessage) (*LoopiaClient, er
// Section 3: Domain Service Provider (DSP) related functions
// ListZones lists the zones on this account.
func (c *LoopiaClient) ListZones() ([]string, error) {
func (c *APIClient) ListZones() ([]string, error) {
listResp, err := c.GetDomains()
listResp, err := c.getDomains()
if err != nil {
return nil, err
}
@ -167,7 +167,7 @@ func (c *LoopiaClient) ListZones() ([]string, error) {
// GetDomainCorrections get the current and existing records,
// post-process them, and generate corrections.
func (c *LoopiaClient) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
func (c *APIClient) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
existing, err := c.GetZoneRecords(dc.Name)
if err != nil {
return nil, err
@ -180,7 +180,7 @@ func (c *LoopiaClient) GetDomainCorrections(dc *models.DomainConfig) ([]*models.
// GetZoneRecords gathers the DNS records and converts them to
// dnscontrol's format.
func (c *LoopiaClient) GetZoneRecords(domain string) (models.Records, error) {
func (c *APIClient) GetZoneRecords(domain string) (models.Records, error) {
// Two approaches. One: get all SubDomains, and get their respective records
// simultaneously, or first get subdomains then fill each subdomain with its
@ -207,7 +207,7 @@ func (c *LoopiaClient) GetZoneRecords(domain string) (models.Records, error) {
}
//step 2: records for subdomains
// Get subdomain records:
subdomainrecords, err := c.GetDomainRecords(domain, subdomain)
subdomainrecords, err := c.getDomainRecords(domain, subdomain)
if err != nil {
return nil, err
}
@ -297,7 +297,7 @@ func gatherAffectedLabels(groups map[models.RecordKey][]string) (labels map[stri
// a list of functions to call to actually make the desired
// correction, and a message to output to the user when the change is
// made.
func (c *LoopiaClient) GenerateZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) {
func (c *APIClient) GenerateZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) {
if c.Debug {
debugRecords("GenerateZoneRecordsCorrections input:\n", existingRecords)
}
@ -409,20 +409,19 @@ func debugRecords(note string, recs []*models.RecordConfig) {
// Section 3: Registrar-related functions
// GetNameservers returns a list of nameservers for domain.
func (c *LoopiaClient) GetNameservers(domain string) ([]*models.Nameserver, error) {
func (c *APIClient) GetNameservers(domain string) ([]*models.Nameserver, error) {
if c.ModifyNameServers {
return nil, nil
} else {
nameservers, err := c.GetDomainNS(domain)
if err != nil {
return nil, err
}
return models.ToNameserversStripTD(nameservers)
}
nameservers, err := c.GetDomainNS(domain)
if err != nil {
return nil, err
}
return models.ToNameserversStripTD(nameservers)
}
// GetRegistrarCorrections returns a list of corrections for this registrar.
func (c *LoopiaClient) GetRegistrarCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
func (c *APIClient) GetRegistrarCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
existingNs, err := c.GetDomainNS(dc.Name)
if err != nil {

View file

@ -110,17 +110,20 @@ type zoneRecord struct {
// Properties map[string]interface{}
}
// zoneRecordsResponse decodes the API zoneRecords call.
type zoneRecordsResponse struct {
responseFault
XMLName xml.Name `xml:"methodResponse"`
ZoneRecords []zoneRecord `xml:"params>param>value>array>data>value>struct"`
}
// Property is an XML Key/value.
type Property struct {
Key string `xml:"name"`
Value Value `xml:"value"`
}
// Value is a xml any
type Value struct {
// String string `xml:",any"`
String string `xml:"string"`
@ -128,10 +131,17 @@ type Value struct {
Bool bool `xml:"bool"`
}
func (p Property) Name() string { return p.Key }
// Name is an accessor to the Property's name.
func (p Property) Name() string { return p.Key }
// String is an accessor to the Property's value when it is a string.
func (p Property) String() string { return p.Value.String }
func (p Property) Int() int { return p.Value.Int }
func (p Property) Bool() bool { return p.Value.Bool }
// Int is an accessor to the Property's value when it is a integer.
func (p Property) Int() int { return p.Value.Int }
// Bool is an accessor to the Property's value when it is a boolean.
func (p Property) Bool() bool { return p.Value.Bool }
func (zr *zoneRecord) GetZR() zRec {
record := zRec{}
@ -157,11 +167,11 @@ func (zrec *zRec) SetZR() zoneRecord {
return zoneRecord{
XMLName: xml.Name{Local: "struct"},
Properties: []Property{
Property{Key: "type", Value: Value{String: zrec.Type}},
Property{Key: "ttl", Value: Value{Int: int(zrec.TTL)}},
Property{Key: "priority", Value: Value{Int: int(zrec.Priority)}},
Property{Key: "rdata", Value: Value{String: zrec.Rdata}},
Property{Key: "record_id", Value: Value{Int: int(zrec.RecordID)}},
{Key: "type", Value: Value{String: zrec.Type}},
{Key: "ttl", Value: Value{Int: int(zrec.TTL)}},
{Key: "priority", Value: Value{Int: int(zrec.Priority)}},
{Key: "rdata", Value: Value{String: zrec.Rdata}},
{Key: "record_id", Value: Value{Int: int(zrec.RecordID)}},
},
}
}