From 6a6ba7218fe83bc991a2ef8da76a2b7d3550e4ed Mon Sep 17 00:00:00 2001 From: wweir Date: Mon, 30 Sep 2024 11:40:30 +0800 Subject: [PATCH] WIP --- Makefile | 3 +- conf/config.go | 18 ++++++++-- go.mod | 1 - go.sum | 2 -- install.go | 93 +++++++++++++++++++++++++++++++++++++++++++++++--- main.go | 22 ++++++------ 6 files changed, 119 insertions(+), 20 deletions(-) diff --git a/Makefile b/Makefile index 10ef513..9ba10f5 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,7 @@ build: -o bin/contatto . run: build ./bin/contatto proxy --debug -c contatto.toml - +install: build + sudo install -m 0755 ./bin/contatto /bin/contatto clean: rm -f ./bin/contatto diff --git a/conf/config.go b/conf/config.go index 1f2bf8e..d22ce37 100644 --- a/conf/config.go +++ b/conf/config.go @@ -62,6 +62,18 @@ func ReadConfig(file string) (*Config, error) { return nil, fmt.Errorf("mapstructure config: %w", err) } + return c.Validate() +} + +func (c *Config) Validate() (*Config, error) { + if c.Addr == "" { + return nil, fmt.Errorf("addr is required") + } + + if c.BaseRule.MirrorRegistry == "" { + return nil, fmt.Errorf("base_rule.mirror_registry is required") + } + for host, registry := range c.Registry { if registry.registry == "" { registry.registry = host @@ -92,12 +104,14 @@ func ReadConfig(file string) (*Config, error) { if rule.PathTpl == "" { rule.pathTpl = c.BaseRule.pathTpl } + if rule.pathTpl == nil { + return nil, fmt.Errorf(`rule."%s".path_tpl is required`, registry) + } if rule.OnMissingTpl == "" { rule.onMissingTpl = c.BaseRule.onMissingTpl } } - - return &c, nil + return c, nil } var envRe = regexp.MustCompile(`\$\{([a-zA-Z0-9_]+)\}`) diff --git a/go.mod b/go.mod index 97e03af..5d5eebb 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,6 @@ require ( github.com/containerd/containerd/v2 v2.0.0-rc.4 github.com/go-viper/mapstructure/v2 v2.2.1 github.com/julienschmidt/httprouter v1.3.0 - github.com/lmittmann/tint v1.0.5 github.com/pelletier/go-toml/v2 v2.2.3 gopkg.in/yaml.v3 v3.0.1 ) diff --git a/go.sum b/go.sum index d238f63..705d762 100644 --- a/go.sum +++ b/go.sum @@ -47,8 +47,6 @@ github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4d github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= -github.com/lmittmann/tint v1.0.5 h1:NQclAutOfYsqs2F1Lenue6OoWCajs5wJcP3DfWVpePw= -github.com/lmittmann/tint v1.0.5/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE= github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg= diff --git a/install.go b/install.go index 87855d5..475f39b 100644 --- a/install.go +++ b/install.go @@ -1,13 +1,98 @@ package main import ( - "log/slog" + "encoding/json" + "fmt" + "os" + + "github.com/pelletier/go-toml/v2" + "github.com/wweir/contatto/conf" ) -type InstallCmd struct{} +type InstallCmd struct { + Interactive *InstallInteractiveCmd `cmd:"" default:"1" hidden:"" help:"123"` + Docker *InstallDockerCmd `cmd:"" help:"inject proxy as mirror to dockerd config file"` + Containerd *InstallContainerdCmd `cmd:"" help:"inject proxy as puller in containerd config file"` +} -func (c *InstallCmd) Run() error { - slog.Info("install") +type InstallInteractiveCmd struct{} +func (c *InstallInteractiveCmd) Run(config *conf.Config) error { return nil } + +type InstallDockerCmd struct { + File string `arg:"" required:"" default:"/etc/docker/daemon.json" help:"dockerd config file, default: /etc/docker/daemon.json"` +} + +func (c *InstallDockerCmd) Run(config *conf.Config) error { + fmt.Printf("inject mirror http://%s into docker config: %s\n", config.Addr, c.File) + + f, err := os.Open(c.File) + if err != nil { + return err + } + defer f.Close() + + dockerConfig := map[string]any{} + if err := json.NewDecoder(f).Decode(&dockerConfig); err != nil { + return err + } + + if dockerConfig["registry-mirrors"] == nil { + dockerConfig["registry-mirrors"] = []string{} + } + + mirrors := dockerConfig["registry-mirrors"].([]any) + proxyAddr := "http://" + config.Addr + for _, mirror := range mirrors { + if mirror.(string) == proxyAddr { + return nil + } + } + + dockerConfig["registry-mirrors"] = append([]any{proxyAddr}, mirrors...) + + f, err = os.OpenFile(c.File+"_safe", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0o644) + if err != nil { + return err + } + defer f.Close() + + en := json.NewEncoder(f) + en.SetIndent("", " ") + if err := en.Encode(dockerConfig); err != nil { + return err + } + + return os.Rename(c.File+"_safe", c.File) +} + +type InstallContainerdCmd struct { + File string `arg:"" required:"" default:"/etc/containerd/config.toml" help:"containerd config file, default: /etc/containerd/config.toml"` +} + +func (c *InstallContainerdCmd) Run(config *conf.Config) error { + fmt.Printf("inject proxy http://%s into containerd config: %s\n", config.Addr, c.File) + + f, err := os.Open(c.File) + if err != nil { + return err + } + defer f.Close() + + containerdConfig := map[string]any{} + if err := toml.NewDecoder(f).Decode(&containerdConfig); err != nil { + return err + } + + switch containerdConfig["version"].(int64) { + case 2: + return c.installContainerdV2(config, containerdConfig) + default: + return fmt.Errorf("unsupported containerd config version: %d", containerdConfig["version"]) + } +} + +func (c *InstallContainerdCmd) installContainerdV2(config *conf.Config, containerdConfig map[string]any) error { +} diff --git a/main.go b/main.go index fb346fb..55b7e8a 100644 --- a/main.go +++ b/main.go @@ -4,38 +4,40 @@ import ( "fmt" "log" "log/slog" - "os" "github.com/alecthomas/kong" - "github.com/lmittmann/tint" "github.com/wweir/contatto/conf" ) var cli struct { - Config string `short:"c" required:"" default:"/etc/contatto.toml"` + Config string `short:"c" default:"/etc/contatto.toml"` Debug bool `help:"Enable debug logging"` - Install *InstallCmd `cmd:"" help:"install contatto"` + Install *InstallCmd `cmd:"" help:"Install proxy setting."` Proxy *ProxyCmd `cmd:"" help:"Execute Contatto as a registry proxy."` } -func main() { - slog.SetDefault(slog.New(tint.NewHandler(os.Stderr, &tint.Options{ - AddSource: true, - Level: slog.LevelDebug, - }))) +func init() { + log.SetFlags(log.LstdFlags | log.Lshortfile) +} +func main() { ctx := kong.Parse(&cli, kong.UsageOnError(), kong.Description(fmt.Sprintf( `Contatto %s(%s) is a container registry transparent proxy.`, conf.Version, conf.Date)), ) + if cli.Debug { + slog.SetLogLoggerLevel(slog.LevelDebug) + } + config, err := conf.ReadConfig(cli.Config) if err != nil { log.Fatalln("failed to read config:", err) } + if err := ctx.Run(config); err != nil { - log.Fatalf("run failed: %v\n", err) + log.Fatalln("run failed:", err) } }