Machines: Systems under Control or Simulation
- class carthage.machine.AbstractMachineModel(*args, **kwargs)
Represents properties of a machine that do not involve interacting with an implementation of that machine. All the AbstractMachineModels in a layout can be instantiated to reason about things like network connections, configuration, and what machines will be built without instantiating any of the machines. Typically if a
Machinehas a model, the model will be made available either by setting the model property on the machine, or by providing a dependency forAbstractModelin the injector in which the machine is instantiated.The most common concrete implementation of a machine model is
carthage.modeling.MachineModel.- classmethod default_class_injection_key()
Called by
Injector.add_provider()in the single argument form to get the injection key to use when this class is added to provide a dependency.
- override_dependencies: bool | Injector | Injectable | InjectionKey = False
If True,
Machine.start_dependencies()will stop collecting dependencies at the injector of this model. In the normal situation where theMachineis instantiated within the model’s dependency context, what this means is that only system dependencies declared on the model will be started. This may also be anInjectionKey, anInjector, or anInjectable. Se the documentation ofMachine.start_dependencies().
- classmethod supplementary_injection_keys(k)
Returns an iteration of
InjectionKeysthat should be added to an injector when this class is added. The current injection key is taken as an argument so that constraints applied can modify what keys are added.
- class carthage.machine.BareMetalMachine(**kwargs)
Represents physical hardware that Carthage cannot start or stop
- async async_ready()
This may need to be overridden, but is provided as a default
- async find()
See if the machine exists. Override if it is desirable to do a dns check or similar.
- async is_machine_running()
- Returns:
Whether the machine is running
Probe whether the machine is running and set self.running appropriately. It is most important that running be set accurately when
start_machine()andstop_machine()can start or stop the machine. ForBareMetalMachineit is reasonable to assume that the machine is running. This interface point should not callssh_online()or confirm the machine is on the network.
- stamp_subdir()
The part of
stamp_path()after config.stamp_dir. For example for a podman container calledexample.comthis might bepodman/containers/example.com
- async start_machine()
Must be overridden. Start the machine.
- async stop_machine()
Must be overridden; stop the machine.
- class carthage.machine.BaseCustomization(apply_to: Machine, stamp=None, **kwargs)
- async apply()
Run setup tasks against host
- async async_ready()
This may need to be overridden, but is provided as a default
- check_stamp(stamp)
- Returns:
a tuple containing the unix time of the stamp and the text contents of the stamp. The first element of the tuple is False if the stamp does not exist
- customization_context()
Can be overridden; context in which customization tasks are run.
- classmethod default_class_injection_key()
Called by
Injector.add_provider()in the single argument form to get the injection key to use when this class is added to provide a dependency.
- description = ''
A description of the customization for inclusion in task logging
- inspect_setup_tasks()
Iterates over the setup tasks of a ninstance and provides an inspector that can determine if a task would run and what its description is.
- async last_run()
- Returns:
the most recent time any setup task on this Customization has run against the given host. Returns false if the tasks definitely need to run.
- runas_user = None
The user to run as
- property stamp_subdir
The part of
stamp_path()after config.stamp_dir. For example for a podman container calledexample.comthis might bepodman/containers/example.com
- class carthage.machine.ContainerCustomization(apply_to, **kwargs)
A customization class for running tasks on
Containerinstances orImageVolumeinstances without actually booting the container. May also run on objects providing_apply_to_container_customization()likecarthage.podman.PodmanContainer. This is valuable for tasks used in image production that want to manipulate the filesystem.
- class carthage.machine.FilesystemCustomization(apply_to, **kwargs)
A Customization class for interacting with the filesystem either of a
carthage.container.Container,ImageVolumeorMachine. If possible (for containers and image volumes), do not actually boot the machine.
- class carthage.machine.Machine(name=None, **kwargs)
Represents a machine that can be interacted with.
This is an abstract class representing the interface to machines independent of the technology being used to control them. This class can be used for:
Local VMsusing KVMVmware
VmContainers or VMs run on other infrastructure.
The main capabilities of this interface are to be able to start and stop machines, know their IP address, and connect via ssh.
- async apply_customization(cust_class, method='apply', **kwargs)
Apply a
BaseCustomizationto this machine..- Parameters:
stamp – A distinguisher for stamps created by the customization. The stamp will include this value as well as the stamp from the
setup_task().
- async dynamic_dependencies()
See
carthage.deployment.Deployable.dynamic_dependencies()for documentation. Returns technology specific networks for links where that is possible.
- filesystem_access(user=None)
An asynchronous context manager that makes the filesystem of the Machine available on a local path.
- Returns:
Path at which the filesystem can be accessed while in the context.
- async is_machine_running()
- Returns:
Whether the machine is running
Probe whether the machine is running and set self.running appropriately. It is most important that running be set accurately when
start_machine()andstop_machine()can start or stop the machine. ForBareMetalMachineit is reasonable to assume that the machine is running. This interface point should not callssh_online()or confirm the machine is on the network.
- machine_running(**kwargs)
Returns a asynchronous context manager; within the context manager, the machine is expected to be running unless
stop_machine()is explicitly called.
- machine_running_ssh_online: bool = True
Should machine_running default to calling ssh_online
- network_implementation_class: type[carthage.network.TechnologySpecificNetwork] = None
A class of
TechnologySpecificNetworkthat will be instantiated for the links on this NetworkedModel.
- rsync_uses_filesystem_access: bool = False
If true, use self.filesystem_access for rsync, otherwise use ssh.
- async run_command(*args, _bg=True, _bg_exc=False, _user=None, **kwargs)
This method is the machine-specific part of
run_command(). Override in subclasses if there is a better way to run a command than sshing into a machine. This method is async, although that is not reflected in the signature because this implementation returns an awaitable.- param user:
The user to run as. defaults to
runas_user.
This implementation calls
ssh(). Ssh has really bad quoting; it effectively removes one level of quoting from the input.This handles quoting and makes sure each argument is a separate argument on the eventual shell; it works like
carthage.container.Container.container_command()and is used to give a consistent interface byrun_command().By the time run_command is awaited, the command will have completed.
- async start_dependencies()
Interface point that should be called by
start_machine()to start any dependent machines such as routers needed by this machine.Default behavior is provided for machines with
AbstractMachineModelsattached to thennn model property. In this case, any providers ofInjectionKey(SystemDependency)with a name constraint are collected. These objects are called with an AsyncInjector. For examplecarthage.system_dependency.MachineDependencywill start some other machine and optionally wait for it to become online.In typical usage, the Machine is contained in the injector context of its model. Dependencies for the current machine may be added directly to its model’s injector. Dependencies shared among a group of machines may be added to injector contexts that contain the model. For example:
network.injector.add_provider(MachineDependency("router.network")) # But the fileserver also needs the domain controller network.fileserver_model.injector.add_provider(MachineDependency("domain-controller.network"))
But in such a situation, the router itself should not depend on itself. Two approaches are possible. The first is to mask out the dependency in the router’s model:
ignore_system_dependency(network.router_model.injector, MachineDependency("router.network"))
Another mechanism is available: the override_dependencies property of
AbstractMachineModel. This property controls how far up the injector chain to look for dependencies:- true
Only consider dependencies directly defined on the model or the Machine. Does not work correctly if the self.injector is not in the injector context of self.model.injector.
- an
Injector Filter out dependencies declared between the parent of the model injector and the provided injector, inclusive. So, consider a machine in a network in an enclave. If the enclave’s injector is provided, then injectors declared on the enclave and network will be ignored, but dependencies declared at a level larger than the enclave will still be started.
- an
Injectable Filter out dependencies between the machine model and the injector contained in the Injectable inclusive.
- an
InjectionKey Instantiate the key, and assume it is an Injectable. Treat as that injectable
For finer grain control, implementations can override this method.
- async start_machine()
Must be overridden. Start the machine.
- async stop_machine()
Must be overridden; stop the machine.
- class carthage.machine.MachineCustomization(apply_to: Machine, stamp=None, **kwargs)
A customization class for running customizations on running machines.
- property customization_context
Can be overridden; context in which customization tasks are run.
- class carthage.machine.NetworkedMixin
Represents something like a
AbstractMachineModelor acarthage.podman.PodmanPodthat generates a set of network_links from aNetworkConfig.When
resolve_networking()is called, if self.injector provides network_namespace_key, then the network_links are reused from the object providing that dependency. Typical usage is for aOciPodor similar network namespace in which aAbstractMachineModelwill be run to provide network_namespace_key.- async resolve_networking(force: bool = False)
Adds all
carthage.network.NetworkLinkobjects specified in thecarthage.network.NetworkConfigto the network_links property.- Parameters:
force – if True, resolve the network config even if it has already been resolved once.
- class carthage.machine.NetworkedModel(*args, **kwargs)
A NetworkedMixin that should be available at modeling time. Generally not a
Deployableunless no_generate_at_ready is True.
- class carthage.machine.ResolvableModel(*args, **kwargs)
In a
carthage.modeling.CarthageLayoutall the models are instantiated as part of bringing the layout to ready. This permits models to contribute to a shared understanding of networking and other global aspects of the layout.This class represents a model that can be instantiated and resolved. A layout will instantiate all
ResolvableModelobjects in the scope of its injector that have a name constraint on theirInjectionKey.This class is defined here rather than in the modeling layer so that
AbstractMachineModeldoes not need to depend on the modeling layer.Subclasses of this model will typically need to override default_class_injection_key and probably supplimentary_injection_keys.
- class carthage.machine.SshMixin
An item that accepts ssh connections.
ip_addressrepresents the endpoint to connect to in order to manage the resource via ssh. In early Carthage development, this was always an IP address. More recently, this can be an IP address or hostname.The
ssh_origininjection key is used to look up aContainerfrom which the ssh should be run. If ssh_origin is provided by the injector hierarchy, then Carthage enters the network namespace of the Container before running ssh. Note that the mount namespace is not typically used, so the host’s ssh binary and keys are used. There is support for using a Linux VRF within the namespace; seecarthage.network.access_ssh_origin()for details.If the injector hierarchy provides
ssh_jump_host, then that is used as a ProxyJump host.If neither ssh_origin nor ssh_jump_host are provided then Carthage connects directly to ip_address.
If ssh_origin is provided but not ssh_jump_host, then Carthage enters the network namespace of ssh_origin and connects to ip_address within the context of that namespace (possibly within a VRF within that namespace). DNS resolution for the connection to ip_address may be performed by the host in the host’s network namespace (systemd-resolved’sNSS plugin or similar) or it may be performed in the ssh_origin network namespace using the host’s nameserver configuration. It is best if ip_address actually is an IP address to avoid this ambiguity.
If ssh_jump_host is provided but not ssh_origin, then Carthage first connects to ssh_jump_host and tunnels a connection to ip_address within the jump host connection. The DNS resolution for the connection to ip_address is performed by the jump host; the DNS resolution for the connection to the jump host is performed by the host.
If both ssh_origin and ssh_jump_host are provided: Carthage enters the namespace of ssh_origin. Within that namespace it establishes an ssh connection to ssh_jump_host. Over that connection it tunnels to ip_address. DNS resolution for the connection to ssh_jump_host is ambiguous; it is best if ip_address is an IP address in this case. DNS resolution to ip_address is performed by ssh_jump_host.
- ip_address()
The IP address or name at which this machine should be managed.
- rsync(*args)
Call rsync with given arguments. An argument may be a
RsyncPathgenerated byrsync_path(). Such a path encapsulates a host name and a path. When rsync is called, Carthage finds the appropriate ssh_origin to select the right namespace for rsync.Typical usage:
await machine.rsync("file", rsync_path("/etc/script") #Copy file to /etc/script on machine
- rsync_path(p)
A marker in a call to
rsync()indicating that p should be copied to or from self. Interacts with the Carthage rsync machinery to select the right network namespace.
- runas_user()
The user to run commands as. Mechanisms like
carthage.become_privileged.BecomePrivilegedMixinprovide a mechanism to use a privilege gateway likesudoso that runas_user can differ fromssh_login_user. Can be set on the machine or model. Defaults to root.
- ssh_jump_host()
An
SshMixinor string to use as a jump host. Also supports aAbstractMachineModelwith amachineattribute.
- ssh_login_user()
The ssh user to log in as. Defaults to root, can be set either on the machine or the model.
- ssh_online_command = 'echo online'
The command run remotely by
ssh_online()
- ssh_rekeyed()
Indicate that this host has been rekeyed
Containers
- class carthage.container.Container(name, *, network_config, skip_ssh_keygen=False, **kwargs)
VMs
- carthage.vm.VM
alias of
Vm
Hardware Configuration
VMs and cloud instances will look for the following properties in a AbstractMachineModel to configure hardware:
- cpus
The number of CPUs on the virtual machine
- memory_mb
The amount of memory in megabytes
- disk_sizes
A sequence of disk sizes for primary and secondary disks. Provided in GiB.
- disk_config
A sequence of dicts configuring primary and secondary disks. The only key defined at this level is size, the size of the disk in GiB. If disk_config is provided, disk_sizes is ignored. The intent of disk_config is to permit MachineImplementation specific configuration of disks. Consult the specific machine implementations for details.
- nested_virt
Boolean indicating whether to allow nested virtualization
- hardware_tpm
Whether to provide a TPM in the virtual machine.
- console_needed
Whether a graphical console is needed.