diff --git a/.github/workflows/dev.yaml b/.github/workflows/dev.yaml index 69e9e10..507595d 100644 --- a/.github/workflows/dev.yaml +++ b/.github/workflows/dev.yaml @@ -1,5 +1,5 @@ --- -name: build on push dev +name: CI devel on: push: @@ -7,6 +7,35 @@ on: - "devel" jobs: + gosec: + runs-on: ubuntu-latest + env: + GO111MODULE: on + steps: + - name: Checkout Source + uses: actions/checkout@v2 + - name: Run Gosec Security Scanner + uses: securego/gosec@master + with: + # we let the report trigger content trigger a failure using the GitHub Security features. + args: "-no-fail -fmt sarif -out results.sarif ./..." + - name: Upload SARIF file + uses: github/codeql-action/upload-sarif@v1 + with: + # Path to SARIF file relative to the root of the repository + sarif_file: results.sarif + snyk: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - uses: snyk/actions/setup@master + - uses: actions/setup-go@v2.1.5 + with: + go-version: "1.17" + - name: Snyk monitor + run: snyk test + env: + SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} build: runs-on: ubuntu-latest steps: diff --git a/.github/workflows/gobuild.yml b/.github/workflows/gobuild.yml index 9145051..cb88776 100644 --- a/.github/workflows/gobuild.yml +++ b/.github/workflows/gobuild.yml @@ -10,5 +10,5 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: actions/setup-go@v2 + - uses: actions/setup-go@v2.1.5 - run: go build . diff --git a/config/config.go b/config/config.go index 5b74e3a..0b4c007 100644 --- a/config/config.go +++ b/config/config.go @@ -2,6 +2,7 @@ package config import ( "os" + "path/filepath" "strconv" uip_aws "github.com/azrod/updateip/pkg/providers/aws" @@ -76,11 +77,15 @@ func LoadConfig() (config CFG) { } // open yaml file - f, err := os.Open(dir + "/" + file) + f, err := os.Open(filepath.Clean(dir + "/" + file)) if err != nil { log.Error().Err(err).Str("path", dir+"/"+file).Msg("Failed to open config file") } else { - defer f.Close() + defer func() { + if err := f.Close(); err != nil { + log.Error().Err(err).Msg("Error closing file") + } + }() // read yaml file err = yaml.NewDecoder(f).Decode(&config) diff --git a/docs/advanced/metrics.md b/docs/advanced/metrics.md index b9ad4ea..e7a9426 100644 --- a/docs/advanced/metrics.md +++ b/docs/advanced/metrics.md @@ -21,7 +21,7 @@ You have some options to enable metrics server. | metrics.path | /metrics | :heavy_multiplication_x: | Path for acceding to metrics web server | | | | | | -```yaml title=config.yaml" +```yaml title="config.yaml" metrics: enable: true # Default: false port: 8080 # Default : 8080 @@ -34,7 +34,6 @@ metrics: | Options | Actions | | -------------- | --------------------------------------- | -| | | | METRICS_ENABLE | Define if start metrics web server | | METRICS_HOST | Set IP address for metrics web server | | METRICS_PORT | Set port for metrics web server | @@ -48,16 +47,38 @@ METRICS_ENABLE=true ./updateip ### Global -| Metrics Name | Description | -| ---------------------------- | -------------------- | -| | | -| updateip_count_event_receive | Total event received | +| Metrics Name | Description | +| ---------------------- | ------------------------------------------ | +| go_build_info | Build information about the main Go module | +| go_gc_duration_seconds | Go garbage collection duration | +| go_goroutines | Number of goroutines | +| go_info | Go runtime information | +| go_memstats_* | Go runtime memory statistics | +| go_threads | Number of threads | ### AWS Provider -| Metrics Name | Description | -| ---------------------- | ------------------------------------ | -| | | -| updateip_aws_func_time | Execution time of each function | -| updateip_aws_status | Return Status of AWS Provider | -| updateip_aws_update | Number of DNS record validity checks | +| Metrics Name | Description | +| -------------------------- | ------------------------------------ | +| updateip_aws_func_time | Execution time of each function | +| updateip_aws_status | Return Status of AWS Provider | +| updateip_aws_update | Number of DNS record validity checks | +| updateip_aws_event_receive | Count of events received | + +### Cloudflare Provider + +| Metrics Name | Description | +| --------------------------------- | ------------------------------------ | +| updateip_cloudflare_func_time | Execution time of each function | +| updateip_cloudflare_status | Return Status of Cloudflare Provider | +| updateip_cloudflare_update | Number of DNS record validity checks | +| updateip_cloudflare_event_receive | Count of events received | + +### OVH Provider + +| Metrics Name | Description | +| -------------------------- | ------------------------------------ | +| updateip_ovh_func_time | Execution time of each function | +| updateip_ovh_status | Return Status of OVH Provider | +| updateip_ovh_update | Number of DNS record validity checks | +| updateip_ovh_event_receive | Count of events received | diff --git a/docs/getting-started.md b/docs/getting-started.md index 899380e..99d8046 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -18,7 +18,7 @@ docker run -itd \ Create the **config.yaml** configuration file -```yaml +```yaml title="config.yaml" log: level: debug # Available : trace debug info warn error fatal panic humanize: true # Default: false @@ -28,4 +28,4 @@ log: ## Setup your provider -Go to the [provider documentation](providers.md) to setup your provider. +Go to the [provider documentation](/providers/) to setup your provider. diff --git a/docs/providers/index.md b/docs/providers/index.md new file mode 100644 index 0000000..2aeb81a --- /dev/null +++ b/docs/providers/index.md @@ -0,0 +1,7 @@ +# Providers + +A lot of providers are available. + +* [AWS](aws.md) +* [Cloudflare](cloudflare.md) +* [OVH](ovh.md) \ No newline at end of file diff --git a/go.mod b/go.mod index c3a43dc..0b86ef5 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/azrod/updateip go 1.17 require ( - github.com/aws/aws-sdk-go v1.42.27 + github.com/aws/aws-sdk-go v1.42.28 github.com/cloudflare/cloudflare-go v0.29.0 github.com/gorilla/mux v1.8.0 github.com/jpillora/go-tld v1.1.1 diff --git a/go.sum b/go.sum index 3d90d6f..52fc312 100644 --- a/go.sum +++ b/go.sum @@ -38,8 +38,8 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/aws/aws-sdk-go v1.42.27 h1:kxsBXQg3ee6LLbqjp5/oUeDgG7TENFrWYDmEVnd7spU= -github.com/aws/aws-sdk-go v1.42.27/go.mod h1:OGr6lGMAKGlG9CVrYnWYDKIyb829c6EVBRjxqjmPepc= +github.com/aws/aws-sdk-go v1.42.28 h1:YJtgL7IGSN41saY4JLW08jya5nU0vGcuAeAa1OL2M6c= +github.com/aws/aws-sdk-go v1.42.28/go.mod h1:OGr6lGMAKGlG9CVrYnWYDKIyb829c6EVBRjxqjmPepc= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= diff --git a/main.go b/main.go index 3aa0512..e01e873 100644 --- a/main.go +++ b/main.go @@ -112,6 +112,14 @@ func main() { m.RegisterPkg(Paws.RegistryMetrics()) } + if c.Providers.CLOUDFLAREAccount.Enable { + m.RegisterPkg(PCloudflare.RegistryMetrics()) + } + + if c.Providers.OVHAccount.Enable { + m.RegisterPkg(PCloudflare.RegistryMetrics()) + } + m.Run() } @@ -122,9 +130,6 @@ LOOP: for { select { case sig := <-sigs: - if c.Metrics.Enable { - (*m.Counters)["eventReceive"].Inc() - } log.Info().Msg(sig.String()) break LOOP } diff --git a/mkdocs.yml b/mkdocs.yml index 2377c23..42e37d8 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -23,7 +23,7 @@ nav: - Getting Started: "getting-started.md" - Setup: - Docker: "setup/docker.md" - - Docker Compose: "setup/docker.md" + - Docker Compose: "setup/docker-compose.md" - Source: "setup/source.md" - Config File: "setup/configfile.md" - Env vars: "setup/envvars.md" diff --git a/pkg/metrics/metrics.go b/pkg/metrics/metrics.go index 506fd36..3f04672 100644 --- a/pkg/metrics/metrics.go +++ b/pkg/metrics/metrics.go @@ -66,6 +66,8 @@ func (m *Metrics) RegisterPkg(rg map[string][]interface{}) { for _, v := range rg["gaugeVec"] { m.registry.MustRegister(v.(*prometheus.HistogramVec)) } + + m.registry.MustRegister(collectors.NewGoCollector()) } func (m *Metrics) hTTPServer() { diff --git a/pkg/providers/aws/aws.go b/pkg/providers/aws/aws.go index 0365e3f..98f532c 100644 --- a/pkg/providers/aws/aws.go +++ b/pkg/providers/aws/aws.go @@ -168,7 +168,8 @@ func (d *Paws) Run() error { for { select { case e := <-d.Events: - log.Info().Msgf("Event: %s", e) + eventReceive.Inc() + log.Info().Msgf("Event => %s", e) case <-d.Loop.C: if ok, err := d.GetChangeStatus(); ok && err == nil { diff --git a/pkg/providers/aws/metrics.go b/pkg/providers/aws/metrics.go index 9fa2c16..a244f68 100644 --- a/pkg/providers/aws/metrics.go +++ b/pkg/providers/aws/metrics.go @@ -29,12 +29,19 @@ var ( }, []string{"where"}, ) + + eventReceive = prometheus.NewCounter( + prometheus.CounterOpts{ + Name: "updateip_aws_event_receive", + Help: "Count of events received on AWS Provider.", + }, + ) ) func (d *Paws) RegistryMetrics() map[string][]interface{} { x := make(map[string][]interface{}) - x["counter"] = []interface{}{countUpdate} + x["counter"] = []interface{}{countUpdate, eventReceive} x["gauge"] = []interface{}{providerStatus} x["gaugeVec"] = []interface{}{funcTime} diff --git a/pkg/providers/cloudflare/cloudflare.go b/pkg/providers/cloudflare/cloudflare.go index 31a187a..dbd2b35 100644 --- a/pkg/providers/cloudflare/cloudflare.go +++ b/pkg/providers/cloudflare/cloudflare.go @@ -20,6 +20,8 @@ var ( // Setup new cloudflare client func (d *PCloudflare) NewClient() error { + defer timeTrackS(time.Now(), "cloudflare_NewClient") + var err error log.Trace().Msg("Creating new Cloudflare client") @@ -44,6 +46,7 @@ func (d *PCloudflare) NewClient() error { // Update record with new IP func (d *PCloudflare) UpdateRecord(ip net.IP) error { + defer timeTrackS(time.Now(), "cloudflare_UpdateRecord") var err error ctx := context.Background() @@ -114,6 +117,8 @@ func (d *PCloudflare) loopCheckApply(ip string) bool { // Get record func (d *PCloudflare) GetRecord() (record string, err error) { + defer timeTrackS(time.Now(), "cloudflare_GetRecord") + log.Trace().Msg("Getting record") if rec.Expire.After(time.Now()) || rec.LastValue == "" { @@ -148,7 +153,8 @@ func (d *PCloudflare) Run() error { for { select { case e := <-d.Events: - log.Info().Msgf("Event: => %s", e) + eventReceive.Inc() + log.Info().Msgf("Event => %s", e) case <-d.Loop.C: r, err := d.GetRecord() @@ -164,7 +170,6 @@ func (d *PCloudflare) Run() error { } if r != i.String() { - // go lock() log.Info().Str("DNSIP", r).Str("ActualIP", i.String()).Msg("New IP address detected. Update") if err = d.UpdateRecord(i); err != nil { diff --git a/pkg/providers/cloudflare/metrics.go b/pkg/providers/cloudflare/metrics.go new file mode 100644 index 0000000..dbf1a44 --- /dev/null +++ b/pkg/providers/cloudflare/metrics.go @@ -0,0 +1,55 @@ +package uip_cloudflare + +import ( + "time" + + "github.com/prometheus/client_golang/prometheus" +) + +var ( + countUpdate = prometheus.NewCounter( + prometheus.CounterOpts{ + Name: "updateip_cloudflare_update", + Help: "Number of ip updated on Cloudflare provider.", + }, + ) + + // Status ... + providerStatus = prometheus.NewGauge( + prometheus.GaugeOpts{ + Name: "updateip_cloudflare_status", + Help: "cloudflare Providers status.", + }, + ) + + // Histo ... + funcTime = prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Name: "updateip_cloudflare_func_time", + Help: "Time taken to do ...", + }, + []string{"where"}, + ) + + eventReceive = prometheus.NewCounter( + prometheus.CounterOpts{ + Name: "updateip_cloudflare_event_receive", + Help: "Count of events received on Cloudflare.", + }, + ) +) + +func (d *PCloudflare) RegistryMetrics() map[string][]interface{} { + + x := make(map[string][]interface{}) + x["counter"] = []interface{}{countUpdate} + x["gauge"] = []interface{}{providerStatus} + x["gaugeVec"] = []interface{}{funcTime} + + return x +} + +// TimeTrackS ... +func timeTrackS(start time.Time, name string) { + elapsed := time.Since(start) + funcTime.WithLabelValues(name).Observe(elapsed.Seconds()) +} diff --git a/pkg/providers/ovh/metrics.go b/pkg/providers/ovh/metrics.go new file mode 100644 index 0000000..9f4d1ac --- /dev/null +++ b/pkg/providers/ovh/metrics.go @@ -0,0 +1,55 @@ +package uip_ovh + +import ( + "time" + + "github.com/prometheus/client_golang/prometheus" +) + +var ( + countUpdate = prometheus.NewCounter( + prometheus.CounterOpts{ + Name: "updateip_ovh_update", + Help: "Number of ip updated on OVH provider.", + }, + ) + + // Status ... + providerStatus = prometheus.NewGauge( + prometheus.GaugeOpts{ + Name: "updateip_ovh_status", + Help: "cloudflare Providers status.", + }, + ) + + // Histo ... + funcTime = prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Name: "updateip_ovh_func_time", + Help: "Time taken to do ...", + }, + []string{"where"}, + ) + + eventReceive = prometheus.NewCounter( + prometheus.CounterOpts{ + Name: "updateip_ovh_event_receive", + Help: "Count of events received on OVH Provider.", + }, + ) +) + +func (d *Povh) RegistryMetrics() map[string][]interface{} { + + x := make(map[string][]interface{}) + x["counter"] = []interface{}{countUpdate} + x["gauge"] = []interface{}{providerStatus} + x["gaugeVec"] = []interface{}{funcTime} + + return x +} + +// TimeTrackS ... +func timeTrackS(start time.Time, name string) { + elapsed := time.Since(start) + funcTime.WithLabelValues(name).Observe(elapsed.Seconds()) +} diff --git a/pkg/providers/ovh/ovh.go b/pkg/providers/ovh/ovh.go index a4a4058..1f33d24 100644 --- a/pkg/providers/ovh/ovh.go +++ b/pkg/providers/ovh/ovh.go @@ -13,6 +13,8 @@ import ( // New Client func (d *Povh) NewClient() (err error) { + defer timeTrackS(time.Now(), "ovh_NewClient") + d.clients.ovh, err = ovh.NewClient( d.Secret.Region, d.Secret.ApplicationKey, @@ -32,6 +34,7 @@ func (d *Povh) NewClient() (err error) { // update record func (d *Povh) UpdateRecord(recordID int, ip net.IP) (err error) { + defer timeTrackS(time.Now(), "ovh_UpdateRecord") var respData txtRecordResponse reqData := txtRecordRequest{FieldType: "A", Target: ip.String(), TTL: 300} @@ -53,7 +56,7 @@ func (d *Povh) UpdateRecord(recordID int, ip net.IP) (err error) { // get record ID func (d *Povh) GetRecordID() (recordID int, err error) { - + defer timeTrackS(time.Now(), "ovh_GetRecordID") var records []int err = d.clients.ovh.Get( "/domain/zone/"+d.Record.Zone+"/record?fieldType=TXT&subDomain="+d.Record.Name, @@ -91,7 +94,7 @@ func (d *Povh) GetRecordID() (recordID int, err error) { // get record with record ID func (d *Povh) GetRecord(recordID int) (record string, err error) { - + defer timeTrackS(time.Now(), "ovh_GetRecord") var respData txtRecordResponse err = d.clients.ovh.Get( "/domain/zone/"+d.Record.Zone+"/record/"+fmt.Sprint(recordID), @@ -108,6 +111,7 @@ func (d *Povh) GetRecord(recordID int) (record string, err error) { // GetchangeStatus returns the status of the change func (d *Povh) GetChangeStatus() (status bool, err error) { + defer timeTrackS(time.Now(), "ovh_GetChangeStatus") var respData StatusResponse err = d.clients.ovh.Get("/domain/zone/"+d.Record.Zone+"/status", respData) return respData.IsDeployed, err @@ -115,6 +119,7 @@ func (d *Povh) GetChangeStatus() (status bool, err error) { // Refresh Zone Records func (d *Povh) RefreshZoneRecords() (err error) { + defer timeTrackS(time.Now(), "ovh_RefreshZoneRecords") var respData []int err = d.clients.ovh.Post( "/domain/zone/"+d.Record.Zone+"/refresh", @@ -150,7 +155,8 @@ func (d *Povh) Run() (err error) { for { select { case e := <-d.Events: - log.Info().Msgf("Event: %s", e) + eventReceive.Inc() + log.Info().Msgf("Event => %s", e) case <-d.Loop.C: if ok, err := d.GetChangeStatus(); ok && err == nil { @@ -172,7 +178,6 @@ func (d *Povh) Run() (err error) { } if r != i.String() { - // go lock() log.Info().Str("DNSIP", r).Str("ActualIP", i.String()).Msg("New IP address detected. Update") if err = d.UpdateRecord(recordID, i); err != nil { log.Error().Err(err).Msg("Failed to update dns record")