Compare commits
3 Commits
features/y
...
main
Author | SHA1 | Date | |
---|---|---|---|
156778729e | |||
209f07dea0 | |||
55043c481e |
34
.drone.yml
Normal file
34
.drone.yml
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
type: docker
|
||||||
|
name: build
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: build image
|
||||||
|
image: plugins/docker
|
||||||
|
settings:
|
||||||
|
repo: jtom38/cloudflare-ddns
|
||||||
|
username: jtom38
|
||||||
|
password:
|
||||||
|
from_secret: DockerPushPat
|
||||||
|
trigger:
|
||||||
|
branch:
|
||||||
|
include:
|
||||||
|
- main
|
||||||
|
- releases/*
|
||||||
|
event:
|
||||||
|
exclude:
|
||||||
|
- pull_request
|
||||||
|
|
||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
type: docker
|
||||||
|
name: compile
|
||||||
|
steps:
|
||||||
|
- name: Compile project
|
||||||
|
image: golang:latest
|
||||||
|
commands:
|
||||||
|
- go build
|
||||||
|
trigger:
|
||||||
|
event:
|
||||||
|
- pull_request
|
64
.github/workflows/docker.build.yaml
vendored
64
.github/workflows/docker.build.yaml
vendored
@ -1,64 +0,0 @@
|
|||||||
name: Docker
|
|
||||||
|
|
||||||
# This workflow uses actions that are not certified by GitHub.
|
|
||||||
# They are provided by a third-party and are governed by
|
|
||||||
# separate terms of service, privacy policy, and support
|
|
||||||
# documentation.
|
|
||||||
|
|
||||||
on:
|
|
||||||
#schedule:
|
|
||||||
# - cron: '21 19 * * *'
|
|
||||||
push:
|
|
||||||
branches: [ master ]
|
|
||||||
# Publish semver tags as releases.
|
|
||||||
tags: [ 'v*.*.*' ]
|
|
||||||
#pull_request:
|
|
||||||
# branches: [ master ]
|
|
||||||
|
|
||||||
env:
|
|
||||||
# Use docker.io for Docker Hub if empty
|
|
||||||
REGISTRY: ghcr.io
|
|
||||||
# github.repository as <account>/<repo>
|
|
||||||
IMAGE_NAME: ${{ github.repository }}
|
|
||||||
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
packages: write
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
|
|
||||||
# Login against a Docker registry except on PR
|
|
||||||
# https://github.com/docker/login-action
|
|
||||||
- name: Log into registry ${{ env.REGISTRY }}
|
|
||||||
if: github.event_name != 'pull_request'
|
|
||||||
uses: docker/login-action@28218f9b04b4f3f62068d7b6ce6ca5b26e35336c
|
|
||||||
with:
|
|
||||||
registry: ${{ env.REGISTRY }}
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
# Extract metadata (tags, labels) for Docker
|
|
||||||
# https://github.com/docker/metadata-action
|
|
||||||
- name: Extract Docker metadata
|
|
||||||
id: meta
|
|
||||||
uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
|
|
||||||
with:
|
|
||||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
|
||||||
#images: ${{ env.REGISTRY }}/newsbot.worker
|
|
||||||
|
|
||||||
# Build and push Docker image with Buildx (don't push on PR)
|
|
||||||
# https://github.com/docker/build-push-action
|
|
||||||
- name: Build and push Docker image
|
|
||||||
uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
push: ${{ github.event_name != 'pull_request' }}
|
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
|
11
Dockerfile
11
Dockerfile
@ -1,11 +1,14 @@
|
|||||||
FROM golang:1.20 as build
|
FROM golang:1.19 as build
|
||||||
|
|
||||||
COPY . /app
|
COPY . /app
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
RUN go build .
|
RUN go build .
|
||||||
|
|
||||||
FROM debian:latest as app
|
FROM alpine:latest as app
|
||||||
|
|
||||||
COPY --from=build /app/ddns /app
|
RUN apk --no-cache add bash libc6-compat && \
|
||||||
|
mkdir /app
|
||||||
|
|
||||||
CMD [ "/app/ddns" ]
|
COPY --from=build /app/ddns /usr/bin/ddns
|
||||||
|
|
||||||
|
CMD [ "ddns" ]
|
76
config.go
76
config.go
@ -6,26 +6,17 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/joho/godotenv"
|
"github.com/joho/godotenv"
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ConfigEmail = "EMAIL"
|
ConfigEmail = "EMAIL"
|
||||||
ConfigToken = "API_TOKEN"
|
ConfigToken = "API_TOKEN"
|
||||||
ConfigDomain = "DOMAIN"
|
ConfigDomain = "DOMAIN"
|
||||||
ConfigHosts = "HOSTS"
|
ConfigHosts = "HOSTS"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ConfigModel struct {
|
|
||||||
Email string `yaml:"Email"`
|
|
||||||
Token string `yaml:"Token"`
|
|
||||||
Domain string `yaml:"Domain"`
|
|
||||||
Hosts []string `yaml:"Hosts"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ConfigClient struct{}
|
type ConfigClient struct{}
|
||||||
|
|
||||||
func NewConfigClient() ConfigClient {
|
func NewConfigClient() ConfigClient {
|
||||||
@ -35,35 +26,6 @@ func NewConfigClient() ConfigClient {
|
|||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cc *ConfigClient) LoadConfig() ConfigModel {
|
|
||||||
// load yaml first
|
|
||||||
|
|
||||||
model, err := LoadYaml("config.yaml")
|
|
||||||
if err != nil {
|
|
||||||
log.Print(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// refresh env to make sure its current
|
|
||||||
cc.RefreshEnv()
|
|
||||||
|
|
||||||
// if no domains pulled from yaml, load from env
|
|
||||||
if len(model.Hosts) == 0 {
|
|
||||||
envHosts := cc.GetConfig(ConfigHosts)
|
|
||||||
model.Hosts = append(model.Hosts, strings.Split(envHosts, ",")...)
|
|
||||||
}
|
|
||||||
if model.Domain == "" {
|
|
||||||
model.Domain = cc.GetConfig(ConfigDomain)
|
|
||||||
}
|
|
||||||
if model.Email == "" {
|
|
||||||
model.Email = cc.GetConfig(ConfigEmail)
|
|
||||||
}
|
|
||||||
if model.Token == "" {
|
|
||||||
model.Token = cc.GetConfig(ConfigToken)
|
|
||||||
}
|
|
||||||
|
|
||||||
return model
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cc *ConfigClient) GetConfig(key string) string {
|
func (cc *ConfigClient) GetConfig(key string) string {
|
||||||
res, filled := os.LookupEnv(key)
|
res, filled := os.LookupEnv(key)
|
||||||
if !filled {
|
if !filled {
|
||||||
@ -107,34 +69,4 @@ func loadEnvFile() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cc *ConfigClient) IsConfigInCurrentDirectory(fileName string) error {
|
|
||||||
_, err := os.Stat(fileName)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func LoadYaml(yamlFile string) (ConfigModel, error) {
|
|
||||||
var results = ConfigModel{}
|
|
||||||
|
|
||||||
// check for the config in the current directory
|
|
||||||
_, err := os.Stat(yamlFile)
|
|
||||||
if err != nil {
|
|
||||||
return ConfigModel{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
content, err := os.ReadFile(yamlFile)
|
|
||||||
if err != nil {
|
|
||||||
return ConfigModel{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = yaml.Unmarshal(content, &results)
|
|
||||||
if err != nil {
|
|
||||||
return ConfigModel{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return results, nil
|
|
||||||
}
|
|
17
cron.go
17
cron.go
@ -7,7 +7,7 @@ import (
|
|||||||
"github.com/robfig/cron/v3"
|
"github.com/robfig/cron/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
type cronClient struct {
|
type cronClient struct{
|
||||||
scheduler *cron.Cron
|
scheduler *cron.Cron
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,18 +37,17 @@ func (c cronClient) RunCloudflareCheck(ApiToken string, Email string, Domain str
|
|||||||
log.Println(err)
|
log.Println(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, host := range Hosts {
|
for _, host := range Hosts {
|
||||||
hostname := fmt.Sprintf("%v.%v", host, Domain)
|
hostname := fmt.Sprintf("%v.%v", host, Domain)
|
||||||
log.Printf("Reviewing '%v'", hostname)
|
log.Printf("Reviewing '%v'", hostname)
|
||||||
dns, err := cf.GetDnsEntriesByDomain(domainDetails.Result[0].ID, host, Domain)
|
dns, err := cf.GetDnsEntriesByDomain(domainDetails.Result[0].ID, host, Domain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("failed to collect dns entry")
|
log.Println("failed to collect dns entry")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = dns.Result[0]
|
if dns.Result[0].Content != currentIp {
|
||||||
if result.Content != currentIp {
|
|
||||||
log.Println("IP Address no longer matches, sending an update")
|
log.Println("IP Address no longer matches, sending an update")
|
||||||
err = cf.UpdateDnsEntry(domainDetails.Result[0].ID, dns, currentIp)
|
err = cf.UpdateDnsEntry(domainDetails.Result[0].ID, dns, currentIp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -57,8 +56,4 @@ func (c cronClient) RunCloudflareCheck(ApiToken string, Email string, Domain str
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.Println("Done!")
|
log.Println("Done!")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c cronClient) HelloWorldJob() {
|
|
||||||
log.Print("Hello World")
|
|
||||||
}
|
|
2
go.mod
2
go.mod
@ -6,5 +6,3 @@ require (
|
|||||||
github.com/joho/godotenv v1.4.0
|
github.com/joho/godotenv v1.4.0
|
||||||
github.com/robfig/cron/v3 v3.0.1
|
github.com/robfig/cron/v3 v3.0.1
|
||||||
)
|
)
|
||||||
|
|
||||||
require gopkg.in/yaml.v3 v3.0.1 // indirect
|
|
||||||
|
3
go.sum
3
go.sum
@ -2,6 +2,3 @@ github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg=
|
|||||||
github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
|
35
main.go
35
main.go
@ -5,15 +5,16 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrInvalidStatusCode error = errors.New("did not get an acceptiable status code from the server")
|
ErrInvalidStatusCode error = errors.New("did not get an acceptiable status code from the server")
|
||||||
ErrFailedToDecodeBody error = errors.New("unable to decode the body")
|
ErrFailedToDecodeBody error = errors.New("unable to decode the body")
|
||||||
ErrFailedToDecodeJson error = errors.New("unexpected json format was returned")
|
ErrFailedToDecodeJson error = errors.New("unexpected json format was returned")
|
||||||
ErrWasNotJson error = errors.New("response from server was not json")
|
ErrWasNotJson error = errors.New("response from server was not json")
|
||||||
ErrDomainNotFound error = errors.New("unable to find requested domain on cloudflare")
|
ErrDomainNotFound error = errors.New("unable to find requested domain on cloudflare")
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetCurrentIpAddress() (string, error) {
|
func GetCurrentIpAddress() (string, error) {
|
||||||
@ -37,36 +38,33 @@ func GetCurrentIpAddress() (string, error) {
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
config := NewConfigClient()
|
config := NewConfigClient()
|
||||||
cfg := config.LoadConfig()
|
email := config.GetConfig(ConfigEmail)
|
||||||
|
if email == "" {
|
||||||
if cfg.Email == "" {
|
|
||||||
log.Println("Unable to find 'EMAIL' env value.")
|
log.Println("Unable to find 'EMAIL' env value.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.Token == "" {
|
token := config.GetConfig(ConfigToken)
|
||||||
|
if token == "" {
|
||||||
log.Println("Unable to find 'API_TOKEN' env value.")
|
log.Println("Unable to find 'API_TOKEN' env value.")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.Domain == "" {
|
domain := config.GetConfig(ConfigDomain)
|
||||||
|
if token == "" {
|
||||||
log.Println("Unable to find 'DOMAIN' env value.")
|
log.Println("Unable to find 'DOMAIN' env value.")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(cfg.Hosts) == 0 {
|
hosts := config.GetConfig(ConfigHosts)
|
||||||
|
if token == "" {
|
||||||
log.Println("Unable to find 'HOSTS' env value.")
|
log.Println("Unable to find 'HOSTS' env value.")
|
||||||
}
|
}
|
||||||
|
hostsArray := strings.Split(hosts, ",")
|
||||||
log.Println("Config Check: OK")
|
log.Println("Env Check: OK")
|
||||||
|
|
||||||
cron := NewCron()
|
cron := NewCron()
|
||||||
log.Println("Cloudflare Check will run every 15 minutes.")
|
log.Println("Cloudflare Check will run every 15 minutes.")
|
||||||
cron.scheduler.AddFunc("0/5 * * * *", func() {
|
cron.scheduler.AddFunc("0,15,30,45 * * * *", func() {
|
||||||
cron.RunCloudflareCheck(cfg.Token, cfg.Email, cfg.Domain, cfg.Hosts)
|
cron.RunCloudflareCheck(token, email, domain, hostsArray)
|
||||||
})
|
|
||||||
cron.scheduler.AddFunc("0/1 * * * *", func() {
|
|
||||||
cron.HelloWorldJob()
|
|
||||||
})
|
})
|
||||||
cron.scheduler.Start()
|
cron.scheduler.Start()
|
||||||
|
|
||||||
@ -76,3 +74,4 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user