mirror of
https://github.com/Dvorinka/Containr.git
synced 2026-10-28 07:41:27 +00:00
fix: e2e QA hardening — honest runtime URLs, health, and read-only anon UI
Backend: - managed DB provisioning: attach DB containers to the platform network and probe the container IP, fixing the 127.0.0.1 reachability failure inside the backend container; log provisioning failures - stop fabricating connection URLs when provisioning produced none - template deploys now carry port + health_check into service runtime fields - service health probed over the project network (backend joins it) instead of an in-container wget that fails on shell-less images - runtime/public/connection URLs rewrite loopback to the request Host so links are usable for LAN/remote clients Frontend: - service Networking panel shows real runtime URLs/ports/health instead of hardcoded containr.dev + 8080->443 - anonymous views hide all mutation controls (new project, add service, group, context menu) - project cards: remove decorative svcN labels; badge says DOWN only when zero services run, IDLE when empty, DEGRADED for partial - mobile projects header no longer clips (fluid search width) - unknown routes render a not-found page instead of silently redirecting Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
d968eb2315
commit
9f5dcc7296
12 files changed
+404
-137
No files matched your search
@@ -6,6 +6,9 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
@@ -23,7 +26,8 @@ import (
|
||||
|
||||
// Client wraps the Docker client with additional functionality
|
||||
type Client struct {
|
||||
cli *client.Client
|
||||
cli *client.Client
|
||||
probeHost string
|
||||
}
|
||||
|
||||
// NewClient creates a new Docker client
|
||||
@@ -45,6 +49,75 @@ func NewClient() (*Client, error) {
|
||||
return &Client{cli: cli}, nil
|
||||
}
|
||||
|
||||
// HostProbeHost returns an address through which host-published container
|
||||
// ports are reachable. When this process runs inside a container, host
|
||||
// loopback is unreachable; the bridge gateway IP routes to ports published
|
||||
// on 0.0.0.0. Result is cached for the process lifetime.
|
||||
func (c *Client) HostProbeHost(ctx context.Context) string {
|
||||
if c.probeHost != "" {
|
||||
return c.probeHost
|
||||
}
|
||||
host := "127.0.0.1"
|
||||
if self, err := c.self(ctx); err == nil && self.NetworkSettings != nil {
|
||||
for _, n := range self.NetworkSettings.Networks {
|
||||
if n != nil && n.Gateway != "" {
|
||||
host = n.Gateway
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
c.probeHost = host
|
||||
return host
|
||||
}
|
||||
|
||||
// OwnNetworkName returns the name of the platform network this process's
|
||||
// container is attached to, or "" when not running containerized. Per-project
|
||||
// and default Docker networks are never selected; among remaining networks
|
||||
// the lexicographically first wins so the choice is deterministic.
|
||||
func (c *Client) OwnNetworkName(ctx context.Context) string {
|
||||
self, err := c.self(ctx)
|
||||
if err != nil || self.NetworkSettings == nil {
|
||||
return ""
|
||||
}
|
||||
names := make([]string, 0, len(self.NetworkSettings.Networks))
|
||||
for name := range self.NetworkSettings.Networks {
|
||||
switch {
|
||||
case name == "bridge" || name == "host" || name == "none":
|
||||
case strings.HasPrefix(name, "containr-proj-"):
|
||||
default:
|
||||
names = append(names, name)
|
||||
}
|
||||
}
|
||||
sort.Strings(names)
|
||||
if len(names) == 0 {
|
||||
return ""
|
||||
}
|
||||
return names[0]
|
||||
}
|
||||
|
||||
// self inspects the container this process runs in (hostname == container ID).
|
||||
func (c *Client) self(ctx context.Context) (types.ContainerJSON, error) {
|
||||
hostname, err := os.Hostname()
|
||||
if err != nil || hostname == "" {
|
||||
return types.ContainerJSON{}, fmt.Errorf("hostname unavailable")
|
||||
}
|
||||
return c.cli.ContainerInspect(ctx, hostname)
|
||||
}
|
||||
|
||||
// ConnectSelfToNetwork attaches this process's container to the given network.
|
||||
// No-op when already attached or when not running containerized.
|
||||
func (c *Client) ConnectSelfToNetwork(ctx context.Context, networkName string) error {
|
||||
hostname, err := os.Hostname()
|
||||
if err != nil || hostname == "" {
|
||||
return fmt.Errorf("hostname unavailable")
|
||||
}
|
||||
err = c.cli.NetworkConnect(ctx, networkName, hostname, &network.EndpointSettings{})
|
||||
if err != nil && strings.Contains(strings.ToLower(err.Error()), "already exists") {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// ListContainers returns all containers
|
||||
func (c *Client) ListContainers(ctx context.Context, all bool) ([]types.Container, error) {
|
||||
return c.cli.ContainerList(ctx, container.ListOptions{
|
||||
|
||||
Reference in new issue
Block a user