99 lines
2.6 KiB
Go
99 lines
2.6 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"log"
|
||
|
"net/http"
|
||
|
"net/http/httputil"
|
||
|
"net/url"
|
||
|
"os"
|
||
|
)
|
||
|
|
||
|
type AutoRegistry struct {
|
||
|
host string
|
||
|
port string
|
||
|
backendRegistryUrl string
|
||
|
reverseProxy *httputil.ReverseProxy
|
||
|
}
|
||
|
|
||
|
func NewAutoRegistry(host, port, backendRegistryUrl string) *AutoRegistry {
|
||
|
proxy := AutoRegistry{
|
||
|
host: host, port: port,
|
||
|
backendRegistryUrl: backendRegistryUrl,
|
||
|
}
|
||
|
url, err := url.Parse(backendRegistryUrl)
|
||
|
if err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
proxy.reverseProxy = httputil.NewSingleHostReverseProxy(url)
|
||
|
return &proxy
|
||
|
}
|
||
|
|
||
|
func (autoProxy *AutoRegistry) setupHandler() {
|
||
|
http.HandleFunc("/", autoProxy.requestHandler())
|
||
|
}
|
||
|
|
||
|
// ProxyRequestHandler handles the http request using proxy
|
||
|
func (autoProxy *AutoRegistry) requestHandler() func(http.ResponseWriter, *http.Request) {
|
||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||
|
autoProxy.pushImageIfNeeded(r, autoProxy.host+":"+autoProxy.port)
|
||
|
autoProxy.reverseProxy.ServeHTTP(w, r)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (autoProxy *AutoRegistry) pushImageIfNeeded(r *http.Request, registry string) {
|
||
|
// below will catch error but can return old image to the user.
|
||
|
// This will lead to a lot of troubleshooting. Better is to fail the request to the client
|
||
|
// when there is a problem with docker.
|
||
|
//defer func() {
|
||
|
// if r := recover(); r != nil {
|
||
|
// log.Println("ERROR: Docker interaction failed: ", r)
|
||
|
// }
|
||
|
//}()
|
||
|
|
||
|
log.Printf("Got request: %s, url: %s\n", r.Method, r.URL.Path)
|
||
|
if r.Method != "HEAD" && r.Method != "GET" {
|
||
|
return
|
||
|
}
|
||
|
image_name, tag_name, ok := ParseImage(r.URL.Path)
|
||
|
if !ok {
|
||
|
// not a manifest request
|
||
|
return
|
||
|
}
|
||
|
docker_id, push_tag := GetDockerImageId(registry, image_name, tag_name)
|
||
|
log.Printf("Docker id %s\n", docker_id)
|
||
|
if docker_id == "" {
|
||
|
return
|
||
|
}
|
||
|
registry_id := GetRegistryId(autoProxy.backendRegistryUrl, image_name, tag_name)
|
||
|
if docker_id == registry_id {
|
||
|
log.Printf("Image %s:%s is up to date in registry\n", image_name, tag_name)
|
||
|
}
|
||
|
log.Printf("image %s:%s is not up to date in registry, pushing it\n", image_name, tag_name)
|
||
|
PushDockerImage(push_tag)
|
||
|
}
|
||
|
|
||
|
func printHelp() {
|
||
|
fmt.Println("Usage: proxy <host> <port> <backendUrl>")
|
||
|
}
|
||
|
|
||
|
func main() {
|
||
|
|
||
|
// make sure we can connect to docker and fail immediately otherwise
|
||
|
CheckDockerAvailable()
|
||
|
|
||
|
if len(os.Args) != 4 {
|
||
|
printHelp()
|
||
|
}
|
||
|
host := os.Args[1]
|
||
|
port := os.Args[2]
|
||
|
backendRegistry := os.Args[3]
|
||
|
|
||
|
log.Printf("Running with: host %s port %s backend %s\n", host, port, backendRegistry)
|
||
|
|
||
|
proxy := NewAutoRegistry(host, port, backendRegistry)
|
||
|
proxy.setupHandler()
|
||
|
// handle all requests to your server using the proxy
|
||
|
log.Fatal(http.ListenAndServe(":"+port, nil))
|
||
|
}
|