Code refactoring to singleton; Added metrics
This commit is contained in:
parent
7df1ea3a0d
commit
bb257692af
5 changed files with 360 additions and 119 deletions
5
go.mod
5
go.mod
|
@ -1,11 +1,8 @@
|
||||||
module openvpn-web-ui
|
module openvpn-admin
|
||||||
|
|
||||||
go 1.14
|
go 1.14
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/Electronn/openvpn_exporter v0.0.0-20181005212047-37f639dc9c7d
|
|
||||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect
|
|
||||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect
|
|
||||||
github.com/prometheus/client_golang v1.8.0
|
github.com/prometheus/client_golang v1.8.0
|
||||||
github.com/prometheus/common v0.15.0 // indirect
|
github.com/prometheus/common v0.15.0 // indirect
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6
|
||||||
|
|
11
go.sum
11
go.sum
|
@ -1,8 +1,6 @@
|
||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/Electronn/openvpn_exporter v0.0.0-20181005212047-37f639dc9c7d h1:OsbfZPacTMb2ljULx/g4Xt9mSbkVx/lfuYQQwbgkD5c=
|
|
||||||
github.com/Electronn/openvpn_exporter v0.0.0-20181005212047-37f639dc9c7d/go.mod h1:wcYOspX0l7/kR2Pd59EUppVpfzvVu/I+vBgMmDOmNH0=
|
|
||||||
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||||
|
@ -44,6 +42,7 @@ github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfc
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||||
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||||
|
@ -92,6 +91,7 @@ github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
|
||||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
|
@ -143,8 +143,10 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
|
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
|
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
|
||||||
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
|
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
|
||||||
|
@ -201,6 +203,7 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
|
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
|
||||||
|
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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||||
|
@ -256,6 +259,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||||
|
@ -353,6 +357,7 @@ golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtn
|
||||||
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
|
@ -383,6 +388,7 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQ
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
|
@ -396,6 +402,7 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
|
13
helpers.go
13
helpers.go
|
@ -10,13 +10,20 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func indexTxtDateToHumanReadable(datetime string) string {
|
func parseDate(layout,datetime string) time.Time {
|
||||||
layout := "060102150405Z"
|
|
||||||
t, err := time.Parse(layout, datetime)
|
t, err := time.Parse(layout, datetime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
}
|
}
|
||||||
return t.Format("2006-01-02 15:04:05")
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseDateToString(layout,datetime,format string) string {
|
||||||
|
return parseDate(layout, datetime).Format(format)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseDateToUnix(layout,datetime string) int64 {
|
||||||
|
return parseDate(layout, datetime).Unix()
|
||||||
}
|
}
|
||||||
|
|
||||||
func runBash(script string) string {
|
func runBash(script string) string {
|
||||||
|
|
448
main.go
448
main.go
|
@ -5,12 +5,15 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
"gopkg.in/alecthomas/kingpin.v2"
|
"gopkg.in/alecthomas/kingpin.v2"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
"time"
|
"time"
|
||||||
|
@ -22,9 +25,13 @@ const (
|
||||||
downloadCcdApiUrl = "/api/data/ccd/download"
|
downloadCcdApiUrl = "/api/data/ccd/download"
|
||||||
certsArchiveFileName = "certs.tar.gz"
|
certsArchiveFileName = "certs.tar.gz"
|
||||||
ccdArchiveFileName = "ccd.tar.gz"
|
ccdArchiveFileName = "ccd.tar.gz"
|
||||||
|
indexTxtDateLayout = "060102150405Z"
|
||||||
|
stringDateFormat = "2006-01-02 15:04:05"
|
||||||
|
ovpnStatusDateLayout = "Mon Jan 2 15:04:05 2006"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
||||||
listenHost = kingpin.Flag("listen.host","host for openvpn-admin").Default("0.0.0.0").String()
|
listenHost = kingpin.Flag("listen.host","host for openvpn-admin").Default("0.0.0.0").String()
|
||||||
listenPort = kingpin.Flag("listen.port","port for openvpn-admin").Default("8080").String()
|
listenPort = kingpin.Flag("listen.port","port for openvpn-admin").Default("8080").String()
|
||||||
serverRole = kingpin.Flag("role","server role master or slave").Default("master").HintOptions("master", "slave").String()
|
serverRole = kingpin.Flag("role","server role master or slave").Default("master").HintOptions("master", "slave").String()
|
||||||
|
@ -37,6 +44,7 @@ var (
|
||||||
openvpnNetwork = kingpin.Flag("ovpn.network","network for openvpn server").Default("172.16.100.0/24").String()
|
openvpnNetwork = kingpin.Flag("ovpn.network","network for openvpn server").Default("172.16.100.0/24").String()
|
||||||
mgmtListenHost = kingpin.Flag("mgmt.host","host for openvpn server mgmt interface").Default("127.0.0.1").String()
|
mgmtListenHost = kingpin.Flag("mgmt.host","host for openvpn server mgmt interface").Default("127.0.0.1").String()
|
||||||
mgmtListenPort = kingpin.Flag("mgmt.port","port for openvpn server mgmt interface").Default("8989").String()
|
mgmtListenPort = kingpin.Flag("mgmt.port","port for openvpn server mgmt interface").Default("8989").String()
|
||||||
|
metricsPath = kingpin.Flag("metrics.path", "URL path for surfacing collected metrics").Default("/metrics").String()
|
||||||
easyrsaDirPath = kingpin.Flag("easyrsa.path", "path to easyrsa dir").Default("/mnt/easyrsa").String()
|
easyrsaDirPath = kingpin.Flag("easyrsa.path", "path to easyrsa dir").Default("/mnt/easyrsa").String()
|
||||||
indexTxtPath = kingpin.Flag("easyrsa.index-path", "path to easyrsa index file.").Default("/mnt/easyrsa/pki/index.txt").String()
|
indexTxtPath = kingpin.Flag("easyrsa.index-path", "path to easyrsa index file.").Default("/mnt/easyrsa/pki/index.txt").String()
|
||||||
ccdDir = kingpin.Flag("ccd.path", "path to client-config-dir").Default("/mnt/ccd").String()
|
ccdDir = kingpin.Flag("ccd.path", "path to client-config-dir").Default("/mnt/ccd").String()
|
||||||
|
@ -45,11 +53,95 @@ var (
|
||||||
|
|
||||||
certsArchivePath = "/tmp/" + certsArchiveFileName
|
certsArchivePath = "/tmp/" + certsArchiveFileName
|
||||||
ccdArchivePath = "/tmp/" + ccdArchiveFileName
|
ccdArchivePath = "/tmp/" + ccdArchiveFileName
|
||||||
lastSyncTime = ""
|
|
||||||
lastSuccessfulSyncTime = ""
|
|
||||||
masterHostBasicAuth = false
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
|
||||||
|
ovpnServerCertExpire = prometheus.NewGauge(prometheus.GaugeOpts{
|
||||||
|
Name: "ovpn_server_cert_expire",
|
||||||
|
Help: "openvpn server certificate expire time in days",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
ovpnServerCaCertExpire = prometheus.NewGauge(prometheus.GaugeOpts{
|
||||||
|
Name: "ovpn_server_ca_cert_expire",
|
||||||
|
Help: "openvpn server CA certificate expire time in days",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
ovpnClientsTotal = prometheus.NewGauge(prometheus.GaugeOpts{
|
||||||
|
Name: "ovpn_clients_total",
|
||||||
|
Help: "total openvpn users",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
ovpnClientsRevoked = prometheus.NewGauge(prometheus.GaugeOpts{
|
||||||
|
Name: "ovpn_clients_revoked",
|
||||||
|
Help: "revoked openvpn users",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
ovpnClientsExpired = prometheus.NewGauge(prometheus.GaugeOpts{
|
||||||
|
Name: "ovpn_clients_expired",
|
||||||
|
Help: "expired openvpn users",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
ovpnClientsConnected = prometheus.NewGauge(prometheus.GaugeOpts{
|
||||||
|
Name: "ovpn_clients_connected",
|
||||||
|
Help: "connected openvpn users",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
ovpnClientCertificateExpire = prometheus.NewGaugeVec(prometheus.GaugeOpts{
|
||||||
|
Name: "ovpn_client_cert_expire",
|
||||||
|
Help: "openvpn user certificate expire time in days",
|
||||||
|
},
|
||||||
|
[]string{"client"},
|
||||||
|
)
|
||||||
|
|
||||||
|
ovpnClientConnectionInfo = prometheus.NewGaugeVec(prometheus.GaugeOpts{
|
||||||
|
Name: "ovpn_client_connection_info",
|
||||||
|
Help: "openvpn user connection info. ip - assigned address from opvn network. value - last time when connection was refreshed in unix format",
|
||||||
|
},
|
||||||
|
[]string{"client", "ip"},
|
||||||
|
)
|
||||||
|
|
||||||
|
ovpnClientConnectionFrom = prometheus.NewGaugeVec(prometheus.GaugeOpts{
|
||||||
|
Name: "ovpn_client_connection_from",
|
||||||
|
Help: "openvpn user connection info. ip - from which address connection was initialized. value - time when connection was initialized in unix format",
|
||||||
|
},
|
||||||
|
[]string{"client", "ip"},
|
||||||
|
)
|
||||||
|
|
||||||
|
ovpnClientBytesReceived = prometheus.NewGaugeVec(prometheus.GaugeOpts{
|
||||||
|
Name: "ovpn_client_bytes_received",
|
||||||
|
Help: "openvpn user bytes received",
|
||||||
|
},
|
||||||
|
[]string{"client"},
|
||||||
|
)
|
||||||
|
|
||||||
|
ovpnClientBytesSent = prometheus.NewGaugeVec(prometheus.GaugeOpts{
|
||||||
|
Name: "ovpn_client_bytes_sent",
|
||||||
|
Help: "openvpn user bytes sent",
|
||||||
|
},
|
||||||
|
[]string{"client"},
|
||||||
|
)
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
type OpenvpnAdmin struct {
|
||||||
|
role string
|
||||||
|
lastSyncTime string
|
||||||
|
lastSuccessfulSyncTime string
|
||||||
|
masterHostBasicAuth bool
|
||||||
|
masterSyncToken string
|
||||||
|
clients []OpenvpnClient
|
||||||
|
activeClients []clientStatus
|
||||||
|
promRegistry *prometheus.Registry
|
||||||
|
}
|
||||||
|
|
||||||
type OpenvpnServer struct {
|
type OpenvpnServer struct {
|
||||||
Host string
|
Host string
|
||||||
Port string
|
Port string
|
||||||
|
@ -101,23 +193,28 @@ type clientStatus struct {
|
||||||
ConnectedSince string
|
ConnectedSince string
|
||||||
VirtualAddress string
|
VirtualAddress string
|
||||||
LastRef string
|
LastRef string
|
||||||
ConnectedSinceFormated string
|
ConnectedSinceFormatted string
|
||||||
LastRefFormated string
|
LastRefFormatted string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (oAdmin *OpenvpnAdmin) userListHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
func userListHandler(w http.ResponseWriter, r *http.Request) {
|
usersList, _ := json.Marshal(oAdmin.clients)
|
||||||
usersList, _ := json.Marshal(usersList())
|
|
||||||
fmt.Fprintf(w, "%s", usersList)
|
fmt.Fprintf(w, "%s", usersList)
|
||||||
}
|
}
|
||||||
|
|
||||||
func userCreateHandler(w http.ResponseWriter, r *http.Request) {
|
func (oAdmin *OpenvpnAdmin) userStatisticHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
if *serverRole == "slave" {
|
r.ParseForm()
|
||||||
|
userStatistic, _ := json.Marshal(oAdmin.getUserStatistic(r.FormValue("username")))
|
||||||
|
fmt.Fprintf(w, "%s", userStatistic)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (oAdmin *OpenvpnAdmin) userCreateHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if oAdmin.role == "slave" {
|
||||||
http.Error(w, `{"status":"error"}`, http.StatusLocked)
|
http.Error(w, `{"status":"error"}`, http.StatusLocked)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
r.ParseForm()
|
r.ParseForm()
|
||||||
userCreated, userCreateStatus := userCreate(r.FormValue("username"))
|
userCreated, userCreateStatus := oAdmin.userCreate(r.FormValue("username"))
|
||||||
|
|
||||||
if userCreated {
|
if userCreated {
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
|
@ -128,44 +225,44 @@ func userCreateHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func userRevokeHandler(w http.ResponseWriter, r *http.Request) {
|
func (oAdmin *OpenvpnAdmin) userRevokeHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
if *serverRole == "slave" {
|
if oAdmin.role == "slave" {
|
||||||
http.Error(w, `{"status":"error"}`, http.StatusLocked)
|
http.Error(w, `{"status":"error"}`, http.StatusLocked)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
r.ParseForm()
|
r.ParseForm()
|
||||||
fmt.Fprintf(w, "%s", userRevoke(r.FormValue("username")))
|
fmt.Fprintf(w, "%s", oAdmin.userRevoke(r.FormValue("username")))
|
||||||
}
|
}
|
||||||
|
|
||||||
func userUnrevokeHandler(w http.ResponseWriter, r *http.Request) {
|
func (oAdmin *OpenvpnAdmin) userUnrevokeHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
if *serverRole == "slave" {
|
if oAdmin.role == "slave" {
|
||||||
http.Error(w, `{"status":"error"}`, http.StatusLocked)
|
http.Error(w, `{"status":"error"}`, http.StatusLocked)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
r.ParseForm()
|
r.ParseForm()
|
||||||
fmt.Fprintf(w, "%s", userUnrevoke(r.FormValue("username")))
|
fmt.Fprintf(w, "%s", oAdmin.userUnrevoke(r.FormValue("username")))
|
||||||
}
|
}
|
||||||
|
|
||||||
func userShowConfigHandler(w http.ResponseWriter, r *http.Request) {
|
func (oAdmin *OpenvpnAdmin) userShowConfigHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
r.ParseForm()
|
r.ParseForm()
|
||||||
fmt.Fprintf(w, "%s", renderClientConfig(r.FormValue("username")))
|
fmt.Fprintf(w, "%s", oAdmin.renderClientConfig(r.FormValue("username")))
|
||||||
}
|
}
|
||||||
|
|
||||||
func userDisconnectHandler(w http.ResponseWriter, r *http.Request) {
|
func (oAdmin *OpenvpnAdmin) userDisconnectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
r.ParseForm()
|
r.ParseForm()
|
||||||
// fmt.Fprintf(w, "%s", userDisconnect(r.FormValue("username")))
|
// fmt.Fprintf(w, "%s", userDisconnect(r.FormValue("username")))
|
||||||
fmt.Fprintf(w, "%s", r.FormValue("username"))
|
fmt.Fprintf(w, "%s", r.FormValue("username"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func userShowCcdHandler(w http.ResponseWriter, r *http.Request) {
|
func (oAdmin *OpenvpnAdmin) userShowCcdHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
r.ParseForm()
|
r.ParseForm()
|
||||||
ccd, _ := json.Marshal(getCcd(r.FormValue("username")))
|
ccd, _ := json.Marshal(oAdmin.getCcd(r.FormValue("username")))
|
||||||
fmt.Fprintf(w, "%s", ccd)
|
fmt.Fprintf(w, "%s", ccd)
|
||||||
}
|
}
|
||||||
|
|
||||||
func userApplyCcdHandler(w http.ResponseWriter, r *http.Request) {
|
func (oAdmin *OpenvpnAdmin) userApplyCcdHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
if *serverRole == "slave" {
|
if oAdmin.role == "slave" {
|
||||||
http.Error(w, `{"status":"error"}`, http.StatusLocked)
|
http.Error(w, `{"status":"error"}`, http.StatusLocked)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -180,7 +277,7 @@ func userApplyCcdHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ccdApplied, applyStatus := modifyCcd(ccd)
|
ccdApplied, applyStatus := oAdmin.modifyCcd(ccd)
|
||||||
|
|
||||||
if ccdApplied {
|
if ccdApplied {
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
|
@ -191,27 +288,27 @@ func userApplyCcdHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func serverRoleHandler(w http.ResponseWriter, r *http.Request) {
|
func (oAdmin *OpenvpnAdmin) serverRoleHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
fmt.Fprintf(w, `{"status":"ok", "serverRole": "%s" }`, *serverRole)
|
fmt.Fprintf(w, `{"status":"ok", "serverRole": "%s" }`, oAdmin.role)
|
||||||
}
|
}
|
||||||
|
|
||||||
func lastSyncTimeHandler(w http.ResponseWriter, r *http.Request) {
|
func (oAdmin *OpenvpnAdmin) lastSyncTimeHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
fmt.Fprint(w, lastSyncTime)
|
fmt.Fprint(w, oAdmin.lastSyncTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
func lastSuccessfulSyncTimeHandler(w http.ResponseWriter, r *http.Request) {
|
func (oAdmin *OpenvpnAdmin) lastSuccessfulSyncTimeHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
fmt.Fprint(w, lastSuccessfulSyncTime)
|
fmt.Fprint(w, oAdmin.lastSuccessfulSyncTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
func downloadCertsHandler(w http.ResponseWriter, r *http.Request) {
|
func (oAdmin *OpenvpnAdmin) downloadCertsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
if *serverRole == "slave" {
|
if oAdmin.role == "slave" {
|
||||||
http.Error(w, `{"status":"error"}`, http.StatusLocked)
|
http.Error(w, `{"status":"error"}`, http.StatusLocked)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
r.ParseForm()
|
r.ParseForm()
|
||||||
token := r.Form.Get("token")
|
token := r.Form.Get("token")
|
||||||
|
|
||||||
if token != *masterSyncToken {
|
if token != oAdmin.masterSyncToken {
|
||||||
http.Error(w, `{"status":"error"}`, http.StatusForbidden)
|
http.Error(w, `{"status":"error"}`, http.StatusForbidden)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -221,15 +318,15 @@ func downloadCertsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
http.ServeFile(w,r, certsArchivePath)
|
http.ServeFile(w,r, certsArchivePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
func downloadCddHandler(w http.ResponseWriter, r *http.Request) {
|
func (oAdmin *OpenvpnAdmin) downloadCddHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
if *serverRole == "slave" {
|
if oAdmin.role == "slave" {
|
||||||
http.Error(w, `{"status":"error"}`, http.StatusLocked)
|
http.Error(w, `{"status":"error"}`, http.StatusLocked)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
r.ParseForm()
|
r.ParseForm()
|
||||||
token := r.Form.Get("token")
|
token := r.Form.Get("token")
|
||||||
|
|
||||||
if token != *masterSyncToken {
|
if token != oAdmin.masterSyncToken {
|
||||||
http.Error(w, `{"status":"error"}`, http.StatusForbidden)
|
http.Error(w, `{"status":"error"}`, http.StatusForbidden)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -242,35 +339,54 @@ func downloadCddHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
func main() {
|
func main() {
|
||||||
kingpin.Parse()
|
kingpin.Parse()
|
||||||
|
|
||||||
|
ovpnAdmin := new(OpenvpnAdmin)
|
||||||
|
ovpnAdmin.lastSyncTime = "unknown"
|
||||||
|
ovpnAdmin.role = *serverRole
|
||||||
|
ovpnAdmin.lastSuccessfulSyncTime = "unknown"
|
||||||
|
ovpnAdmin.masterSyncToken = *masterSyncToken
|
||||||
|
ovpnAdmin.promRegistry = prometheus.NewRegistry()
|
||||||
|
|
||||||
|
ovpnAdmin.registerMetrics()
|
||||||
|
ovpnAdmin.setState()
|
||||||
|
|
||||||
|
go ovpnAdmin.updateState()
|
||||||
|
|
||||||
if *masterBasicAuthPassword != "" && *masterBasicAuthUser != "" {
|
if *masterBasicAuthPassword != "" && *masterBasicAuthUser != "" {
|
||||||
masterHostBasicAuth = true
|
ovpnAdmin.masterHostBasicAuth = true
|
||||||
|
} else {
|
||||||
|
ovpnAdmin.masterHostBasicAuth = false
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Bind: http://" + *listenHost + ":" + *listenPort)
|
if ovpnAdmin.role == "slave" {
|
||||||
|
ovpnAdmin.syncDataFromMaster()
|
||||||
if *serverRole == "slave" {
|
go ovpnAdmin.syncWithMaster()
|
||||||
syncDataFromMaster()
|
|
||||||
go syncWithMaster()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fs := CacheControlWrapper(http.FileServer(http.Dir(*staticPath)))
|
fs := CacheControlWrapper(http.FileServer(http.Dir(*staticPath)))
|
||||||
|
|
||||||
http.Handle("/", fs)
|
http.Handle("/", fs)
|
||||||
http.HandleFunc("/api/server/role", serverRoleHandler)
|
http.HandleFunc("/api/server/role", ovpnAdmin.serverRoleHandler)
|
||||||
http.HandleFunc("/api/users/list", userListHandler)
|
http.HandleFunc("/api/users/list", ovpnAdmin.userListHandler)
|
||||||
http.HandleFunc("/api/user/create", userCreateHandler)
|
http.HandleFunc("/api/user/create", ovpnAdmin.userCreateHandler)
|
||||||
http.HandleFunc("/api/user/revoke", userRevokeHandler)
|
http.HandleFunc("/api/user/revoke", ovpnAdmin.userRevokeHandler)
|
||||||
http.HandleFunc("/api/user/unrevoke", userUnrevokeHandler)
|
http.HandleFunc("/api/user/unrevoke", ovpnAdmin.userUnrevokeHandler)
|
||||||
http.HandleFunc("/api/user/config/show", userShowConfigHandler)
|
http.HandleFunc("/api/user/config/show", ovpnAdmin.userShowConfigHandler)
|
||||||
http.HandleFunc("/api/user/disconnect", userDisconnectHandler)
|
http.HandleFunc("/api/user/disconnect", ovpnAdmin.userDisconnectHandler)
|
||||||
http.HandleFunc("/api/user/ccd", userShowCcdHandler)
|
http.HandleFunc("/api/user/statistic", ovpnAdmin.userStatisticHandler)
|
||||||
http.HandleFunc("/api/user/ccd/apply", userApplyCcdHandler)
|
http.HandleFunc("/api/user/ccd", ovpnAdmin.userShowCcdHandler)
|
||||||
|
http.HandleFunc("/api/user/ccd/apply", ovpnAdmin.userApplyCcdHandler)
|
||||||
|
|
||||||
http.HandleFunc("/api/sync/last/try", lastSyncTimeHandler)
|
http.HandleFunc("/api/sync/last/try", ovpnAdmin.lastSyncTimeHandler)
|
||||||
http.HandleFunc("/api/sync/last/successful", lastSuccessfulSyncTimeHandler)
|
http.HandleFunc("/api/sync/last/successful", ovpnAdmin.lastSuccessfulSyncTimeHandler)
|
||||||
http.HandleFunc(downloadCertsApiUrl, downloadCertsHandler)
|
http.HandleFunc(downloadCertsApiUrl, ovpnAdmin.downloadCertsHandler)
|
||||||
http.HandleFunc(downloadCcdApiUrl, downloadCddHandler)
|
http.HandleFunc(downloadCcdApiUrl, ovpnAdmin.downloadCddHandler)
|
||||||
|
|
||||||
|
http.Handle(*metricsPath, promhttp.HandlerFor(ovpnAdmin.promRegistry, promhttp.HandlerOpts{}))
|
||||||
|
http.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprintf(w, "pong")
|
||||||
|
})
|
||||||
|
|
||||||
|
fmt.Println("Bind: http://" + *listenHost + ":" + *listenPort)
|
||||||
log.Fatal(http.ListenAndServe(*listenHost + ":" + *listenPort, nil))
|
log.Fatal(http.ListenAndServe(*listenHost + ":" + *listenPort, nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,6 +397,38 @@ func CacheControlWrapper(h http.Handler) http.Handler {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (oAdmin *OpenvpnAdmin) registerMetrics() {
|
||||||
|
oAdmin.promRegistry.MustRegister(ovpnServerCertExpire)
|
||||||
|
oAdmin.promRegistry.MustRegister(ovpnServerCaCertExpire)
|
||||||
|
oAdmin.promRegistry.MustRegister(ovpnClientsTotal)
|
||||||
|
oAdmin.promRegistry.MustRegister(ovpnClientsRevoked)
|
||||||
|
oAdmin.promRegistry.MustRegister(ovpnClientsConnected)
|
||||||
|
oAdmin.promRegistry.MustRegister(ovpnClientsExpired)
|
||||||
|
oAdmin.promRegistry.MustRegister(ovpnClientCertificateExpire)
|
||||||
|
oAdmin.promRegistry.MustRegister(ovpnClientConnectionInfo)
|
||||||
|
oAdmin.promRegistry.MustRegister(ovpnClientConnectionFrom)
|
||||||
|
oAdmin.promRegistry.MustRegister(ovpnClientBytesReceived)
|
||||||
|
oAdmin.promRegistry.MustRegister(ovpnClientBytesSent)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (oAdmin *OpenvpnAdmin) setState() {
|
||||||
|
oAdmin.activeClients = oAdmin.mgmtGetActiveClients()
|
||||||
|
oAdmin.clients = oAdmin.usersList()
|
||||||
|
|
||||||
|
ovpnServerCaCertExpire.Set(float64(getOpvnCaCertExpireDate().Unix() - time.Now().Unix() / 3600 / 24))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (oAdmin *OpenvpnAdmin) updateState() {
|
||||||
|
for {
|
||||||
|
time.Sleep(time.Duration(28) * time.Second)
|
||||||
|
ovpnClientBytesSent.Reset()
|
||||||
|
ovpnClientBytesReceived.Reset()
|
||||||
|
ovpnClientConnectionFrom.Reset()
|
||||||
|
ovpnClientConnectionInfo.Reset()
|
||||||
|
go oAdmin.setState()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func indexTxtParser(txt string) []indexTxtLine {
|
func indexTxtParser(txt string) []indexTxtLine {
|
||||||
var indexTxt []indexTxtLine
|
var indexTxt []indexTxtLine
|
||||||
|
|
||||||
|
@ -298,6 +446,7 @@ func indexTxtParser(txt string) []indexTxtLine {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return indexTxt
|
return indexTxt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -315,7 +464,7 @@ func renderIndexTxt(data []indexTxtLine) string {
|
||||||
return indexTxt
|
return indexTxt
|
||||||
}
|
}
|
||||||
|
|
||||||
func renderClientConfig(username string) string {
|
func (oAdmin *OpenvpnAdmin) renderClientConfig(username string) string {
|
||||||
if checkUserExist(username) {
|
if checkUserExist(username) {
|
||||||
var hosts []OpenvpnServer
|
var hosts []OpenvpnServer
|
||||||
|
|
||||||
|
@ -333,18 +482,21 @@ func renderClientConfig(username string) string {
|
||||||
|
|
||||||
t, _ := template.ParseFiles("client.conf.tpl")
|
t, _ := template.ParseFiles("client.conf.tpl")
|
||||||
var tmp bytes.Buffer
|
var tmp bytes.Buffer
|
||||||
t.Execute(&tmp, conf)
|
err := t.Execute(&tmp, conf)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("WARNING: something goes wrong during rendering config for %s", username )
|
||||||
|
}
|
||||||
|
|
||||||
hosts = nil
|
hosts = nil
|
||||||
|
|
||||||
fmt.Printf("%+v\n", tmp.String())
|
fmt.Printf("%+v\n", tmp.String())
|
||||||
return (fmt.Sprintf("%+v\n", tmp.String()))
|
return fmt.Sprintf("%+v\n", tmp.String())
|
||||||
}
|
}
|
||||||
fmt.Printf("User \"%s\" not found", username)
|
fmt.Printf("User \"%s\" not found", username)
|
||||||
return fmt.Sprintf("User \"%s\" not found", username)
|
return fmt.Sprintf("User \"%s\" not found", username)
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseCcd(username string) Ccd {
|
func (oAdmin *OpenvpnAdmin) parseCcd(username string) Ccd {
|
||||||
ccd := Ccd{}
|
ccd := Ccd{}
|
||||||
ccd.User = username
|
ccd.User = username
|
||||||
ccd.ClientAddress = "dynamic"
|
ccd.ClientAddress = "dynamic"
|
||||||
|
@ -367,7 +519,7 @@ func parseCcd(username string) Ccd {
|
||||||
return ccd
|
return ccd
|
||||||
}
|
}
|
||||||
|
|
||||||
func modifyCcd(ccd Ccd) (bool, string) {
|
func (oAdmin *OpenvpnAdmin) modifyCcd(ccd Ccd) (bool, string) {
|
||||||
ccdErr := "something goes wrong"
|
ccdErr := "something goes wrong"
|
||||||
|
|
||||||
if fCreate(*ccdDir + "/" + ccd.User) {
|
if fCreate(*ccdDir + "/" + ccd.User) {
|
||||||
|
@ -446,14 +598,14 @@ func validateCcd(ccd Ccd) (bool, string) {
|
||||||
return true, ccdErr
|
return true, ccdErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func getCcd(username string) Ccd {
|
func (oAdmin *OpenvpnAdmin) getCcd(username string) Ccd {
|
||||||
ccd := Ccd{}
|
ccd := Ccd{}
|
||||||
ccd.User = username
|
ccd.User = username
|
||||||
ccd.ClientAddress = "dynamic"
|
ccd.ClientAddress = "dynamic"
|
||||||
ccd.CustomRoutes = []ccdRoute{}
|
ccd.CustomRoutes = []ccdRoute{}
|
||||||
|
|
||||||
if fCreate(*ccdDir + "/" + username) {
|
if fCreate(*ccdDir + "/" + username) {
|
||||||
ccd = parseCcd(username)
|
ccd = oAdmin.parseCcd(username)
|
||||||
}
|
}
|
||||||
return ccd
|
return ccd
|
||||||
}
|
}
|
||||||
|
@ -481,33 +633,64 @@ func checkUserExist(username string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func usersList() []OpenvpnClient {
|
func (oAdmin *OpenvpnAdmin) usersList() []OpenvpnClient {
|
||||||
var users []OpenvpnClient
|
var users []OpenvpnClient
|
||||||
activeClients := mgmtGetActiveClients()
|
|
||||||
|
totalCerts := 0
|
||||||
|
validCerts := 0
|
||||||
|
revokedCerts := 0
|
||||||
|
expiredCerts := 0
|
||||||
|
connectedUsers := 0
|
||||||
|
apochNow := time.Now().Unix()
|
||||||
|
|
||||||
for _, line := range indexTxtParser(fRead(*indexTxtPath)) {
|
for _, line := range indexTxtParser(fRead(*indexTxtPath)) {
|
||||||
if line.Identity != "server" {
|
if line.Identity != "server" {
|
||||||
ovpnClient := OpenvpnClient{Identity: line.Identity, ExpirationDate: indexTxtDateToHumanReadable(line.ExpirationDate)}
|
totalCerts += 1
|
||||||
|
ovpnClient := OpenvpnClient{Identity: line.Identity, ExpirationDate: parseDateToString(indexTxtDateLayout, line.ExpirationDate, stringDateFormat)}
|
||||||
switch {
|
switch {
|
||||||
case line.Flag == "V":
|
case line.Flag == "V":
|
||||||
ovpnClient.AccountStatus = "Active"
|
ovpnClient.AccountStatus = "Active"
|
||||||
case line.Flag == "R":
|
ovpnClientCertificateExpire.WithLabelValues(line.Identity).Set(float64(parseDateToUnix(indexTxtDateLayout, line.ExpirationDate) - apochNow / 3600 / 24))
|
||||||
|
validCerts += 1
|
||||||
|
case line.Flag == "R":
|
||||||
ovpnClient.AccountStatus = "Revoked"
|
ovpnClient.AccountStatus = "Revoked"
|
||||||
ovpnClient.RevocationDate = indexTxtDateToHumanReadable(line.RevocationDate)
|
ovpnClient.RevocationDate = parseDateToString(indexTxtDateLayout, line.RevocationDate, stringDateFormat)
|
||||||
|
ovpnClientCertificateExpire.WithLabelValues(line.Identity).Set(float64(parseDateToUnix(indexTxtDateLayout, line.ExpirationDate) - apochNow / 3600 / 24))
|
||||||
|
revokedCerts += 1
|
||||||
case line.Flag == "E":
|
case line.Flag == "E":
|
||||||
ovpnClient.AccountStatus = "Expired"
|
ovpnClient.AccountStatus = "Expired"
|
||||||
|
ovpnClientCertificateExpire.WithLabelValues(line.Identity).Set(float64(parseDateToUnix(indexTxtDateLayout, line.ExpirationDate) - apochNow / 3600 / 24))
|
||||||
|
expiredCerts += 1
|
||||||
}
|
}
|
||||||
if isUserConnected(line.Identity, activeClients) {
|
|
||||||
|
if isUserConnected(line.Identity, oAdmin.activeClients) {
|
||||||
ovpnClient.ConnectionStatus = "Connected"
|
ovpnClient.ConnectionStatus = "Connected"
|
||||||
|
connectedUsers += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
users = append(users, ovpnClient)
|
users = append(users, ovpnClient)
|
||||||
}
|
|
||||||
|
} else {
|
||||||
|
ovpnServerCertExpire.Set(float64(parseDateToUnix(indexTxtDateLayout,line.ExpirationDate) - apochNow / 3600 / 24))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
otherCerts := totalCerts - validCerts - revokedCerts - expiredCerts
|
||||||
|
|
||||||
|
if otherCerts != 0 {
|
||||||
|
log.Printf("WARNING: there are %d otherCerts", otherCerts)
|
||||||
|
}
|
||||||
|
|
||||||
|
ovpnClientsTotal.Set(float64(totalCerts))
|
||||||
|
ovpnClientsRevoked.Set(float64(revokedCerts))
|
||||||
|
ovpnClientsExpired.Set(float64(expiredCerts))
|
||||||
|
ovpnClientsConnected.Set(float64(connectedUsers))
|
||||||
|
|
||||||
return users
|
return users
|
||||||
}
|
}
|
||||||
|
|
||||||
func userCreate(username string) (bool, string) {
|
func (oAdmin *OpenvpnAdmin) userCreate(username string) (bool, string) {
|
||||||
ucErr := ""
|
ucErr := fmt.Sprintf("User \"%s\" created", username)
|
||||||
// TODO: add password for user cert . priority=low
|
// TODO: add password for user cert . priority=low
|
||||||
if validateUsername(username) == false {
|
if validateUsername(username) == false {
|
||||||
ucErr = fmt.Sprintf("Username \"%s\" incorrect, you can use only %s\n", username, usernameRegexp)
|
ucErr = fmt.Sprintf("Username \"%s\" incorrect, you can use only %s\n", username, usernameRegexp)
|
||||||
|
@ -525,21 +708,35 @@ func userCreate(username string) (bool, string) {
|
||||||
}
|
}
|
||||||
o := runBash(fmt.Sprintf("date +%%Y-%%m-%%d\\ %%H:%%M:%%S && cd %s && easyrsa build-client-full %s nopass", *easyrsaDirPath, username))
|
o := runBash(fmt.Sprintf("date +%%Y-%%m-%%d\\ %%H:%%M:%%S && cd %s && easyrsa build-client-full %s nopass", *easyrsaDirPath, username))
|
||||||
fmt.Println(o)
|
fmt.Println(o)
|
||||||
return true, fmt.Sprintf("User \"%s\" created", username)
|
if *debug {
|
||||||
|
log.Printf("INFO: user created: %s", username)
|
||||||
|
}
|
||||||
|
oAdmin.clients = oAdmin.usersList()
|
||||||
|
return true, ucErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func userRevoke(username string) string {
|
func (oAdmin *OpenvpnAdmin) getUserStatistic(username string) clientStatus {
|
||||||
|
for _, u := range oAdmin.activeClients {
|
||||||
|
if u.CommonName == username {
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return clientStatus{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (oAdmin *OpenvpnAdmin) userRevoke(username string) string {
|
||||||
if checkUserExist(username) {
|
if checkUserExist(username) {
|
||||||
// check certificate valid flag 'V'
|
// check certificate valid flag 'V'
|
||||||
o := runBash(fmt.Sprintf("date +%%Y-%%m-%%d\\ %%H:%%M:%%S && cd %s && echo yes | easyrsa revoke %s && easyrsa gen-crl", *easyrsaDirPath, username))
|
o := runBash(fmt.Sprintf("date +%%Y-%%m-%%d\\ %%H:%%M:%%S && cd %s && echo yes | easyrsa revoke %s && easyrsa gen-crl", *easyrsaDirPath, username))
|
||||||
crlFix()
|
crlFix()
|
||||||
|
oAdmin.clients = oAdmin.usersList()
|
||||||
return fmt.Sprintln(o)
|
return fmt.Sprintln(o)
|
||||||
}
|
}
|
||||||
fmt.Printf("User \"%s\" not found", username)
|
fmt.Printf("User \"%s\" not found", username)
|
||||||
return fmt.Sprintf("User \"%s\" not found", username)
|
return fmt.Sprintf("User \"%s\" not found", username)
|
||||||
}
|
}
|
||||||
|
|
||||||
func userUnrevoke(username string) string {
|
func (oAdmin *OpenvpnAdmin) userUnrevoke(username string) string {
|
||||||
if checkUserExist(username) {
|
if checkUserExist(username) {
|
||||||
// check certificate revoked flag 'R'
|
// check certificate revoked flag 'R'
|
||||||
usersFromIndexTxt := indexTxtParser(fRead(*indexTxtPath))
|
usersFromIndexTxt := indexTxtParser(fRead(*indexTxtPath))
|
||||||
|
@ -549,18 +746,20 @@ func userUnrevoke(username string) string {
|
||||||
usersFromIndexTxt[i].Flag = "V"
|
usersFromIndexTxt[i].Flag = "V"
|
||||||
usersFromIndexTxt[i].RevocationDate = ""
|
usersFromIndexTxt[i].RevocationDate = ""
|
||||||
o := runBash(fmt.Sprintf("cd %s && cp pki/revoked/certs_by_serial/%s.crt pki/issued/%s.crt", *easyrsaDirPath, usersFromIndexTxt[i].SerialNumber, username))
|
o := runBash(fmt.Sprintf("cd %s && cp pki/revoked/certs_by_serial/%s.crt pki/issued/%s.crt", *easyrsaDirPath, usersFromIndexTxt[i].SerialNumber, username))
|
||||||
fmt.Println(o)
|
//fmt.Println(o)
|
||||||
o = runBash(fmt.Sprintf("cd %s && cp pki/revoked/certs_by_serial/%s.crt pki/certs_by_serial/%s.pem", *easyrsaDirPath, usersFromIndexTxt[i].SerialNumber, usersFromIndexTxt[i].SerialNumber))
|
o = runBash(fmt.Sprintf("cd %s && cp pki/revoked/certs_by_serial/%s.crt pki/certs_by_serial/%s.pem", *easyrsaDirPath, usersFromIndexTxt[i].SerialNumber, usersFromIndexTxt[i].SerialNumber))
|
||||||
fmt.Println(o)
|
//fmt.Println(o)
|
||||||
o = runBash(fmt.Sprintf("cd %s && cp pki/revoked/private_by_serial/%s.key pki/private/%s.key", *easyrsaDirPath, usersFromIndexTxt[i].SerialNumber, username))
|
o = runBash(fmt.Sprintf("cd %s && cp pki/revoked/private_by_serial/%s.key pki/private/%s.key", *easyrsaDirPath, usersFromIndexTxt[i].SerialNumber, username))
|
||||||
fmt.Println(o)
|
//fmt.Println(o)
|
||||||
o = runBash(fmt.Sprintf("cd %s && cp pki/revoked/reqs_by_serial/%s.req pki/reqs/%s.req", *easyrsaDirPath, usersFromIndexTxt[i].SerialNumber, username))
|
o = runBash(fmt.Sprintf("cd %s && cp pki/revoked/reqs_by_serial/%s.req pki/reqs/%s.req", *easyrsaDirPath, usersFromIndexTxt[i].SerialNumber, username))
|
||||||
fmt.Println(o)
|
//fmt.Println(o)
|
||||||
fWrite(*indexTxtPath, renderIndexTxt(usersFromIndexTxt))
|
fWrite(*indexTxtPath, renderIndexTxt(usersFromIndexTxt))
|
||||||
fmt.Print(renderIndexTxt(usersFromIndexTxt))
|
//fmt.Print(renderIndexTxt(usersFromIndexTxt))
|
||||||
o = runBash(fmt.Sprintf("cd %s && easyrsa gen-crl", *easyrsaDirPath))
|
o = runBash(fmt.Sprintf("cd %s && easyrsa gen-crl", *easyrsaDirPath))
|
||||||
fmt.Println(o)
|
//fmt.Println(o)
|
||||||
crlFix()
|
crlFix()
|
||||||
|
o = ""
|
||||||
|
fmt.Println(o)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -568,6 +767,7 @@ func userUnrevoke(username string) string {
|
||||||
fWrite(*indexTxtPath, renderIndexTxt(usersFromIndexTxt))
|
fWrite(*indexTxtPath, renderIndexTxt(usersFromIndexTxt))
|
||||||
fmt.Print(renderIndexTxt(usersFromIndexTxt))
|
fmt.Print(renderIndexTxt(usersFromIndexTxt))
|
||||||
crlFix()
|
crlFix()
|
||||||
|
oAdmin.clients = oAdmin.usersList()
|
||||||
return fmt.Sprintf("{\"msg\":\"User %s successfully unrevoked\"}", username)
|
return fmt.Sprintf("{\"msg\":\"User %s successfully unrevoked\"}", username)
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("{\"msg\":\"User \"%s\" not found\"}", username)
|
return fmt.Sprintf("{\"msg\":\"User \"%s\" not found\"}", username)
|
||||||
|
@ -579,14 +779,14 @@ func userChangePassword(username string, newPassword string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func ovpnMgmtRead(conn net.Conn) string {
|
func (oAdmin *OpenvpnAdmin) mgmtRead(conn net.Conn) string {
|
||||||
buf := make([]byte, 32768)
|
buf := make([]byte, 32768)
|
||||||
bufLen, _ := conn.Read(buf)
|
bufLen, _ := conn.Read(buf)
|
||||||
s := string(buf[:bufLen])
|
s := string(buf[:bufLen])
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func mgmtConnectedUsersParser(text string) []clientStatus {
|
func (oAdmin *OpenvpnAdmin) mgmtConnectedUsersParser(text string) []clientStatus {
|
||||||
var u []clientStatus
|
var u []clientStatus
|
||||||
isClientList := false
|
isClientList := false
|
||||||
isRouteTable := false
|
isRouteTable := false
|
||||||
|
@ -611,7 +811,20 @@ func mgmtConnectedUsersParser(text string) []clientStatus {
|
||||||
}
|
}
|
||||||
if isClientList {
|
if isClientList {
|
||||||
user := strings.Split(txt, ",")
|
user := strings.Split(txt, ",")
|
||||||
u = append(u, clientStatus{CommonName: user[0], RealAddress: user[1], BytesReceived: user[2], BytesSent: user[3], ConnectedSince: user[4]})
|
|
||||||
|
userName := user[0]
|
||||||
|
userAddress := user[1]
|
||||||
|
userBytesRecieved:= user[2]
|
||||||
|
userBytesSent:= user[3]
|
||||||
|
userConnectedSince := user[4]
|
||||||
|
|
||||||
|
userStatus := clientStatus{CommonName: userName, RealAddress: userAddress, BytesReceived: userBytesRecieved, BytesSent: userBytesSent, ConnectedSince: userConnectedSince}
|
||||||
|
u = append(u, userStatus)
|
||||||
|
bytesSent, _ := strconv.Atoi(userBytesSent)
|
||||||
|
bytesReceive, _ := strconv.Atoi(userBytesRecieved)
|
||||||
|
ovpnClientConnectionFrom.WithLabelValues(userName, userAddress).Set(float64(parseDateToUnix(ovpnStatusDateLayout, userConnectedSince)))
|
||||||
|
ovpnClientBytesSent.WithLabelValues(userName).Set(float64(bytesSent))
|
||||||
|
ovpnClientBytesReceived.WithLabelValues(userName).Set(float64(bytesReceive))
|
||||||
}
|
}
|
||||||
if isRouteTable {
|
if isRouteTable {
|
||||||
user := strings.Split(txt, ",")
|
user := strings.Split(txt, ",")
|
||||||
|
@ -619,6 +832,7 @@ func mgmtConnectedUsersParser(text string) []clientStatus {
|
||||||
if u[i].CommonName == user[1] {
|
if u[i].CommonName == user[1] {
|
||||||
u[i].VirtualAddress = user[0]
|
u[i].VirtualAddress = user[0]
|
||||||
u[i].LastRef = user[3]
|
u[i].LastRef = user[3]
|
||||||
|
ovpnClientConnectionInfo.WithLabelValues(user[1], user[0]).Set(float64(parseDateToUnix(ovpnStatusDateLayout, user[3])))
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -627,27 +841,27 @@ func mgmtConnectedUsersParser(text string) []clientStatus {
|
||||||
return u
|
return u
|
||||||
}
|
}
|
||||||
|
|
||||||
func mgmtKillUserConnection(username string) {
|
func (oAdmin *OpenvpnAdmin) mgmtKillUserConnection(username string) {
|
||||||
conn, err := net.Dial("tcp", *mgmtListenHost+":"+*mgmtListenPort)
|
conn, err := net.Dial("tcp", *mgmtListenHost+":"+*mgmtListenPort)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("ERROR: openvpn mgmt interface is not reachable")
|
log.Println("ERROR: openvpn mgmt interface is not reachable")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ovpnMgmtRead(conn) // read welcome message
|
oAdmin.mgmtRead(conn) // read welcome message
|
||||||
conn.Write([]byte(fmt.Sprintf("kill %s\n", username)))
|
conn.Write([]byte(fmt.Sprintf("kill %s\n", username)))
|
||||||
fmt.Printf("%v", ovpnMgmtRead(conn))
|
fmt.Printf("%v", oAdmin.mgmtRead(conn))
|
||||||
conn.Close()
|
conn.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func mgmtGetActiveClients() []clientStatus {
|
func (oAdmin *OpenvpnAdmin) mgmtGetActiveClients() []clientStatus {
|
||||||
conn, err := net.Dial("tcp", *mgmtListenHost+":"+*mgmtListenPort)
|
conn, err := net.Dial("tcp", *mgmtListenHost+":"+*mgmtListenPort)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("ERROR: openvpn mgmt interface is not reachable")
|
log.Println("ERROR: openvpn mgmt interface is not reachable")
|
||||||
return []clientStatus{}
|
return []clientStatus{}
|
||||||
}
|
}
|
||||||
ovpnMgmtRead(conn) // read welcome message
|
oAdmin.mgmtRead(conn) // read welcome message
|
||||||
conn.Write([]byte("status\n"))
|
conn.Write([]byte("status\n"))
|
||||||
activeClients := mgmtConnectedUsersParser(ovpnMgmtRead(conn))
|
activeClients := oAdmin.mgmtConnectedUsersParser(oAdmin.mgmtRead(conn))
|
||||||
conn.Close()
|
conn.Close()
|
||||||
return activeClients
|
return activeClients
|
||||||
}
|
}
|
||||||
|
@ -661,11 +875,11 @@ func isUserConnected(username string, connectedUsers []clientStatus) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func downloadCerts() bool {
|
func (oAdmin *OpenvpnAdmin) downloadCerts() bool {
|
||||||
if fExist(certsArchivePath) {
|
if fExist(certsArchivePath) {
|
||||||
fDelete(certsArchivePath)
|
fDelete(certsArchivePath)
|
||||||
}
|
}
|
||||||
err := fDownload(certsArchivePath, *masterHost + downloadCertsApiUrl + "?token=" + *masterSyncToken, masterHostBasicAuth)
|
err := fDownload(certsArchivePath, *masterHost + downloadCertsApiUrl + "?token=" + oAdmin.masterSyncToken, oAdmin.masterHostBasicAuth)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
return false
|
return false
|
||||||
|
@ -674,12 +888,12 @@ func downloadCerts() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func downloadCcd() bool {
|
func (oAdmin *OpenvpnAdmin) downloadCcd() bool {
|
||||||
if fExist(ccdArchivePath) {
|
if fExist(ccdArchivePath) {
|
||||||
fDelete(ccdArchivePath)
|
fDelete(ccdArchivePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := fDownload(ccdArchivePath, *masterHost + downloadCcdApiUrl + "?token=" + *masterSyncToken, masterHostBasicAuth)
|
err := fDownload(ccdArchivePath, *masterHost + downloadCcdApiUrl + "?token=" + oAdmin.masterSyncToken, oAdmin.masterHostBasicAuth)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
return false
|
return false
|
||||||
|
@ -710,19 +924,17 @@ func unArchiveCcd() {
|
||||||
fmt.Println(o)
|
fmt.Println(o)
|
||||||
}
|
}
|
||||||
|
|
||||||
func syncDataFromMaster() {
|
func (oAdmin *OpenvpnAdmin) syncDataFromMaster() {
|
||||||
log.Println("Downloading archives from master")
|
|
||||||
retryCountMax := 3
|
retryCountMax := 3
|
||||||
|
|
||||||
certsDownloadFailed := true
|
certsDownloadFailed := true
|
||||||
ccdDownloadFailed := true
|
ccdDownloadFailed := true
|
||||||
|
|
||||||
certsDownloadRetries := 0
|
certsDownloadRetries := 0
|
||||||
ccdDownloadRetries := 0
|
ccdDownloadRetries := 0
|
||||||
|
|
||||||
for certsDownloadFailed && certsDownloadRetries < retryCountMax {
|
for certsDownloadFailed && certsDownloadRetries < retryCountMax {
|
||||||
certsDownloadRetries += 1
|
certsDownloadRetries += 1
|
||||||
if downloadCerts() {
|
log.Printf("Downloading certs archive from master. Attempt %d", certsDownloadRetries)
|
||||||
|
if oAdmin.downloadCerts() {
|
||||||
certsDownloadFailed = false
|
certsDownloadFailed = false
|
||||||
log.Println("Decompression certs archive from master")
|
log.Println("Decompression certs archive from master")
|
||||||
unArchiveCerts()
|
unArchiveCerts()
|
||||||
|
@ -733,7 +945,8 @@ func syncDataFromMaster() {
|
||||||
|
|
||||||
for ccdDownloadFailed && ccdDownloadRetries < retryCountMax {
|
for ccdDownloadFailed && ccdDownloadRetries < retryCountMax {
|
||||||
ccdDownloadRetries += 1
|
ccdDownloadRetries += 1
|
||||||
if downloadCcd() {
|
log.Printf("Downloading ccd archive from master. Attempt %d", ccdDownloadRetries)
|
||||||
|
if oAdmin.downloadCcd() {
|
||||||
ccdDownloadFailed = false
|
ccdDownloadFailed = false
|
||||||
log.Println("Decompression ccd archive from master")
|
log.Println("Decompression ccd archive from master")
|
||||||
unArchiveCcd()
|
unArchiveCcd()
|
||||||
|
@ -742,24 +955,41 @@ func syncDataFromMaster() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lastSyncTime = time.Now().Format("2006-01-02 15:04:05")
|
oAdmin.lastSyncTime = time.Now().Format("2006-01-02 15:04:05")
|
||||||
if !ccdDownloadFailed && !certsDownloadFailed {
|
if !ccdDownloadFailed && !certsDownloadFailed {
|
||||||
lastSuccessfulSyncTime = time.Now().Format("2006-01-02 15:04:05")
|
oAdmin.lastSuccessfulSyncTime = time.Now().Format("2006-01-02 15:04:05")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func syncWithMaster() {
|
func (oAdmin *OpenvpnAdmin) syncWithMaster() {
|
||||||
for {
|
for {
|
||||||
time.Sleep(time.Duration(*masterSyncFrequency) * time.Second)
|
time.Sleep(time.Duration(*masterSyncFrequency) * time.Second)
|
||||||
syncDataFromMaster()
|
oAdmin.syncDataFromMaster()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getOpvnCaCertExpireDate() time.Time {
|
||||||
|
caCertPath := *easyrsaDirPath + "/pki/ca.crt"
|
||||||
|
caCertExpireDate := runBash(fmt.Sprintf("openssl x509 -in %s -noout -enddate | awk -F \"=\" {'print $2'}", caCertPath))
|
||||||
|
|
||||||
|
dateLayout := "Jan 2 15:04:05 2006 MST"
|
||||||
|
t, err := time.Parse(dateLayout, strings.TrimSpace(caCertExpireDate))
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("WARNING: can`t parse expire date for CA cert: %v", err)
|
||||||
|
return time.Now()
|
||||||
|
}
|
||||||
|
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
// https://community.openvpn.net/openvpn/ticket/623
|
// https://community.openvpn.net/openvpn/ticket/623
|
||||||
func crlFix() {
|
func crlFix() {
|
||||||
os.Chmod(*easyrsaDirPath + "/pki", 0755)
|
err1 := os.Chmod(*easyrsaDirPath + "/pki", 0755)
|
||||||
err := os.Chmod(*easyrsaDirPath + "/pki/crl.pem", 0644)
|
if err1 != nil {
|
||||||
if err != nil {
|
log.Println(err1)
|
||||||
log.Println(err)
|
|
||||||
}
|
}
|
||||||
}
|
err2 := os.Chmod(*easyrsaDirPath + "/pki/crl.pem", 0644)
|
||||||
|
if err2 != nil {
|
||||||
|
log.Println(err2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
project: openvpn-web-ui
|
project: openvpn-admin
|
||||||
configVersion: 1
|
configVersion: 1
|
||||||
deploy:
|
deploy:
|
||||||
helmRelease: "[[ project ]]-[[ env ]]"
|
helmRelease: "[[ project ]]-[[ env ]]"
|
||||||
|
|
Loading…
Reference in a new issue