github.com/vmware/govmomi@v0.37.1/internal/helpers.go (about) 1 /* 2 Copyright (c) 2020-2023 VMware, Inc. All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package internal 18 19 import ( 20 "context" 21 "fmt" 22 "net" 23 "net/http" 24 "net/url" 25 "os" 26 "path" 27 28 "github.com/vmware/govmomi/vim25" 29 "github.com/vmware/govmomi/vim25/mo" 30 "github.com/vmware/govmomi/vim25/soap" 31 "github.com/vmware/govmomi/vim25/types" 32 ) 33 34 const ( 35 vCenterHostGatewaySocket = "/var/run/envoy-hgw/hgw-pipe" 36 vCenterHostGatewaySocketEnv = "VCENTER_ENVOY_HOST_GATEWAY" 37 ) 38 39 // InventoryPath composed of entities by Name 40 func InventoryPath(entities []mo.ManagedEntity) string { 41 val := "/" 42 43 for _, entity := range entities { 44 // Skip root folder in building inventory path. 45 if entity.Parent == nil { 46 continue 47 } 48 val = path.Join(val, entity.Name) 49 } 50 51 return val 52 } 53 54 func HostSystemManagementIPs(config []types.VirtualNicManagerNetConfig) []net.IP { 55 var ips []net.IP 56 57 for _, nc := range config { 58 if nc.NicType != string(types.HostVirtualNicManagerNicTypeManagement) { 59 continue 60 } 61 for ix := range nc.CandidateVnic { 62 for _, selectedVnicKey := range nc.SelectedVnic { 63 if nc.CandidateVnic[ix].Key != selectedVnicKey { 64 continue 65 } 66 ip := net.ParseIP(nc.CandidateVnic[ix].Spec.Ip.IpAddress) 67 if ip != nil { 68 ips = append(ips, ip) 69 } 70 } 71 } 72 } 73 74 return ips 75 } 76 77 // UsingEnvoySidecar determines if the given *vim25.Client is using vCenter's 78 // local Envoy sidecar (as opposed to using the HTTPS port.) 79 // Returns a boolean indicating whether to use the sidecar or not. 80 func UsingEnvoySidecar(c *vim25.Client) bool { 81 envoySidecarPort := os.Getenv("GOVMOMI_ENVOY_SIDECAR_PORT") 82 if envoySidecarPort == "" { 83 envoySidecarPort = "1080" 84 } 85 envoySidecarHost := os.Getenv("GOVMOMI_ENVOY_SIDECAR_HOST") 86 if envoySidecarHost == "" { 87 envoySidecarHost = "localhost" 88 } 89 return c.URL().Hostname() == envoySidecarHost && c.URL().Scheme == "http" && c.URL().Port() == envoySidecarPort 90 } 91 92 // ClientWithEnvoyHostGateway clones the provided soap.Client and returns a new 93 // one that uses a Unix socket to leverage vCenter's local Envoy host 94 // gateway. 95 // This should be used to construct clients that talk to ESX. 96 // This method returns a new *vim25.Client and does not modify the original input. 97 // This client disables HTTP keep alives and is intended for a single round 98 // trip. (eg. guest file transfer, datastore file transfer) 99 func ClientWithEnvoyHostGateway(vc *vim25.Client) *vim25.Client { 100 // Override the vim client with a new one that wraps a Unix socket transport. 101 // Using HTTP here so secure means nothing. 102 sc := soap.NewClient(vc.URL(), true) 103 // Clone the underlying HTTP transport, only replacing the dialer logic. 104 transport := sc.DefaultTransport().Clone() 105 hostGatewaySocketPath := os.Getenv(vCenterHostGatewaySocketEnv) 106 if hostGatewaySocketPath == "" { 107 hostGatewaySocketPath = vCenterHostGatewaySocket 108 } 109 transport.DialContext = func(_ context.Context, _, _ string) (net.Conn, error) { 110 return net.Dial("unix", hostGatewaySocketPath) 111 } 112 // We use this client for a single request, so we don't require keepalives. 113 transport.DisableKeepAlives = true 114 sc.Client = http.Client{ 115 Transport: transport, 116 } 117 newVC := &vim25.Client{ 118 Client: sc, 119 } 120 return newVC 121 } 122 123 // HostGatewayTransferURL rewrites the provided URL to be suitable for use 124 // with the Envoy host gateway on vCenter. 125 // It returns a copy of the provided URL with the host, scheme rewritten as needed. 126 // Receivers of such URLs must typically also use ClientWithEnvoyHostGateway to 127 // use the appropriate http.Transport to be able to make use of the host 128 // gateway. 129 // nil input yields an uninitialized struct. 130 func HostGatewayTransferURL(u *url.URL, hostMoref types.ManagedObjectReference) *url.URL { 131 if u == nil { 132 return &url.URL{} 133 } 134 // Make a copy of the provided URL. 135 turl := *u 136 turl.Host = "localhost" 137 turl.Scheme = "http" 138 oldPath := turl.Path 139 turl.Path = fmt.Sprintf("/hgw/%s%s", hostMoref.Value, oldPath) 140 return &turl 141 }