github.com/containers/podman/v4@v4.9.4/pkg/machine/machine_common.go (about) 1 //go:build amd64 || arm64 2 // +build amd64 arm64 3 4 package machine 5 6 import ( 7 "encoding/json" 8 "fmt" 9 "net/url" 10 "os" 11 "strconv" 12 13 "github.com/containers/storage/pkg/ioutils" 14 ) 15 16 // GetDevNullFiles returns pointers to Read-only and Write-only DevNull files 17 func GetDevNullFiles() (*os.File, *os.File, error) { 18 dnr, err := os.OpenFile(os.DevNull, os.O_RDONLY, 0755) 19 if err != nil { 20 return nil, nil, err 21 } 22 23 dnw, err := os.OpenFile(os.DevNull, os.O_WRONLY, 0755) 24 if err != nil { 25 if e := dnr.Close(); e != nil { 26 err = e 27 } 28 return nil, nil, err 29 } 30 31 return dnr, dnw, nil 32 } 33 34 // AddSSHConnectionsToPodmanSocket adds SSH connections to the podman socket if 35 // no ignition path is provided 36 func AddSSHConnectionsToPodmanSocket(uid, port int, identityPath, name, remoteUsername string, opts InitOptions) error { 37 if len(opts.IgnitionPath) > 0 { 38 fmt.Println("An ignition path was provided. No SSH connection was added to Podman") 39 return nil 40 } 41 uri := SSHRemoteConnection.MakeSSHURL(LocalhostIP, fmt.Sprintf("/run/user/%d/podman/podman.sock", uid), strconv.Itoa(port), remoteUsername) 42 uriRoot := SSHRemoteConnection.MakeSSHURL(LocalhostIP, "/run/podman/podman.sock", strconv.Itoa(port), "root") 43 44 uris := []url.URL{uri, uriRoot} 45 names := []string{name, name + "-root"} 46 47 // The first connection defined when connections is empty will become the default 48 // regardless of IsDefault, so order according to rootful 49 if opts.Rootful { 50 uris[0], names[0], uris[1], names[1] = uris[1], names[1], uris[0], names[0] 51 } 52 53 for i := 0; i < 2; i++ { 54 if err := AddConnection(&uris[i], names[i], identityPath, opts.IsDefault && i == 0); err != nil { 55 return err 56 } 57 } 58 return nil 59 } 60 61 // WaitAPIAndPrintInfo prints info about the machine and does a ping test on the 62 // API socket 63 func WaitAPIAndPrintInfo(forwardState APIForwardingState, name, helper, forwardSock string, noInfo, isIncompatible, rootful bool) { 64 suffix := "" 65 var fmtString string 66 67 if name != DefaultMachineName { 68 suffix = " " + name 69 } 70 71 if isIncompatible { 72 fmtString = ` 73 !!! ACTION REQUIRED: INCOMPATIBLE MACHINE !!! 74 75 This machine was created by an older podman release that is incompatible 76 with this release of podman. It has been started in a limited operational 77 mode to allow you to copy any necessary files before recreating it. This 78 can be accomplished with the following commands: 79 80 # Login and copy desired files (Optional) 81 # podman machine ssh%[1]s tar cvPf - /path/to/files > backup.tar 82 83 # Recreate machine (DESTRUCTIVE!) 84 podman machine stop%[1]s 85 podman machine rm -f%[1]s 86 podman machine init --now%[1]s 87 88 # Copy back files (Optional) 89 # cat backup.tar | podman machine ssh%[1]s tar xvPf - 90 91 ` 92 93 fmt.Fprintf(os.Stderr, fmtString, suffix) 94 } 95 96 if forwardState == NoForwarding { 97 return 98 } 99 100 WaitAndPingAPI(forwardSock) 101 102 if !noInfo { 103 if !rootful { 104 fmtString = ` 105 This machine is currently configured in rootless mode. If your containers 106 require root permissions (e.g. ports < 1024), or if you run into compatibility 107 issues with non-podman clients, you can switch using the following command: 108 109 podman machine set --rootful%s 110 111 ` 112 113 fmt.Printf(fmtString, suffix) 114 } 115 116 fmt.Printf("API forwarding listening on: %s\n", forwardSock) 117 if forwardState == DockerGlobal { 118 fmt.Printf("Docker API clients default to this address. You do not need to set DOCKER_HOST.\n\n") 119 } else { 120 stillString := "still " 121 switch forwardState { 122 case NotInstalled: 123 124 fmtString = ` 125 The system helper service is not installed; the default Docker API socket 126 address can't be used by podman. ` 127 128 if len(helper) < 1 { 129 fmt.Print(fmtString) 130 } else { 131 fmtString += `If you would like to install it, run the following commands: 132 133 sudo %s install 134 podman machine stop%[2]s; podman machine start%[2]s 135 136 ` 137 fmt.Printf(fmtString, helper, suffix) 138 } 139 case MachineLocal: 140 fmt.Printf("\nAnother process was listening on the default Docker API socket address.\n") 141 case ClaimUnsupported: 142 fallthrough 143 default: 144 stillString = "" 145 } 146 147 fmtString = `You can %sconnect Docker API clients by setting DOCKER_HOST using the 148 following command in your terminal session: 149 150 export DOCKER_HOST='unix://%s' 151 152 ` 153 154 fmt.Printf(fmtString, stillString, forwardSock) 155 } 156 } 157 } 158 159 // SetRootful modifies the machine's default connection to be either rootful or 160 // rootless 161 func SetRootful(rootful bool, name, rootfulName string) error { 162 changeCon, err := AnyConnectionDefault(name, rootfulName) 163 if err != nil { 164 return err 165 } 166 167 if changeCon { 168 newDefault := name 169 if rootful { 170 newDefault += "-root" 171 } 172 err := ChangeDefault(newDefault) 173 if err != nil { 174 return err 175 } 176 } 177 return nil 178 } 179 180 // WriteConfig writes the machine's JSON config file 181 func WriteConfig(configPath string, v VM) error { 182 opts := &ioutils.AtomicFileWriterOptions{ExplicitCommit: true} 183 w, err := ioutils.NewAtomicFileWriterWithOpts(configPath, 0644, opts) 184 if err != nil { 185 return err 186 } 187 defer w.Close() 188 189 enc := json.NewEncoder(w) 190 enc.SetIndent("", " ") 191 192 if err := enc.Encode(v); err != nil { 193 return err 194 } 195 196 // Commit the changes to disk if no errors 197 return w.Commit() 198 }