k8s.io/kubernetes@v1.29.3/pkg/kubelet/util/util_unix.go (about) 1 //go:build freebsd || linux || darwin 2 // +build freebsd linux darwin 3 4 /* 5 Copyright 2017 The Kubernetes Authors. 6 7 Licensed under the Apache License, Version 2.0 (the "License"); 8 you may not use this file except in compliance with the License. 9 You may obtain a copy of the License at 10 11 http://www.apache.org/licenses/LICENSE-2.0 12 13 Unless required by applicable law or agreed to in writing, software 14 distributed under the License is distributed on an "AS IS" BASIS, 15 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 See the License for the specific language governing permissions and 17 limitations under the License. 18 */ 19 20 package util 21 22 import ( 23 "context" 24 "fmt" 25 "net" 26 "net/url" 27 "os" 28 "path/filepath" 29 30 "golang.org/x/sys/unix" 31 "k8s.io/klog/v2" 32 ) 33 34 const ( 35 // unixProtocol is the network protocol of unix socket. 36 unixProtocol = "unix" 37 ) 38 39 // CreateListener creates a listener on the specified endpoint. 40 func CreateListener(endpoint string) (net.Listener, error) { 41 protocol, addr, err := parseEndpointWithFallbackProtocol(endpoint, unixProtocol) 42 if err != nil { 43 return nil, err 44 } 45 if protocol != unixProtocol { 46 return nil, fmt.Errorf("only support unix socket endpoint") 47 } 48 49 // Unlink to cleanup the previous socket file. 50 err = unix.Unlink(addr) 51 if err != nil && !os.IsNotExist(err) { 52 return nil, fmt.Errorf("failed to unlink socket file %q: %v", addr, err) 53 } 54 55 if err := os.MkdirAll(filepath.Dir(addr), 0750); err != nil { 56 return nil, fmt.Errorf("error creating socket directory %q: %v", filepath.Dir(addr), err) 57 } 58 59 // Create the socket on a tempfile and move it to the destination socket to handle improper cleanup 60 file, err := os.CreateTemp(filepath.Dir(addr), "") 61 if err != nil { 62 return nil, fmt.Errorf("failed to create temporary file: %v", err) 63 } 64 65 if err := os.Remove(file.Name()); err != nil { 66 return nil, fmt.Errorf("failed to remove temporary file: %v", err) 67 } 68 69 l, err := net.Listen(protocol, file.Name()) 70 if err != nil { 71 return nil, err 72 } 73 74 if err = os.Rename(file.Name(), addr); err != nil { 75 return nil, fmt.Errorf("failed to move temporary file to addr %q: %v", addr, err) 76 } 77 78 return l, nil 79 } 80 81 // GetAddressAndDialer returns the address parsed from the given endpoint and a context dialer. 82 func GetAddressAndDialer(endpoint string) (string, func(ctx context.Context, addr string) (net.Conn, error), error) { 83 protocol, addr, err := parseEndpointWithFallbackProtocol(endpoint, unixProtocol) 84 if err != nil { 85 return "", nil, err 86 } 87 if protocol != unixProtocol { 88 return "", nil, fmt.Errorf("only support unix socket endpoint") 89 } 90 91 return addr, dial, nil 92 } 93 94 func dial(ctx context.Context, addr string) (net.Conn, error) { 95 return (&net.Dialer{}).DialContext(ctx, unixProtocol, addr) 96 } 97 98 func parseEndpointWithFallbackProtocol(endpoint string, fallbackProtocol string) (protocol string, addr string, err error) { 99 if protocol, addr, err = parseEndpoint(endpoint); err != nil && protocol == "" { 100 fallbackEndpoint := fallbackProtocol + "://" + endpoint 101 protocol, addr, err = parseEndpoint(fallbackEndpoint) 102 if err == nil { 103 klog.InfoS("Using this endpoint is deprecated, please consider using full URL format", "endpoint", endpoint, "URL", fallbackEndpoint) 104 } 105 } 106 return 107 } 108 109 func parseEndpoint(endpoint string) (string, string, error) { 110 u, err := url.Parse(endpoint) 111 if err != nil { 112 return "", "", err 113 } 114 115 switch u.Scheme { 116 case "tcp": 117 return "tcp", u.Host, nil 118 119 case "unix": 120 return "unix", u.Path, nil 121 122 case "": 123 return "", "", fmt.Errorf("using %q as endpoint is deprecated, please consider using full url format", endpoint) 124 125 default: 126 return u.Scheme, "", fmt.Errorf("protocol %q not supported", u.Scheme) 127 } 128 } 129 130 // LocalEndpoint returns the full path to a unix socket at the given endpoint 131 func LocalEndpoint(path, file string) (string, error) { 132 u := url.URL{ 133 Scheme: unixProtocol, 134 Path: path, 135 } 136 return filepath.Join(u.String(), file+".sock"), nil 137 } 138 139 // NormalizePath is a no-op for Linux for now 140 func NormalizePath(path string) string { 141 return path 142 }