provider/cloudflare.go
func (p *CloudFlareProvider) submitChanges(changes []*cloudFlareChange) error {
	// return early if there is nothing to change
	if len(changes) == 0 {
		return nil
	}

	zones, err := p.Zones()
	if err != nil {
		return err
	}
	// separate into per-zone change sets to be passed to the API.
	changesByZone := p.changesByZone(zones, changes)

	for zoneID, changes := range changesByZone {
		records, err := p.Client.DNSRecords(zoneID, cloudflare.DNSRecord{})
		if err != nil {
			return fmt.Errorf("could not fetch records from zone, %v", err)
		}
		for _, change := range changes {
			logFields := log.Fields{
				"record":  change.ResourceRecordSet[0].Name,
				"type":    change.ResourceRecordSet[0].Type,
				"ttl":     change.ResourceRecordSet[0].TTL,
				"targets": len(change.ResourceRecordSet),
				"action":  change.Action,
				"zone":    zoneID,
			}

			log.WithFields(logFields).Info("Changing record.")

			if p.DryRun {
				continue
			}

			recordIDs := p.getRecordIDs(records, change.ResourceRecordSet[0])

			// to simplify bookkeeping for multiple records, an update is executed as delete+create
			if change.Action == cloudFlareDelete || change.Action == cloudFlareUpdate {
				for _, recordID := range recordIDs {
					err := p.Client.DeleteDNSRecord(zoneID, recordID)
					if err != nil {
						log.WithFields(logFields).Errorf("failed to delete record: %v", err)
					}
				}
			}

			if change.Action == cloudFlareCreate || change.Action == cloudFlareUpdate {
				for _, record := range change.ResourceRecordSet {
					_, err := p.Client.CreateDNSRecord(zoneID, record)
					if err != nil {
						log.WithFields(logFields).Errorf("failed to create record: %v", err)
					}
				}
			}
		}
	}
	return nil
}
func (p *CloudFlareProvider) submitChanges(changes []*cloudFlareChange) error {
	// return early if there is nothing to change
	if len(changes) == 0 {
		return nil
	}

	zones, err := p.Zones()
	if err != nil {
		return err
	}
	// separate into per-zone change sets to be passed to the API.
	changesByZone := p.changesByZone(zones, changes)

	for zoneID, changes := range changesByZone {
		records, err := p.Client.DNSRecords(zoneID, cloudflare.DNSRecord{})
		if err != nil {
			return fmt.Errorf("could not fetch records from zone, %v", err)
		}
		for _, change := range changes {
			logFields := log.Fields{
				"record":  change.ResourceRecordSet[0].Name,
				"type":    change.ResourceRecordSet[0].Type,
				"ttl":     change.ResourceRecordSet[0].TTL,
				"targets": len(change.ResourceRecordSet),
				"action":  change.Action,
				"zone":    zoneID,
			}

			log.WithFields(logFields).Info("Changing record.")

			if p.DryRun {
				continue
			}

			recordIDs := p.getRecordIDs(records, change.ResourceRecordSet[0])

			// to simplify bookkeeping for multiple records, an update is executed as delete+create
			if change.Action == cloudFlareDelete || change.Action == cloudFlareUpdate {
				for _, recordID := range recordIDs {
					err := p.Client.DeleteDNSRecord(zoneID, recordID)
					if err != nil {
						log.WithFields(logFields).Errorf("failed to delete record: %v", err)
					}
				}
			}

			if change.Action == cloudFlareCreate || change.Action == cloudFlareUpdate {
				for _, record := range change.ResourceRecordSet {
					_, err := p.Client.CreateDNSRecord(zoneID, record)
					if err != nil {
						log.WithFields(logFields).Errorf("failed to create record: %v", err)
					}
				}
			}
		}
	}
	return nil
}
// submitChanges takes a zone and a collection of Changes and sends them as a single transaction.