From 72548fbd1bb314fe8fe4e6491156af298924be05 Mon Sep 17 00:00:00 2001 From: Pavel Sviderski Date: Wed, 26 Feb 2025 21:10:55 +1000 Subject: [PATCH] feat(dns): allow to specify http(s) ports without hostname to default to cluster domain --- cmd/uncloud/service/run.go | 4 ++- internal/api/port.go | 7 +---- internal/api/port_test.go | 58 ++++++++++++++++---------------------- 3 files changed, 29 insertions(+), 40 deletions(-) diff --git a/cmd/uncloud/service/run.go b/cmd/uncloud/service/run.go index 5a0fc4bb..27ef6cb6 100644 --- a/cmd/uncloud/service/run.go +++ b/cmd/uncloud/service/run.go @@ -53,8 +53,10 @@ func NewRunCommand() *cobra.Command { cmd.Flags().StringSliceVarP(&opts.publish, "publish", "p", nil, "Publish a service port to make it accessible outside the cluster. Can be specified multiple times.\n"+ "Format: [hostname:][load_balancer_port:]container_port[/protocol] or [host_ip:]:host_port:container_port[/protocol]@host\n"+ - "Supported protocols: tcp, udp, http, https (default is tcp). If a hostname for http(s) port is not specified, a random hostname is generated.\n"+ + "Supported protocols: tcp, udp, http, https (default is tcp). If a hostname for http(s) port is not specified,\n"+ + "service-name.cluster-domain will be used as the hostname.\n"+ "Examples:\n"+ + " -p 8080/https Publish port 8080 as HTTPS via load balancer with default service-name.cluster-domain hostname\n"+ " -p app.example.com:8080/https Publish port 8080 as HTTPS via load balancer with custom hostname\n"+ " -p 9000:8080 Publish port 8080 as TCP port 9000 via load balancer\n"+ " -p 53:5353/udp@host Bind UDP port 5353 to host port 53") diff --git a/internal/api/port.go b/internal/api/port.go index 7965b86d..7a3cf22c 100644 --- a/internal/api/port.go +++ b/internal/api/port.go @@ -62,9 +62,6 @@ func (p *PortSpec) Validate() error { return fmt.Errorf("invalid hostname '%s': %w", p.Hostname, err) } } - if p.Hostname == "" && (p.Protocol == ProtocolHTTP || p.Protocol == ProtocolHTTPS) { - return fmt.Errorf("hostname is required with '%s' or '%s' protocols", ProtocolHTTP, ProtocolHTTPS) - } case PortModeHost: if p.PublishedPort == 0 { return fmt.Errorf("published port is required in %s mode", PortModeHost) @@ -216,9 +213,7 @@ func ParsePortSpec(port string) (PortSpec, error) { return spec, fmt.Errorf("invalid host IP '%s': %w", parts[0], err) } } else { - if parts[0] == "" { - return spec, fmt.Errorf("hostname must not be empty") - } + // Hostname may be empty. spec.Hostname = parts[0] } diff --git a/internal/api/port_test.go b/internal/api/port_test.go index e6d062d6..a8e9050f 100644 --- a/internal/api/port_test.go +++ b/internal/api/port_test.go @@ -50,6 +50,22 @@ func TestPortSpec_Validate(t *testing.T) { Mode: PortModeIngress, }, }, + { + name: "ingress mode without hostname http", + spec: PortSpec{ + ContainerPort: 8080, + Protocol: ProtocolHTTP, + Mode: PortModeIngress, + }, + }, + { + name: "ingress mode without hostname https", + spec: PortSpec{ + ContainerPort: 8080, + Protocol: ProtocolHTTPS, + Mode: PortModeIngress, + }, + }, { name: "ingress mode with hostname and http", spec: PortSpec{ @@ -164,24 +180,6 @@ func TestPortSpec_Validate(t *testing.T) { }, wantErr: "invalid hostname 'app': must be a valid domain name containing at least one dot", }, - { - name: "missing hostname with http", - spec: PortSpec{ - ContainerPort: 8080, - Protocol: ProtocolHTTP, - Mode: PortModeIngress, - }, - wantErr: "hostname is required with 'http' or 'https' protocols", - }, - { - name: "missing hostname with https", - spec: PortSpec{ - ContainerPort: 8080, - Protocol: ProtocolHTTPS, - Mode: PortModeIngress, - }, - wantErr: "hostname is required with 'http' or 'https' protocols", - }, { name: "host IP in ingress mode", spec: PortSpec{ @@ -468,6 +466,15 @@ func TestParsePortSpec(t *testing.T) { Mode: PortModeIngress, }, }, + { + name: "container port http without hostname", + port: "8080/http", + expected: PortSpec{ + ContainerPort: 8080, + Protocol: ProtocolHTTP, + Mode: PortModeIngress, + }, + }, { name: "hostname and container port http", port: "app.example.com:8080/http", @@ -602,21 +609,6 @@ func TestParsePortSpec(t *testing.T) { port: "app.example.com:invalid:8080", wantErr: "invalid published port", }, - { - name: "missing hostname with http", - port: "8080/http", - wantErr: "hostname is required", - }, - { - name: "missing hostname with http", - port: "8080/https", - wantErr: "hostname is required", - }, - { - name: "missing hostname with published https port", - port: "8000:8080/https", - wantErr: "hostname is required", - }, { name: "invalid hostname", port: "app:8080/http",