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 }