github.com/juju/juju@v0.0.0-20240327075706-a90865de2538/worker/uniter/paths.go (about) 1 // Copyright 2012-2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package uniter 5 6 import ( 7 "crypto/tls" 8 "fmt" 9 "path/filepath" 10 11 "github.com/juju/names/v5" 12 13 "github.com/juju/juju/agent" 14 "github.com/juju/juju/agent/tools" 15 caasconstants "github.com/juju/juju/caas/kubernetes/provider/constants" 16 "github.com/juju/juju/juju/sockets" 17 ) 18 19 // Paths represents the set of filesystem paths a uniter worker has reason to 20 // care about. 21 type Paths struct { 22 23 // ToolsDir is the directory containing the jujud executable running this 24 // process; and also containing jujuc tool symlinks to that executable. It's 25 // the only path in this struct that is not typically pointing inside the 26 // directory reserved for the exclusive use of this worker (typically 27 // /var/lib/juju/agents/$UNIT_TAG/ ) 28 ToolsDir string 29 30 // Runtime represents the set of paths that are relevant at runtime. 31 Runtime RuntimePaths 32 33 // State represents the set of paths that hold persistent local state for 34 // the uniter. 35 State StatePaths 36 } 37 38 // GetToolsDir exists to satisfy the context.Paths interface. 39 func (paths Paths) GetToolsDir() string { 40 return paths.ToolsDir 41 } 42 43 // GetBaseDir exists to satisfy the context.Paths interface. 44 func (paths Paths) GetBaseDir() string { 45 return paths.State.BaseDir 46 } 47 48 // GetCharmDir exists to satisfy the context.Paths interface. 49 func (paths Paths) GetCharmDir() string { 50 return paths.State.CharmDir 51 } 52 53 // GetResourcesDir exists to satisfy the context.Paths interface. 54 func (paths Paths) GetResourcesDir() string { 55 return paths.State.ResourcesDir 56 } 57 58 // GetJujucClientSocket exists to satisfy the context.Paths interface. 59 func (paths Paths) GetJujucClientSocket(remote bool) sockets.Socket { 60 if remote { 61 return paths.Runtime.RemoteJujucServerSocket.Client 62 } 63 return paths.Runtime.LocalJujucServerSocket.Client 64 } 65 66 // GetJujucServerSocket exists to satisfy the context.Paths interface. 67 func (paths Paths) GetJujucServerSocket(remote bool) sockets.Socket { 68 if remote { 69 return paths.Runtime.RemoteJujucServerSocket.Server 70 } 71 return paths.Runtime.LocalJujucServerSocket.Server 72 } 73 74 // GetMetricsSpoolDir exists to satisfy the runner.Paths interface. 75 func (paths Paths) GetMetricsSpoolDir() string { 76 return paths.State.MetricsSpoolDir 77 } 78 79 const jujucServerSocketPort = 30000 80 81 // SocketPair is a server+client pair of socket descriptors. 82 type SocketPair struct { 83 Server sockets.Socket 84 Client sockets.Socket 85 } 86 87 // RuntimePaths represents the set of paths that are relevant at runtime. 88 type RuntimePaths struct { 89 // LocalJujuExecSocket listens for juju-exec invocations, and is always 90 // active. 91 LocalJujuExecSocket SocketPair 92 93 // RemoteJujuExecSocket listens for remote juju-exec invocations. 94 RemoteJujuExecSocket SocketPair 95 96 // JujucServerSocket listens for jujuc invocations, and is only 97 // active when supporting a jujuc execution context. 98 LocalJujucServerSocket SocketPair 99 100 // RemoteJujucServerSocket listens for remote jujuc invocations, and is only 101 // active when supporting a jujuc execution context. 102 RemoteJujucServerSocket SocketPair 103 } 104 105 // StatePaths represents the set of paths that hold persistent local state for 106 // the uniter. 107 type StatePaths struct { 108 // BaseDir is the unit agent's base directory. 109 BaseDir string 110 111 // CharmDir is the directory to which the charm the uniter runs is deployed. 112 CharmDir string 113 114 // ResourcesDir is the directory to which the charm the uniter runs is deployed. 115 ResourcesDir string 116 117 // BundlesDir holds downloaded charms. 118 BundlesDir string 119 120 // DeployerDir holds metadata about charms that are installing or have 121 // been installed. 122 DeployerDir string 123 124 // MetricsSpoolDir acts as temporary storage for metrics being sent from 125 // the uniter to state. 126 MetricsSpoolDir string 127 } 128 129 // SocketConfig specifies information for remote sockets. 130 type SocketConfig struct { 131 ServiceAddress string 132 OperatorAddress string 133 TLSConfig *tls.Config 134 } 135 136 // NewPaths returns the set of filesystem paths that the supplied unit should 137 // use, given the supplied root juju data directory path. 138 // If socketConfig is specified, all sockets will be TLS over TCP. 139 func NewPaths(dataDir string, unitTag names.UnitTag, socketConfig *SocketConfig) Paths { 140 return NewWorkerPaths(dataDir, unitTag, "", socketConfig) 141 } 142 143 // NewWorkerPaths returns the set of filesystem paths that the supplied unit worker should 144 // use, given the supplied root juju data directory path and worker identifier. 145 // Distinct worker identifiers ensure that runtime paths of different worker do not interfere. 146 // If socketConfig is specified, all sockets will be TLS over TCP. 147 func NewWorkerPaths(dataDir string, unitTag names.UnitTag, worker string, socketConfig *SocketConfig) Paths { 148 baseDir := agent.Dir(dataDir, unitTag) 149 join := filepath.Join 150 stateDir := join(baseDir, "state") 151 152 var newSocket func(name string) SocketPair 153 if socketConfig != nil { 154 newSocket = func(name string) SocketPair { 155 var port int 156 var address string 157 switch name { 158 case "agent": 159 port = jujucServerSocketPort + unitTag.Number() 160 address = socketConfig.OperatorAddress 161 case "run": 162 port = caasconstants.JujuExecServerSocketPort 163 address = socketConfig.ServiceAddress 164 default: 165 return SocketPair{} 166 } 167 return SocketPair{ 168 Client: sockets.Socket{ 169 Network: "tcp", 170 Address: fmt.Sprintf("%s:%d", address, port), 171 TLSConfig: socketConfig.TLSConfig, 172 }, 173 Server: sockets.Socket{ 174 Network: "tcp", 175 Address: fmt.Sprintf(":%d", port), 176 TLSConfig: socketConfig.TLSConfig, 177 }, 178 } 179 } 180 } else { 181 newSocket = func(name string) SocketPair { 182 return SocketPair{} 183 } 184 } 185 186 toolsDir := tools.ToolsDir(dataDir, unitTag.String()) 187 return Paths{ 188 ToolsDir: filepath.FromSlash(toolsDir), 189 Runtime: RuntimePaths{ 190 RemoteJujuExecSocket: newSocket("run"), 191 RemoteJujucServerSocket: newSocket("agent"), 192 LocalJujuExecSocket: newUnixSocket(baseDir, unitTag, worker, "run", false), 193 LocalJujucServerSocket: newUnixSocket(baseDir, unitTag, worker, "agent", true), 194 }, 195 State: StatePaths{ 196 BaseDir: baseDir, 197 CharmDir: join(baseDir, "charm"), 198 ResourcesDir: join(baseDir, "resources"), 199 BundlesDir: join(stateDir, "bundles"), 200 DeployerDir: join(stateDir, "deployer"), 201 MetricsSpoolDir: join(stateDir, "spool", "metrics"), 202 }, 203 } 204 } 205 206 func newUnixSocket(baseDir string, unitTag names.UnitTag, worker string, name string, abstract bool) SocketPair { 207 socket := sockets.Socket{Network: "unix"} 208 path := filepath.Join(baseDir, name+".socket") 209 if worker != "" { 210 path = filepath.Join(baseDir, fmt.Sprintf("%s-%s.socket", worker, name)) 211 } 212 if abstract { 213 path = "@" + path 214 } 215 socket.Address = path 216 return SocketPair{socket, socket} 217 }