11package main
22
33import (
4- "log"
54 "net"
65 "net/http"
76 "net/url"
@@ -13,68 +12,66 @@ import(
1312 "sync"
1413 "regexp"
1514 "strconv"
16- "flag"
1715 "time"
16+
17+ "github.com/11notes/go"
1818)
1919
2020var (
21+ Eleven eleven.New = eleven.New {}
2122 proxy * httputil.ReverseProxy
2223 socket net.Listener
2324 wg sync.WaitGroup
2425 socketProxy string
25- dockerSocket * net.Conn
26+ keepAlive string = os .Getenv ("SOCKET_PROXY_KEEPALIVE" )
27+ timeout string = os .Getenv ("SOCKET_PROXY_TIMEOUT" )
28+ uid string = os .Getenv ("SOCKET_PROXY_UID" )
29+ gid string = os .Getenv ("SOCKET_PROXY_GID" )
30+ volume string = os .Getenv ("SOCKET_PROXY_VOLUME" )
31+ dockerSocket string = os .Getenv ("SOCKET_PROXY_DOCKER_SOCKET" )
2632)
2733
28- func signals (){
29- signalChannel := make (chan os.Signal , 1 )
30- signal .Notify (signalChannel , os .Interrupt , syscall .SIGTERM , syscall .SIGSTOP , syscall .SIGINT )
31- go func () {
32- <- signalChannel
33- os .Exit (0 )
34- }()
35- }
36-
3734func prepareFileSystemDropPrivileges (){
3835 // unprivileged user
39- proxyUID , err := strconv .Atoi (os . Getenv ( "SOCKET_PROXY_UID" ) )
36+ proxyUID , err := strconv .Atoi (uid )
4037 if err != nil {
41- log . Fatalf ("SOCKET_PROXY_UID must be a number %v" , err )
38+ Eleven . LogFatal ("SOCKET_PROXY_UID must be a number %v" , err )
4239 }
43- proxyGID , err := strconv .Atoi (os . Getenv ( "SOCKET_PROXY_GID" ) )
40+ proxyGID , err := strconv .Atoi (gid )
4441 if err != nil {
45- log . Fatalf ("SOCKET_PROXY_GID must be a number %v" , err )
42+ Eleven . LogFatal ("SOCKET_PROXY_GID must be a number %v" , err )
4643 }
47- proxyVolume := regexp .MustCompile (`/+$` ).ReplaceAllString (os . Getenv ( "SOCKET_PROXY_VOLUME" ) , "" )
44+ proxyVolume := regexp .MustCompile (`/+$` ).ReplaceAllString (volume , "" )
4845
4946 // chown file system for unprivileged user
5047 if err := os .Chown (proxyVolume , proxyUID , proxyGID ); err != nil {
51- log . Fatalf ("could not chown folder %s" , proxyVolume , err )
48+ Eleven . LogFatal ("could not chown folder %s" , proxyVolume , err )
5249 }
5350
5451 // check docker socket permissions
55- stat , err := os .Stat (os . Getenv ( "SOCKET_PROXY_DOCKER_SOCKET" ) )
52+ stat , err := os .Stat (dockerSocket )
5653 if err != nil {
57- log . Fatalf ("could not evaluate ownership of docker socket, permission issue %v" , err )
54+ Eleven . LogFatal ("could not evaluate ownership of docker socket, permission issue %v" , err )
5855 }
5956 if ownership , ok := stat .Sys ().(* syscall.Stat_t ); ! ok {
60- log . Fatalf ("could not evaluate ownership of docker socket, permission issue %v" , err )
57+ Eleven . LogFatal ("could not evaluate ownership of docker socket, permission issue %v" , err )
6158 }else {
6259 if (int (ownership .Uid ) != os .Getuid ()){
63- log . Fatalf ("can’t access docker socket as UID %d owned by UID %d\n please change the user setting in your compose to the correct UID/GID pair like this: \n services: \n socket-proxy: \n user: \" %d:%d\" " , os .Getuid (), ownership .Uid , ownership .Uid , ownership .Gid )
60+ Eleven . LogFatal ("can’t access docker socket as UID %d owned by UID %d. Please change the user setting in your compose to the correct UID/GID pair like this >> user: %d:%d" , os .Getuid (), ownership .Uid , ownership .Uid , ownership .Gid )
6461 }else {
6562 if (int (ownership .Gid ) != os .Getgid ()){
66- log . Fatalf ("can’t access docker socket as GID %d owned by GID %d\n please change the user setting in your compose to the correct UID/GID pair like this: \n services: \n socket-proxy: \n user: \" %d:%d\" " , os .Getgid (), ownership .Gid , os .Getuid (), ownership .Gid )
63+ Eleven . LogFatal ("can’t access docker socket as GID %d owned by GID %d. Please change the user setting in your compose to the correct UID/GID pair like this >> user: %d:%d" , os .Getgid (), ownership .Gid , os .Getuid (), ownership .Gid )
6764 }
6865 }
6966 }
7067
7168 // drop privileges since only the proxy must access the socket as root and nothing else
7269 if err := syscall .Setgid (proxyGID ); err != nil {
73- log . Fatalf ("could not set GID to %d %v" , proxyGID , err )
70+ Eleven . LogFatal ("could not set GID to %d %v" , proxyGID , err )
7471 }
7572
7673 if err := syscall .Setuid (proxyUID ); err != nil {
77- log . Fatalf ("could not set UID to %d %v" , proxyUID , err )
74+ Eleven . LogFatal ("could not set UID to %d %v" , proxyUID , err )
7875 }
7976}
8077
@@ -104,54 +101,62 @@ func httpProxy(w http.ResponseWriter, r *http.Request){
104101 if ((method == "GET" || method == "HEAD" ) && ! httpProxyBlockedPaths (url )){
105102 proxy .ServeHTTP (w , r )
106103 }else {
107- log . Printf ( "blocked: %s %s" , method , url )
104+ Eleven . Log ( "INF" , "blocked: %s %s" , method , url )
108105 http .Error (w , "" , http .StatusForbidden )
109106 }
110107}
111108
109+ func healthcheck (exit bool ){
110+ healthcheckSockerDialer := & net.Dialer {Timeout : 2 * time .Second }
111+ socket , err := healthcheckSockerDialer .Dial ("unix" , socketProxy )
112+ if err != nil {
113+ os .Exit (1 )
114+ }
115+ err = socket .Close ()
116+ if err != nil {
117+ os .Exit (1 )
118+ }
119+ if (exit ){
120+ os .Exit (0 )
121+ }else {
122+ Eleven .Log ("DBG" , "health check successfully" )
123+ }
124+ }
125+
112126func main (){
113127 // set socket proxy file path
114- socketProxy = regexp .MustCompile (`/+$` ).ReplaceAllString (os .Getenv ("SOCKET_PROXY_VOLUME" ), "" ) + "/docker.sock"
115-
116- // check for command line flags
117- healthCheckFlag := flag .Bool ("healthcheck" , false , "just run healthcheck" )
118- flag .Parse ()
128+ socketProxy = regexp .MustCompile (`/+$` ).ReplaceAllString (volume , "" ) + "/docker.sock"
119129
120- if (* healthCheckFlag ){
130+ if (Eleven . Util . CommandLineArgumentExists ( "--healthcheck" ) ){
121131 // only run healthcheck
122- _ , err := net .Dial ("unix" , socketProxy )
123- if err != nil {
124- os .Exit (1 )
125- }
126- os .Exit (0 )
132+ healthcheck (true )
127133 }else {
128- log .Println ("starting socket-proxy v" + os .Getenv ("APP_VERSION" ))
134+ // start app
135+ Eleven .Log ("START" , "" )
136+
129137 // setup signal handler
130- signals ()
138+ signalChannel := make (chan os.Signal , 1 )
139+ signal .Notify (signalChannel , os .Interrupt , syscall .SIGTERM , syscall .SIGSTOP , syscall .SIGINT )
140+ go func (){
141+ <- signalChannel
142+ os .Exit (1 )
143+ }()
131144
132145 // setup proxy to docker socket as root
133- keepAlive , err := time .ParseDuration (os . Getenv ( "SOCKET_PROXY_KEEPALIVE" ) )
146+ keepAlive , err := time .ParseDuration (keepAlive )
134147 if err != nil {
135- log . Fatalf ("%s not a valid time format: %s" , os . Getenv ( "SOCKET_PROXY_KEEPALIVE" ) , err )
148+ Eleven . LogFatal ("%s not a valid time format: %s" , keepAlive , err )
136149 }
137- timeout , err := time .ParseDuration (os . Getenv ( "SOCKET_PROXY_TIMEOUT" ) )
150+ timeout , err := time .ParseDuration (timeout )
138151 if err != nil {
139- log .Fatalf ("%s not a valid time format: %s" , os .Getenv ("SOCKET_PROXY_TIMEOUT" ), err )
140- }
141- docketSockerDialer := & net.Dialer {KeepAlive : keepAlive , Timeout : timeout }
142- dockerSocket , err := docketSockerDialer .Dial ("unix" , os .Getenv ("SOCKET_PROXY_DOCKER_SOCKET" ))
143- if err != nil {
144- log .Fatalf ("could not access docker socket %v" , err )
152+ Eleven .LogFatal ("%s not a valid time format: %s" , timeout , err )
145153 }
146154 localhost , _ := url .Parse ("http://localhost" )
147155 proxy = httputil .NewSingleHostReverseProxy (localhost )
156+ docketSockerDialer := & net.Dialer {KeepAlive : keepAlive , Timeout : timeout }
148157 proxy .Transport = & http.Transport {
149- DialContext : func (_ context.Context , _ , _ string )(net.Conn , error ){
150- dockerSocket , err = docketSockerDialer .Dial ("unix" , os .Getenv ("SOCKET_PROXY_DOCKER_SOCKET" ))
151- if err != nil {
152- log .Fatalf ("could not access docker socket %v" , err )
153- }
154- return dockerSocket , err
158+ DialContext :func (_ context.Context , _ , _ string )(net.Conn , error ){
159+ return (docketSockerDialer .Dial ("unix" , dockerSocket ))
155160 },
156161 }
157162
@@ -165,14 +170,14 @@ func main(){
165170 os .Remove (socketProxy )
166171 unix , err := net .Listen ("unix" , socketProxy )
167172 if err != nil {
168- log . Fatalf ("could not start unix socket %v" , err )
173+ Eleven . LogFatal ("could not start unix socket %v" , err )
169174 }
170175 wg .Add (1 )
171176 go func (){
172177 defer wg .Done ()
173- log . Println ( "starting proxy UNIX socket ..." )
178+ Eleven . Log ( "INF" , "starting proxy UNIX socket ..." )
174179 if err := unixServer .Serve (unix ); err != nil {
175- log . Fatalf ("could not start unix socket %v" , err )
180+ Eleven . LogFatal ("could not start unix socket %v" , err )
176181 }
177182 }()
178183
@@ -183,33 +188,43 @@ func main(){
183188
184189 tcp , err := net .Listen ("tcp" , "0.0.0.0:2375" )
185190 if err != nil {
186- log . Fatalf ("could not start tcp socket %v" , err )
191+ Eleven . LogFatal ("could not start tcp socket %v" , err )
187192 }
188193 wg .Add (1 )
189194 go func (){
190195 defer wg .Done ()
191- log . Println ( "starting proxy TCP socket ..." )
196+ Eleven . Log ( "INF" , "starting proxy TCP socket ..." )
192197 if err := httpServer .Serve (tcp ); err != nil {
193- log . Fatalf ("could not start tcp socket %v" , err )
198+ Eleven . LogFatal ("could not start tcp socket %v" , err )
194199 }
195200 }()
196201
197202 // try to access the socket proxy
198203 client := & http.Client {}
199204 req , err := http .NewRequest (http .MethodGet , "http://localhost:2375/version" , nil )
200205 if err != nil {
201- log . Fatalf ("could not create HTTP request %v" , err )
206+ Eleven . LogFatal ("could not create HTTP request %v" , err )
202207 }
203208 res , err := client .Do (req )
204209 if err != nil {
205- log . Fatalf ("could not proxy to docker socket %v" , err )
210+ Eleven . LogFatal ("could not proxy to docker socket %v" , err )
206211 }
207212 res .Body .Close ()
208213 if res .StatusCode != http .StatusOK {
209- log .Fatalf ("could not proxy to docker socket %v" , err )
214+ Eleven .LogFatal ("could not proxy to docker socket %v" , err )
215+ }
216+
217+ // set internal socket check
218+ ticker := time .NewTicker (5 * time .Second )
219+ defer ticker .Stop ()
220+ for {
221+ select {
222+ case <- ticker .C :
223+ healthcheck (false )
224+ }
210225 }
211- log .Println ("proxy connection to docker socket established" )
212226
227+ // wait for socket to get stopped
213228 wg .Wait ()
214229 }
215230}
0 commit comments