github.com/vmware/govmomi@v0.37.2/internal/helpers_test.go (about)

     1  /*
     2  Copyright (c) 2021 VMware, Inc. All Rights Reserved.
     3  Licensed under the Apache License, Version 2.0 (the "License");
     4  you may not use this file except in compliance with the License.
     5  You may obtain a copy of the License at
     6      http://www.apache.org/licenses/LICENSE-2.0
     7  Unless required by applicable law or agreed to in writing, software
     8  distributed under the License is distributed on an "AS IS" BASIS,
     9  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    10  See the License for the specific language governing permissions and
    11  limitations under the License.
    12  */
    13  
    14  package internal_test
    15  
    16  import (
    17  	"crypto/rand"
    18  	"encoding/hex"
    19  	"fmt"
    20  	"io"
    21  	"net"
    22  	"net/http"
    23  	"net/url"
    24  	"os"
    25  	"path/filepath"
    26  	"testing"
    27  	"time"
    28  
    29  	"github.com/stretchr/testify/require"
    30  
    31  	"github.com/vmware/govmomi/internal"
    32  	"github.com/vmware/govmomi/simulator/esx"
    33  	"github.com/vmware/govmomi/vim25"
    34  	"github.com/vmware/govmomi/vim25/soap"
    35  	"github.com/vmware/govmomi/vim25/types"
    36  )
    37  
    38  func TestHostSystemManagementIPs(t *testing.T) {
    39  	ips := internal.HostSystemManagementIPs(esx.HostSystem.Config.VirtualNicManagerInfo.NetConfig)
    40  
    41  	if len(ips) != 1 {
    42  		t.Fatalf("no mgmt ip found")
    43  	}
    44  	if ips[0].String() != "127.0.0.1" {
    45  		t.Fatalf("Expected management ip %s, got %s", "127.0.0.1", ips[0].String())
    46  	}
    47  }
    48  
    49  func TestUsingVCEnvoySidecar(t *testing.T) {
    50  	t.Run("VC HTTPS port", func(t *testing.T) {
    51  		scheme := "https"
    52  		hostname := "my-vcenter"
    53  		port := 443
    54  		u := &url.URL{Scheme: scheme, Host: fmt.Sprintf("%s:%d", hostname, port)}
    55  		client := &vim25.Client{Client: soap.NewClient(u, true)}
    56  		usingSidecar := internal.UsingEnvoySidecar(client)
    57  		require.False(t, usingSidecar)
    58  	})
    59  	t.Run("Envoy sidecar", func(t *testing.T) {
    60  		scheme := "http"
    61  		hostname := "localhost"
    62  		port := 1080
    63  		u := &url.URL{Scheme: scheme, Host: fmt.Sprintf("%s:%d", hostname, port)}
    64  		client := &vim25.Client{Client: soap.NewClient(u, true)}
    65  		usingSidecar := internal.UsingEnvoySidecar(client)
    66  		require.True(t, usingSidecar)
    67  	})
    68  }
    69  
    70  func TestClientUsingEnvoyHostGateway(t *testing.T) {
    71  	prefix := "hgw"
    72  	suffix := ".sock"
    73  	randBytes := make([]byte, 16)
    74  	_, err := rand.Read(randBytes)
    75  	require.NoError(t, err)
    76  
    77  	testSocketPath := filepath.Join(os.TempDir(), prefix+hex.EncodeToString(randBytes)+suffix)
    78  
    79  	l, err := net.Listen("unix", testSocketPath)
    80  	require.NoError(t, err)
    81  	handler := &testHTTPServer{
    82  		expectedURL: "http://localhost/foo",
    83  		response:    "Hello, Unix socket!",
    84  		t:           t,
    85  	}
    86  	server := http.Server{
    87  		Handler: handler,
    88  	}
    89  	go server.Serve(l)
    90  	defer server.Close()
    91  	defer l.Close()
    92  
    93  	// First make sure the test server works fine, since we're starting a goroutine.
    94  	unixDialer := func(proto, addr string) (conn net.Conn, err error) {
    95  		return net.Dial("unix", testSocketPath)
    96  	}
    97  	tr := &http.Transport{
    98  		Dial: unixDialer,
    99  	}
   100  	client := &http.Client{Transport: tr}
   101  
   102  	require.Eventually(t, func() bool {
   103  		_, err := client.Get(handler.expectedURL)
   104  		return err == nil
   105  	}, 15*time.Second, 1*time.Second, "Expected test HTTP server to be up")
   106  
   107  	envVar := "VCENTER_ENVOY_HOST_GATEWAY"
   108  	oldValue := os.Getenv(envVar)
   109  	defer os.Setenv(envVar, oldValue)
   110  	os.Setenv(envVar, testSocketPath)
   111  
   112  	// Build a new client using the test unix socket.
   113  	vc := &vim25.Client{Client: soap.NewClient(&url.URL{}, true)}
   114  	newClient := internal.ClientWithEnvoyHostGateway(vc)
   115  
   116  	// An HTTP request made using the new client should hit the server listening on the Unix socket.
   117  	resp, err := newClient.Get(handler.expectedURL)
   118  
   119  	// ...but should successfully connect to the Unix socket set up for testing.
   120  	require.NoError(t, err)
   121  	response, err := io.ReadAll(resp.Body)
   122  	require.NoError(t, err)
   123  
   124  	require.Equal(t, response, []byte(handler.response))
   125  }
   126  
   127  type testHTTPServer struct {
   128  	expectedURL string
   129  	response    string
   130  	t           *testing.T
   131  }
   132  
   133  func (t *testHTTPServer) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
   134  	require.Equal(t.t, "/foo", req.URL.Path)
   135  	resp.Write([]byte(t.response))
   136  }
   137  
   138  func TestRewriteURLForHostGateway(t *testing.T) {
   139  	testURL, err := url.Parse("https://foo.bar/baz?query_param=1")
   140  	require.NoError(t, err)
   141  
   142  	hostMoref := types.ManagedObjectReference{
   143  		Type:  "HostSystem",
   144  		Value: "host-123",
   145  	}
   146  	result := internal.HostGatewayTransferURL(testURL, hostMoref)
   147  	require.Equal(t, "localhost", result.Host)
   148  	require.Equal(t, "/hgw/host-123/baz", result.Path)
   149  	values := url.Values{"query_param": []string{"1"}}
   150  	require.Equal(t, values, result.Query())
   151  }