code/autoregistry/proxy/main.go

99 lines
2.6 KiB
Go
Raw Normal View History

2024-08-31 17:58:24 +00:00
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))
}