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 ¢OSCloudConfig{ 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 )