github.com/teknogeek/dnscontrol@v0.2.8/providers/gandi/protocol.go (about)

     1  package gandi
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/pkg/errors"
     7  	gandiclient "github.com/prasmussen/gandi-api/client"
     8  	gandidomain "github.com/prasmussen/gandi-api/domain"
     9  	gandinameservers "github.com/prasmussen/gandi-api/domain/nameservers"
    10  	gandizone "github.com/prasmussen/gandi-api/domain/zone"
    11  	gandirecord "github.com/prasmussen/gandi-api/domain/zone/record"
    12  	gandiversion "github.com/prasmussen/gandi-api/domain/zone/version"
    13  	gandioperation "github.com/prasmussen/gandi-api/operation"
    14  
    15  	"github.com/StackExchange/dnscontrol/models"
    16  )
    17  
    18  // fetchDomainList gets list of domains for account. Cache ids for easy lookup.
    19  func (c *GandiApi) fetchDomainList() error {
    20  	if c.domainIndex != nil {
    21  		return nil
    22  	}
    23  	c.domainIndex = map[string]int64{}
    24  	gc := gandiclient.New(c.ApiKey, gandiclient.Production)
    25  	domain := gandidomain.New(gc)
    26  	domains, err := domain.List()
    27  	if err != nil {
    28  		// fmt.Println(err)
    29  		return err
    30  	}
    31  	for _, d := range domains {
    32  		c.domainIndex[d.Fqdn] = d.Id
    33  	}
    34  	return nil
    35  }
    36  
    37  // fetchDomainInfo gets information about a domain.
    38  func (c *GandiApi) fetchDomainInfo(fqdn string) (*gandidomain.DomainInfo, error) {
    39  	gc := gandiclient.New(c.ApiKey, gandiclient.Production)
    40  	domain := gandidomain.New(gc)
    41  	return domain.Info(fqdn)
    42  }
    43  
    44  // setDomainNameservers updates the nameservers of a domain.
    45  func (c *GandiApi) setDomainNameservers(fqdn string, nameservers []string) (*gandioperation.OperationInfo, error) {
    46  	gc := gandiclient.New(c.ApiKey, gandiclient.Production)
    47  	nameserversapi := gandinameservers.New(gc)
    48  	return nameserversapi.Set(fqdn, nameservers)
    49  }
    50  
    51  // getRecordsForDomain returns a list of records for a zone.
    52  func (c *GandiApi) getZoneRecords(zoneid int64, origin string) ([]*models.RecordConfig, error) {
    53  	gc := gandiclient.New(c.ApiKey, gandiclient.Production)
    54  	record := gandirecord.New(gc)
    55  	recs, err := record.List(zoneid, 0)
    56  	if err != nil {
    57  		return nil, err
    58  	}
    59  	rcs := make([]*models.RecordConfig, 0, len(recs))
    60  	for _, r := range recs {
    61  		rcs = append(rcs, nativeToRecord(r, origin))
    62  	}
    63  	return rcs, nil
    64  }
    65  
    66  // convert takes a DNS record from Gandi and returns our native RecordConfig format.
    67  func nativeToRecord(r *gandirecord.RecordInfo, origin string) *models.RecordConfig {
    68  
    69  	rc := &models.RecordConfig{
    70  		//NameFQDN: dnsutil.AddOrigin(r.Name, origin),
    71  		//Name:     r.Name,
    72  		//Type:     r.Type,
    73  		TTL:      uint32(r.Ttl),
    74  		Original: r,
    75  		//Target:   r.Value,
    76  	}
    77  	rc.SetLabel(r.Name, origin)
    78  	switch rtype := r.Type; rtype {
    79  	default: //  "A", "AAAA", "CAA", "NS", "CNAME", "MX", "PTR", "SRV", "TXT"
    80  		if err := rc.PopulateFromString(rtype, r.Value, origin); err != nil {
    81  			panic(errors.Wrap(err, "unparsable record received from gandi"))
    82  		}
    83  	}
    84  	return rc
    85  }
    86  
    87  // listZones retrieves the list of zones.
    88  func (c *GandiApi) listZones() ([]*gandizone.ZoneInfoBase, error) {
    89  	gc := gandiclient.New(c.ApiKey, gandiclient.Production)
    90  	zone := gandizone.New(gc)
    91  	return zone.List()
    92  }
    93  
    94  // setZone assigns a particular zone to a domain.
    95  func (c *GandiApi) setZones(domainname string, zoneID int64) (*gandidomain.DomainInfo, error) {
    96  	gc := gandiclient.New(c.ApiKey, gandiclient.Production)
    97  	zone := gandizone.New(gc)
    98  	return zone.Set(domainname, zoneID)
    99  }
   100  
   101  // getZoneInfo gets ZoneInfo about a zone.
   102  func (c *GandiApi) getZoneInfo(zoneid int64) (*gandizone.ZoneInfo, error) {
   103  	gc := gandiclient.New(c.ApiKey, gandiclient.Production)
   104  	zone := gandizone.New(gc)
   105  	return zone.Info(zoneid)
   106  }
   107  
   108  // createZone creates an entirely new zone.
   109  func (c *GandiApi) createZone(name string) (*gandizone.ZoneInfo, error) {
   110  	gc := gandiclient.New(c.ApiKey, gandiclient.Production)
   111  	zone := gandizone.New(gc)
   112  	return zone.Create(name)
   113  }
   114  
   115  func (c *GandiApi) getEditableZone(domainname string, zoneinfo *gandizone.ZoneInfo) (int64, error) {
   116  	var zoneID int64
   117  	if zoneinfo.Domains < 2 {
   118  		// If there is only on{ domain linked to this zone, use it.
   119  		zoneID = zoneinfo.Id
   120  		fmt.Printf("Using zone id=%d named %#v\n", zoneID, zoneinfo.Name)
   121  		return zoneID, nil
   122  	}
   123  
   124  	// We can't use the zone_id given to us. Let's make/find a new one.
   125  	zones, err := c.listZones()
   126  	if err != nil {
   127  		return 0, err
   128  	}
   129  	zonename := fmt.Sprintf("%s dnscontrol", domainname)
   130  	for _, z := range zones {
   131  		if z.Name == zonename {
   132  			zoneID = z.Id
   133  			fmt.Printf("Recycling zone id=%d named %#v\n", zoneID, z.Name)
   134  			return zoneID, nil
   135  		}
   136  	}
   137  	zoneinfo, err = c.createZone(zonename)
   138  	if err != nil {
   139  		return 0, err
   140  	}
   141  	zoneID = zoneinfo.Id
   142  	fmt.Printf("Created zone id=%d named %#v\n", zoneID, zoneinfo.Name)
   143  	return zoneID, nil
   144  }
   145  
   146  // makeEditableZone
   147  func (c *GandiApi) makeEditableZone(zoneID int64) (int64, error) {
   148  	gc := gandiclient.New(c.ApiKey, gandiclient.Production)
   149  	version := gandiversion.New(gc)
   150  	return version.New(zoneID, 0)
   151  }
   152  
   153  // setZoneRecords
   154  func (c *GandiApi) setZoneRecords(zoneID, versionID int64, records []gandirecord.RecordSet) ([]*gandirecord.RecordInfo, error) {
   155  	gc := gandiclient.New(c.ApiKey, gandiclient.Production)
   156  	record := gandirecord.New(gc)
   157  	return record.SetRecords(zoneID, versionID, records)
   158  }
   159  
   160  // activateVersion
   161  func (c *GandiApi) activateVersion(zoneID, versionID int64) (bool, error) {
   162  	gc := gandiclient.New(c.ApiKey, gandiclient.Production)
   163  	version := gandiversion.New(gc)
   164  	return version.Set(zoneID, versionID)
   165  }
   166  
   167  func (c *GandiApi) createGandiZone(domainname string, zoneID int64, records []gandirecord.RecordSet) error {
   168  
   169  	// Get the zone_id of the zone we'll be updating.
   170  	zoneinfo, err := c.getZoneInfo(zoneID)
   171  	if err != nil {
   172  		return err
   173  	}
   174  	zoneID, err = c.getEditableZone(domainname, zoneinfo)
   175  	if err != nil {
   176  		return err
   177  	}
   178  
   179  	// Get the versionID of the zone we're updating.
   180  	versionID, err := c.makeEditableZone(zoneID)
   181  	if err != nil {
   182  		return err
   183  	}
   184  
   185  	// Update the new version.
   186  	_, err = c.setZoneRecords(zoneID, versionID, records)
   187  	if err != nil {
   188  		return err
   189  	}
   190  
   191  	// Activate zone version
   192  	_, err = c.activateVersion(zoneID, versionID)
   193  	if err != nil {
   194  		return err
   195  	}
   196  	_, err = c.setZones(domainname, zoneID)
   197  	if err != nil {
   198  		return err
   199  	}
   200  
   201  	return nil
   202  }