github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/cloudconfig/cloudinit/interface.go (about)

     1  // Copyright 2011, 2013, 2015 Canonical Ltd.
     2  // Copyright 2015 Cloudbase Solutions SRL
     3  // Licensed under the AGPLv3, see LICENCE file for details.
     4  
     5  package cloudinit
     6  
     7  import (
     8  	"github.com/juju/errors"
     9  	"github.com/juju/packaging/v3"
    10  	"github.com/juju/packaging/v3/commands"
    11  	"github.com/juju/packaging/v3/config"
    12  	"github.com/juju/proxy"
    13  	"github.com/juju/utils/v3/shell"
    14  	"golang.org/x/crypto/ssh"
    15  
    16  	corenetwork "github.com/juju/juju/core/network"
    17  	"github.com/juju/juju/core/os/ostype"
    18  	jujupackaging "github.com/juju/juju/packaging"
    19  )
    20  
    21  // CloudConfig is the interface of all cloud-init cloudconfig options.
    22  type CloudConfig interface {
    23  	// SetAttr sets an arbitrary attribute in the cloudinit config.
    24  	// The value will be marshalled according to the rules
    25  	// of the goyaml.Marshal.
    26  	SetAttr(string, interface{})
    27  
    28  	// UnsetAttr unsets the attribute given from the cloudinit config.
    29  	// If the attribute has not been previously set, no error occurs.
    30  	UnsetAttr(string)
    31  
    32  	// GetOS returns the os this CloudConfig was made for.
    33  	GetOS() string
    34  
    35  	// CloudConfig also contains all the smaller interfaces for config
    36  	// management:
    37  
    38  	UsersConfig
    39  	SystemUpdateConfig
    40  	SystemUpgradeConfig
    41  	PackageProxyConfig
    42  	PackageMirrorConfig
    43  	PackageSourcesConfig
    44  	PackagingConfig
    45  	RunCmdsConfig
    46  	BootCmdsConfig
    47  	EC2MetadataConfig
    48  	FinalMessageConfig
    49  	LocaleConfig
    50  	DeviceMountConfig
    51  	OutputConfig
    52  	SSHAuthorizedKeysConfig
    53  	SSHKeysConfig
    54  	RootUserConfig
    55  	WrittenFilesConfig
    56  	RenderConfig
    57  	AdvancedPackagingConfig
    58  	HostnameConfig
    59  	NetworkingConfig
    60  }
    61  
    62  // SystemUpdateConfig is the interface for managing all system update options.
    63  type SystemUpdateConfig interface {
    64  	// SetSystemUpdate sets whether the system should refresh the local package
    65  	// database on first boot.
    66  	// NOTE: This option is active in cloudinit by default and must be
    67  	// explicitly set to false if it is not desired.
    68  	SetSystemUpdate(bool)
    69  
    70  	// UnsetSystemUpdate unsets the package list updating option set by
    71  	// SetSystemUpdate, returning it to the cloudinit *default of true*.
    72  	// If the option has not previously been set, no error occurs.
    73  	UnsetSystemUpdate()
    74  
    75  	// SystemUpdate returns the value set with SetSystemUpdate or false
    76  	// NOTE: even though not set, the cloudinit-defined default is true.
    77  	SystemUpdate() bool
    78  }
    79  
    80  // SystemUpgradeConfig is the interface for managing all system upgrade settings.
    81  type SystemUpgradeConfig interface {
    82  	// SetSystemUpgrade sets whether cloud-init should run the process of upgrading
    83  	// all the packages with available newer versions on the machine's *first* boot.
    84  	SetSystemUpgrade(bool)
    85  
    86  	// UnsetSystemUpgrade unsets the value set by SetSystemUpgrade.
    87  	// If the option has not previously been set, no error occurs.
    88  	UnsetSystemUpgrade()
    89  
    90  	// SystemUpgrade returns the value set by SetSystemUpgrade or
    91  	// false if no call to SetSystemUpgrade has been made.
    92  	SystemUpgrade() bool
    93  }
    94  
    95  // PackageProxyConfig is the interface for packaging proxy settings on a cloudconfig
    96  type PackageProxyConfig interface {
    97  	// SetPackageProxy sets the URL to be used as a proxy by the
    98  	// specific package manager
    99  	SetPackageProxy(string)
   100  
   101  	// UnsetPackageProxy unsets the option set by SetPackageProxy
   102  	// If it has not been previously set, no error occurs
   103  	UnsetPackageProxy()
   104  
   105  	// PackageProxy returns the URL of the proxy server set using
   106  	// SetPackageProxy or an empty string if it has not been set
   107  	PackageProxy() string
   108  }
   109  
   110  // PackageMirrorConfig is the interface for package mirror settings on a cloudconfig.
   111  type PackageMirrorConfig interface {
   112  	// SetPackageMirror sets the URL to be used as the mirror for
   113  	// pulling packages by the system's specific package manager.
   114  	SetPackageMirror(string)
   115  
   116  	// UnsetPackageMirror unsets the value set by SetPackageMirror
   117  	// If it has not been previously set, no error occurs.
   118  	UnsetPackageMirror()
   119  
   120  	// PackageMirror returns the URL of the package mirror set by
   121  	// SetPackageMirror or an empty string if not previously set.
   122  	PackageMirror() string
   123  }
   124  
   125  // PackageSourcesConfig is the interface for package source settings on a cloudconfig.
   126  type PackageSourcesConfig interface {
   127  	// AddPackageSource adds a new repository and optional key to be
   128  	// used as a package source by the system's specific package manager.
   129  	AddPackageSource(packaging.PackageSource)
   130  
   131  	// PackageSources returns all sources set with AddPackageSource.
   132  	PackageSources() []packaging.PackageSource
   133  
   134  	// AddPackagePreferences adds the necessary options and/or bootcmds to
   135  	// enable the given packaging.PackagePreferences.
   136  	AddPackagePreferences(packaging.PackagePreferences)
   137  
   138  	// PackagePreferences returns the previously-added PackagePreferences.
   139  	PackagePreferences() []packaging.PackagePreferences
   140  }
   141  
   142  // PackagingConfig is the interface for all packaging-related operations.
   143  type PackagingConfig interface {
   144  	// AddPackage adds a package to be installed on *first* boot.
   145  	AddPackage(string)
   146  
   147  	// RemovePackage removes a package from the list of to be installed packages
   148  	// If the package has not been previously installed, no error occurs.
   149  	RemovePackage(string)
   150  
   151  	// Packages returns a list of all packages that will be installed.
   152  	Packages() []string
   153  }
   154  
   155  // RunCmdsConfig is the interface for all operations on first-boot commands.
   156  type RunCmdsConfig interface {
   157  	// AddRunCmd adds a command to be executed on *first* boot.
   158  	// It can receive any number of string arguments, which will be joined into
   159  	// a single command and passed to cloudinit to be executed.
   160  	// NOTE: metacharacters will *not* be escaped!
   161  	AddRunCmd(...string)
   162  
   163  	// AddScripts simply calls AddRunCmd on every string passed to it.
   164  	// NOTE: this means that each given string must be a full command plus
   165  	// all of its arguments.
   166  	// NOTE: metacharacters will not be escaped.
   167  	AddScripts(...string)
   168  
   169  	// PrependRunCmd adds a command to the beginning of the list of commands
   170  	// to be run on first boot.
   171  	PrependRunCmd(...string)
   172  
   173  	// RemoveRunCmd removes the given command from the list of commands to be
   174  	// run on first boot. If it has not been previously added, no error occurs.
   175  	RemoveRunCmd(string)
   176  
   177  	// RunCmds returns all the commands added with AddRunCmd or AddScript.
   178  	RunCmds() []string
   179  }
   180  
   181  // BootCmdsConfig is the interface for all operations on early-boot commands.
   182  type BootCmdsConfig interface {
   183  	// AddBootCmd adds a command to be executed on *every* boot.
   184  	// It can receive any number of string arguments, which will be joined into
   185  	// a single command.
   186  	// NOTE: metacharecters will not be escaped.
   187  	AddBootCmd(...string)
   188  
   189  	// RemoveBootCmd removes the given command from the list of commands to be
   190  	// run every boot. If it has not been previously added, no error occurs.
   191  	RemoveBootCmd(string)
   192  
   193  	// BootCmds returns all the commands added with AddBootCmd.
   194  	BootCmds() []string
   195  }
   196  
   197  // EC2MetadataConfig is the interface for all EC2-metadata related settings.
   198  type EC2MetadataConfig interface {
   199  	// SetDisableEC2Metadata sets whether access to the EC2 metadata service is
   200  	// disabled early in boot via a null route. The default value is false.
   201  	// (route del -host 169.254.169.254 reject).
   202  	SetDisableEC2Metadata(bool)
   203  
   204  	// UnsetDisableEC2Metadata unsets the value set by SetDisableEC2Metadata,
   205  	// returning it to the cloudinit-defined value of false.
   206  	// If the option has not been previously set, no error occurs.
   207  	UnsetDisableEC2Metadata()
   208  
   209  	// DisableEC2Metadata returns the value set by SetDisableEC2Metadata or
   210  	// false if it has not been previously set.
   211  	DisableEC2Metadata() bool
   212  }
   213  
   214  // FinalMessageConfig is the interface for all settings related to the
   215  // cloudinit final message.
   216  type FinalMessageConfig interface {
   217  	// SetFinalMessage sets to message that will be written when the system has
   218  	// finished booting for the first time. By default, the message is:
   219  	// "cloud-init boot finished at $TIMESTAMP. Up $UPTIME seconds".
   220  	SetFinalMessage(string)
   221  
   222  	// UnsetFinalMessage unsets the value set by SetFinalMessage.
   223  	// If it has not been previously set, no error occurs.
   224  	UnsetFinalMessage()
   225  
   226  	// FinalMessage returns the value set using SetFinalMessage or an empty
   227  	// string if it has not previously been set.
   228  	FinalMessage() string
   229  }
   230  
   231  // LocaleConfig is the interface for all locale-related setting operations.
   232  type LocaleConfig interface {
   233  	// SetLocale sets the locale; it defaults to en_US.UTF-8
   234  	SetLocale(string)
   235  
   236  	// UnsetLocale unsets the option set by SetLocale, returning it to the
   237  	// cloudinit-defined default of en_US.UTF-8
   238  	// If it has not been previously set, no error occurs
   239  	UnsetLocale()
   240  
   241  	// Locale returns the locale set with SetLocale
   242  	// If it has not been previously set, an empty string is returned
   243  	Locale() string
   244  }
   245  
   246  // DeviceMountConfig is the interface for all device mounting settings.
   247  type DeviceMountConfig interface {
   248  	// AddMount adds takes arguments for installing a mount point in /etc/fstab
   249  	// The options are of the order and format specific to fstab entries:
   250  	// <device> <mountpoint> <filesystem> <options> <backup setting> <fsck priority>
   251  	AddMount(...string)
   252  }
   253  
   254  // OutputConfig is the interface for all stdout and stderr setting options.
   255  type OutputConfig interface {
   256  	// SetOutput specifies the destinations of standard output and standard error of
   257  	// particular kinds of an output stream.
   258  	// Valid values include:
   259  	//	- init:		the output of cloudinit itself
   260  	//	- config:	cloud-config caused output
   261  	//	- final:	the final output of cloudinit (plus that set with SetFinalMessage)
   262  	//	- all:		all of the above
   263  	// Both stdout and stderr can take the following forms:
   264  	//	- > file:	write to given file. Will truncate of file exists
   265  	//	- >>file:	append to given file
   266  	//	- | command:	pipe output to given command
   267  	SetOutput(OutputKind, string, string)
   268  
   269  	// Output returns the destination set by SetOutput for the given OutputKind.
   270  	// If it has not been previously set, empty strings are returned.
   271  	Output(OutputKind) (string, string)
   272  }
   273  
   274  // SSHAuthorizedKeysConfig is the interface for adding ssh authorized keys.
   275  type SSHAuthorizedKeysConfig interface {
   276  	// SetSSHAuthorizedKeys puts a set of authorized keys for the default
   277  	// user in the ~/.ssh/authorized_keys file.
   278  	SetSSHAuthorizedKeys(string)
   279  }
   280  
   281  // SSHKeysConfig is the interface for setting ssh host keys.
   282  type SSHKeysConfig interface {
   283  	// SetSSHKeys sets the SSH host keys for the machine.
   284  	SetSSHKeys(SSHKeys) error
   285  }
   286  
   287  // RootUserConfig is the interface for all root user-related settings.
   288  type RootUserConfig interface {
   289  	// SetDisableRoot sets whether ssh login to the root account of the new server
   290  	// through the ssh authorized key provided with the config should be disabled.
   291  	// This option is set to true (ie. disabled) by default.
   292  	SetDisableRoot(bool)
   293  
   294  	// UnsetDisable unsets the value set with SetDisableRoot, returning it to the
   295  	// cloudinit-defined default of true.
   296  	UnsetDisableRoot()
   297  
   298  	// DisableRoot returns the value set by SetDisableRoot or false if the
   299  	// option had not been previously set.
   300  	DisableRoot() bool
   301  }
   302  
   303  // WrittenFilesConfig is the interface for all file writing operations.
   304  type WrittenFilesConfig interface {
   305  	// AddRunTextFile simply issues some AddRunCmd's to set the contents of a
   306  	// given file with the specified file permissions on *first* boot.
   307  	// NOTE: if the file already exists, it will be truncated.
   308  	AddRunTextFile(string, string, uint)
   309  
   310  	// AddBootTextFile simply issues some AddBootCmd's to set the contents of a
   311  	// given file with the specified file permissions on *every* boot.
   312  	// NOTE: if the file already exists, it will be truncated.
   313  	AddBootTextFile(string, string, uint)
   314  
   315  	// AddRunBinaryFile simply issues some AddRunCmd's to set the binary contents
   316  	// of a given file with the specified file permissions on *first* boot.
   317  	// NOTE: if the file already exists, it will be truncated.
   318  	AddRunBinaryFile(string, []byte, uint)
   319  
   320  	// SetFileTransporter sets an alternative transporter for files added with
   321  	// AddRunBinaryFile.
   322  	SetFileTransporter(FileTransporter)
   323  }
   324  
   325  // RenderConfig provides various ways to render a CloudConfig.
   326  type RenderConfig interface {
   327  	// Renders the current cloud config as valid YAML
   328  	RenderYAML() ([]byte, error)
   329  
   330  	// Renders a script that will execute the cloud config
   331  	// It is used over ssh for bootstrapping with the manual provider.
   332  	RenderScript() (string, error)
   333  
   334  	// ShellRenderer returns the shell renderer of this particular instance.
   335  	ShellRenderer() shell.Renderer
   336  
   337  	// getCommandsForAddingPackages is a helper function which returns all the
   338  	// necessary shell commands for adding all the configured package settings.
   339  	getCommandsForAddingPackages() ([]string, error)
   340  }
   341  
   342  // PackageManagerProxyConfig provides access to the proxy settings for various
   343  // package managers.
   344  type PackageManagerProxyConfig interface {
   345  	AptProxy() proxy.Settings
   346  	AptMirror() string
   347  	SnapProxy() proxy.Settings
   348  	SnapStoreAssertions() string
   349  	SnapStoreProxyID() string
   350  	SnapStoreProxyURL() string
   351  }
   352  
   353  // Makes two more advanced package commands available
   354  type AdvancedPackagingConfig interface {
   355  	// Adds the necessary commands for installing the required packages for
   356  	// each OS is they are necessary.
   357  	AddPackageCommands(
   358  		proxyCfg PackageManagerProxyConfig,
   359  		addUpdateScripts bool,
   360  		addUpgradeScripts bool,
   361  	) error
   362  
   363  	// getPackagingConfigurer returns the PackagingConfigurer of the CloudConfig
   364  	// for the specified package manager.
   365  	getPackagingConfigurer(jujupackaging.PackageManagerName) config.PackagingConfigurer
   366  
   367  	// addRequiredPackages is a helper to add packages that juju requires in
   368  	// order to operate.
   369  	addRequiredPackages()
   370  
   371  	//TODO(bogdanteleaga): this might be the same as the exported proxy setting up above, need
   372  	//to investigate how they're used
   373  	updateProxySettings(PackageManagerProxyConfig) error
   374  }
   375  
   376  type User struct {
   377  	// Login name for the user.
   378  	Name string
   379  
   380  	// Additional groups to add the user to.
   381  	Groups []string
   382  
   383  	// Path to shell to use by default.
   384  	Shell string
   385  
   386  	// SSH keys to add to the authorized keys file.
   387  	SSHAuthorizedKeys string
   388  
   389  	// Sudo directives to add.
   390  	Sudo string
   391  }
   392  
   393  // UsersConfig is the interface for managing user additions
   394  type UsersConfig interface {
   395  	// AddUser sets a new user to be created with the given configuration.
   396  	AddUser(*User)
   397  
   398  	// UnsetUsers unsets any users set in the config, meaning the default
   399  	// user specified in the image cloud config will be used.
   400  	UnsetUsers()
   401  }
   402  
   403  // HostnameConfig is the interface for managing the hostname.
   404  type HostnameConfig interface {
   405  	// ManageEtcHosts enables or disables management of /etc/hosts.
   406  	ManageEtcHosts(manage bool)
   407  }
   408  
   409  // NetworkingConfig is the interface for managing configuration of network
   410  type NetworkingConfig interface {
   411  	// AddNetworkConfig adds network config from interfaces to the container.
   412  	AddNetworkConfig(interfaces corenetwork.InterfaceInfos) error
   413  }
   414  
   415  func WithDisableNetplanMACMatch(cfg *cloudConfig) {
   416  	cfg.omitNetplanHWAddrMatch = true
   417  }
   418  
   419  // FileTransporter is the interface set on CloudConfig when it wants to optionally
   420  // deliver files by its own means.
   421  type FileTransporter interface {
   422  	// SendBytes will ensure the payload is written to the target machine
   423  	// using the given hint in the file name (for debugging purposes).
   424  	// SendBytes returns the path on the target machine where the payload is
   425  	// stored.
   426  	SendBytes(hint string, payload []byte) string
   427  }
   428  
   429  // New returns a new Config with no options set.
   430  func New(osname string, opts ...func(*cloudConfig)) (CloudConfig, error) {
   431  	osType := ostype.OSTypeForName(osname)
   432  	r, _ := shell.NewRenderer("bash")
   433  
   434  	cfg := &cloudConfig{
   435  		osName:   osname,
   436  		renderer: r,
   437  		attrs:    make(map[string]interface{}),
   438  	}
   439  	for _, opt := range opts {
   440  		opt(cfg)
   441  	}
   442  
   443  	switch osType {
   444  	case ostype.Ubuntu:
   445  		cfg.paccmder = map[jujupackaging.PackageManagerName]commands.PackageCommander{
   446  			jujupackaging.AptPackageManager:  commands.NewAptPackageCommander(),
   447  			jujupackaging.SnapPackageManager: commands.NewSnapPackageCommander(),
   448  		}
   449  		cfg.pacconfer = map[jujupackaging.PackageManagerName]config.PackagingConfigurer{
   450  			jujupackaging.AptPackageManager: config.NewAptPackagingConfigurer(),
   451  		}
   452  		return &ubuntuCloudConfig{cfg}, nil
   453  	case ostype.CentOS:
   454  		cfg.paccmder = map[jujupackaging.PackageManagerName]commands.PackageCommander{
   455  			jujupackaging.YumPackageManager: commands.NewYumPackageCommander(),
   456  		}
   457  		cfg.pacconfer = map[jujupackaging.PackageManagerName]config.PackagingConfigurer{
   458  			jujupackaging.YumPackageManager: config.NewYumPackagingConfigurer(),
   459  		}
   460  		return &centOSCloudConfig{
   461  			cloudConfig: cfg,
   462  			helper:      centOSHelper{},
   463  		}, nil
   464  	default:
   465  		return nil, errors.NotFoundf("cloudconfig for os %q", osname)
   466  	}
   467  }
   468  
   469  // TODO: de duplicate with cloudconfig/instancecfg
   470  // SSHKeys contains SSH host keys to configure on a machine.
   471  type SSHKeys []SSHKey
   472  
   473  // TODO: de duplicate with cloudconfig/instancecfg
   474  // SSHKey is an SSH key pair.
   475  type SSHKey struct {
   476  	// Private is the SSH private key.
   477  	Private string
   478  
   479  	// Public is the SSH public key.
   480  	Public string
   481  
   482  	// PublicKeyAlgorithm contains the public key algorithm as defined by golang.org/x/crypto/ssh KeyAlgo*
   483  	PublicKeyAlgorithm string
   484  }
   485  
   486  // SSHKeyType is the type of the four used key types passed to cloudinit
   487  // through the cloudconfig
   488  type SSHKeyType string
   489  
   490  // The constant SSH key types sent to cloudinit through the cloudconfig
   491  const (
   492  	RSAPrivate     SSHKeyType = "rsa_private"
   493  	RSAPublic      SSHKeyType = "rsa_public"
   494  	DSAPrivate     SSHKeyType = "dsa_private"
   495  	DSAPublic      SSHKeyType = "dsa_public"
   496  	ECDSAPrivate   SSHKeyType = "ecdsa_private"
   497  	ECDSAPublic    SSHKeyType = "ecdsa_public"
   498  	ED25519Private SSHKeyType = "ed25519_private"
   499  	ED25519Public  SSHKeyType = "ed25519_public"
   500  )
   501  
   502  func NamesForSSHKeyAlgorithm(sshPublicKeyAlgorithm string) (private SSHKeyType, public SSHKeyType, err error) {
   503  	switch sshPublicKeyAlgorithm {
   504  	case ssh.KeyAlgoDSA:
   505  		return DSAPrivate, DSAPublic, nil
   506  	case ssh.KeyAlgoED25519:
   507  		return ED25519Private, ED25519Public, nil
   508  	case ssh.KeyAlgoRSA:
   509  		return RSAPrivate, RSAPublic, nil
   510  	case ssh.KeyAlgoECDSA256, ssh.KeyAlgoECDSA384, ssh.KeyAlgoECDSA521:
   511  		return ECDSAPrivate, ECDSAPublic, nil
   512  	}
   513  	return "", "", errors.NotValidf("ssh key type %s", sshPublicKeyAlgorithm)
   514  }
   515  
   516  // OutputKind represents the available destinations for command output as sent
   517  // through the cloudnit cloudconfig
   518  type OutputKind string
   519  
   520  // The constant output redirection options available to be passed to cloudinit
   521  const (
   522  	// the output of cloudinit iself
   523  	OutInit OutputKind = "init"
   524  	// cloud-config caused output
   525  	OutConfig OutputKind = "config"
   526  	// the final output of cloudinit
   527  	OutFinal OutputKind = "final"
   528  	// all of the above
   529  	OutAll OutputKind = "all"
   530  )