good morning!!!!

Skip to content
Snippets Groups Projects
handler.go 11.8 KiB
Newer Older
Garet Halliday's avatar
Garet Halliday committed
package gatcaddyfile

import (
	"strconv"
Garet Halliday's avatar
Garet Halliday committed
	"strings"
	"time"
Garet Halliday's avatar
Garet Halliday committed

	"github.com/caddyserver/caddy/v2"
Garet Halliday's avatar
Garet Halliday committed
	"github.com/caddyserver/caddy/v2/caddyconfig"
Garet Halliday's avatar
Garet Halliday committed
	"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"

Garet Halliday's avatar
Garet Halliday committed
	error_handler "gfx.cafe/gfx/pggat/lib/gat/handlers/error"
	"gfx.cafe/gfx/pggat/lib/gat/handlers/pgbouncer_spilo"
	pool_handler "gfx.cafe/gfx/pggat/lib/gat/handlers/pool"

Garet Halliday's avatar
Garet Halliday committed
	"gfx.cafe/gfx/pggat/lib/bouncer"
Garet Halliday's avatar
Garet Halliday committed
	"gfx.cafe/gfx/pggat/lib/gat/handlers/allowed_startup_parameters"
	"gfx.cafe/gfx/pggat/lib/gat/handlers/discovery"
Garet Halliday's avatar
Garet Halliday committed
	"gfx.cafe/gfx/pggat/lib/gat/handlers/pgbouncer"
	"gfx.cafe/gfx/pggat/lib/gat/handlers/require_ssl"
Garet Halliday's avatar
Garet Halliday committed
	"gfx.cafe/gfx/pggat/lib/gat/handlers/rewrite_database"
	"gfx.cafe/gfx/pggat/lib/gat/handlers/rewrite_parameter"
	"gfx.cafe/gfx/pggat/lib/gat/handlers/rewrite_password"
	"gfx.cafe/gfx/pggat/lib/gat/handlers/rewrite_user"
	"gfx.cafe/gfx/pggat/lib/gat/ssl/clients/insecure_skip_verify"
	"gfx.cafe/gfx/pggat/lib/util/strutil"
Garet Halliday's avatar
Garet Halliday committed
)

