Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
./static
];
};
vendorHash = "sha256-QFlT4k2cnV6jJzNBtsSS29WIXcEjkB2De2LYu/niOQI=";
vendorHash = "sha256-3z1f7BLLCjTK2ZhgCnAKI7Xy4HpVx/+EQj6Lil86Ngo=";
meta.mainProgram = "dockdns";
};

Expand Down
11 changes: 6 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ module github.com/Tarow/dockdns
go 1.23.0

require (
github.com/a-h/templ v0.3.833
github.com/cloudflare/cloudflare-go v0.115.0
github.com/a-h/templ v0.3.819
github.com/cloudflare/cloudflare-go/v4 v4.1.0
github.com/docker/docker v27.5.1+incompatible
github.com/ilyakaznacheev/cleanenv v1.5.0
)
Expand All @@ -19,16 +19,18 @@ require (
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/goccy/go-json v0.10.5 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/joho/godotenv v1.5.1 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/moby/term v0.5.0 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/tidwall/gjson v1.14.4 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/tidwall/sjson v1.2.5 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.52.0 // indirect
go.opentelemetry.io/otel v1.27.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.27.0 // indirect
Expand All @@ -37,7 +39,6 @@ require (
go.opentelemetry.io/otel/trace v1.27.0 // indirect
golang.org/x/net v0.34.0 // indirect
golang.org/x/sys v0.29.0 // indirect
golang.org/x/text v0.21.0 // indirect
golang.org/x/time v0.9.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gotest.tools/v3 v3.5.1 // indirect
Expand Down
36 changes: 17 additions & 19 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/a-h/templ v0.3.833 h1:L/KOk/0VvVTBegtE0fp2RJQiBm7/52Zxv5fqlEHiQUU=
github.com/a-h/templ v0.3.833/go.mod h1:cAu4AiZhtJfBjMY0HASlyzvkrtjnHWPeEsyGK2YYmfk=
github.com/a-h/templ v0.3.819 h1:KDJ5jTFN15FyJnmSmo2gNirIqt7hfvBD2VXVDTySckM=
github.com/a-h/templ v0.3.819/go.mod h1:iDJKJktpttVKdWoTkRNNLcllRI+BlpopJc+8au3gOUo=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/cloudflare/cloudflare-go v0.115.0 h1:84/dxeeXweCc0PN5Cto44iTA8AkG1fyT11yPO5ZB7sM=
github.com/cloudflare/cloudflare-go v0.115.0/go.mod h1:Ds6urDwn/TF2uIU24mu7H91xkKP8gSAHxQ44DSZgVmU=
github.com/cloudflare/cloudflare-go/v4 v4.1.0 h1:1SjQZaPbUe23fSoCuMuN7EblVo+RIldNGd4pfkPCpW4=
github.com/cloudflare/cloudflare-go/v4 v4.1.0/go.mod h1:XcYpLe7Mf6FN87kXzEWVnJ6z+vskW/k6eUqgqfhFE9k=
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
Expand All @@ -30,15 +30,10 @@ github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k=
github.com/ilyakaznacheev/cleanenv v1.5.0 h1:0VNZXggJE2OYdXE87bfSSwGxeiGt9moSR2lOrsHHvr4=
Expand All @@ -47,10 +42,6 @@ github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
Expand All @@ -65,12 +56,20 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg=
github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM=
github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.52.0 h1:9l89oX4ba9kHbBol3Xin3leYJ+252h0zszDtBwyKe2A=
Expand Down Expand Up @@ -130,9 +129,8 @@ google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY=
google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg=
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
Expand Down
2 changes: 1 addition & 1 deletion internal/dns/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func (h Handler) updateRecords(provider Provider, domains []config.DomainRecord)
func (h Handler) updateRecord(provider Provider, domain config.DomainRecord, recordType string) {
existingRecord, err := provider.Get(domain.Name, recordType)
if err != nil {
slog.Error("failed to fetch existing record", "name", domain.Name, "type", recordType, "action", "skip record")
slog.Error("failed to fetch existing record", "name", domain.Name, "type", recordType, "action", "skip record", "error", err)
return
}
if isEqual(existingRecord, domain, recordType) {
Expand Down
131 changes: 64 additions & 67 deletions internal/provider/cloudflare/cloudflare.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,24 @@ import (

"github.com/Tarow/dockdns/internal/constants"
"github.com/Tarow/dockdns/internal/dns"
"github.com/cloudflare/cloudflare-go"
"github.com/cloudflare/cloudflare-go/v4"
cfDns "github.com/cloudflare/cloudflare-go/v4/dns"
"github.com/cloudflare/cloudflare-go/v4/option"
)

type cloudflareProvider struct {
apiToken string
zoneID *cloudflare.ResourceContainer
api *cloudflare.API
zoneID string
service *cfDns.RecordService
}

func New(apiToken, zoneId string) (cloudflareProvider, error) {
api, err := cloudflare.NewWithAPIToken(apiToken)
if err != nil {
return cloudflareProvider{}, err
}

func New(apiToken, zoneID string) (cloudflareProvider, error) {
return cloudflareProvider{
apiToken: apiToken,
zoneID: &cloudflare.ResourceContainer{
Type: "zone",
Identifier: zoneId,
},
api: api,
zoneID: zoneID,
service: cfDns.NewRecordService(option.WithEnvironmentProduction(), option.WithAPIToken(apiToken)),
}, nil

}

func (cfp cloudflareProvider) List() ([]dns.Record, error) {
Expand All @@ -51,81 +46,87 @@ func (cfp cloudflareProvider) List() ([]dns.Record, error) {
}

func (cfp cloudflareProvider) list(recordType string) ([]dns.Record, error) {
var allRecords []cloudflare.DNSRecord

page := 1
perPage := 100
for {
records, resultInfo, err := cfp.api.ListDNSRecords(context.Background(), cfp.zoneID, cloudflare.ListDNSRecordsParams{
Type: recordType,
ResultInfo: cloudflare.ResultInfo{
Page: page,
PerPage: perPage,
},
})
if err != nil {
return nil, err
}
allRecords = append(allRecords, records...)
if resultInfo.Page == resultInfo.TotalPages {
return mapRecords(allRecords), nil
}
var allRecords []cfDns.RecordResponse

records := cfp.service.ListAutoPaging(context.Background(), cfDns.RecordListParams{
ZoneID: cloudflare.F(cfp.zoneID),
Type: cloudflare.F(cfDns.RecordListParamsType(recordType)),
PerPage: cloudflare.F(float64(100)),
})

page++
for records.Next() {
if records.Err() != nil {
return nil, records.Err()
}
allRecords = append(allRecords, records.Current())
}

return mapRecords(allRecords), nil
}

func (cfp cloudflareProvider) Get(domain, recordType string) (dns.Record, error) {
records, _, err := cfp.api.ListDNSRecords(context.Background(), cfp.zoneID, cloudflare.ListDNSRecordsParams{
Type: recordType,
Name: domain,
records := cfp.service.ListAutoPaging(context.Background(), cfDns.RecordListParams{
ZoneID: cloudflare.F(cfp.zoneID),
Type: cloudflare.F(cfDns.RecordListParamsType(recordType)),
Name: cloudflare.F(cfDns.RecordListParamsName{
Exact: cloudflare.F(domain),
}),
})
if err != nil {
return dns.Record{}, err
if records.Err() != nil {
return dns.Record{}, records.Err()
}
if len(records) == 0 {
if !records.Next() {
return dns.Record{}, nil
}
return mapRecord(records[0]), nil
return mapRecord(records.Current()), nil
}

func (cfp cloudflareProvider) Create(record dns.Record) (dns.Record, error) {
createdRecord, err := cfp.api.CreateDNSRecord(context.Background(), cfp.zoneID, cloudflare.CreateDNSRecordParams{
Name: record.Name,
Type: record.Type,
Proxied: &record.Proxied,
TTL: int(record.TTL),
Content: record.Content,
Comment: record.Comment,
createdRecord, err := cfp.service.New(context.Background(), cfDns.RecordNewParams{
ZoneID: cloudflare.F(cfp.zoneID),
Record: cfDns.RecordParam{
Name: cloudflare.F(record.Name),
Type: cloudflare.F(cfDns.RecordType(record.Type)),
Proxied: cloudflare.F(record.Proxied),
TTL: cloudflare.F(cfDns.TTL(record.TTL)),
Content: cloudflare.F(record.Content),
Comment: cloudflare.F(record.Comment),
},
})

if err != nil {
return dns.Record{}, err
}
return mapRecord(createdRecord), nil
return mapRecord(*createdRecord), nil
}

func (cfp cloudflareProvider) Update(record dns.Record) (dns.Record, error) {
updatedRecord, err := cfp.api.UpdateDNSRecord(context.Background(), cfp.zoneID, cloudflare.UpdateDNSRecordParams{
ID: record.ID,
Type: record.Type,
Proxied: &record.Proxied,
TTL: record.TTL,
Content: record.Content,
Comment: &record.Comment,
updatedRecord, err := cfp.service.Update(context.Background(), record.ID, cfDns.RecordUpdateParams{
ZoneID: cloudflare.F(cfp.zoneID),
Record: cfDns.RecordParam{
Name: cloudflare.F(record.Name),
Type: cloudflare.F(cfDns.RecordType(record.Type)),
Proxied: cloudflare.F(record.Proxied),
TTL: cloudflare.F(cfDns.TTL(record.TTL)),
Content: cloudflare.F(record.Content),
Comment: cloudflare.F(record.Comment),
},
})

if err != nil {
return dns.Record{}, err
}
return mapRecord(updatedRecord), nil
return mapRecord(*updatedRecord), nil
}

func (cfp cloudflareProvider) Delete(record dns.Record) error {
return cfp.api.DeleteDNSRecord(context.Background(), cfp.zoneID, record.ID)
_, err := cfp.service.Delete(context.Background(), record.ID, cfDns.RecordDeleteParams{
ZoneID: cloudflare.F(cfp.zoneID),
})
return err
}

func mapRecords(records []cloudflare.DNSRecord) []dns.Record {
func mapRecords(records []cfDns.RecordResponse) []dns.Record {
var mappedRecords []dns.Record

for _, record := range records {
Expand All @@ -135,18 +136,14 @@ func mapRecords(records []cloudflare.DNSRecord) []dns.Record {
return mappedRecords
}

func mapRecord(r cloudflare.DNSRecord) dns.Record {
var proxied bool
if r.Proxied != nil {
proxied = *r.Proxied
}
func mapRecord(r cfDns.RecordResponse) dns.Record {
return dns.Record{
ID: r.ID,
Name: r.Name,
Type: r.Type,
Type: string(r.Type),
Content: r.Content,
Proxied: proxied,
TTL: r.TTL,
Proxied: r.Proxied,
TTL: int(r.TTL),
Comment: r.Comment,
}
}