diff --git a/README.md b/README.md index 2cd0613..e0eb900 100644 --- a/README.md +++ b/README.md @@ -1198,6 +1198,8 @@ When access to the VM must go through a proxy, the proxy configuration should be To configure the IP-port mapping, use the cidr-port-rel key. This requires a list of entries in the format "CIDR:initial-port". Based on this list, the system will assign a port by matching the allocated IP with the corresponding CIDR and applying the specified initial port. +In order to allow reusing a backend definitions, the proxy configuration is not used by spread when it can ssh directly to the destination IP address. + ## Linode backend diff --git a/smoke/spread.yaml b/smoke/spread.yaml index 72c3b1b..d0d92f6 100644 --- a/smoke/spread.yaml +++ b/smoke/spread.yaml @@ -23,6 +23,8 @@ backends: halt-timeout: 2h wait-timeout: 5m groups: [default] + proxy: ingress-haproxy.ps7.canonical.com + cidr-port-rel: [10.151.54.0/24:4000] environment: HTTP_PROXY: 'http://egress.ps7.internal:3128' HTTPS_PROXY: 'http://egress.ps7.internal:3128' @@ -83,6 +85,8 @@ backends: halt-timeout: 2h wait-timeout: 5m groups: [default] + proxy: ingress-haproxy.ps7.canonical.com + cidr-port-rel: [10.151.89.0/24:8000] environment: HTTP_PROXY: 'http://egress.ps7.internal:3128' HTTPS_PROXY: 'http://egress.ps7.internal:3128' diff --git a/spread.yaml b/spread.yaml index ec8334e..ecaaad2 100644 --- a/spread.yaml +++ b/spread.yaml @@ -28,6 +28,8 @@ backends: plan: shared.small halt-timeout: 2h wait-timeout: 10m + proxy: ingress-haproxy.ps7.canonical.com + cidr-port-rel: [10.151.54.0/24:4000] groups: [default] environment: &openstack-env HTTP_PROXY: 'http://egress.ps7.internal:3128' diff --git a/spread/openstack.go b/spread/openstack.go index c30470f..bc474c5 100644 --- a/spread/openstack.go +++ b/spread/openstack.go @@ -574,6 +574,29 @@ func (p *openstackProvider) waitProvision(ctx context.Context, s *openstackServe var openstackServerBootTimeout = 5 * time.Minute var openstackServerBootRetry = 5 * time.Second +var openstackDirectSSHProbeTimeout = 3 * time.Second + +func canReachDirectSSH(ctx context.Context, address string, timeout time.Duration) bool { + if net.ParseIP(address) == nil { + return false + } + + dialCtx := ctx + if _, hasDeadline := ctx.Deadline(); !hasDeadline { + var cancel context.CancelFunc + dialCtx, cancel = context.WithTimeout(ctx, timeout) + defer cancel() + } + + dialer := net.Dialer{Timeout: timeout} + conn, err := dialer.DialContext(dialCtx, "tcp", net.JoinHostPort(address, "22")) + if err != nil { + debugf("Direct SSH probe to %s failed: %v", address, err) + return false + } + _ = conn.Close() + return true +} func countIPsBetween(initialIp net.IP, finalIp net.IP) (uint32, error) { ip1Int := binary.BigEndian.Uint32(initialIp.To4()) @@ -594,6 +617,11 @@ func (p *openstackProvider) updateAddressIfProxyDefined(ctx context.Context, s * return nil } + if canReachDirectSSH(ctx, s.address, openstackDirectSSHProbeTimeout) { + printf("Server reachable directly via SSH, skipping proxy mapping (%s)", s.d.Name) + return nil + } + for _, rel := range s.p.backend.CIDRPortRel { parts := strings.SplitN(rel, ":", 2) if len(parts) != 2 {