func init() {
Garet Halliday's avatar
Garet Halliday committed
	RegisterDirective(Handler, "require_ssl", func(d *caddyfile.Dispenser, _ *[]caddyconfig.Warning) (caddy.Module, error) {
Garet Halliday's avatar
Garet Halliday committed
		var ssl = true
Garet Halliday's avatar
Garet Halliday committed
		if d.NextArg() {
Garet Halliday's avatar
Garet Halliday committed
			switch d.Val() {
			case "true":
				ssl = true
			case "false":
				ssl = false
			default:
				return nil, d.SyntaxErr("boolean")
			}
		}
		return &require_ssl.Module{
			SSL: ssl,
		}, nil
	})
Garet Halliday's avatar
Garet Halliday committed
	RegisterDirective(Handler, "allowed_startup_parameters", func(d *caddyfile.Dispenser, _ *[]caddyconfig.Warning) (caddy.Module, error) {
		if !d.NextBlock(d.Nesting()) {
			return nil, d.ArgErr()
		}

		var module allowed_startup_parameters.Module

		for {
			if d.Val() == "}" {
				break
			}

			module.Parameters = append(module.Parameters, strutil.MakeCIString(d.Val()))

			if !d.NextLine() {
				return nil, d.EOFErr()
			}
		}

		return &module, nil
	})
	RegisterDirective(Handler, "user", func(d *caddyfile.Dispenser, _ *[]caddyconfig.Warning) (caddy.Module, error) {
		if !d.NextArg() {
			return nil, d.ArgErr()
		}

		mode := d.Val()

		if d.NextArg() {
			return &rewrite_user.Module{
				Mode: mode,
				User: d.Val(),
			}, nil
		} else {
			return &rewrite_user.Module{
				User: mode,
			}, nil
		}
Garet Halliday's avatar
Garet Halliday committed
	})
	RegisterDirective(Handler, "password", func(d *caddyfile.Dispenser, _ *[]caddyconfig.Warning) (caddy.Module, error) {
		if !d.NextArg() {
			return nil, d.ArgErr()
		}

		return &rewrite_password.Module{
			Password: d.Val(),
		}, nil
	})
	RegisterDirective(Handler, "database", func(d *caddyfile.Dispenser, _ *[]caddyconfig.Warning) (caddy.Module, error) {
		if !d.NextArg() {
			return nil, d.ArgErr()
		}

		mode := d.Val()

		if d.NextArg() {
			return &rewrite_database.Module{
				Mode:     mode,
				Database: d.Val(),
			}, nil
		} else {
			return &rewrite_database.Module{
				Database: mode,
			}, nil
		}
Garet Halliday's avatar
Garet Halliday committed
	})
	RegisterDirective(Handler, "parameter", func(d *caddyfile.Dispenser, _ *[]caddyconfig.Warning) (caddy.Module, error) {
		if !d.NextArg() {
			return nil, d.ArgErr()
		}

		keyValue := d.Val()
		key, value, ok := strings.Cut(keyValue, "=")
		if !ok {
			return nil, d.SyntaxErr("key=value")
		}

		return &rewrite_parameter.Module{
			Key:   strutil.MakeCIString(key),
			Value: value,
		}, nil
	})
Garet Halliday's avatar
Garet Halliday committed
	RegisterDirective(Handler, "error", func(d *caddyfile.Dispenser, _ *[]caddyconfig.Warning) (caddy.Module, error) {
		if !d.NextArg() {
			return nil, d.ArgErr()
		}

		message := d.Val()

		return &error_handler.Module{
			Message: message,
		}, nil
	})
Garet Halliday's avatar
Garet Halliday committed
	RegisterDirective(Handler, "pgbouncer", func(d *caddyfile.Dispenser, _ *[]caddyconfig.Warning) (caddy.Module, error) {
Garet Halliday's avatar
Garet Halliday committed
		var config = "pgbouncer.ini"
Garet Halliday's avatar
Garet Halliday committed
		if d.NextArg() {
Garet Halliday's avatar
Garet Halliday committed
			config = d.Val()
		}
		return &pgbouncer.Module{
			ConfigFile: config,
		}, nil
	})
Garet Halliday's avatar
Garet Halliday committed
	RegisterDirective(Handler, "discovery", func(d *caddyfile.Dispenser, warnings *[]caddyconfig.Warning) (caddy.Module, error) {
		module := discovery.Module{
			Config: discovery.Config{
Garet Halliday's avatar
a  
Garet Halliday committed
				ReconcilePeriod: caddy.Duration(5 * time.Minute),
Garet Halliday's avatar
Garet Halliday committed
				Pool: JSONModuleObject(
					defaultPool,
					Pool,
					"pool",
Garet Halliday's avatar
Garet Halliday committed
					warnings,
				),
Garet Halliday's avatar
Garet Halliday committed
				ServerSSLMode: bouncer.SSLModePrefer,
Garet Halliday's avatar
Garet Halliday committed
				ServerSSL: JSONModuleObject(
					&insecure_skip_verify.Client{},
					SSLClient,
					"provider",
					warnings,
				),
a's avatar
a committed
				ServerMaxConnections: 100,
Garet Halliday's avatar
Garet Halliday committed
			},
		}

		if d.NextArg() {
			// discoverer
			var err error
			module.Discoverer, err = UnmarshalDirectiveJSONModuleObject(
				d,
				Discoverer,
				"discoverer",
				warnings,
			)

			if err != nil {
				return nil, err
			}
		} else {
			if !d.NextBlock(d.Nesting()) {
				return nil, d.ArgErr()
			}

			for {
				if d.Val() == "}" {
					break
				}

				directive := d.Val()
				switch directive {
				case "reconcile_period":
					if !d.NextArg() {
						return nil, d.ArgErr()
					}

					val, err := time.ParseDuration(d.Val())
					if err != nil {
						return nil, d.WrapErr(err)
					}
Garet Halliday's avatar
a  
Garet Halliday committed
					module.ReconcilePeriod = caddy.Duration(val)
				case "max_connections":
					if !d.NextArg() {
						return nil, d.ArgErr()
					}

					val, err := strconv.Atoi(d.Val())
					if err != nil {
						return nil, d.WrapErr(err)
					}
					module.ServerMaxConnections = val
				case "min_connections":
					if !d.NextArg() {
						return nil, d.ArgErr()
					}

					val, err := strconv.Atoi(d.Val())
					if err != nil {
						return nil, d.WrapErr(err)
					}
					module.ServerMinConnections = val
Garet Halliday's avatar
Garet Halliday committed
				case "discoverer":
					if !d.NextArg() {
						return nil, d.ArgErr()
					}

					var err error
					module.Discoverer, err = UnmarshalDirectiveJSONModuleObject(
						d,
						Discoverer,
						"discoverer",
						warnings,
					)
					if err != nil {
						return nil, err
					}
Garet Halliday's avatar
Garet Halliday committed
				case "pool":
Garet Halliday's avatar
Garet Halliday committed
					if !d.NextArg() {
						return nil, d.ArgErr()
					}

					var err error
Garet Halliday's avatar
Garet Halliday committed
					module.Pool, err = UnmarshalDirectiveJSONModuleObject(
Garet Halliday's avatar
Garet Halliday committed
						d,
Garet Halliday's avatar
Garet Halliday committed
						Pool,
						"pool",
Garet Halliday's avatar
Garet Halliday committed
						warnings,
					)
					if err != nil {
						return nil, err
					}
				case "ssl":
					if !d.NextArg() {
						return nil, d.ArgErr()
					}

Garet Halliday's avatar
Garet Halliday committed
					module.ServerSSLMode = bouncer.SSLMode(d.Val())
Garet Halliday's avatar
Garet Halliday committed

					if !d.NextArg() {
						return nil, d.ArgErr()
					}

					var err error
					module.ServerSSL, err = UnmarshalDirectiveJSONModuleObject(
						d,
						SSLClient,
						"provider",
						warnings,
					)
					if err != nil {
						return nil, err
					}
				case "parameter":
					if !d.NextArg() {
						return nil, d.ArgErr()
					}

					keyValue := d.Val()
					key, value, ok := strings.Cut(keyValue, "=")
					if !ok {
						return nil, d.SyntaxErr("key=value")
					}
					if module.ServerStartupParameters == nil {
						module.ServerStartupParameters = make(map[string]string)
					}
					module.ServerStartupParameters[key] = value
Garet Halliday's avatar
Garet Halliday committed
				default:
					return nil, d.ArgErr()
Garet Halliday's avatar
Garet Halliday committed
				}

				if !d.NextLine() {
					return nil, d.EOFErr()
				}
			}
		}

		return &module, nil
	})
	RegisterDirective(Handler, "pgbouncer_spilo", func(d *caddyfile.Dispenser, warnings *[]caddyconfig.Warning) (caddy.Module, error) {
		module := pgbouncer_spilo.Module{}

		if !d.NextBlock(d.Nesting()) {
			return nil, d.ArgErr()
		}

		for {
			if d.Val() == "}" {
				break
			}

			directive := d.Val()
			switch directive {
			case "host":
				if !d.NextArg() {
					return nil, d.ArgErr()
				}

				module.Host = d.Val()
			case "port":
				if !d.NextArg() {
					return nil, d.ArgErr()
				}

				var err error
				module.Port, err = strconv.Atoi(d.Val())
				if err != nil {
					return nil, d.WrapErr(err)
				}
			case "user":
				if !d.NextArg() {
					return nil, d.ArgErr()
				}

				module.User = d.Val()
			case "schema":
				if !d.NextArg() {
					return nil, d.ArgErr()
				}

				module.Schema = d.Val()
			case "password":
				if !d.NextArg() {
					return nil, d.ArgErr()
				}

				module.Password = d.Val()
			case "mode":
				if !d.NextArg() {
					return nil, d.ArgErr()
				}

				module.Mode = d.Val()
			case "default_size":
				if !d.NextArg() {
					return nil, d.ArgErr()
				}

				var err error
				module.DefaultSize, err = strconv.Atoi(d.Val())
				if err != nil {
					return nil, d.WrapErr(err)
				}
			case "min_size":
				if !d.NextArg() {
					return nil, d.ArgErr()
				}

				var err error
				module.MinSize, err = strconv.Atoi(d.Val())
				if err != nil {
					return nil, d.WrapErr(err)
				}
			case "reserve_size":
				if !d.NextArg() {
					return nil, d.ArgErr()
				}

				var err error
				module.ReserveSize, err = strconv.Atoi(d.Val())
				if err != nil {
					return nil, d.WrapErr(err)
				}
			case "max_client_conn":
				if !d.NextArg() {
					return nil, d.ArgErr()
				}

				var err error
				module.MaxClientConn, err = strconv.Atoi(d.Val())
				if err != nil {
					return nil, d.WrapErr(err)
				}
			case "max_db_conn":
				if !d.NextArg() {
					return nil, d.ArgErr()
				}

				var err error
				module.MaxDBConn, err = strconv.Atoi(d.Val())
				if err != nil {
					return nil, d.WrapErr(err)
				}
			default:
				return nil, d.ArgErr()
			}

			if !d.NextLine() {
				return nil, d.EOFErr()
			}
		}

Garet Halliday's avatar
Garet Halliday committed
		return &module, nil
	})
	RegisterDirective(Handler, "pool", func(d *caddyfile.Dispenser, warnings *[]caddyconfig.Warning) (caddy.Module, error) {
		module := pool_handler.Module{
Garet Halliday's avatar
Garet Halliday committed
			Pool: JSONModuleObject(
				defaultPool,
				Pool,
				"pool",
				warnings,
			),
			Recipe: pool_handler.Recipe{
				Dialer: pool_handler.Dialer{
					SSLMode: bouncer.SSLModePrefer,
					RawSSL: JSONModuleObject(
						&insecure_skip_verify.Client{},
						SSLClient,
						"provider",
						warnings,
					),
				},
Garet Halliday's avatar
Garet Halliday committed
			},
		}

		if d.NextArg() {
Garet Halliday's avatar
Garet Halliday committed
			module.Recipe.Dialer.Address = d.Val()
Garet Halliday's avatar
Garet Halliday committed

			if !d.NextArg() {
				return nil, d.ArgErr()
			}
Garet Halliday's avatar
Garet Halliday committed
			module.Recipe.Dialer.Database = d.Val()
Garet Halliday's avatar
Garet Halliday committed

			if !d.NextArg() {
				return nil, d.ArgErr()
			}
Garet Halliday's avatar
Garet Halliday committed
			module.Recipe.Dialer.Username = d.Val()
Garet Halliday's avatar
Garet Halliday committed

			if !d.NextArg() {
				return nil, d.ArgErr()
			}
Garet Halliday's avatar
Garet Halliday committed
			module.Recipe.Dialer.RawPassword = d.Val()
Garet Halliday's avatar
Garet Halliday committed
		} else {
			for nesting := d.Nesting(); d.NextBlock(nesting); {
Garet Halliday's avatar
Garet Halliday committed
				directive := d.Val()
				switch directive {
Garet Halliday's avatar
Garet Halliday committed
				case "pool":
Garet Halliday's avatar
Garet Halliday committed
					if !d.NextArg() {
						return nil, d.ArgErr()
					}

					var err error
Garet Halliday's avatar
Garet Halliday committed
					module.Pool, err = UnmarshalDirectiveJSONModuleObject(
Garet Halliday's avatar
Garet Halliday committed
						d,
Garet Halliday's avatar
Garet Halliday committed
						Pool,
						"pool",
Garet Halliday's avatar
Garet Halliday committed
						warnings,
					)
					if err != nil {
						return nil, err
					}
				case "address":
					if !d.NextArg() {
						return nil, d.ArgErr()
					}

Garet Halliday's avatar
Garet Halliday committed
					module.Recipe.Dialer.Address = d.Val()
Garet Halliday's avatar
Garet Halliday committed
				case "ssl":
					if !d.NextArg() {
						return nil, d.ArgErr()
					}

Garet Halliday's avatar
Garet Halliday committed
					module.Recipe.Dialer.SSLMode = bouncer.SSLMode(d.Val())
Garet Halliday's avatar
Garet Halliday committed

					if !d.NextArg() {
						return nil, d.ArgErr()
					}

					var err error
Garet Halliday's avatar
Garet Halliday committed
					module.Recipe.Dialer.RawSSL, err = UnmarshalDirectiveJSONModuleObject(
Garet Halliday's avatar
Garet Halliday committed
						d,
						SSLClient,
						"provider",
						warnings,
					)
					if err != nil {
						return nil, err
					}
				case "username":
					if !d.NextArg() {
						return nil, d.ArgErr()
					}

Garet Halliday's avatar
Garet Halliday committed
					module.Recipe.Dialer.Username = d.Val()
Garet Halliday's avatar
Garet Halliday committed
				case "password":
					if !d.NextArg() {
						return nil, d.ArgErr()
					}

Garet Halliday's avatar
Garet Halliday committed
					module.Recipe.Dialer.RawPassword = d.Val()
Garet Halliday's avatar
Garet Halliday committed
				case "database":
					if !d.NextArg() {
						return nil, d.ArgErr()
					}

Garet Halliday's avatar
Garet Halliday committed
					module.Recipe.Dialer.Database = d.Val()
Garet Halliday's avatar
Garet Halliday committed
				case "parameter":
					if !d.NextArg() {
						return nil, d.ArgErr()
					}

					keyValue := d.Val()
					key, value, ok := strings.Cut(keyValue, "=")
					if !ok {
						return nil, d.SyntaxErr("key=value")
					}
Garet Halliday's avatar
Garet Halliday committed
					if module.Recipe.Dialer.RawParameters == nil {
						module.Recipe.Dialer.RawParameters = make(map[string]string)
Garet Halliday's avatar
Garet Halliday committed
					}
Garet Halliday's avatar
Garet Halliday committed
					module.Recipe.Dialer.RawParameters[key] = value
Garet Halliday's avatar
Garet Halliday committed
				default:
					return nil, d.ArgErr()
				}
			}
		}

Garet Halliday's avatar
Garet Halliday committed
		return &module, nil
	})
Thomas Guinther's avatar
Thomas Guinther committed

	RegisterDirective(Handler, "tracing", func(d *caddyfile.Dispenser, warnings *[]caddyconfig.Warning) (caddy.Module, error) {
		var module caddy.Module
		var err error

		if !d.NextArg() {
			return nil, d.Errf("expected a tracing directive")
		}

		directive := d.Val()

		switch directive {
		case OtelTracing:
			module, err = UnmarshalModule(
				d,
				Tracing,
				warnings,
			)
			if err != nil {
				return nil, err
			}
		}

		return module, nil
	})
Garet Halliday's avatar
Garet Halliday committed
}