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  }