AppManager: Support exposing cross-cluster ports
Change-Id: I4bdb3573209935f6777656ec2f3481e79d84a9c9
diff --git a/core/dns-api/init.go b/core/dns-api/init.go
index 0544611..5e494ae 100644
--- a/core/dns-api/init.go
+++ b/core/dns-api/init.go
@@ -40,6 +40,8 @@
{{- range $i, $ns := .nameserverIP }}
ns{{ add1 $i }}.{{ $zone }}. 10800 IN A {{ $ns }}
{{- end }}
+ns.p.{{ $zone }}. 10800 IN A 100.100.100.100
+devices.p.{{ $zone }}. 10800 IN NS ns.p.{{ $zone }}
{{- range .publicIP }}
{{ $zone }}. 10800 IN A {{ . }}
*.{{ $zone }}. 10800 IN A {{ . }}
diff --git a/core/installer/app.go b/core/installer/app.go
index 948e17e..e57fee8 100644
--- a/core/installer/app.go
+++ b/core/installer/app.go
@@ -95,6 +95,7 @@
}
type PortForward struct {
+ Cluster string `json:"cluster,omitempty"`
Allocator string `json:"allocator"`
ReserveAddr string `json:"reservator"`
RemoveAddr string `json:"deallocator"`
diff --git a/core/installer/app_configs/app_base.cue b/core/installer/app_configs/app_base.cue
index 7698553..7330b1e 100644
--- a/core/installer/app_configs/app_base.cue
+++ b/core/installer/app_configs/app_base.cue
@@ -109,9 +109,9 @@
imageRegistry: string | *"docker.io"
}
-// TODO(gio): Support inter-cluster porf forwarding
#PortForward: {
network: #Network
+ cluster?: string | null
port: int
service: close({
name: string
@@ -507,15 +507,44 @@
_volumeClaimName: "\(name)-postgresql"
_name: name
- openPort: [for i, e in expose {
- network: networks[strings.ToLower(e.network)]
- port: input["port_postgresql_\(_name)_\(i)"]
- protocol: "TCP"
- service: {
- name: "postgres-\(_name)"
- port: 5432
+ openPort: list.FlattenN([for i, e in expose {
+ if cluster == _|_ {
+ network: networks[strings.ToLower(e.network)]
+ port: input["port_postgresql_\(_name)_\(i)"]
+ protocol: "TCP"
+ service: {
+ name: "postgres-\(_name)"
+ port: 5432
+ }
}
- }]
+ if cluster != _|_ {
+ [{
+ network: #Network & {
+ name: "cluster_\(cluster.name)"
+ ingressClass: "default"
+ domain: ""
+ allocatePortAddr: "http://port-allocator.\(global.id)-cluster-\(cluster.name)-network.svc.cluster.local/api/allocate"
+ reservePortAddr: "http://port-allocator.\(global.id)-cluster-\(cluster.name)-network.svc.cluster.local/api/reserve"
+ deallocatePortAddr: "http://port-allocator.\(global.id)-cluster-\(cluster.name)-network.svc.cluster.local/api/remmove"
+ }
+ port: input["port_postgresql_\(_name)_\(i)_cluster"]
+ protocol: "TCP"
+ service: {
+ name: "postgres-\(_name)"
+ port: 5432
+ }
+ }, {
+ cluster: _cluster.name
+ network: networks[strings.ToLower(e.network)]
+ port: input["port_postgresql_\(_name)_\(i)"]
+ protocol: "TCP"
+ service: {
+ name: "cluster-\(cluster).private-network-proxy.devices.\(global.privateDomain)"
+ port: input["port_postgresql_\(_name)_\(i)_cluster"]
+ }
+ }]
+ }
+ }], -1)
images: {
postgres: {
diff --git a/core/installer/app_configs/app_global_env.cue b/core/installer/app_configs/app_global_env.cue
index 3841f02..6a02df2 100644
--- a/core/installer/app_configs/app_global_env.cue
+++ b/core/installer/app_configs/app_global_env.cue
@@ -62,8 +62,8 @@
if _cluster != _|_ {
clusterProxy: {
"\(name)": {
- from: _domain
_sanitizedDomain: strings.Replace(_domain, ".", "-", -1)
+ from: _domain
to: "\(_sanitizedDomain).\(_cluster.name).cluster.\(global.privateDomain)"
}
}
diff --git a/core/installer/app_configs/dodo_app.cue b/core/installer/app_configs/dodo_app.cue
index bf5a7f8..6f7001a 100644
--- a/core/installer/app_configs/dodo_app.cue
+++ b/core/installer/app_configs/dodo_app.cue
@@ -24,6 +24,9 @@
for v in _postgresql {
for i, e in v.expose {
"port_postgresql_\(v.name)_\(i)": int @role(port)
+ if input.cluster != _|_ {
+ "port_postgresql_\(v.name)_\(i)_cluster": int @role(port)
+ }
}
}
for v in _mongodb {
diff --git a/core/installer/app_manager.go b/core/installer/app_manager.go
index c5b849f..3285c19 100644
--- a/core/installer/app_manager.go
+++ b/core/installer/app_manager.go
@@ -182,10 +182,19 @@
Secret string `json:"secret"`
}
-func reservePorts(ports map[string]string) (map[string]reservePortResp, error) {
+type reservePortInfo struct {
+ reserveAddr string
+ RemoteProxy bool `json:"remoteProxy"`
+}
+
+func reservePorts(ports map[string]reservePortInfo) (map[string]reservePortResp, error) {
ret := map[string]reservePortResp{}
- for p, reserveAddr := range ports {
- resp, err := http.Post(reserveAddr, "application/json", nil) // TODO(gio): address
+ for p, cfg := range ports {
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(cfg); err != nil {
+ return nil, err
+ }
+ resp, err := http.Post(cfg.reserveAddr, "application/json", &buf)
if err != nil {
return nil, err
}
@@ -205,11 +214,17 @@
func openPorts(ports []PortForward, reservations map[string]reservePortResp, allocators map[string]string, ns string) error {
for _, p := range ports {
+ var target string
+ if p.Cluster == "" {
+ target = fmt.Sprintf("%s/%s", ns, p.Service.Name)
+ } else {
+ target = p.Service.Name
+ }
var buf bytes.Buffer
req := allocatePortReq{
Protocol: p.Protocol,
SourcePort: p.Port,
- TargetService: fmt.Sprintf("%s/%s", ns, p.Service.Name),
+ TargetService: target,
TargetPort: p.Service.Port,
}
allocator := ""
@@ -475,10 +490,13 @@
if err != nil {
return ReleaseResources{}, err
}
- reservators := map[string]string{}
+ reservators := map[string]reservePortInfo{}
allocators := map[string]string{}
for _, pf := range rendered.Ports {
- reservators[portFields[pf.Port]] = pf.ReserveAddr
+ reservators[portFields[pf.Port]] = reservePortInfo{
+ reserveAddr: pf.ReserveAddr,
+ RemoteProxy: pf.Cluster != "",
+ }
allocators[portFields[pf.Port]] = pf.Allocator
}
portReservations, err := reservePorts(reservators)
@@ -530,7 +548,7 @@
return ReleaseResources{}, err
}
for _, p := range rendered.ClusterProxies {
- if err := m.cnc.AddProxy(p.From, p.To); err != nil {
+ if err := m.cnc.AddIngressProxy(p.From, p.To); err != nil {
return ReleaseResources{}, err
}
}
@@ -651,7 +669,7 @@
}
}
if !found {
- if err := m.cnc.RemoveProxy(ocp.From, ocp.To); err != nil {
+ if err := m.cnc.RemoveIngressProxy(ocp.From, ocp.To); err != nil {
return ReleaseResources{}, err
}
}
@@ -665,7 +683,7 @@
}
}
if !found {
- if err := m.cnc.AddProxy(ncp.From, ncp.To); err != nil {
+ if err := m.cnc.AddIngressProxy(ncp.From, ncp.To); err != nil {
return ReleaseResources{}, err
}
}
@@ -723,7 +741,7 @@
return err
}
for _, cp := range cfg.Out.ClusterProxy {
- if err := m.cnc.RemoveProxy(cp.From, cp.To); err != nil {
+ if err := m.cnc.RemoveIngressProxy(cp.From, cp.To); err != nil {
return err
}
}
diff --git a/core/installer/canvas-app.cue b/core/installer/canvas-app.cue
index a8be305..6843277 100644
--- a/core/installer/canvas-app.cue
+++ b/core/installer/canvas-app.cue
@@ -24,14 +24,14 @@
"enabled": false
}
}],
- "mongodb": [{
+ "postgresql": [{
"name": "pgg",
"size": "2Gi",
"expose": [{
"network": "private",
- "subdomain": "mongoo"
+ "subdomain": "pggp"
}]
}],
- "cluster": "ct"
+ "cluster": "asdc"
}
}
diff --git a/core/installer/cluster.go b/core/installer/cluster.go
index 19220af..ac7d970 100644
--- a/core/installer/cluster.go
+++ b/core/installer/cluster.go
@@ -16,21 +16,26 @@
"github.com/giolekva/pcloud/core/installer/soft"
+ corev1 "k8s.io/api/core/v1"
+ "k8s.io/apimachinery/pkg/util/intstr"
"sigs.k8s.io/yaml"
)
type ClusterNetworkConfigurator interface {
AddCluster(name string, ingressIP net.IP) error
RemoveCluster(name string, ingressIP net.IP) error
- AddProxy(src, dst string) error
- RemoveProxy(src, dst string) error
+ AddProxy(src int, dst string, protocol Protocol) (string, error)
+ AddIngressProxy(src, dst string) error
+ RemoveProxy(src int, dst string, protocol Protocol) error
+ RemoveIngressProxy(src, dst string) error
}
type NginxProxyConfigurator struct {
PrivateSubdomain string
DNSAPIAddr string
Repo soft.RepoIO
- NginxConfigPath string
+ ConfigPath string
+ ServicePath string
}
type createARecordReq struct {
@@ -80,10 +85,47 @@
return nil
}
-func (c *NginxProxyConfigurator) AddProxy(src, dst string) error {
+func (c *NginxProxyConfigurator) AddProxy(src int, dst string, protocol Protocol) (string, error) {
+ var namespace string
_, err := c.Repo.Do(func(fs soft.RepoFS) (string, error) {
+ if err := func() error {
+ r, err := fs.Reader(c.ServicePath)
+ if err != nil {
+ return err
+ }
+ defer r.Close()
+ var buf bytes.Buffer
+ if _, err := io.Copy(&buf, r); err != nil {
+ return err
+ }
+ var svc corev1.Service
+ if err := yaml.Unmarshal(buf.Bytes(), &svc); err != nil {
+ return err
+ }
+ svc.Spec.Ports = append(svc.Spec.Ports, corev1.ServicePort{
+ Name: fmt.Sprintf("p%d", src),
+ Protocol: corev1.Protocol(ProtocolToString(protocol)),
+ Port: int32(src),
+ TargetPort: intstr.FromInt(src),
+ })
+ w, err := fs.Writer(c.ServicePath)
+ if err != nil {
+ return err
+ }
+ defer w.Close()
+ tmp, err := yaml.Marshal(svc)
+ if err != nil {
+ return err
+ }
+ if _, err := io.Copy(w, bytes.NewReader(tmp)); err != nil {
+ return err
+ }
+ return nil
+ }(); err != nil {
+ return "", err
+ }
cfg, err := func() (NginxProxyConfig, error) {
- r, err := fs.Reader(c.NginxConfigPath)
+ r, err := fs.Reader(c.ConfigPath)
if err != nil {
return NginxProxyConfig{}, err
}
@@ -93,11 +135,19 @@
if err != nil {
return "", err
}
- if v, ok := cfg.Proxies[src]; ok && v != dst {
- return "", fmt.Errorf("wrong mapping %s already exists (%s)", src, v)
+ namespace = cfg.Namespace
+ var proxyMap map[int]string
+ switch protocol {
+ case ProtocolTCP:
+ proxyMap = cfg.TCP
+ case ProtocolUDP:
+ proxyMap = cfg.UDP
+ default:
+ return "", fmt.Errorf("invalid protocol: %v", protocol)
}
- cfg.Proxies[src] = dst
- w, err := fs.Writer(c.NginxConfigPath)
+ // TODO(gio): check for already existing mapping
+ proxyMap[src] = dst
+ w, err := fs.Writer(c.ConfigPath)
if err != nil {
return "", err
}
@@ -108,7 +158,7 @@
return "", err
}
hash := base64.StdEncoding.EncodeToString(h.Sum(nil))
- nginxPath := filepath.Join(filepath.Dir(c.NginxConfigPath), "ingress-nginx.yaml")
+ nginxPath := filepath.Join(filepath.Dir(c.ConfigPath), "ingress-nginx.yaml")
nginx, err := func() (map[string]any, error) {
r, err := fs.Reader(nginxPath)
if err != nil {
@@ -149,15 +199,18 @@
if _, err := io.Copy(w, bytes.NewReader(buf)); err != nil {
return "", err
}
- return fmt.Sprintf("add proxy mapping: %s %s", src, dst), nil
+ return fmt.Sprintf("add proxy mapping: %d %s", src, dst), nil
})
- return err
+ if err != nil {
+ return "", err
+ }
+ return namespace, nil
}
-func (c *NginxProxyConfigurator) RemoveProxy(src, dst string) error {
+func (c *NginxProxyConfigurator) AddIngressProxy(src, dst string) error {
_, err := c.Repo.Do(func(fs soft.RepoFS) (string, error) {
cfg, err := func() (NginxProxyConfig, error) {
- r, err := fs.Reader(c.NginxConfigPath)
+ r, err := fs.Reader(c.ConfigPath)
if err != nil {
return NginxProxyConfig{}, err
}
@@ -167,11 +220,11 @@
if err != nil {
return "", err
}
- if v, ok := cfg.Proxies[src]; !ok || v != dst {
- return "", fmt.Errorf("wrong mapping from source: %s actual: %s expected: %s", src, v, dst)
+ if v, ok := cfg.Ingress[src]; ok && v != dst {
+ return "", fmt.Errorf("wrong mapping %s already exists (%s)", src, v)
}
- delete(cfg.Proxies, src)
- w, err := fs.Writer(c.NginxConfigPath)
+ cfg.Ingress[src] = dst
+ w, err := fs.Writer(c.ConfigPath)
if err != nil {
return "", err
}
@@ -182,7 +235,198 @@
return "", err
}
hash := base64.StdEncoding.EncodeToString(h.Sum(nil))
- nginxPath := filepath.Join(filepath.Dir(c.NginxConfigPath), "ingress-nginx.yaml")
+ nginxPath := filepath.Join(filepath.Dir(c.ConfigPath), "ingress-nginx.yaml")
+ nginx, err := func() (map[string]any, error) {
+ r, err := fs.Reader(nginxPath)
+ if err != nil {
+ return nil, err
+ }
+ defer r.Close()
+ var buf bytes.Buffer
+ if _, err := io.Copy(&buf, r); err != nil {
+ return nil, err
+ }
+ ret := map[string]any{}
+ if err := yaml.Unmarshal(buf.Bytes(), &ret); err != nil {
+ return nil, err
+ }
+ return ret, nil
+ }()
+ if err != nil {
+ return "", err
+ }
+ cv := nginx["spec"].(map[string]any)["values"].(map[string]any)["controller"].(map[string]any)
+ var annotations map[string]any
+ if a, ok := cv["podAnnotations"]; ok {
+ annotations = a.(map[string]any)
+ } else {
+ annotations = map[string]any{}
+ cv["podAnnotations"] = annotations
+ }
+ annotations["dodo.cloud/hash"] = string(hash)
+ buf, err := yaml.Marshal(nginx)
+ if err != nil {
+ return "", err
+ }
+ w, err = fs.Writer(nginxPath)
+ if err != nil {
+ return "", err
+ }
+ defer w.Close()
+ if _, err := io.Copy(w, bytes.NewReader(buf)); err != nil {
+ return "", err
+ }
+ return fmt.Sprintf("add ingress proxy mapping: %s %s", src, dst), nil
+ })
+ return err
+}
+
+func (c *NginxProxyConfigurator) RemoveProxy(src int, dst string, protocol Protocol) error {
+ _, err := c.Repo.Do(func(fs soft.RepoFS) (string, error) {
+ if err := func() error {
+ r, err := fs.Reader(c.ServicePath)
+ if err != nil {
+ return err
+ }
+ defer r.Close()
+ var buf bytes.Buffer
+ if _, err := io.Copy(&buf, r); err != nil {
+ return err
+ }
+ var svc corev1.Service
+ if err := yaml.Unmarshal(buf.Bytes(), &svc); err != nil {
+ return err
+ }
+ for i, p := range svc.Spec.Ports {
+ if p.Port == int32(src) {
+ svc.Spec.Ports = append(svc.Spec.Ports[:i], svc.Spec.Ports[i+1:]...)
+ break
+ }
+ }
+ w, err := fs.Writer(c.ServicePath)
+ if err != nil {
+ return err
+ }
+ defer w.Close()
+ tmp, err := yaml.Marshal(svc)
+ if err != nil {
+ return err
+ }
+ if _, err := io.Copy(w, bytes.NewReader(tmp)); err != nil {
+ return err
+ }
+ return nil
+ }(); err != nil {
+ return "", err
+ }
+ cfg, err := func() (NginxProxyConfig, error) {
+ r, err := fs.Reader(c.ConfigPath)
+ if err != nil {
+ return NginxProxyConfig{}, err
+ }
+ defer r.Close()
+ return ParseNginxProxyConfig(r)
+ }()
+ if err != nil {
+ return "", err
+ }
+ var proxyMap map[int]string
+ switch protocol {
+ case ProtocolTCP:
+ proxyMap = cfg.TCP
+ case ProtocolUDP:
+ proxyMap = cfg.UDP
+ default:
+ return "", fmt.Errorf("invalid protocol: %v", protocol)
+ }
+ // TODO(gio): check for already existing mapping
+ delete(proxyMap, src)
+ w, err := fs.Writer(c.ConfigPath)
+ if err != nil {
+ return "", err
+ }
+ defer w.Close()
+ h := sha256.New()
+ o := io.MultiWriter(w, h)
+ if err := cfg.Render(o); err != nil {
+ return "", err
+ }
+ hash := base64.StdEncoding.EncodeToString(h.Sum(nil))
+ nginxPath := filepath.Join(filepath.Dir(c.ConfigPath), "ingress-nginx.yaml")
+ nginx, err := func() (map[string]any, error) {
+ r, err := fs.Reader(nginxPath)
+ if err != nil {
+ return nil, err
+ }
+ defer r.Close()
+ var buf bytes.Buffer
+ if _, err := io.Copy(&buf, r); err != nil {
+ return nil, err
+ }
+ ret := map[string]any{}
+ if err := yaml.Unmarshal(buf.Bytes(), &ret); err != nil {
+ return nil, err
+ }
+ return ret, nil
+ }()
+ if err != nil {
+ return "", err
+ }
+ cv := nginx["spec"].(map[string]any)["values"].(map[string]any)["controller"].(map[string]any)
+ var annotations map[string]any
+ if a, ok := cv["podAnnotations"]; ok {
+ annotations = a.(map[string]any)
+ } else {
+ annotations = map[string]any{}
+ cv["podAnnotations"] = annotations
+ }
+ annotations["dodo.cloud/hash"] = string(hash)
+ buf, err := yaml.Marshal(nginx)
+ if err != nil {
+ return "", err
+ }
+ w, err = fs.Writer(nginxPath)
+ if err != nil {
+ return "", err
+ }
+ defer w.Close()
+ if _, err := io.Copy(w, bytes.NewReader(buf)); err != nil {
+ return "", err
+ }
+ return fmt.Sprintf("remove proxy mapping: %d %s", src, dst), nil
+ })
+ return err
+}
+
+func (c *NginxProxyConfigurator) RemoveIngressProxy(src, dst string) error {
+ _, err := c.Repo.Do(func(fs soft.RepoFS) (string, error) {
+ cfg, err := func() (NginxProxyConfig, error) {
+ r, err := fs.Reader(c.ConfigPath)
+ if err != nil {
+ return NginxProxyConfig{}, err
+ }
+ defer r.Close()
+ return ParseNginxProxyConfig(r)
+ }()
+ if err != nil {
+ return "", err
+ }
+ if v, ok := cfg.Ingress[src]; !ok || v != dst {
+ return "", fmt.Errorf("wrong mapping from source: %s actual: %s expected: %s", src, v, dst)
+ }
+ delete(cfg.Ingress, src)
+ w, err := fs.Writer(c.ConfigPath)
+ if err != nil {
+ return "", err
+ }
+ defer w.Close()
+ h := sha256.New()
+ o := io.MultiWriter(w, h)
+ if err := cfg.Render(o); err != nil {
+ return "", err
+ }
+ hash := base64.StdEncoding.EncodeToString(h.Sum(nil))
+ nginxPath := filepath.Join(filepath.Dir(c.ConfigPath), "ingress-nginx.yaml")
nginx, err := func() (map[string]any, error) {
r, err := fs.Reader(nginxPath)
if err != nil {
@@ -228,11 +472,40 @@
return err
}
+type Protocol int
+
+const (
+ ProtocolTCP Protocol = iota
+ ProtocolUDP
+)
+
+func ProtocolToString(p Protocol) string {
+ if p == ProtocolTCP {
+ return "TCP"
+ } else {
+ return "UDP"
+ }
+}
+
type NginxProxyConfig struct {
- Port int
- Resolvers []net.IP
- Proxies map[string]string
- PreConf []string
+ Namespace string
+ IngressPort int
+ Resolvers []net.IP
+ Ingress map[string]string
+ TCP map[int]string
+ UDP map[int]string
+ PreConf []string
+}
+
+func parseProtocol(s string) (Protocol, error) {
+ switch strings.ToLower(s) {
+ case "tcp":
+ return ProtocolTCP, nil
+ case "udp":
+ return ProtocolUDP, nil
+ default:
+ return ProtocolUDP, fmt.Errorf("invalid protocol: %s", s)
+ }
}
func ParseNginxProxyConfig(r io.Reader) (NginxProxyConfig, error) {
@@ -241,13 +514,19 @@
return NginxProxyConfig{}, err
}
ret := NginxProxyConfig{
- Port: -1,
- Resolvers: nil,
- Proxies: make(map[string]string),
+ IngressPort: -1,
+ Resolvers: nil,
+ Ingress: make(map[string]string),
+ TCP: make(map[int]string),
+ UDP: make(map[int]string),
}
lines := strings.Split(buf.String(), "\n")
- insideConf := true
+ insidePreConf := true
+ insideHttp := false
insideMap := false
+ insideStream := false
+ streamPort := -1
+ streamPortProtocol := ProtocolTCP
for _, l := range lines {
items := strings.Fields(strings.TrimSuffix(l, ";"))
if len(items) == 0 {
@@ -255,19 +534,49 @@
}
if strings.Contains(l, "nginx.conf") {
ret.PreConf = append(ret.PreConf, l)
- insideConf = false
- } else if insideConf {
+ insidePreConf = false
+ } else if insidePreConf {
ret.PreConf = append(ret.PreConf, l)
+ items := strings.Fields(l)
+ if items[0] == "namespace:" {
+ ret.Namespace = items[1]
+ }
+ } else if items[0] == "http" {
+ insideHttp = true
+ } else if insideHttp && items[0] == "map" {
+ insideMap = true
+ } else if items[0] == "stream" {
+ insideHttp = false
+ insideMap = false
+ insideStream = true
} else if strings.Contains(l, "listen") {
if len(items) < 2 {
- return NginxProxyConfig{}, fmt.Errorf("invalid listen: %s\n", l)
+ return NginxProxyConfig{}, fmt.Errorf("invalid listen: %s", l)
}
port, err := strconv.Atoi(items[1])
if err != nil {
return NginxProxyConfig{}, err
}
- ret.Port = port
- } else if strings.Contains(l, "resolver") {
+ if insideHttp {
+ if len(items) > 2 {
+ return NginxProxyConfig{}, fmt.Errorf("invalid http listen: %s", l)
+ }
+ ret.IngressPort = port
+ } else {
+ if !insideStream {
+ return NginxProxyConfig{}, fmt.Errorf("invalid state, expected to be inside stream section")
+ }
+ streamPort = port
+ if len(items) == 3 {
+ streamPortProtocol, err = parseProtocol(items[2])
+ if err != nil {
+ return NginxProxyConfig{}, err
+ }
+ } else {
+ streamPortProtocol = ProtocolTCP
+ }
+ }
+ } else if insideHttp && strings.Contains(l, "resolver") {
if len(items) < 2 {
return NginxProxyConfig{}, fmt.Errorf("invalid resolver: %s", l)
}
@@ -276,7 +585,7 @@
return NginxProxyConfig{}, fmt.Errorf("invalid resolver ip: %s", l)
}
ret.Resolvers = append(ret.Resolvers, ip)
- } else if insideMap {
+ } else if insideHttp && insideMap {
if items[0] == "}" {
insideMap = false
continue
@@ -284,9 +593,19 @@
if len(items) < 2 {
return NginxProxyConfig{}, fmt.Errorf("invalid map: %s", l)
}
- ret.Proxies[items[0]] = items[1]
- } else if items[0] == "map" {
- insideMap = true
+ ret.Ingress[items[0]] = items[1]
+ } else if insideStream && strings.Contains(l, "proxy_pass") {
+ if streamPort == -1 {
+ return NginxProxyConfig{}, fmt.Errorf("invalid state, expected server port to be defined")
+ }
+ if len(items) < 2 {
+ return NginxProxyConfig{}, fmt.Errorf("invalid proxy_pass: %s", l)
+ }
+ if streamPortProtocol == ProtocolTCP {
+ ret.TCP[streamPort] = items[1]
+ } else {
+ ret.UDP[streamPort] = items[1]
+ }
}
}
return ret, nil
@@ -310,12 +629,12 @@
}
http {
map $http_host $backend {
- {{- range $from, $to := .Proxies }}
+ {{- range $from, $to := .Ingress }}
{{ $from }} {{ $to }};
{{- end }}
}
server {
- listen {{ .Port }};
+ listen {{ .IngressPort }};
location / {
{{- range .Resolvers }}
resolver {{ . }};
@@ -323,4 +642,22 @@
proxy_pass http://$backend;
}
}
- }`
+ }
+ {{- if or .TCP .UDP }}
+ stream {
+ {{- range $port, $upstream := .TCP }}
+ server {
+ listen {{ $port }};
+ resolver 100.100.100.100;
+ proxy_pass {{ $upstream }};
+ }
+ {{- end }}
+ {{- range $port, $upstream := .UDP }}
+ server {
+ listen {{ $port }} udp;
+ resolver 100.100.100.100;
+ proxy_pass {{ $upstream }};
+ }
+ {{- end }}
+ }
+ {{- end }}`
diff --git a/core/installer/cluster_test.go b/core/installer/cluster_test.go
index e315202..b2ecd99 100644
--- a/core/installer/cluster_test.go
+++ b/core/installer/cluster_test.go
@@ -7,7 +7,14 @@
)
func TestParseNginxProxyConfig(t *testing.T) {
- cfg, err := ParseNginxProxyConfig(strings.NewReader(`nginx.conf: |
+ cfg, err := ParseNginxProxyConfig(strings.NewReader(`
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: proxy-backend-config
+ namespace: foo
+data:
+nginx.conf: |
# user www www;
worker_processes 1;
error_log /dev/null crit;
@@ -33,33 +40,66 @@
}
}
}
+stream {
+ server {
+ listen 9091;
+ proxy_pass foo:1;
+ }
+ server {
+ listen 9092 udp;
+ proxy_pass bar:2;
+ }
+ server {
+ listen 9093;
+ proxy_pass dev:3;
+ }
+}
`))
if err != nil {
t.Fatal(err)
}
- if cfg.Port != 9090 {
- t.Errorf("invalid port: expected 9090, got %d", cfg.Port)
+ if cfg.Namespace != "foo" {
+ t.Errorf("invalid namespace: expeced foo, got %s", cfg.Namespace)
+ }
+ if cfg.IngressPort != 9090 {
+ t.Errorf("invalid port: expected 9090, got %d", cfg.IngressPort)
}
if len(cfg.Resolvers) != 2 ||
!cfg.Resolvers[0].Equal(net.ParseIP("1.1.1.1")) ||
!cfg.Resolvers[1].Equal(net.ParseIP("2.2.2.2")) {
t.Errorf("invalid resolvers: expected [1.1.1.1 2.2.2.2], got %s", cfg.Resolvers)
}
- if len(cfg.Proxies) != 2 ||
- cfg.Proxies["a"] != "A" ||
- cfg.Proxies["b"] != "B" {
- t.Errorf("invalid proxies: expected map[a:A, b:B], got %s", cfg.Proxies)
+ if len(cfg.Ingress) != 2 ||
+ cfg.Ingress["a"] != "A" ||
+ cfg.Ingress["b"] != "B" {
+ t.Errorf("invalid ingress proxies: expected map[a:A, b:B], got %s", cfg.Ingress)
+ }
+ if len(cfg.TCP) != 2 ||
+ cfg.TCP[9091] != "foo:1" ||
+ cfg.TCP[9093] != "dev:3" {
+ t.Errorf("invalid TCP proxies: expected map[9091:foo:1, 9093:dev:3], got %v", cfg.TCP)
+ }
+ if len(cfg.UDP) != 1 ||
+ cfg.UDP[9092] != "bar:2" {
+ t.Errorf("invalid UDP proxies: expected map[9092:bar:2], got %v", cfg.UDP)
}
}
func TestRenderNginxProxyConfig(t *testing.T) {
cfg := NginxProxyConfig{
- Port: 8080,
- Resolvers: []net.IP{net.ParseIP("1.1.1.1"), net.ParseIP("2.2.2.2")},
- Proxies: map[string]string{
+ IngressPort: 8080,
+ Resolvers: []net.IP{net.ParseIP("1.1.1.1"), net.ParseIP("2.2.2.2")},
+ Ingress: map[string]string{
"a": "A",
"b": "B",
},
+ TCP: map[int]string{
+ 1: "foo:1",
+ 3: "dev:3",
+ },
+ UDP: map[int]string{
+ 2: "bar:2",
+ },
PreConf: []string{"line1", "line2"},
}
var buf strings.Builder
diff --git a/core/installer/cmd/app_manager.go b/core/installer/cmd/app_manager.go
index afc7d32..c2547d6 100644
--- a/core/installer/cmd/app_manager.go
+++ b/core/installer/cmd/app_manager.go
@@ -3,8 +3,8 @@
import (
"log"
"os"
-
- "golang.org/x/crypto/ssh"
+ "path/filepath"
+ "strings"
"github.com/giolekva/pcloud/core/installer"
"github.com/giolekva/pcloud/core/installer/server/appmanager"
@@ -80,20 +80,14 @@
if err != nil {
return err
}
- signer, err := ssh.ParsePrivateKey(sshKey)
+ items := strings.Split(appManagerFlags.repoAddr, "/")
+ ipPort := items[len(items)-2]
+ repoName := items[len(items)-1]
+ ssClient, err := soft.NewClient(ipPort, sshKey, log.Default())
if err != nil {
return err
}
- addr, err := soft.ParseRepositoryAddress(appManagerFlags.repoAddr)
- if err != nil {
- return err
- }
- repo, err := soft.CloneRepository(addr, signer)
- if err != nil {
- return err
- }
- log.Println("Cloned repository")
- repoIO, err := soft.NewRepoIO(repo, signer)
+ repoIO, err := ssClient.GetRepo(repoName)
if err != nil {
return err
}
@@ -112,7 +106,8 @@
PrivateSubdomain: "p",
DNSAPIAddr: appManagerFlags.dnsAPIAddr,
Repo: repoIO,
- NginxConfigPath: appManagerFlags.clusterProxyConfigPath,
+ ConfigPath: appManagerFlags.clusterProxyConfigPath,
+ ServicePath: filepath.Join(filepath.Dir(appManagerFlags.clusterProxyConfigPath), "proxy-backend-service.yaml"),
}
m, err := installer.NewAppManager(repoIO, nsc, jc, hf, vpnAPIClient, cnc, "/apps")
if err != nil {
@@ -145,6 +140,7 @@
}
s, err := appmanager.NewServer(
appManagerFlags.port,
+ ssClient,
repoIO,
m,
r,
diff --git a/core/installer/cmd/dodo_app.go b/core/installer/cmd/dodo_app.go
index adc8beb..9b5da30 100644
--- a/core/installer/cmd/dodo_app.go
+++ b/core/installer/cmd/dodo_app.go
@@ -245,6 +245,8 @@
return s.Start()
}
+// TODO(gio): this should be removed, all of app installtions including dodo app
+// must be done directly by main app manager.
type proxyConfigurator struct {
apiAddr string
}
@@ -262,7 +264,7 @@
To string `json:"to"`
}
-func (pc *proxyConfigurator) AddProxy(src, dst string) error {
+func (pc *proxyConfigurator) AddIngressProxy(src, dst string) error {
var buf bytes.Buffer
if err := json.NewEncoder(&buf).Encode(proxyPair{src, dst}); err != nil {
return err
@@ -279,7 +281,17 @@
return nil
}
-func (pc *proxyConfigurator) RemoveProxy(src, dst string) error {
+func (pc *proxyConfigurator) AddProxy(src int, dst string, protocol installer.Protocol) (string, error) {
+ // TODO(gio): implement
+ return "", fmt.Errorf("NOT IMPLEMENTED")
+}
+
+func (pc *proxyConfigurator) RemoveProxy(src int, dst string, protocol installer.Protocol) error {
+ // TODO(gio): implement
+ return fmt.Errorf("NOT IMPLEMENTED")
+}
+
+func (pc *proxyConfigurator) RemoveIngressProxy(src, dst string) error {
var buf bytes.Buffer
if err := json.NewEncoder(&buf).Encode(proxyPair{src, dst}); err != nil {
return err
diff --git a/core/installer/dodo_app_test.go b/core/installer/dodo_app_test.go
index 5b0f3b1..eaad590 100644
--- a/core/installer/dodo_app_test.go
+++ b/core/installer/dodo_app_test.go
@@ -1,6 +1,8 @@
package installer
import (
+ "bytes"
+ "encoding/json"
"testing"
"cuelang.org/go/cue/errors"
@@ -210,3 +212,61 @@
}
t.Log(string(r.Raw))
}
+
+const exposeRemoteCluster = `
+{
+ "cluster": "remote",
+ "postgresql": [{
+ "name": "db",
+ "size": "1Gi",
+ "expose": [{
+ "network": "Private",
+ "subdomain": "pg"
+ }]
+ }],
+}
+`
+
+func TestExposeRemoteCluster(t *testing.T) {
+ var buf bytes.Buffer
+ if _, err := buf.WriteString(exposeRemoteCluster); err != nil {
+ t.Fatal(err)
+ }
+ clusters := []Cluster{{
+ Name: "remote",
+ Kubeconfig: "<KUBECONFIG>",
+ IngressClassName: "<INGRESS_CLASS_NAME>",
+ }}
+ if err := json.NewEncoder(&buf).Encode(struct {
+ Clusters []Cluster `json:"clusters"`
+ }{
+ clusters,
+ }); err != nil {
+ t.Fatal(err)
+ }
+ app, err := NewDodoApp(buf.Bytes())
+ if err != nil {
+ for _, e := range errors.Errors(err) {
+ t.Log(e)
+ }
+ t.Fatal(err)
+ }
+ release := Release{
+ Namespace: "foo",
+ AppInstanceId: "foo-bar",
+ RepoAddr: "ssh://192.168.100.210:22/config",
+ AppDir: "/foo/bar",
+ }
+ keyGen := testKeyGen{}
+ r, err := app.Render(release, env, networks, clusters, map[string]any{
+ "managerAddr": "",
+ "appId": "",
+ "sshPrivateKey": "",
+ "port_postgresql_db_0": 1,
+ "port_postgresql_db_0_cluster": 2,
+ }, nil, keyGen)
+ if err != nil {
+ t.Fatal(err)
+ }
+ t.Log(string(r.Raw))
+}
diff --git a/core/installer/server/appmanager/server.go b/core/installer/server/appmanager/server.go
index b3a0883..3360ff4 100644
--- a/core/installer/server/appmanager/server.go
+++ b/core/installer/server/appmanager/server.go
@@ -41,6 +41,7 @@
type Server struct {
l sync.Locker
port int
+ ssClient soft.Client
repo soft.RepoIO
m *installer.AppManager
r installer.AppRepository
@@ -98,6 +99,7 @@
func NewServer(
port int,
+ ssClient soft.Client,
repo soft.RepoIO,
m *installer.AppManager,
r installer.AppRepository,
@@ -114,6 +116,7 @@
return &Server{
l: &sync.Mutex{},
port: port,
+ ssClient: ssClient,
repo: repo,
m: m,
r: r,
@@ -187,7 +190,7 @@
return
}
appDir := filepath.Join("/dodo-app", req.Id)
- namespace := "dodo-app-test" // TODO(gio)
+ namespace := "dodo-app-testttt" // TODO(gio)
if _, err := s.m.Install(app, req.Id, appDir, namespace, map[string]any{
"managerAddr": "", // TODO(gio)
"appId": req.Id,
@@ -238,7 +241,7 @@
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
- if err := s.cnc.AddProxy(req.From, req.To); err != nil {
+ if err := s.cnc.AddIngressProxy(req.From, req.To); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
@@ -250,7 +253,7 @@
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
- if err := s.cnc.RemoveProxy(req.From, req.To); err != nil {
+ if err := s.cnc.RemoveIngressProxy(req.From, req.To); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
@@ -891,6 +894,17 @@
if err != nil {
return installer.ReleaseResources{}, err
}
+ keys, err := installer.NewSSHKeyPair("port-allocator")
+ if err != nil {
+ return installer.ReleaseResources{}, err
+ }
+ user := fmt.Sprintf("%s-cluster-%s-port-allocator", env.Id, name)
+ if err := s.ssClient.AddUser(user, keys.AuthorizedKey()); err != nil {
+ return installer.ReleaseResources{}, err
+ }
+ if err := s.ssClient.AddReadWriteCollaborator("config", user); err != nil {
+ return installer.ReleaseResources{}, err
+ }
instanceId := fmt.Sprintf("%s-%s", app.Slug(), name)
appDir := fmt.Sprintf("/clusters/%s/ingress", name)
namespace := fmt.Sprintf("%scluster-%s-network", env.NamespacePrefix, name)
@@ -903,6 +917,7 @@
// TODO(gio): remove hardcoded user
"vpnUser": vpnUser,
"vpnProxyHostname": hostname,
+ "sshPrivateKey": string(keys.RawPrivateKey()),
})
if err != nil {
return installer.ReleaseResources{}, err
diff --git a/core/installer/values-tmpl/cluster-network.cue b/core/installer/values-tmpl/cluster-network.cue
index 393ac41..85551e6 100644
--- a/core/installer/values-tmpl/cluster-network.cue
+++ b/core/installer/values-tmpl/cluster-network.cue
@@ -1,5 +1,5 @@
import (
- // "encoding/base64"
+ "encoding/base64"
)
input: {
@@ -7,7 +7,7 @@
vpnUser: string
vpnProxyHostname: string
vpnAuthKey: string @role(VPNAuthKey) @usernameField(vpnUser)
- // TODO(gio): support port allocator
+ sshPrivateKey: string
}
name: "Cluster Network"
@@ -28,12 +28,12 @@
tag: "v1.82.0"
pullPolicy: "IfNotPresent"
}
- // portAllocator: {
- // repository: "giolekva"
- // name: "port-allocator"
- // tag: "latest"
- // pullPolicy: "Always"
- // }
+ portAllocator: {
+ repository: "giolekva"
+ name: "port-allocator"
+ tag: "latest"
+ pullPolicy: "Always"
+ }
}
charts: {
@@ -55,12 +55,12 @@
branch: "main"
path: "charts/tailscale-proxy"
}
- // portAllocator: {
- // kind: "GitRepository"
- // address: "https://code.v1.dodo.cloud/helm-charts"
- // branch: "main"
- // path: "charts/port-allocator"
- // }
+ portAllocator: {
+ kind: "GitRepository"
+ address: "https://code.v1.dodo.cloud/helm-charts"
+ branch: "main"
+ path: "charts/port-allocator"
+ }
}
helm: {
@@ -119,20 +119,23 @@
}]
}]
}
+ tcp: {}
+ udp: {}
}
}
- // "port-allocator": {
- // chart: charts.portAllocator
- // values: {
- // repoAddr: release.repoAddr
- // sshPrivateKey: base64.Encode(null, input.sshPrivateKey)
- // ingressNginxPath: "\(release.appDir)/resources/ingress-nginx.yaml"
- // image: {
- // repository: images.portAllocator.fullName
- // tag: images.portAllocator.tag
- // pullPolicy: images.portAllocator.pullPolicy
- // }
- // }
- // }
+ "port-allocator": {
+ chart: charts.portAllocator
+ cluster: null
+ values: {
+ repoAddr: release.repoAddr
+ sshPrivateKey: base64.Encode(null, input.sshPrivateKey)
+ ingressNginxPath: "\(release.appDir)/resources/ingress-nginx.yaml"
+ image: {
+ repository: images.portAllocator.fullName
+ tag: "amd64" // TODO(gio): images.portAllocator.tag
+ pullPolicy: images.portAllocator.pullPolicy
+ }
+ }
+ }
}
}
diff --git a/core/port-allocator/Makefile b/core/port-allocator/Makefile
index eb16feb..3133983 100644
--- a/core/port-allocator/Makefile
+++ b/core/port-allocator/Makefile
@@ -1,4 +1,4 @@
-repo_name ?= dtabidze
+repo_name ?= giolekva
podman ?= docker
ifeq ($(podman), podman)
manifest_dest=docker://docker.io/$(repo_name)/port-allocator:latest
diff --git a/core/port-allocator/go.mod b/core/port-allocator/go.mod
index b0c73b9..dd099e8 100644
--- a/core/port-allocator/go.mod
+++ b/core/port-allocator/go.mod
@@ -6,33 +6,174 @@
require (
github.com/giolekva/pcloud/core/installer v0.0.0-00010101000000-000000000000
- golang.org/x/crypto v0.24.0
+ github.com/go-git/go-billy/v5 v5.5.0
+ golang.org/x/crypto v0.26.0
)
require (
+ cuelabs.dev/go/oci/ociregistry v0.0.0-20240807094312-a32ad29eed79 // indirect
+ cuelang.org/go v0.10.0 // indirect
dario.cat/mergo v1.0.0 // indirect
+ github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect
+ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
+ github.com/BurntSushi/toml v1.3.2 // indirect
+ github.com/MakeNowJust/heredoc v1.0.0 // indirect
+ github.com/Masterminds/goutils v1.1.1 // indirect
+ github.com/Masterminds/semver/v3 v3.2.1 // indirect
+ github.com/Masterminds/sprig/v3 v3.2.3 // indirect
+ github.com/Masterminds/squirrel v1.5.4 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
+ github.com/Microsoft/hcsshim v0.12.2 // indirect
github.com/ProtonMail/go-crypto v1.0.0 // indirect
+ github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
+ github.com/beorn7/perks v1.0.1 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
+ github.com/cespare/xxhash/v2 v2.2.0 // indirect
+ github.com/chai2010/gettext-go v1.0.2 // indirect
+ github.com/charmbracelet/keygen v0.5.0 // indirect
github.com/cloudflare/circl v1.3.7 // indirect
+ github.com/cockroachdb/apd/v3 v3.2.1 // indirect
+ github.com/containerd/containerd v1.7.14 // indirect
+ github.com/containerd/log v0.1.0 // indirect
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
+ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
+ github.com/distribution/reference v0.6.0 // indirect
+ github.com/docker/cli v26.0.0+incompatible // indirect
+ github.com/docker/distribution v2.8.3+incompatible // indirect
+ github.com/docker/docker v26.0.0+incompatible // indirect
+ github.com/docker/docker-credential-helpers v0.8.1 // indirect
+ github.com/docker/go-connections v0.5.0 // indirect
+ github.com/docker/go-metrics v0.0.1 // indirect
+ github.com/emicklei/go-restful/v3 v3.12.0 // indirect
+ github.com/emicklei/proto v1.13.2 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
+ github.com/evanphx/json-patch v5.9.0+incompatible // indirect
+ github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect
+ github.com/fatih/color v1.16.0 // indirect
+ github.com/felixge/httpsnoop v1.0.4 // indirect
+ github.com/fluxcd/helm-controller/api v1.0.1 // indirect
+ github.com/fluxcd/pkg/apis/kustomize v1.5.0 // indirect
+ github.com/fluxcd/pkg/apis/meta v1.5.0 // indirect
+ github.com/go-errors/errors v1.5.1 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
- github.com/go-git/go-billy/v5 v5.5.0 // indirect
github.com/go-git/go-git/v5 v5.12.0 // indirect
+ github.com/go-gorp/gorp/v3 v3.1.0 // indirect
+ github.com/go-logr/logr v1.4.1 // indirect
+ github.com/go-logr/stdr v1.2.2 // indirect
+ github.com/go-openapi/jsonpointer v0.21.0 // indirect
+ github.com/go-openapi/jsonreference v0.21.0 // indirect
+ github.com/go-openapi/swag v0.23.0 // indirect
+ github.com/gobwas/glob v0.2.3 // indirect
+ github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
+ github.com/golang/protobuf v1.5.4 // indirect
+ github.com/google/btree v1.1.2 // indirect
+ github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 // indirect
+ github.com/google/go-cmp v0.6.0 // indirect
+ github.com/google/gofuzz v1.2.0 // indirect
+ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
+ github.com/google/uuid v1.6.0 // indirect
+ github.com/gorilla/mux v1.8.1 // indirect
+ github.com/gorilla/websocket v1.5.1 // indirect
+ github.com/gosuri/uitable v0.0.4 // indirect
+ github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
+ github.com/hashicorp/errwrap v1.1.0 // indirect
+ github.com/hashicorp/go-multierror v1.1.1 // indirect
+ github.com/huandu/xstrings v1.4.0 // indirect
+ github.com/imdario/mergo v0.3.16 // indirect
+ github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
+ github.com/jmoiron/sqlx v1.3.5 // indirect
+ github.com/josharian/intern v1.0.0 // indirect
+ github.com/json-iterator/go v1.1.12 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
+ github.com/klauspost/compress v1.17.7 // indirect
+ github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
+ github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
+ github.com/lib/pq v1.10.9 // indirect
+ github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
+ github.com/mailru/easyjson v0.7.7 // indirect
+ github.com/mattn/go-colorable v0.1.13 // indirect
+ github.com/mattn/go-isatty v0.0.20 // indirect
+ github.com/mattn/go-runewidth v0.0.15 // indirect
+ github.com/mitchellh/copystructure v1.2.0 // indirect
+ github.com/mitchellh/go-wordwrap v1.0.1 // indirect
+ github.com/mitchellh/reflectwalk v1.0.2 // indirect
+ github.com/moby/locker v1.0.1 // indirect
+ github.com/moby/spdystream v0.2.0 // indirect
+ github.com/moby/term v0.5.0 // indirect
+ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
+ github.com/modern-go/reflect2 v1.0.2 // indirect
+ github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
+ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
+ github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
+ github.com/opencontainers/go-digest v1.0.0 // indirect
+ github.com/opencontainers/image-spec v1.1.0 // indirect
+ github.com/pelletier/go-toml/v2 v2.2.2 // indirect
+ github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/pjbgf/sha1cd v0.3.0 // indirect
+ github.com/pkg/errors v0.9.1 // indirect
+ github.com/prometheus/client_golang v1.19.0 // indirect
+ github.com/prometheus/client_model v0.6.1 // indirect
+ github.com/prometheus/common v0.52.2 // indirect
+ github.com/prometheus/procfs v0.13.0 // indirect
+ github.com/protocolbuffers/txtpbfmt v0.0.0-20230328191034-3462fbc510c0 // indirect
+ github.com/rivo/uniseg v0.4.7 // indirect
+ github.com/rogpeppe/go-internal v1.12.1-0.20240709150035-ccf4b4329d21 // indirect
+ github.com/rubenv/sql-migrate v1.6.1 // indirect
+ github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
+ github.com/shopspring/decimal v1.4.0 // indirect
+ github.com/sirupsen/logrus v1.9.3 // indirect
github.com/skeema/knownhosts v1.2.2 // indirect
+ github.com/spf13/cast v1.6.0 // indirect
+ github.com/spf13/cobra v1.8.1 // indirect
+ github.com/spf13/pflag v1.0.5 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
+ github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
+ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
+ github.com/xeipuuv/gojsonschema v1.2.0 // indirect
+ github.com/xlab/treeprint v1.2.0 // indirect
+ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect
+ go.opentelemetry.io/otel v1.24.0 // indirect
+ go.opentelemetry.io/otel/metric v1.24.0 // indirect
+ go.opentelemetry.io/otel/trace v1.24.0 // indirect
+ go.starlark.net v0.0.0-20240329153429-e6e8e7ce1b7a // indirect
golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 // indirect
- golang.org/x/mod v0.17.0 // indirect
- golang.org/x/net v0.25.0 // indirect
- golang.org/x/sync v0.7.0 // indirect
- golang.org/x/sys v0.22.0 // indirect
- golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
+ golang.org/x/mod v0.20.0 // indirect
+ golang.org/x/net v0.28.0 // indirect
+ golang.org/x/oauth2 v0.22.0 // indirect
+ golang.org/x/sync v0.8.0 // indirect
+ golang.org/x/sys v0.23.0 // indirect
+ golang.org/x/term v0.23.0 // indirect
+ golang.org/x/text v0.17.0 // indirect
+ golang.org/x/time v0.5.0 // indirect
+ golang.org/x/tools v0.24.0 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda // indirect
+ google.golang.org/grpc v1.63.0 // indirect
+ google.golang.org/protobuf v1.33.0 // indirect
+ gopkg.in/evanphx/json-patch.v5 v5.9.0 // indirect
+ gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
+ gopkg.in/yaml.v2 v2.4.0 // indirect
+ gopkg.in/yaml.v3 v3.0.1 // indirect
+ helm.sh/helm/v3 v3.14.3 // indirect
+ k8s.io/api v0.30.0 // indirect
+ k8s.io/apiextensions-apiserver v0.30.0 // indirect
+ k8s.io/apimachinery v0.30.0 // indirect
+ k8s.io/apiserver v0.30.0 // indirect
+ k8s.io/cli-runtime v0.29.3 // indirect
+ k8s.io/client-go v0.30.0 // indirect
+ k8s.io/component-base v0.30.0 // indirect
+ k8s.io/klog/v2 v2.120.1 // indirect
+ k8s.io/kube-openapi v0.0.0-20240403164606-bc84c2ddaf99 // indirect
+ k8s.io/kubectl v0.29.3 // indirect
+ k8s.io/utils v0.0.0-20240310230437-4693a0247e57 // indirect
+ oras.land/oras-go v1.2.5 // indirect
+ sigs.k8s.io/controller-runtime v0.18.1 // indirect
+ sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
+ sigs.k8s.io/kustomize/api v0.16.0 // indirect
+ sigs.k8s.io/kustomize/kyaml v0.16.0 // indirect
+ sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect
)
diff --git a/core/port-allocator/go.sum b/core/port-allocator/go.sum
index 51258fc..87eef09 100644
--- a/core/port-allocator/go.sum
+++ b/core/port-allocator/go.sum
@@ -1,32 +1,141 @@
+cuelabs.dev/go/oci/ociregistry v0.0.0-20240807094312-a32ad29eed79 h1:EceZITBGET3qHneD5xowSTY/YHbNybvMWGh62K2fG/M=
+cuelabs.dev/go/oci/ociregistry v0.0.0-20240807094312-a32ad29eed79/go.mod h1:5A4xfTzHTXfeVJBU6RAUf+QrlfTCW+017q/QiW+sMLg=
+cuelang.org/go v0.10.0 h1:Y1Pu4wwga5HkXfLFK1sWAYaSWIBdcsr5Cb5AWj2pOuE=
+cuelang.org/go v0.10.0/go.mod h1:HzlaqqqInHNiqE6slTP6+UtxT9hN6DAzgJgdbNxXvX8=
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
+github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU=
+github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
+github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
+github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
+github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
+github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
+github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU=
+github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU=
+github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
+github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
+github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
+github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
+github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
+github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=
+github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
+github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA=
+github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM=
+github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM=
+github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10=
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
+github.com/Microsoft/hcsshim v0.12.2 h1:AcXy+yfRvrx20g9v7qYaJv5Rh+8GaHOS6b8G6Wx/nKs=
+github.com/Microsoft/hcsshim v0.12.2/go.mod h1:RZV12pcHCXQ42XnlQ3pz6FZfmrC1C+R4gaOHhRNML1g=
github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78=
github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
+github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs=
+github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
+github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
+github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
+github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/bshuster-repo/logrus-logstash-hook v1.0.0 h1:e+C0SB5R1pu//O4MQ3f9cFuPGoOVeF2fE4Og9otCc70=
+github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
+github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd h1:rFt+Y/IK1aEZkEHchZRSq9OQbsSzIT/OrI8YFFmRIng=
+github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
+github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b h1:otBG+dV+YK+Soembjv71DPz3uX/V/6MMlSyD9JBQ6kQ=
+github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
+github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXer/kZD8Ri1aaunCxIEsOst1BVJswV0o=
+github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
+github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
+github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk=
+github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA=
+github.com/charmbracelet/keygen v0.5.0 h1:XY0fsoYiCSM9axkrU+2ziE6u6YjJulo/b9Dghnw6MZc=
+github.com/charmbracelet/keygen v0.5.0/go.mod h1:DfvCgLHxZ9rJxdK0DGw3C/LkV4SgdGbnliHcObV3L+8=
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
+github.com/cockroachdb/apd/v3 v3.2.1 h1:U+8j7t0axsIgvQUqthuNm82HIrYXodOV2iWLWtEaIwg=
+github.com/cockroachdb/apd/v3 v3.2.1/go.mod h1:klXJcjp+FffLTHlhIG69tezTDvdP065naDsHzKhYSqc=
+github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM=
+github.com/containerd/cgroups/v3 v3.0.2 h1:f5WFqIVSgo5IZmtTT3qVBo6TzI1ON6sycSBKkymb9L0=
+github.com/containerd/cgroups/v3 v3.0.2/go.mod h1:JUgITrzdFqp42uI2ryGA+ge0ap/nxzYgkGmIcetmErE=
+github.com/containerd/containerd v1.7.14 h1:H/XLzbnGuenZEGK+v0RkwTdv2u1QFAruMe5N0GNPJwA=
+github.com/containerd/containerd v1.7.14/go.mod h1:YMC9Qt5yzNqXx/fO4j/5yYVIHXSRrlB3H7sxkUTvspg=
+github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM=
+github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ=
+github.com/containerd/errdefs v0.1.0 h1:m0wCRBiu1WJT/Fr+iOoQHMQS/eP5myQ8lCv4Dz5ZURM=
+github.com/containerd/errdefs v0.1.0/go.mod h1:YgWiiHtLmSeBrvpw+UfPijzbLaB77mEG1WwJTDETIV0=
+github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
+github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
+github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
+github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
+github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2 h1:aBfCb7iqHmDEIp6fBvC/hQUddQfg+3qdYjwzaiP9Hnc=
+github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2/go.mod h1:WHNsWjnIn2V1LYOrME7e8KxSeKunYHsxEm4am0BUtcI=
+github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
+github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
+github.com/docker/cli v26.0.0+incompatible h1:90BKrx1a1HKYpSnnBFR6AgDq/FqkHxwlUyzJVPxD30I=
+github.com/docker/cli v26.0.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
+github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
+github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
+github.com/docker/docker v26.0.0+incompatible h1:Ng2qi+gdKADUa/VM+6b6YaY2nlZhk/lVJiKR/2bMudU=
+github.com/docker/docker v26.0.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/docker-credential-helpers v0.8.1 h1:j/eKUktUltBtMzKqmfLB0PAgqYyMHOp5vfsD1807oKo=
+github.com/docker/docker-credential-helpers v0.8.1/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
+github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
+github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
+github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8=
+github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
+github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8=
+github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw=
+github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1 h1:ZClxb8laGDf5arXfYcAtECDFgAgHklGI8CxgjHnXKJ4=
+github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU=
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
+github.com/emicklei/go-restful/v3 v3.12.0 h1:y2DdzBAURM29NFF94q6RaY4vjIH1rtwDapwQtU84iWk=
+github.com/emicklei/go-restful/v3 v3.12.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
+github.com/emicklei/proto v1.13.2 h1:z/etSFO3uyXeuEsVPzfl56WNgzcvIr42aQazXaQmFZY=
+github.com/emicklei/proto v1.13.2/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A=
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
+github.com/evanphx/json-patch v5.9.0+incompatible h1:fBXyNpNMuTTDdquAq/uisOr2lShz4oaXpDTX2bLe7ls=
+github.com/evanphx/json-patch v5.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
+github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f h1:Wl78ApPPB2Wvf/TIe2xdyJxTlb6obmF18d8QdkxNDu4=
+github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f/go.mod h1:OSYXu++VVOHnXeitef/D8n/6y4QV8uLHSFXX4NeXMGc=
+github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
+github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
+github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
+github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
+github.com/fluxcd/helm-controller/api v1.0.1 h1:Gn9qEVuif6D5+gHmVwTEZkR4+nmLOcOhKx4Sw2gL2EA=
+github.com/fluxcd/helm-controller/api v1.0.1/go.mod h1:/6AD5a2qjo/ttxVM8GR33syLZwqigta60DCLdy8GrME=
+github.com/fluxcd/pkg/apis/kustomize v1.5.0 h1:ah4sfqccnio+/5Edz/tVz6LetFhiBoDzXAElj6fFCzU=
+github.com/fluxcd/pkg/apis/kustomize v1.5.0/go.mod h1:nEzhnhHafhWOUUV8VMFLojUOH+HHDEsL75y54mt/c30=
+github.com/fluxcd/pkg/apis/meta v1.5.0 h1:/G82d2Az5D9op3F+wJUpD8jw/eTV0suM6P7+cSURoUM=
+github.com/fluxcd/pkg/apis/meta v1.5.0/go.mod h1:Y3u7JomuuKtr5fvP1Iji2/50FdRe5GcBug2jawNVkdM=
+github.com/foxcpp/go-mockdns v1.0.0 h1:7jBqxd3WDWwi/6WhDvacvH1XsN3rOLXyHM1uhvIx6FI=
+github.com/foxcpp/go-mockdns v1.0.0/go.mod h1:lgRN6+KxQBawyIghpnl5CezHFGS9VLzvtVlwxvzXTQ4=
+github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
+github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE=
github.com/gliderlabs/ssh v0.3.7/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8=
+github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk=
+github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU=
@@ -35,15 +144,106 @@
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys=
github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY=
+github.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs=
+github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
+github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
+github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
+github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
+github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
+github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
+github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
+github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
+github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
+github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI=
+github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow=
+github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
+github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
+github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
+github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
+github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
+github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
+github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
+github.com/gomodule/redigo v1.8.2 h1:H5XSIre1MB5NbPYFp+i1NBbb5qN1W8Y8YAQoAYbkm8k=
+github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
+github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
+github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
+github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 h1:0VpGH+cDhbDtdcweoyCVsF3fhN8kejK6rFe/2FFX2nU=
+github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49/go.mod h1:BkkQ4L1KS1xMt2aWSPStnn55ChGC0DPOn2FQYj+f25M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
+github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec=
+github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
+github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
+github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4=
+github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
+github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
+github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
+github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
+github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
+github.com/gosuri/uitable v0.0.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY=
+github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo=
+github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
+github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
+github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
+github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
+github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
+github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
+github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
+github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
+github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU=
+github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
+github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
+github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
+github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
+github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
+github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
+github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g=
+github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ=
+github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
+github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
+github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
+github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg=
+github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
@@ -51,79 +251,257 @@
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
-github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
+github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
+github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
+github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw=
+github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o=
+github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk=
+github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw=
+github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
+github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
+github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
+github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
+github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
+github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
+github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
+github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
+github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
+github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
+github.com/mattn/go-sqlite3 v1.14.19 h1:fhGleo2h1p8tVChob4I9HpmVFIAkKGpiukdrgQbWfGI=
+github.com/mattn/go-sqlite3 v1.14.19/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4=
+github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY=
+github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
+github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
+github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
+github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
+github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
+github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
+github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
+github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
+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/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8=
+github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
+github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78=
+github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI=
+github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
+github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
+github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0=
+github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
+github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
+github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus=
+github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
+github.com/onsi/ginkgo/v2 v2.17.1 h1:V++EzdbhI4ZV4ev0UTIj0PzhzOcReJFyJaLjtSF55M8=
+github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs=
+github.com/onsi/gomega v1.32.0 h1:JRYU78fJ1LPxlckP6Txi/EYqJvjtMrDC04/MM5XRHPk=
+github.com/onsi/gomega v1.32.0/go.mod h1:a4x4gW6Pz2yK1MAmvluYme5lvYTn61afQ2ETw/8n4Lg=
+github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
+github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
+github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
+github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
+github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
+github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
+github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
+github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
+github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI=
+github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
-github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
+github.com/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY=
+github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjzg=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
+github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
+github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU=
+github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
+github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
+github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
+github.com/prometheus/common v0.52.2 h1:LW8Vk7BccEdONfrJBDffQGRtpSzi5CQaRZGtboOO2ck=
+github.com/prometheus/common v0.52.2/go.mod h1:lrWtQx+iDfn2mbH5GUzlH9TSHyfZpHkSiG1W7y3sF2Q=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
+github.com/prometheus/procfs v0.13.0 h1:GqzLlQyfsPbaEHaQkO7tbDlriv/4o5Hudv6OXHGKX7o=
+github.com/prometheus/procfs v0.13.0/go.mod h1:cd4PFCR54QLnGKPaKGA6l+cfuNXtht43ZKY6tow0Y1g=
+github.com/protocolbuffers/txtpbfmt v0.0.0-20230328191034-3462fbc510c0 h1:sadMIsgmHpEOGbUs6VtHBXRR1OHevnj7hLx9ZcdNGW4=
+github.com/protocolbuffers/txtpbfmt v0.0.0-20230328191034-3462fbc510c0/go.mod h1:jgxiZysxFPM+iWKwQwPR+y+Jvo54ARd4EisXxKYpB5c=
+github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
+github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
+github.com/rogpeppe/go-internal v1.12.1-0.20240709150035-ccf4b4329d21 h1:igWZJluD8KtEtAgRyF4x6lqcxDry1ULztksMJh2mnQE=
+github.com/rogpeppe/go-internal v1.12.1-0.20240709150035-ccf4b4329d21/go.mod h1:RMRJLmBOqWacUkmJHRMiPKh1S1m3PA7Zh4W80/kWPpg=
+github.com/rubenv/sql-migrate v1.6.1 h1:bo6/sjsan9HaXAsNxYP/jCEDUGibHp8JmOBw7NTGRos=
+github.com/rubenv/sql-migrate v1.6.1/go.mod h1:tPzespupJS0jacLfhbwto/UjSX+8h2FdWB7ar+QlHa0=
+github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
+github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
+github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
+github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
+github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
+github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A=
github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo=
+github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
+github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
+github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
+github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
+github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
+github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
+github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
+github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
+github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
+github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
+github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
+github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
+github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ=
+github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
+github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
+github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43 h1:+lm10QQTNSBd8DVTNGHx7o/IKu9HYDvLMffDhbyLccI=
+github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
+github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50 h1:hlE8//ciYMztlGpl/VA+Zm1AcTPHYkHJPbHqE6WJUXE=
+github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
+github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f h1:ERexzlUfuTvpE74urLSbIQW0Z/6hF9t8U4NsJLaioAY=
+github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
+go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
+go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw=
+go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
+go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
+go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI=
+go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
+go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
+go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
+go.starlark.net v0.0.0-20240329153429-e6e8e7ce1b7a h1:Oe+v9w90BBIxQZ4U39+axR8KxrBbxqnRudPPcBIlP3o=
+go.starlark.net v0.0.0-20240329153429-e6e8e7ce1b7a/go.mod h1:YKMCv9b1WrfWmeqdV5MAuEHWsu5iC+fe6kYl2sQjdI8=
+go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
+go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
-golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
-golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
+golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
+golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 h1:985EYyeCOxTpcgOTJpflJUwOeEz0CQOdPt73OzpE9F8=
golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI=
+golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
-golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
-golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
+golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
-golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
-golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
+golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
+golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
+golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA=
+golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
-golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
+golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
-golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
+golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
-golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
-golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
+golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU=
+golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@@ -131,24 +509,85 @@
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
-golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
-golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
+golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
+golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
+golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
+golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
-golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
-golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
+golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
+golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda h1:LI5DOvAxUPMv/50agcLLoo+AdWc1irS9Rzz4vPuD1V4=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
+google.golang.org/grpc v1.63.0 h1:WjKe+dnvABXyPJMD7KDNLxtoGk5tgk+YFWN6cBWjZE8=
+google.golang.org/grpc v1.63.0/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA=
+google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
+google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/evanphx/json-patch.v5 v5.9.0 h1:hx1VU2SGj4F8r9b8GUwJLdc8DNO8sy79ZGui0G05GLo=
+gopkg.in/evanphx/json-patch.v5 v5.9.0/go.mod h1:/kvTRh1TVm5wuM6OkHxqXtE/1nUZZpihg29RtuIyfvk=
+gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
+gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o=
+gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g=
+helm.sh/helm/v3 v3.14.3 h1:HmvRJlwyyt9HjgmAuxHbHv3PhMz9ir/XNWHyXfmnOP4=
+helm.sh/helm/v3 v3.14.3/go.mod h1:v6myVbyseSBJTzhmeE39UcPLNv6cQK6qss3dvgAySaE=
+k8s.io/api v0.30.0 h1:siWhRq7cNjy2iHssOB9SCGNCl2spiF1dO3dABqZ8niA=
+k8s.io/api v0.30.0/go.mod h1:OPlaYhoHs8EQ1ql0R/TsUgaRPhpKNxIMrKQfWUp8QSE=
+k8s.io/apiextensions-apiserver v0.30.0 h1:jcZFKMqnICJfRxTgnC4E+Hpcq8UEhT8B2lhBcQ+6uAs=
+k8s.io/apiextensions-apiserver v0.30.0/go.mod h1:N9ogQFGcrbWqAY9p2mUAL5mGxsLqwgtUce127VtRX5Y=
+k8s.io/apimachinery v0.30.0 h1:qxVPsyDM5XS96NIh9Oj6LavoVFYff/Pon9cZeDIkHHA=
+k8s.io/apimachinery v0.30.0/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc=
+k8s.io/apiserver v0.30.0 h1:QCec+U72tMQ+9tR6A0sMBB5Vh6ImCEkoKkTDRABWq6M=
+k8s.io/apiserver v0.30.0/go.mod h1:smOIBq8t0MbKZi7O7SyIpjPsiKJ8qa+llcFCluKyqiY=
+k8s.io/cli-runtime v0.29.3 h1:r68rephmmytoywkw2MyJ+CxjpasJDQY7AGc3XY2iv1k=
+k8s.io/cli-runtime v0.29.3/go.mod h1:aqVUsk86/RhaGJwDhHXH0jcdqBrgdF3bZWk4Z9D4mkM=
+k8s.io/client-go v0.30.0 h1:sB1AGGlhY/o7KCyCEQ0bPWzYDL0pwOZO4vAtTSh/gJQ=
+k8s.io/client-go v0.30.0/go.mod h1:g7li5O5256qe6TYdAMyX/otJqMhIiGgTapdLchhmOaY=
+k8s.io/component-base v0.30.0 h1:cj6bp38g0ainlfYtaOQuRELh5KSYjhKxM+io7AUIk4o=
+k8s.io/component-base v0.30.0/go.mod h1:V9x/0ePFNaKeKYA3bOvIbrNoluTSG+fSJKjLdjOoeXQ=
+k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw=
+k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
+k8s.io/kube-openapi v0.0.0-20240403164606-bc84c2ddaf99 h1:w6nThEmGo9zcL+xH1Tu6pjxJ3K1jXFW+V0u4peqN8ks=
+k8s.io/kube-openapi v0.0.0-20240403164606-bc84c2ddaf99/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98=
+k8s.io/kubectl v0.29.3 h1:RuwyyIU42MAISRIePaa8Q7A3U74Q9P4MoJbDFz9o3us=
+k8s.io/kubectl v0.29.3/go.mod h1:yCxfY1dbwgVdEt2zkJ6d5NNLOhhWgTyrqACIoFhpdd4=
+k8s.io/utils v0.0.0-20240310230437-4693a0247e57 h1:gbqbevonBh57eILzModw6mrkbwM0gQBEuevE/AaBsHY=
+k8s.io/utils v0.0.0-20240310230437-4693a0247e57/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
+oras.land/oras-go v1.2.5 h1:XpYuAwAb0DfQsunIyMfeET92emK8km3W4yEzZvUbsTo=
+oras.land/oras-go v1.2.5/go.mod h1:PuAwRShRZCsZb7g8Ar3jKKQR/2A/qN+pkYxIOd/FAoo=
+sigs.k8s.io/controller-runtime v0.18.1 h1:RpWbigmuiylbxOCLy0tGnq1cU1qWPwNIQzoJk+QeJx4=
+sigs.k8s.io/controller-runtime v0.18.1/go.mod h1:tuAt1+wbVsXIT8lPtk5RURxqAnq7xkpv2Mhttslg7Hw=
+sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
+sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
+sigs.k8s.io/kustomize/api v0.16.0 h1:/zAR4FOQDCkgSDmVzV2uiFbuy9bhu3jEzthrHCuvm1g=
+sigs.k8s.io/kustomize/api v0.16.0/go.mod h1:MnFZ7IP2YqVyVwMWoRxPtgl/5hpA+eCCrQR/866cm5c=
+sigs.k8s.io/kustomize/kyaml v0.16.0 h1:6J33uKSoATlKZH16unr2XOhDI+otoe2sR3M8PDzW3K0=
+sigs.k8s.io/kustomize/kyaml v0.16.0/go.mod h1:xOK/7i+vmE14N2FdFyugIshB8eF6ALpy7jI87Q2nRh4=
+sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=
+sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
diff --git a/core/port-allocator/main.go b/core/port-allocator/main.go
index 6bc89e4..8b3ab80 100644
--- a/core/port-allocator/main.go
+++ b/core/port-allocator/main.go
@@ -1,6 +1,7 @@
package main
import (
+ "bytes"
"encoding/base64"
"encoding/json"
"errors"
@@ -12,11 +13,13 @@
"math/rand"
"net/http"
"os"
+ "path/filepath"
"strconv"
"strings"
"sync"
"time"
+ "github.com/giolekva/pcloud/core/installer"
"github.com/giolekva/pcloud/core/installer/soft"
"golang.org/x/crypto/ssh"
@@ -36,25 +39,42 @@
var preOpenPortsBatchSize = flag.Int("pre-open-ports-batch-size", 10, "Number of new ports to open at a time")
type client interface {
- ReservePort() (int, string, error)
+ ReservePort(remoteProxy bool) (int, string, error)
ReleaseReservedPort(port ...int)
AddPortForwarding(protocol string, port int, secret, dest string) error
RemovePortForwarding(protocol string, port int) error
}
+type Reservation struct {
+ Secret string `json:"secret"`
+ IsRemoteProxy bool `json:"isRemoteProxy"`
+}
+
type repoClient struct {
l sync.Locker
repo soft.RepoIO
path string
secretGenerator SecretGenerator
+ proxyCfg *installer.NginxProxyConfigurator
minPreOpenPorts int
preOpenPortsBatchSize int
preOpenPorts []int
+ proxyPreOpenPorts []int
blocklist map[int]struct{}
- reserve map[int]string
+ reserve map[int]Reservation
availablePorts []int
}
+func getProxyBackendConfigPath(repo soft.RepoIO, path string) (string, error) {
+ cfgPath := filepath.Join(filepath.Dir(path), "proxy-backend-config.yaml")
+ inp, err := repo.Reader(cfgPath)
+ if err != nil {
+ return "", nil
+ }
+ defer inp.Close()
+ return cfgPath, nil
+}
+
func newRepoClient(
repo soft.RepoIO,
path string,
@@ -62,16 +82,29 @@
preOpenPortsBatchSize int,
secretGenerator SecretGenerator,
) (client, error) {
+ proxyCfg, err := getProxyBackendConfigPath(repo, path)
+ if err != nil {
+ return nil, err
+ }
+ var cnc *installer.NginxProxyConfigurator
+ if proxyCfg != "" {
+ cnc = &installer.NginxProxyConfigurator{
+ Repo: repo,
+ ConfigPath: proxyCfg,
+ ServicePath: filepath.Join(filepath.Dir(proxyCfg), "proxy-backend-service.yaml"),
+ }
+ }
ret := &repoClient{
l: &sync.Mutex{},
repo: repo,
path: path,
secretGenerator: secretGenerator,
+ proxyCfg: cnc,
minPreOpenPorts: minPreOpenPorts,
preOpenPortsBatchSize: preOpenPortsBatchSize,
preOpenPorts: []int{},
blocklist: map[int]struct{}{},
- reserve: map[int]string{},
+ reserve: map[int]Reservation{},
availablePorts: []int{},
}
st, err := ret.readState(repo)
@@ -103,19 +136,31 @@
return ret, nil
}
-func (c *repoClient) ReservePort() (int, string, error) {
+func (c *repoClient) ReservePort(remoteProxy bool) (int, string, error) {
c.l.Lock()
defer c.l.Unlock()
- if len(c.preOpenPorts) == 0 {
- return -1, "", fmt.Errorf("no pre-open ports are available")
+ var port int
+ if !remoteProxy {
+ if len(c.preOpenPorts) == 0 {
+ return -1, "", fmt.Errorf("no pre-open ports are available")
+ }
+ port = c.preOpenPorts[0]
+ c.preOpenPorts = c.preOpenPorts[1:]
+ } else {
+ if c.proxyCfg == nil {
+ return -1, "", fmt.Errorf("does not support TCP/UDP proxy")
+ }
+ if len(c.proxyPreOpenPorts) == 0 {
+ return -1, "", fmt.Errorf("no proxy pre-open ports are available")
+ }
+ port = c.proxyPreOpenPorts[0]
+ c.proxyPreOpenPorts = c.proxyPreOpenPorts[1:]
}
- port := c.preOpenPorts[0]
- c.preOpenPorts = c.preOpenPorts[1:]
secret, err := c.secretGenerator()
if err != nil {
return -1, "", err
}
- c.reserve[port] = secret
+ c.reserve[port] = Reservation{secret, remoteProxy}
return port, secret, nil
}
@@ -127,8 +172,16 @@
defer c.l.Unlock()
if _, err := c.repo.Do(func(fs soft.RepoFS) (string, error) {
for _, p := range port {
+ r, ok := c.reserve[p]
+ if !ok {
+ continue
+ }
delete(c.reserve, p)
- c.preOpenPorts = append(c.preOpenPorts, p)
+ if r.IsRemoteProxy {
+ c.proxyPreOpenPorts = append(c.proxyPreOpenPorts, p)
+ } else {
+ c.preOpenPorts = append(c.preOpenPorts, p)
+ }
}
if err := c.writeState(fs); err != nil {
return "", err
@@ -139,30 +192,56 @@
}
}
+type oldState struct {
+ PreOpenPorts []int `json:"preOpenPorts"`
+ ProxyPreOpenPorts []int `json:"proxyPreOpenPorts"`
+ Blocklist map[int]struct{} `json:"blocklist"`
+ Reserve map[int]string `json:"reserve"`
+}
+
type state struct {
- PreOpenPorts []int `json:"preOpenPorts"`
- Blocklist map[int]struct{} `json:"blocklist"`
- Reserve map[int]string `json:"reserve"`
+ PreOpenPorts []int `json:"preOpenPorts"`
+ ProxyPreOpenPorts []int `json:"proxyPreOpenPorts"`
+ Blocklist map[int]struct{} `json:"blocklist"`
+ Reserve map[int]Reservation `json:"reserve"`
}
func (c *repoClient) preOpenNewPorts() error {
c.l.Lock()
defer c.l.Unlock()
- if len(c.preOpenPorts) >= c.minPreOpenPorts {
+ var ports []int
+ if len(c.preOpenPorts) < c.minPreOpenPorts {
+ for count := c.preOpenPortsBatchSize; count > 0; count-- {
+ if len(c.availablePorts) == 0 {
+ return fmt.Errorf("could not open new port")
+ }
+ r := rand.Intn(len(c.availablePorts))
+ p := c.availablePorts[r]
+ c.availablePorts[r] = c.availablePorts[len(c.availablePorts)-1]
+ c.availablePorts = c.availablePorts[:len(c.availablePorts)-1]
+ ports = append(ports, p)
+ c.preOpenPorts = append(c.preOpenPorts, p)
+ c.blocklist[p] = struct{}{}
+ }
return nil
}
- var ports []int
- for count := c.preOpenPortsBatchSize; count > 0; count-- {
- if len(c.availablePorts) == 0 {
- return fmt.Errorf("could not open new port")
+ if c.proxyCfg != nil && len(c.proxyPreOpenPorts) < c.minPreOpenPorts {
+ for count := c.preOpenPortsBatchSize; count > 0; count-- {
+ if len(c.availablePorts) == 0 {
+ return fmt.Errorf("could not open new port")
+ }
+ r := rand.Intn(len(c.availablePorts))
+ p := c.availablePorts[r]
+ c.availablePorts[r] = c.availablePorts[len(c.availablePorts)-1]
+ c.availablePorts = c.availablePorts[:len(c.availablePorts)-1]
+ ports = append(ports, p)
+ c.proxyPreOpenPorts = append(c.proxyPreOpenPorts, p)
+ c.blocklist[p] = struct{}{}
}
- r := rand.Intn(len(c.availablePorts))
- p := c.availablePorts[r]
- c.availablePorts[r] = c.availablePorts[len(c.availablePorts)-1]
- c.availablePorts = c.availablePorts[:len(c.availablePorts)-1]
- ports = append(ports, p)
- c.preOpenPorts = append(c.preOpenPorts, p)
- c.blocklist[p] = struct{}{}
+ return nil
+ }
+ if len(ports) == 0 {
+ return nil
}
_, err := c.repo.Do(func(fs soft.RepoFS) (string, error) {
if err := c.writeState(fs); err != nil {
@@ -172,10 +251,17 @@
if err != nil {
return "", err
}
- svcType, err := extractString(rel, "spec.values.controller.service.type")
+ svcType := ""
+ svcEnabled, err := extractBool(rel, "spec.values.controller.service.enabled")
if err != nil {
return "", err
}
+ if svcEnabled {
+ svcType, err = extractString(rel, "spec.values.controller.service.type")
+ if err != nil {
+ return "", err
+ }
+ }
if svcType == "NodePort" {
tcp, err := extractPorts(rel, "spec.values.controller.service.nodePorts.tcp")
if err != nil {
@@ -213,10 +299,31 @@
}()
c.l.Lock()
defer c.l.Unlock()
- if sec, ok := c.reserve[port]; !ok || sec != secret {
+ r, ok := c.reserve[port]
+ if !ok || r.Secret != secret {
return fmt.Errorf("wrong secret")
}
delete(c.reserve, port)
+ if r.IsRemoteProxy {
+ if c.proxyCfg == nil {
+ return fmt.Errorf("does not support TCP/UDP proxy")
+ }
+ var namespace string
+ var err error
+ switch strings.ToLower(protocol) {
+ case "tcp":
+ if namespace, err = c.proxyCfg.AddProxy(port, dest, installer.ProtocolTCP); err != nil {
+ return err
+ }
+ case "udp":
+ if namespace, err = c.proxyCfg.AddProxy(port, dest, installer.ProtocolUDP); err != nil {
+ return err
+ }
+ default:
+ return fmt.Errorf("unknown protocol: %s", protocol)
+ }
+ dest = fmt.Sprintf("%s/proxy-backend-service:%d", namespace, port)
+ }
_, err := c.repo.Do(func(fs soft.RepoFS) (string, error) {
if err := c.writeState(fs); err != nil {
return "", err
@@ -279,10 +386,17 @@
default:
panic("MUST NOT REACH")
}
- svcType, err := extractString(rel, "spec.values.controller.service.type")
+ svcType := ""
+ svcEnabled, err := extractBool(rel, "spec.values.controller.service.enabled")
if err != nil {
return "", err
}
+ if svcEnabled {
+ svcType, err = extractString(rel, "spec.values.controller.service.type")
+ if err != nil {
+ return "", err
+ }
+ }
if svcType == "NodePort" {
svcTCP, err := extractPorts(rel, "spec.values.controller.service.nodePorts.tcp")
if err != nil {
@@ -313,10 +427,27 @@
return state{}, err
}
defer r.Close()
- var ret state
- if err := json.NewDecoder(r).Decode(&ret); err != nil {
+ buf, err := io.ReadAll(r)
+ if err != nil {
return state{}, err
}
+ var ret state
+ if err := json.NewDecoder(bytes.NewReader(buf)).Decode(&ret); err == nil {
+ return ret, nil
+ }
+ var old oldState
+ if err := json.NewDecoder(bytes.NewReader(buf)).Decode(&old); err != nil {
+ return state{}, err
+ }
+ ret = state{
+ PreOpenPorts: old.PreOpenPorts,
+ ProxyPreOpenPorts: []int{},
+ Blocklist: old.Blocklist,
+ Reserve: map[int]Reservation{},
+ }
+ for port, secret := range old.Reserve {
+ ret.Reserve[port] = Reservation{secret, false}
+ }
return ret, err
}
@@ -326,7 +457,7 @@
return err
}
defer w.Close()
- if err := json.NewEncoder(w).Encode(state{c.preOpenPorts, c.blocklist, c.reserve}); err != nil {
+ if err := json.NewEncoder(w).Encode(state{c.preOpenPorts, c.proxyPreOpenPorts, c.blocklist, c.reserve}); err != nil {
return err
}
return err
@@ -422,7 +553,7 @@
for _, i := range strings.Split(path, ".") {
valM, ok := val.(map[string]any)
if !ok {
- return nil, fmt.Errorf("expected map")
+ return nil, fmt.Errorf("expected map, %s", i)
}
val, ok = valM[i]
if !ok {
@@ -451,7 +582,19 @@
}
retS, ok := ret.(string)
if !ok {
- return "", fmt.Errorf("expected map")
+ return "", fmt.Errorf("expected string")
+ }
+ return retS, nil
+}
+
+func extractBool(data map[string]any, path string) (bool, error) {
+ ret, err := extractField(data, path)
+ if err != nil {
+ return false, err
+ }
+ retS, ok := ret.(bool)
+ if !ok {
+ return false, fmt.Errorf("expected boolean")
}
return retS, nil
}
@@ -496,15 +639,26 @@
}
}
+type reserveReq struct {
+ RemoteProxy bool `json:"remoteProxy"`
+}
+
func (s *server) handleReserve(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "only post method is supported", http.StatusBadRequest)
return
}
+ var req reserveReq
+ if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
+ fmt.Println(err.Error())
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ fmt.Printf("%+v\n", req)
var port int
var secret string
var err error
- if port, secret, err = s.client.ReservePort(); err != nil {
+ if port, secret, err = s.client.ReservePort(req.RemoteProxy); err != nil {
fmt.Println(err.Error())
http.Error(w, err.Error(), http.StatusInternalServerError)
return
diff --git a/core/port-allocator/main_test.go b/core/port-allocator/main_test.go
index 93ae574..1596667 100644
--- a/core/port-allocator/main_test.go
+++ b/core/port-allocator/main_test.go
@@ -26,7 +26,8 @@
"values": map[string]any{
"controller": map[string]any{
"service": map[string]any{
- "type": "ClusterIP",
+ "enabled": true,
+ "type": "ClusterIP",
},
},
"tcp": map[string]any{},
@@ -47,7 +48,8 @@
"values": map[string]any{
"controller": map[string]any{
"service": map[string]any{
- "type": "ClusterIP",
+ "enabled": true,
+ "type": "ClusterIP",
},
},
"tcp": tcp,
@@ -57,7 +59,7 @@
}
for i := 0; i < 500; i++ {
for _, protocol := range []string{"tcp", "udp"} {
- port, secret, err := c.ReservePort()
+ port, secret, err := c.ReservePort(false)
if err != nil {
t.Fatal(err)
}